From 91d1a54373188d1660241eeef1180e8d1652175d Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Mon, 17 Aug 2026 15:53:34 +0800 Subject: [PATCH] feat(i2s): add turn-on time config for mic recorder example --- .../peripherals/i2s/mic_recorder/README.md | 8 +++++- .../i2s/mic_recorder/main/Kconfig.projbuild | 12 +++++++++ .../main/mic_recorder_example_main.c | 25 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/examples/peripherals/i2s/mic_recorder/README.md b/examples/peripherals/i2s/mic_recorder/README.md index de261b1d4d6..fe1cd579a25 100644 --- a/examples/peripherals/i2s/mic_recorder/README.md +++ b/examples/peripherals/i2s/mic_recorder/README.md @@ -42,6 +42,7 @@ idf.py menuconfig In the `Example Configuration` menu: * Use `Microphone type` to select between the digital (PDM) and the analog (ES8389) microphone. +* Use `Startup data to discard (ms)` to drop the first N milliseconds of PCM after the microphone path is running. The default is 20 ms. Set it to 0 to keep every sample. Refer to the microphone datasheet for the startup delay (also called turn-on time). * The configuration menu shown below the mic type is updated automatically: * `PDM MIC Configuration` — assign the PDM clock and data GPIOs (digital microphone). * `ES8389 Codec Configuration` — assign the I2C and I2S GPIOs, plus the mic gain (analog microphone). @@ -71,7 +72,7 @@ A digital-microphone run looks like: ``` PDM MIC recording example start -------------------------------------- -I (...) mic_rec_example: Starting recording for 2 seconds! +I (...) mic_rec_example: Starting PDM recording for 2 seconds! I (...) mic_rec_example: Recording done, sending PCM data over console AUDIO_META sample_rate=16000 bits_per_sample=16 channels=2 data_size=128000 encoding=base64 AUDIO_BASE64_BEGIN @@ -123,4 +124,9 @@ Open it with [Audacity](https://www.audacityteam.org/) to listen to the recordin * Check the I2C wiring (SDA/SCL) and that `ES8389 Codec Configuration` matches your board. * Increase `Mic gain (dB)` in the `Example Configuration` menu. +* Recording starts with a pop, click, or a short stretch of invalid audio + + * Increase `Startup data to discard (ms)` in the `Example Configuration` menu. The stored recording length stays the same. + * Refer to the microphone datasheet for the startup delay (also called turn-on time). + For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/i2s/mic_recorder/main/Kconfig.projbuild b/examples/peripherals/i2s/mic_recorder/main/Kconfig.projbuild index ea64a9192c5..82c2056f2df 100644 --- a/examples/peripherals/i2s/mic_recorder/main/Kconfig.projbuild +++ b/examples/peripherals/i2s/mic_recorder/main/Kconfig.projbuild @@ -24,6 +24,18 @@ menu "Example Configuration" select CODEC_ES8389_SUPPORT endchoice + config EXAMPLE_STARTUP_DISCARD_MS + int "Startup data to discard (ms)" + default 20 + range 0 500 + help + Number of milliseconds of PCM to read and discard after the + microphone path is running, before the recording is stored. + Use this to skip the microphone or codec startup transient. + The default is 20 ms. Set to 0 to keep every sample. + Refer to the microphone datasheet for the startup delay + (also called turn-on time). + menu "PDM MIC Configuration" depends on EXAMPLE_MIC_TYPE_DMIC diff --git a/examples/peripherals/i2s/mic_recorder/main/mic_recorder_example_main.c b/examples/peripherals/i2s/mic_recorder/main/mic_recorder_example_main.c index 8cf02b759dd..2680e5c0572 100644 --- a/examples/peripherals/i2s/mic_recorder/main/mic_recorder_example_main.c +++ b/examples/peripherals/i2s/mic_recorder/main/mic_recorder_example_main.c @@ -57,6 +57,27 @@ static void capture_pcm(i2s_chan_handle_t rx_handle, uint8_t *pcm_data, size_t p } } +static void discard_startup_pcm(i2s_chan_handle_t rx_handle) +{ + const size_t bytes_to_discard = (size_t)EXAMPLE_SAMPLE_RATE * EXAMPLE_CHANNEL_COUNT * + (EXAMPLE_BITS_PER_SAMPLE / 8) * CONFIG_EXAMPLE_STARTUP_DISCARD_MS / 1000; + if (bytes_to_discard == 0) { + return; + } + + uint8_t discard_buf[EXAMPLE_DMA_READ_SIZE]; + size_t bytes_discarded = 0; + + ESP_LOGI(TAG, "Discarding the first %d ms of startup data", CONFIG_EXAMPLE_STARTUP_DISCARD_MS); + while (bytes_discarded < bytes_to_discard) { + size_t bytes_to_read = bytes_to_discard - bytes_discarded; + bytes_to_read = MIN(bytes_to_read, EXAMPLE_DMA_READ_SIZE); + size_t bytes_read = 0; + ESP_ERROR_CHECK(i2s_channel_read(rx_handle, discard_buf, bytes_to_read, &bytes_read, 1000)); + bytes_discarded += bytes_read; + } +} + static void send_pcm_as_base64(const uint8_t *pcm_data, size_t pcm_size) { unsigned char encoded_chunk[EXAMPLE_BASE64_BUFFER_SIZE]; @@ -100,6 +121,8 @@ static void record_from_pdm_microphone(uint8_t *pcm_data, size_t pcm_size) ESP_ERROR_CHECK(i2s_channel_init_pdm_rx_mode(rx_handle, &pdm_rx_cfg)); ESP_ERROR_CHECK(i2s_channel_enable(rx_handle)); + /* Discard the startup PCM to skip the microphone startup transient. */ + discard_startup_pcm(rx_handle); ESP_LOGI(TAG, "Starting PDM recording for %d seconds!", EXAMPLE_RECORD_TIME_SECONDS); capture_pcm(rx_handle, pcm_data, pcm_size); @@ -191,6 +214,8 @@ static void record_from_es8389_microphone(uint8_t *pcm_data, size_t pcm_size) ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(codec_handle, CONFIG_EXAMPLE_MIC_GAIN)); ESP_LOGI(TAG, "ES8389 codec initialized"); + /* Discard the startup PCM to skip the microphone or codec startup transient. */ + discard_startup_pcm(rx_handle); ESP_LOGI(TAG, "Starting ES8389 recording for %d seconds!", EXAMPLE_RECORD_TIME_SECONDS); capture_pcm(rx_handle, pcm_data, pcm_size);