ICS-43434 I²S Mic Issues on ESP32-S3

Kamil_Kosi
Posts: 1
Joined: Fri Mar 28, 2025 9:49 pm

ICS-43434 I²S Mic Issues on ESP32-S3

Postby Kamil_Kosi » 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 :cry: , 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
  • 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
IMAGE: Here’s a reference I²S signal from the ICS-43434 datasheet:
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

    Code: Select all

    i2s_channel_read()
    into a uint8_t array.
  • 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));
}
Possible Issues and my prediction:
  • 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! :? If you have any ideas, no matter how small, I’d be beyond grateful!
Thank you so much in advance! :lol:

MicroController
Posts: 2663
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: ICS-43434 I²S Mic Issues on ESP32-S3

Postby MicroController » Tue Apr 01, 2025 2:36 pm

As set up, the I2S returns 32-bit samples. Each sample value should contain big-endian, 'left-aligned' 24-bit data plus 8 'undefined' bits.
In the WAV file, each sample is only 16 bits in size and little-endian, so you'd have to extract from every 32-bit sample value the highest 16 bits and write them to the file, discarding the lower 16 bits.

Code: Select all

int16_t sample = (int16_t)((i2s_readraw_buff[0] << 8) | (i2s_readraw_buff[1]));
should be what you need to do, just for every sample in i2s_readraw_buff. (Note that each sample value in i2s_readraw_buff is 4 bytes in size, so the second sample value starts at i2s_readraw_buff[4], the third at i2s_readraw_buff[8] &c.)

gparvind
Posts: 4
Joined: Mon Jul 27, 2020 7:48 am

Re: ICS-43434 I²S Mic Issues on ESP32-S3

Postby gparvind » Wed Jun 18, 2025 3:15 am

@Kamil_Kosi were you able to get it working?

Who is online

Users browsing this forum: ChatGPT-User, meta-externalagent and 3 guests