SPH0645LM4H with ESP32-S3

Pippadi
Posts: 3
Joined: Mon Apr 10, 2023 4:27 am

SPH0645LM4H with ESP32-S3

Postby Pippadi » Fri Aug 25, 2023 6:48 am

It is rather well-known that the SPH0645 uses a nonstandard I2S interface (See https://www.youtube.com/watch?v=3g7l5bm7fZ8).
An ESP32-specific workaround has been circulated online. I have found a similar workaround for the ESP32-S3. The code below simply modifies the I2S RX registers to delay reading serial data by falling edge of the clock line, and subsequently force Philips mode.

There may be a better way to do this, but this is what worked for me. Hope this helps someone!
  1. #include <driver/i2s.h>
  2. #include <soc/i2s_reg.h>
  3.  
  4. #define BUF_LEN 2048
  5. #define SAMPLE_RATE 44100
  6. #define I2S_PORT I2S_NUM_0
  7.  
  8. #define DATA_PIN 7
  9. #define BCLK_PIN 4
  10. #define WS_PIN 17
  11.  
  12. void setup() {
  13.     Serial.begin(115200);
  14.  
  15.     const i2s_config_t micCfg = {
  16.         .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
  17.         .sample_rate = SAMPLE_RATE,
  18.         .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
  19.         .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
  20.         // My microphone is configured to send on the right channel.
  21.         // A bug in ESP-IDF swaps the two, so this is set to left.
  22.         // See https://github.com/espressif/esp-idf/issues/6625
  23.  
  24.         .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S),
  25.         .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
  26.         .dma_buf_count = 8,
  27.         .dma_buf_len = 1024,
  28.         .use_apll = false,
  29.         .tx_desc_auto_clear = false,
  30.         .fixed_mclk = 0,
  31.     };
  32.  
  33.     i2s_pin_config_t micPins = {
  34.         .bck_io_num = BCLK_PIN,
  35.         .ws_io_num = WS_PIN,
  36.         .data_out_num = -1,
  37.         .data_in_num = DATA_PIN,
  38.     };
  39.  
  40.     esp_err_t err;
  41.     err = i2s_driver_install(I2S_PORT, &micCfg, 0, NULL);
  42.     if (err != ESP_OK) {
  43.         Serial.println("I2S driver initialization failed");
  44.         while (true);
  45.     }
  46.  
  47.     // Delay by falling edge
  48.     REG_SET_BIT(I2S_RX_TIMING_REG(I2S_PORT), BIT(1));
  49.     // Force Philips mode
  50.     REG_SET_BIT(I2S_RX_CONF1_REG(I2S_PORT), I2S_RX_MSB_SHIFT);
  51.  
  52.     err = i2s_set_pin(I2S_PORT, &micPins);
  53.     if (err != ESP_OK) {
  54.         Serial.println("Setting pins failed");
  55.         while (true);
  56.     }
  57. }
  58.  
  59. void loop() {
  60.     static int32_t buf32[BUF_LEN];
  61.     static int16_t buf16[BUF_LEN];
  62.     size_t bytesRead;
  63.  
  64.     esp_err_t err = i2s_read(I2S_PORT, (uint8_t*) buf32, BUF_LEN*sizeof(int32_t), &bytesRead, portMAX_DELAY);
  65.     if (err != ESP_OK) {
  66.         Serial.println("Error reading from microphone");
  67.         Serial.println(err);
  68.         return;
  69.     }
  70.  
  71.     size_t samplesRead = bytesRead / sizeof(int32_t);
  72.     for (int i=0; i<samplesRead; i++) {
  73.         // Discard unused lower 12 bits. Sign bit is already where it needs to be.
  74.         buf32[i] >>= 12;
  75.         buf16[i] = (int16_t) (buf32[i] & 0xFFFF);
  76.     }
  77.  
  78.     // Do stuff with signed 16-bit little-endian samples.
  79. }

LonlyBinary
Posts: 1
Joined: Sun Feb 04, 2024 11:30 am

Re: SPH0645LM4H with ESP32-S3

Postby LonlyBinary » Sun Feb 04, 2024 11:37 am

Thank you.
I tried to use your code and he seems to work fine, but on the serial plotter it feels very unusual, it's almost quiet around me, but the values are changing very drastically.
SCR-20240204-rbqu.png
pic
SCR-20240204-rbqu.png (1000.08 KiB) Viewed 14915 times
  1. #include <Arduino.h>
  2. #include <driver/i2s.h>
  3. #include <soc/i2s_reg.h>
  4.  
  5. #define BUF_LEN     2048
  6. #define SAMPLE_RATE 16000
  7. #define I2S_PORT    I2S_NUM_0
  8.  
  9. #define DATA_PIN 38
  10. #define BCLK_PIN 21
  11. #define WS_PIN   47
  12.  
  13. void setup() {
  14.     delay(2000);
  15.     USBSerial.begin(115200);
  16.  
  17.     const i2s_config_t micCfg = {
  18.         .mode            = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
  19.         .sample_rate     = SAMPLE_RATE,
  20.         .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
  21.         .channel_format  = I2S_CHANNEL_FMT_ONLY_LEFT,
  22.         // My microphone is configured to send on the right channel.
  23.         // A bug in ESP-IDF swaps the two, so this is set to left.
  24.         // See https://github.com/espressif/esp-idf/issues/6625
  25.  
  26.         .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S),
  27.         .intr_alloc_flags     = ESP_INTR_FLAG_LEVEL1,
  28.         .dma_buf_count        = 4,
  29.         .dma_buf_len          = 8,
  30.         .use_apll             = false,
  31.         .tx_desc_auto_clear   = false,
  32.         .fixed_mclk           = 0,
  33.     };
  34.  
  35.     i2s_pin_config_t micPins = {
  36.         .bck_io_num   = BCLK_PIN,
  37.         .ws_io_num    = WS_PIN,
  38.         .data_out_num = -1,
  39.         .data_in_num  = DATA_PIN,
  40.     };
  41.  
  42.     esp_err_t err;
  43.     err = i2s_driver_install(I2S_PORT, &micCfg, 0, NULL);
  44.     if (err != ESP_OK) {
  45.         USBSerial.println("I2S driver initialization failed");
  46.         while (true)
  47.             ;
  48.     }
  49.  
  50.     // Delay by falling edge
  51.     REG_SET_BIT(I2S_RX_TIMING_REG(I2S_PORT), BIT(1));
  52.     // Force Philips mode
  53.     REG_SET_BIT(I2S_RX_CONF1_REG(I2S_PORT), I2S_RX_MSB_SHIFT);
  54.  
  55.     err = i2s_set_pin(I2S_PORT, &micPins);
  56.     if (err != ESP_OK) {
  57.         USBSerial.println("Setting pins failed");
  58.         while (true)
  59.             ;
  60.     }
  61. }
  62.  
  63. void loop() {
  64.     static int32_t buf32[BUF_LEN];
  65.     static int16_t buf16[BUF_LEN];
  66.     size_t bytesRead;
  67.  
  68.     esp_err_t err =
  69.         i2s_read(I2S_PORT, (uint8_t*)buf32, BUF_LEN * sizeof(int32_t),
  70.                  &bytesRead, portMAX_DELAY);
  71.     if (err != ESP_OK) {
  72.         USBSerial.println("Error reading from microphone");
  73.         USBSerial.println(err);
  74.         return;
  75.     }
  76.  
  77.     size_t samplesRead = bytesRead / sizeof(int32_t);
  78.     for (int i = 0; i < samplesRead; i++) {
  79.         // Discard unused lower 12 bits. Sign bit is already where it needs to
  80.         // be.
  81.         buf32[i] >>= 12;
  82.         buf16[i] = (int16_t)(buf32[i] & 0xFFFF);
  83.     }
  84.  
  85.     for (int i = 0; i < samplesRead; i++) {
  86.         // 输出样本值到串口终端
  87.         USBSerial.println(buf32[i]);
  88.     }
  89.     USBSerial.println("ok\n");
  90.     // Do stuff with signed 16-bit little-endian samples.
  91. }

Pippadi
Posts: 3
Joined: Mon Apr 10, 2023 4:27 am

Re: SPH0645LM4H with ESP32-S3

Postby Pippadi » Sat Feb 17, 2024 7:47 am

In my case at least, it seems to pick up a lot of noise. At times, the fan in the room is louder than my voice, even when I'm right next to it.

Going by the graph in the datasheet, the microphone is more sensitive to higher frequencies. I guess the noise is more of a problem with the microphone :)

Who is online

Users browsing this forum: No registered users and 96 guests