espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.61k stars 7.27k forks source link

I2S unexplained issue (IDFGH-11126) #12296

Closed dacattack closed 11 months ago

dacattack commented 1 year ago

Board esp32dev

Device Description esp32dev

Hardware Configuration GPIO 25,32,33 are WS,BCK,SD pins for the i2s connection with the INMP441 MEMS microphone

Version v2.0.4

IDE Name I've tested it in Arduino IDE and VS Code with PlatformIO

Operating System Windows 10

Flash frequency 80 MHz

PSRAM enabled no

Upload speed 921600

Description I have a simple code to plot the INMP441 audio input into the Serial Plotter. However I find two major issues after testing the code: -The sample rate does not match with the sample rate I set in the i2s_config structure. In fact, is the half of the frequency i set up in the .sample_rate variable. For instance, in my case, setting up the sample rate to 44.1KHz will mean that sound frequencies above 11025 Hz won’t be captured by the microphone. If I set up to 88.2KHz then it will capture sound waves untill 22.5 KHz.

#include <driver/i2s.h>

#define I2S_BCK_PIN 32
#define I2S_SD_PIN 33
#define I2S_WS_PIN 25
#define I2S_PORT I2S_NUM_0

const uint8_t dma_count=8;
const uint16_t dma_len=256;

void i2s_install(){
 const i2s_config_t i2s_config={
   .mode=i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
   .sample_rate=44100,
   .bits_per_sample=I2S_BITS_PER_SAMPLE_16BIT,
   .channel_format=I2S_CHANNEL_FMT_ONLY_LEFT,
   .communication_format= i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S),
   .intr_alloc_flags=ESP_INTR_FLAG_LEVEL1,
   .dma_buf_count=dma_count,
   .dma_buf_len=dma_len,
   .use_apll=false,  
   .tx_desc_auto_clear = true,
   .mclk_multiple = I2S_MCLK_MULTIPLE_256,
 };

 const i2s_pin_config_t pin_config={
   .bck_io_num=I2S_BCK_PIN,
   .ws_io_num=I2S_WS_PIN,
   .data_out_num=I2S_PIN_NO_CHANGE,
   .data_in_num=I2S_SD_PIN
 };

 i2s_driver_install(I2S_PORT,&i2s_config,0,NULL);
 i2s_set_pin(I2S_PORT,&pin_config);
}

void setup(){
   i2s_install();
   Serial.begin(115200);
   Serial.printf("Inicio del programa de comunicación con el micrófono MEMS INMP441 mediante protocolo I2S.\nSe utilizará el Serial Plotter para visualizar los datos de audio.\n ");
   delay(2000);
}
void loop(){
   size_t bytes_read=0;
   int16_t samples=dma_len*dma_count;
   int32_t buffer[samples]; 
   uint16_t samples_read=0;

   esp_err_t i2s_err= i2s_read(I2S_PORT,&buffer,samples*sizeof(int16_t),&bytes_read,portMAX_DELAY);
   samples_read=bytes_read/sizeof(int32_t);
   if(i2s_err==ESP_OK){
        for(uint16_t i=0; i<samples; i++){
         Serial.println(buffer[i]);
        }
    }
}
SlimyRedstone commented 12 months ago

The INMP441 characteristic's are: (see page 11 & 12 in the datasheet here)

You need to set:

Other than that, I strongly recommend you to use a newer version of IDF (eg. v5.1), because many things have changed since v2.0 and are better in later version.

L-KAYA commented 11 months ago

Thanks @SlimyRedstone for the reply! Just one more supplement, bits_per_chan should be set to I2S_BITS_PER_CHAN_32BIT while bits_per_sample is I2S_DATA_BIT_WIDTH_24BIT.

And please migrate to the newer IDF version since v5.0 if possible, which I2S driver is redesigned and more stable.

dacattack commented 11 months ago

Thanks for your replies. There wasn't a single factor involved, but rather many that contributed to the issue I was experiencing. Some of these factors have already been mentioned by you above, but there's something else. -Bits per sample was set to 32 bits. Then the following 12 bits are ruled out ( last 8 bytes are high impedance bytes and the following 4 bits are useless noise bits). -Slot width or bits per channel must be set to 32 bits. And now there's another important thing: -There are issues with the ESP-IDF I2S library. In my project, I'm using version 5.1.1 of ESP-IDF, and surprisingly, it has the left and right channels swapped. To fix this, in the i2s_config structure, we must change the .channel_format value to "right" instead of "left" if we want to capture the left channel coming from the MEMS microphone: .channel_format=I2S_CHANNEL_FMT_ONLY_RIGHT. I started to figure this out when I tried the same code inside the 1.8.18 version of Arduino IDE where the code worked. That's because that Arduino version was using an older ESP-IDF version. Hope this works for anyone reading this.

L-KAYA commented 11 months ago

Thanks for your further investigation!

Channel swapping issue should not exist on the new I2S driver but might occur in the legacy driver, it's related to the slot_bit_width and msb_right on ESP32 (see the default config).

I would say it's kind of a workaround in the software. The legacy I2S driver coupled a lot with such issues, meanwhile msb_right is not a public configuration, so swap the channel can be the best solution in application.

That's why recommend to migrate to the new I2S driver which is more stable and has less known issues