ICS-43434 I²S Mic Issues on ESP32-S3
Posted: Sat Mar 29, 2025 8:40 am
Hello everyone,
I've been troubleshooting my I²S microphone ICS-43434 with an ESP32-S3 for the past week
, but I'm facing an issue where the recorded values remain around ±20 and do not respond to sound, even when playing loud music.
Microphone and I²S Configuration
https://media-hosting.imagekit.io/43de7 ... Lg0CpO6w__
IMAGE: The ESP32-S3 and microphone are on a custom PCB, and I’ve verified the I²S signal using a Saleae logic analyzer:
https://media-hosting.imagekit.io/17cf6 ... WGtwwX2A__
Problem Description
The captured I²S signal looks correct, but when processing the audio with the ESP32-S3, the values stay around ±20 and do not respond to sound.
What I’ve Tried So Far
IMAGE: Here’s a terminal output screenshot showing the issue:
https://media-hosting.imagekit.io/ef444 ... hAU6nOgQ__
CODE: My modified recorder example
Possible Issues and my prediction:
I'm truly stuck on this issue, and any insights or suggestions would mean the world to me!
If you have any ideas, no matter how small, I’d be beyond grateful!
Thank you so much in advance!
I've been troubleshooting my I²S microphone ICS-43434 with an ESP32-S3 for the past week
Microphone and I²S Configuration
- ICS-43434 from InvenSense
- 24-bit I²S interface
- 32-bit word length
- 1-bit shift (I believe - Philips preset)
- Only the left channel is transmitted - hardware configuration
https://media-hosting.imagekit.io/43de7 ... Lg0CpO6w__
IMAGE: The ESP32-S3 and microphone are on a custom PCB, and I’ve verified the I²S signal using a Saleae logic analyzer:
https://media-hosting.imagekit.io/17cf6 ... WGtwwX2A__
Problem Description
The captured I²S signal looks correct, but when processing the audio with the ESP32-S3, the values stay around ±20 and do not respond to sound.
What I’ve Tried So Far
- My code is based on the ESP-IDF I²S recorder example, with the following modifications:
- Changed the microphone configuration from PDM to Standard I²S (STD mode).
- Initially saved data to an SD card, but only noise was recorded.
- To debug, I commented out the write function and observed the raw data. - I read data using into a uint8_t array.
Code: Select all
i2s_channel_read() - Since I²S slots are 32-bit, I attempted to reconstruct the audio by combining the first two bytes of each sample.
- However, the values still don’t react to sound.
IMAGE: Here’s a terminal output screenshot showing the issue:
https://media-hosting.imagekit.io/ef444 ... hAU6nOgQ__
CODE: My modified recorder example
Code: Select all
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* I2S Digital Microphone Recording Example */
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_system.h"
#include "esp_vfs_fat.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "driver/gpio.h"
#include "driver/spi_common.h"
#include "sdmmc_cmd.h"
#include "format_wav.h"
#include "esp_log.h"
static const char *TAG = "std_rec_example";
#define CONFIG_EXAMPLE_BIT_SAMPLE 32
#define CONFIG_EXAMPLE_SAMPLE_RATE 44100
#define CONFIG_EXAMPLE_SPI_MOSI_GPIO GPIO_NUM_5
#define CONFIG_EXAMPLE_SPI_MISO_GPIO GPIO_NUM_2
#define CONFIG_EXAMPLE_SPI_SCLK_GPIO GPIO_NUM_4
#define CONFIG_EXAMPLE_SPI_CS_GPIO GPIO_NUM_6
#define CONFIG_EXAMPLE_I2S_BCLK_GPIO GPIO_NUM_40
#define CONFIG_EXAMPLE_I2S_DATA_GPIO GPIO_NUM_41
#define CONFIG_EXAMPLE_I2S_WS_GPIO GPIO_NUM_39
#define CONFIG_EXAMPLE_REC_TIME 5
#define SPI_DMA_CHAN SPI_DMA_CH_AUTO
#define NUM_CHANNELS (1) // For mono recording only!
#define SD_MOUNT_POINT "/sdcard"
#define SAMPLE_SIZE (CONFIG_EXAMPLE_BIT_SAMPLE * 1024)
#define BYTE_RATE (CONFIG_EXAMPLE_SAMPLE_RATE * (CONFIG_EXAMPLE_BIT_SAMPLE / 8)) * NUM_CHANNELS
// When testing SD and SPI modes, keep in mind that once the card has been
// initialized in SPI mode, it can not be reinitialized in SD mode without
// toggling power to the card.
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
sdmmc_card_t *card;
i2s_chan_handle_t rx_handle = NULL;
static uint8_t i2s_readraw_buff[SAMPLE_SIZE * 2];
size_t bytes_read;
const int WAVE_HEADER_SIZE = 44;
void mount_sdcard(void)
{
esp_err_t ret;
// Options for mounting the filesystem.
// If format_if_mount_failed is set to true, SD card will be partitioned and
// formatted in case when mounting fails.
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = true,
.max_files = 5,
.allocation_unit_size = 8 * 1024
};
ESP_LOGI(TAG, "Initializing SD card");
spi_bus_config_t bus_cfg = {
.mosi_io_num = CONFIG_EXAMPLE_SPI_MOSI_GPIO,
.miso_io_num = CONFIG_EXAMPLE_SPI_MISO_GPIO,
.sclk_io_num = CONFIG_EXAMPLE_SPI_SCLK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
ret = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CHAN);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize bus.");
return;
}
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = CONFIG_EXAMPLE_SPI_CS_GPIO;
slot_config.host_id = host.slot;
ret = esp_vfs_fat_sdspi_mount(SD_MOUNT_POINT, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem.");
} else {
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
}
return;
}
// Card has been initialized, print its properties
sdmmc_card_print_info(stdout, card);
}
void record_wav(uint32_t rec_time)
{
// Use POSIX and C standard library functions to work with files.
int flash_wr_size = 0;
ESP_LOGI(TAG, "Opening file");
uint32_t flash_rec_time = BYTE_RATE * rec_time;
const wav_header_t wav_header =
WAV_HEADER_PCM_DEFAULT(flash_rec_time, 16, CONFIG_EXAMPLE_SAMPLE_RATE, 1);
// First check if file exists before creating a new file.
struct stat st;
if (stat(SD_MOUNT_POINT"/record.wav", &st) == 0) {
// Delete it if it exists
unlink(SD_MOUNT_POINT"/record.wav");
}
// Create new WAV file
FILE *f = fopen(SD_MOUNT_POINT"/record.wav", "a");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
// Write the header to the WAV file
fwrite(&wav_header, sizeof(wav_header), 1, f);
// Start recording
while (flash_wr_size < flash_rec_time) {
// Read the RAW samples from the microphone
if (i2s_channel_read(rx_handle, (char *)i2s_readraw_buff, SAMPLE_SIZE, &bytes_read, 1000) == ESP_OK) {
printf("[0] %u [1] %u [2] %u [3]%u [4] %u [5] %u [6] %u [7]%u...\n", i2s_readraw_buff[0], i2s_readraw_buff[1], i2s_readraw_buff[2], i2s_readraw_buff[3], i2s_readraw_buff[4], i2s_readraw_buff[5], i2s_readraw_buff[6], i2s_readraw_buff[7]);
// For debuging purposes
int16_t sample = (int16_t)((i2s_readraw_buff[0] << 8) | (i2s_readraw_buff[1]));
printf("%d\n", sample);
// Write the samples to the WAV file
//fwrite(i2s_readraw_buff, bytes_read, 1, f);
flash_wr_size += bytes_read;
} else {
printf("Read Failed!\n");
}
}
ESP_LOGI(TAG, "Recording done!");
fclose(f);
ESP_LOGI(TAG, "File written on SDCard");
// All done, unmount partition and disable SPI peripheral
esp_vfs_fat_sdcard_unmount(SD_MOUNT_POINT, card);
ESP_LOGI(TAG, "Card unmounted");
// Deinitialize the bus after all devices are removed
spi_bus_free(host.slot);
}
void init_microphone(void)
{
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, NULL, &rx_handle));
i2s_std_config_t std_cfg = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(CONFIG_EXAMPLE_SAMPLE_RATE),
.slot_cfg = {
.data_bit_width = I2S_DATA_BIT_WIDTH_32BIT,
.slot_bit_width = I2S_SLOT_BIT_WIDTH_32BIT,
.slot_mode = I2S_SLOT_MODE_MONO,
.slot_mask = I2S_STD_SLOT_LEFT,
.ws_width = I2S_DATA_BIT_WIDTH_32BIT,
.ws_pol = false,
.bit_shift = true,
.left_align = true,
.big_endian = true,
.bit_order_lsb = false
},
.gpio_cfg = {
.bclk = CONFIG_EXAMPLE_I2S_BCLK_GPIO,
.din = CONFIG_EXAMPLE_I2S_DATA_GPIO,
.ws = CONFIG_EXAMPLE_I2S_WS_GPIO,
.invert_flags = {
.bclk_inv = false, //mogoče samo tukaj treba true
},
},
};
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
}
void app_main(void)
{
printf("STD microphone recording example start\n--------------------------------------\n");
// Mount the SDCard for recording the audio file
mount_sdcard();
// Acquire a I2S PDM channel for the PDM digital microphone
init_microphone();
ESP_LOGI(TAG, "Starting recording for %d seconds!", CONFIG_EXAMPLE_REC_TIME);
// Start Recording
record_wav(CONFIG_EXAMPLE_REC_TIME);
// Stop I2S driver and destroy
ESP_ERROR_CHECK(i2s_channel_disable(rx_handle));
ESP_ERROR_CHECK(i2s_del_channel(rx_handle));
}
- Am I misinterpreting how the ESP32-S3 handles 24-bit I²S data?
- Is there a better way to extract meaningful audio data from the 32-bit slots?
I'm truly stuck on this issue, and any insights or suggestions would mean the world to me!
Thank you so much in advance!