0
\$\begingroup\$

I would like to use a digital I2S microphone to record audio and store it as wav on a PC, preferably over serial connection. I have tried this with the boards ESP32 dev kit v1, MKR Wifi 1010 and Adafruit Feather M0 in combination with the microphones SPH0645 or INMP441, but never succeeded.

Here are the example programs for the use of the ESP32 dev kit v1 with the SPH0645 from Adafruit (https://learn.adafruit.com/adafruit-i2s-mems-microphone-breakout).

Arduino code:

#include <driver/i2s.h>

const i2s_port_t I2S_PORT = I2S_NUM_0;

void setup() {
  Serial.begin(115200);
  Serial.println("Configuring I2S...");

  const i2s_config_t i2s_config = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate = 16000,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
    .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 8, // Increased buffer count
    .dma_buf_len = 64   // Increased buffer length
};

  const i2s_pin_config_t pin_config = {
    .bck_io_num = 33,   // BCKL
    .ws_io_num = 25,    // LRCL
    .data_out_num = -1, // not used (only for speakers)
    .data_in_num = 32   // DOUT
  };

  esp_err_t err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
  if (err != ESP_OK) {
    Serial.printf("Failed installing driver: %d\n", err);
    while (true);
  }

  err = i2s_set_pin(I2S_PORT, &pin_config);
  if (err != ESP_OK) {
    Serial.printf("Failed setting pin: %d\n", err);
    while (true);
  }

  Serial.println("I2S driver installed.");
}

void loop() {
  // Wait for the start command from the Python script
  if (Serial.available() > 0) {
    char command = Serial.read();
    if (command == 's') { // Start command received
      int duration = 10; // Recording duration in seconds
      int sample_rate = 16000; // Same as the ESP32 sample rate
      int samples_to_send = duration * sample_rate;
      
      for (int i = 0; i < samples_to_send; i++) {
        int32_t sample = 0;
        size_t bytes_read;
        i2s_read(I2S_PORT, &sample, 4, &bytes_read, portMAX_DELAY); // no timeout
        if (bytes_read > 0) {
          sample >>= 14;
          int16_t out = sample;
          Serial.println(out);
        }
      }
      Serial.write('e'); // Send an end signal to the Python script
    }
  }
}

Python code:

import serial
import datetime
import wave

# open a serial connection to the Arduino
ser = serial.Serial('COM16', 115200)

# ask the user for the length of the audio in seconds
length = int(input("Enter the length of the recording in seconds: "))

# get the current date and time
now = datetime.datetime.now()

# create a filename with a datetimestamp
filename = "recording_{}.wav".format(now.strftime("%Y-%m-%d_%H-%M-%S"))

# set the WAV file parameters
channels = 1
sample_width = 2 # 2 bytes per sample
sample_rate = 16000

# open a file for writing the audio data
with wave.open(filename, 'wb') as f:
    # set the WAV file parameters
    f.setnchannels(channels)
    f.setsampwidth(sample_width)
    f.setframerate(sample_rate)

    # read audio data from the serial port and write it to the file
    for i in range(length*sample_rate):
        data = ser.read(2)
        if data:
            f.writeframes(data)

# close the serial connection
ser.close()

print("Recording saved as {}".format(filename))

The above setup with the ESP32 dev kit v1 and the SPH0645 results in a wav file with the correct file structure (44 byte header etc.) but a signal that doesn't show the expected amplitudes and spectrogram features. It rather looks interrupted and distorted (see image).

Capture

Has anyone tried this and could help me figure out the correct hardware and code setup to achieve a successful recording?

\$\endgroup\$
8
  • \$\begingroup\$ What would you consider as successful recording? Please note that a baud rate of 115200 allows you to sample 16-bit data in real time at sampling rate of 5760 Hz, which is quite useless, as it allows to produce frequencies up to 2880 Hz, so worse than landline phones. \$\endgroup\$
    – Justme
    Apr 18, 2023 at 16:30
  • \$\begingroup\$ Good point. I am aiming for at least a 16 kHz sampling rate. I am basically looking for an I2S digital USB microphone solution. \$\endgroup\$
    – VGF
    Apr 18, 2023 at 17:10
  • \$\begingroup\$ An USB serial port can't be an USB audio device. Switch to USB and make the MCU look like an USB audio device. \$\endgroup\$
    – Justme
    Apr 18, 2023 at 17:41
  • 2
    \$\begingroup\$ Why are you starting with an i2s microphone? There are so many easier ways to get microphone signals into a PC for recording. \$\endgroup\$ Apr 18, 2023 at 20:21
  • 1
    \$\begingroup\$ some context would be helpful here as there is a serious amount of wheel-reinvention going on. What is the OP actually trying to achieve? is this for fun, a school project, is the project driven by a real world requirement? what is the story? \$\endgroup\$
    – danmcb
    Nov 8, 2023 at 10:35

2 Answers 2

0
\$\begingroup\$

ESP32

For something ESP32 based, one should use hardware which has native USB, such as the ESP32-S2 and the ESP32-S3. The official ESP-IDF does not have any examples for USB Audio. But the USB implementation is based on TinyUSB, so with some adaptation it is probably possible to use some of the TinyUSB audio examples.

There are other microcontroller platforms which are a bit more plug-and-play for this usecase.

RP2040

There is a microphone library for the RP2040 microcontroller. It has a ready-to-run example for USB microphone. It can be used with a standard RP2040 development board. But there also exists dedicated open-source hardware kits, such as mico.

STM32

For STM32 there is an official firmware package called X-CUBE-USB-AUDIO. It has example code for digital. Work with a wide range of devices/boards, such as those based on STM32L4xx, STM32F4xx et.c. And example hardware project walkthrough for STM32 by Andy Brown.

Plug-and-play hardware

There exists off-the-shelf hardware solutions for using I2S/PDM digital MEMS microphones with a computer. An example would be MiniDSP MCHStreamer.

\$\endgroup\$
0
\$\begingroup\$

It might be because you've set the the sampling frequency too low, the range is mentioned as "32-64 kHz" in this mems I2S datasheet taken from the Adafruit product site for the development board

But it also depends where you get your device from: This datasheet from makers portal shows it may work with a range that is different (different min Fsck=0.5 MHz instead of 2048 kHz)


Haven't gotten a working example on the esp32 dev module but have found success using a Raspberry Pi 3b+.

Here's some useful links for the raspberry pi:

Enabling i2s audio with the mems mic

  1. Follow this blog, Note: As of this post, doesn't work on bookworm, only buster
  2. sudo apt-get install libopenblas-dev, if you have any problems running the example

Enabling i2c

  1. Follow the OG tutorial

Self Hosted WiFi manager web app

  1. curl -sL https://install.raspap.com | bash -s -- --yes, https://docs.raspap.com
  2. Go to the pi's address @ port 80 in your browser
@wifi web portal 
user: admin
pass secret
  1. The hotspot tab should allow you to configure a WiFi hotspot

Fing is also a great app for finding the pi on your network, you can get it on your phone or desktop for free.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.