diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index 374f3bf6282..05f4a093fb1 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -449,7 +449,7 @@ The examples of the I2S driver can be found in the directory :example:`periphera Standard TX/RX Usage ^^^^^^^^^^^^^^^^^^^^ -- :example:`peripherals/i2s/i2s_codec/i2s_es8311` demonstrates how to use the I2S ES8311 audio codec with {IDF_TARGET_NAME} to play music or echo sounds, featuring high performance and low power multi-bit delta-sigma audio ADC and DAC, with options to customize music and adjust mic gain and volume. +- :example:`peripherals/i2s/wav_player` demonstrates how to play an embedded WAV file through I2S STD TX to an ES8311 or ES8389 codec DAC on {IDF_TARGET_NAME}. - :example:`peripherals/i2s/i2s_basic/i2s_std` demonstrates how to use the I2S standard mode in either simplex or full-duplex mode on {IDF_TARGET_NAME}. - :example:`peripherals/i2s/mic_recorder` demonstrates how to record audio from an analog microphone connected to an ES8389 codec through the I2S STD interface. diff --git a/docs/zh_CN/api-reference/peripherals/i2s.rst b/docs/zh_CN/api-reference/peripherals/i2s.rst index 2d472aa6a9b..7fc0704533b 100644 --- a/docs/zh_CN/api-reference/peripherals/i2s.rst +++ b/docs/zh_CN/api-reference/peripherals/i2s.rst @@ -449,7 +449,7 @@ I2S 驱动例程请参考 :example:`peripherals/i2s` 目录。以下为每种模 标准 TX/RX 模式的应用 ^^^^^^^^^^^^^^^^^^^^^ -- :example:`peripherals/i2s/i2s_codec/i2s_es8311` 演示了如何在 {IDF_TARGET_NAME} 上使用 I2S ES8311 音频编解码器来播放音乐或回声,具有高性能和低功耗的多位 delta-sigma 音频 ADC 和 DAC,提供自定义音乐、调整麦克风增益和音量的选项。 +- :example:`peripherals/i2s/wav_player` 演示了如何在 {IDF_TARGET_NAME} 上使用 I2S STD TX,将嵌入的 WAV 音频通过 ES8311 或 ES8389 音频编解码器播放。 - :example:`peripherals/i2s/i2s_basic/i2s_std` 演示了如何在 {IDF_TARGET_NAME} 上以单工或全双工模式使用 I2S 标准模式。 - :example:`peripherals/i2s/mic_recorder` 演示了如何通过 I2S STD 接口,使用 ES8389 音频编解码器录制模拟麦克风的音频。 diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 565c3171c17..eaa584f299e 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -241,17 +241,6 @@ examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm: - esp_hal_i2s - soc -examples/peripherals/i2s/i2s_codec/i2s_es8311: - disable: - - if: (SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1) - reason: rely on I2S STD mode and I2C to config es7210 - depends_components: - - esp_driver_dma - - esp_driver_i2s - - esp_driver_i2c - - esp_hal_i2s - - soc - examples/peripherals/i2s/mic_recorder: disable: - if: SOC_I2S_SUPPORTED != 1 @@ -260,6 +249,17 @@ examples/peripherals/i2s/mic_recorder: - esp_hal_i2s - soc +examples/peripherals/i2s/wav_player: + disable: + - if: (SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1) + reason: rely on I2S STD TX and I2C to configure the DAC codec + depends_components: + - esp_driver_dma + - esp_driver_i2s + - esp_driver_i2c + - esp_hal_i2s + - soc + examples/peripherals/i3c/i3c_i2c_basic: disable: - if: SOC_I3C_MASTER_SUPPORTED != 1 diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md b/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md deleted file mode 100644 index 1d30dbb9f6b..00000000000 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md +++ /dev/null @@ -1,163 +0,0 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | - -# I2S ES8311 Example - -(See the README.md file in the upper level 'examples' directory for more information about examples.) - -In this example, you can choose music mode or echo mode in menuconfig. In music mode, the example will play a piece of music in 'canon.pcm', and in echo mode, you can hear what you said in earphone. - -## ES8311 brief - -ES8311 low power mono audio codec features: - -- High performance and low power multi-bit delta-sigma audio ADC and DAC -- I2S/PCM master or slave serial data port -- I2C interface for configuration -- ADC: 24-bit, 8 to 96 kHz sampling frequency -- ADC: 100 dB signal to noise ratio, -93 dB THD+N -- DAC: 24-bit, 8 to 96 kHz sampling frequency -- DAC: 110 dB signal to noise ratio, -80 dB THD+N - -For more details, see [ES8311 datasheet](http://www.everest-semi.com/pdf/ES8311%20PB.pdf) - -## How to Use Example - -### Hardware Required - -* A development board with any supported Espressif SOC chip (see `Supported Targets` table above) - * The example can be preconfigured for [ESP-BOX](https://components.espressif.com/components/espressif/esp-box), [ESP32-S2-Kaluga-kit](https://components.espressif.com/components/espressif/esp32_s2_kaluga_kit) and [ESP32-S3-LCD-EV-board](https://components.espressif.com/components/espressif/esp32_s3_lcd_ev_board). More information is in 'Configure the Project' section. -* A USB cable for power supply and programming. -* A board with ES8311 codec, mic and earphone interface(e.g. ESP-LyraT-8311A extension board). - -### Connection -``` -┌─────────────────┐ ┌──────────────────────────┐ -│ ESP │ │ ES8311 │ -│ │ │ │ -│ I2S_MCK_IO├──────────►│PIN2-MCLK │ -│ │ │ │ ┌─────────┐ -│ I2S_BCK_IO├──────────►│PIN6-BCLK PIN12-OUTP├───────────┤ │ -│ │ │ │ │ EARPHONE│ -│ I2S_WS_IO├──────────►│PIN8-LRCK PIN13-OUTN├───────────┤ │ -│ │ │ │ └─────────┘ -│ I2S_DO_IO├──────────►│PIN9-SDIN │ -│ │ │ │ -│ I2S_DI_IO│◄──────────┤PIN7-SDOUT │ -│ │ │ │ ┌─────────┐ -│ │ │ PIN18-MIC1P├───────────┤ │ -│ I2C_SCL_IO├──────────►│PIN1 -CCLK │ │ MIC │ -│ │ │ PIN17-MIC1N├───────────┤ │ -│ I2C_SDA_IO│◄─────────►│PIN19-CDATA │ └─────────┘ -│ │ │ │ -│ VCC 3.3├───────────┤VCC │ -│ │ │ │ -│ GND├───────────┤GND │ -└─────────────────┘ └──────────────────────────┘ -``` -Note: Since ESP32-C3 & ESP32-H2 board does not have GPIO 16/17, you can use other available GPIOs instead. In this example, we set GPIO 6/7 as I2C pins for ESP32-C3 and GPIO 8/9 ESP32-H2 and GPIO 16/17 for other chips, same as GPIO 18/19, we use GPIO 2/3 instead. - -### Dependency - -This example is based on [esp_codec_dev component](https://components.espressif.com/components/espressif/esp_codec_dev) - -The component can be installed by [IDF Component Manager](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html). This example already includes it. If you want to install [esp_codec_dev component](https://components.espressif.com/components/espressif/esp_codec_dev) separately in your project, you can input the following command: -``` -idf.py add-dependency "espressif/esp_codec_dev^1.3.4" -``` - -If the dependency is added, you can check `idf_component.yml` for more detail. When building this example or other projects with managed components, the component manager will search for the required components online and download them into the `managed_components` folder. - -### Configure the Project - -``` -idf.py menuconfig -``` -You can find configurations for this example in 'Example Configuration' tag. - -* In 'Example mode' subtag, you can set the example mode to 'music' or 'echo'. You can hear a piece of music in 'music' mode and echo the sound sampled by mic in 'echo' mode. You can also customize you own music to play as shown below. - -* In 'Set MIC gain' subtag, you can set the mic gain for echo mode. - -* In 'Voice volume', you can set the volume between 0 to 100. - -* In 'Enable Board Support Package (BSP) support' you can enable support for BSP. You can pick specific BSP in [idf_component.yml](main/idf_component.yml). - -### Build and Flash - -Build the project and flash it to the board, then run monitor tool to view serial output: - -``` -idf.py -p PORT flash monitor -``` - -(To exit the serial monitor, type ``Ctrl-]``.) - -See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. - -## Example Output - -Running this example in music mode, you can hear a piece of music (canon), the log is shown as follow: - -``` -I (348) I2S: DMA Malloc info, datalen=blocksize=1200, dma_desc_num=6 -I (348) I2S: DMA Malloc info, datalen=blocksize=1200, dma_desc_num=6 -I (358) I2S: I2S0, MCLK output by GPIO0 -I (368) DRV8311: ES8311 in Slave mode -I (378) gpio: GPIO[10]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 -I (3718) i2s_es8311: I2S music played, 213996 bytes are written. -I (7948) i2s_es8311: I2S music played, 213996 bytes are written. -...... -``` - -Running this example in echo mode, you can hear the sound in earphone that collected by mic. -``` -I (312) I2S: DMA Malloc info, datalen=blocksize=1200, dma_desc_num=6 -I (312) I2S: DMA Malloc info, datalen=blocksize=1200, dma_desc_num=6 -I (322) I2S: I2S0, MCLK output by GPIO0 -I (332) DRV8311: ES8311 in Slave mode -I (342) gpio: GPIO[10]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 -``` - -If you have a logic analyzer, you can use a logic analyzer to grab GPIO signal directly. The following table describes the pins we use by default (Note that you can also use other pins for the same purpose). - -| pin name| function | gpio_num | -|:---:|:---:|:---:| -| MCLK |module clock | GPIO_NUM_0| -| BCLK |bit clock | GPIO_NUM_4 | -| WS |word select | GPIO_NUM_5 | -| SDOUT |serial data out| GPIO_NUM_18/2 | -| SDIN |serial data in | GPIO_NUM_19/3 | - -Other pins like I2C please refer to `example_config.h`. - -Please note that the power amplifier on some development boards (like P4 EV board) are disabled by default, you might need to set the PA_CTRL pin to high to play the music via a speaker. -The PA_CTRL pin can be configured by `idf.py menuconfig`, please check if the PA_CTRL pin is correct on your board if the audio can only be played from the earphones but not the speaker. - -### Customize your own music - -The example have contained a piece of music in canon.pcm, if you want to play your own music, you can follow these steps: - -1. Choose the music in any format you want to play (e.g. a.mp3) -2. Install 'ffmpeg' tool -3. Check your music format using ```ffprobe a.mp3```, you can get the stream format (e.g. Stream #0.0: Audio: mp3, 44100Hz, stereo, s16p, 64kb/s) -4. Cut your music since there is no enough space for the whole piece of music. ```ffmpeg -i a.mp3 -ss 00:00:00 -t 00:00:20 a_cut.mp3``` -5. Transfer the music format into .pcm. ```ffmpeg -i a_cut.mp3 -f s16le -ar 16000 -ac 2 -acodec pcm_s16le a.pcm``` -6. Move 'a.pcm' under 'main' directory -7. Replace 'canon.pcm' with 'a.pcm' in 'CMakeLists.txt' under 'main' directory -8. Replace '_binary_canon_pcm_start' and '_binary_canon_pcm_end' with '_binary_a_pcm_start' and '_binary_a_pcm_end' in `i2s_es8311_example.c` -9. Download the example and enjoy your own music - -## Troubleshooting - -* Program upload failure - - * Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs. - * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. - -* Failed to get audio from specker - - * The PA (Power Amplifier) on some dev-kits might be disabled by default, please check the schematic to see if PA_CTRL is connected to any GPIO or something. - * Pull-up the PA_CTRL pin either by setting that GPIO to high or by connecting it to 3.3V with a jump wire should help. - -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/i2s_codec/i2s_es8311/main/CMakeLists.txt b/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/CMakeLists.txt deleted file mode 100644 index e757853d56b..00000000000 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -idf_component_register(SRCS "i2s_es8311_example.c" - PRIV_REQUIRES esp_driver_i2s esp_driver_i2c esp_driver_gpio - EMBED_FILES "canon.pcm") diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/Kconfig.projbuild b/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/Kconfig.projbuild deleted file mode 100644 index acd2c34a6ba..00000000000 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/Kconfig.projbuild +++ /dev/null @@ -1,78 +0,0 @@ -menu "Example Configuration" - - menu "Example IO Configuration" - config EXAMPLE_PA_CTRL_IO - int "Power Amplifier control IO" - default 53 if IDF_TARGET_ESP32P4 - default -1 - help - Set GPIO number for PA control. Set -1 to disable PA control. - - config EXAMPLE_I2C_SDA_IO - int "I2C SDA IO" - default 17 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32H4 - default 9 if IDF_TARGET_ESP32H2 - default 7 - - config EXAMPLE_I2C_SCL_IO - int "I2C SCL IO" - default 16 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32H4 - default 8 if IDF_TARGET_ESP32H2 || IDF_TARGET_ESP32P4 - default 6 - - config EXAMPLE_I2S_MCLK_IO - int "I2S MCLK IO" - default 13 if IDF_TARGET_ESP32P4 - default 0 - - config EXAMPLE_I2S_BCLK_IO - int "I2S BCLK IO" - default 12 if IDF_TARGET_ESP32P4 - default 4 - - config EXAMPLE_I2S_WS_IO - int "I2S WS IO" - default 10 if IDF_TARGET_ESP32P4 - default 5 - - config EXAMPLE_I2S_DIN_IO - int "I2S DIN IO" - default 19 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 - default 11 if IDF_TARGET_ESP32P4 - default 3 - - config EXAMPLE_I2S_DOUT_IO - int "I2S DOUT IO" - default 18 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 - default 9 if IDF_TARGET_ESP32P4 - default 2 - - endmenu - - choice EXAMPLE_MODE - prompt "Example mode" - default EXAMPLE_MODE_MUSIC - help - Select example work mode - - config EXAMPLE_MODE_MUSIC - bool "music" - config EXAMPLE_MODE_ECHO - depends on !EXAMPLE_BSP - bool "echo" - endchoice - - config EXAMPLE_MIC_GAIN - int "Set MIC gain (unit: dB)" - depends on EXAMPLE_MODE_ECHO - default 18 - help - Select mic gain for echo mode - - config EXAMPLE_VOICE_VOLUME - int "Voice volume" - range 0 100 - default 60 - help - Set voice volume -endmenu diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/canon.pcm b/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/canon.pcm deleted file mode 100644 index 71ccd2c7729..00000000000 Binary files a/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/canon.pcm and /dev/null differ diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/example_config.h b/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/example_config.h deleted file mode 100644 index c56eb46b5c5..00000000000 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/example_config.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: CC0-1.0 - */ - -#pragma once - -#include "sdkconfig.h" - -/* Example configurations */ -#define EXAMPLE_RECV_BUF_SIZE (2400) -#define EXAMPLE_SAMPLE_RATE (16000) -#define EXAMPLE_MCLK_MULTIPLE (384) // If not using 24-bit data width, 256 should be enough -#define EXAMPLE_MCLK_FREQ_HZ (EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE) -#define EXAMPLE_VOICE_VOLUME CONFIG_EXAMPLE_VOICE_VOLUME -#define EXAMPLE_PA_CTRL_IO CONFIG_EXAMPLE_PA_CTRL_IO -#if CONFIG_EXAMPLE_MODE_ECHO -#define EXAMPLE_MIC_GAIN CONFIG_EXAMPLE_MIC_GAIN -#endif - -/* I2C port and GPIOs */ -#define I2C_NUM (0) -#define I2C_SCL_IO CONFIG_EXAMPLE_I2C_SCL_IO -#define I2C_SDA_IO CONFIG_EXAMPLE_I2C_SDA_IO - -/* I2S port and GPIOs */ -#define I2S_NUM (0) -#define I2S_MCK_IO CONFIG_EXAMPLE_I2S_MCLK_IO -#define I2S_BCK_IO CONFIG_EXAMPLE_I2S_BCLK_IO -#define I2S_WS_IO CONFIG_EXAMPLE_I2S_WS_IO -#define I2S_DO_IO CONFIG_EXAMPLE_I2S_DOUT_IO -#define I2S_DI_IO CONFIG_EXAMPLE_I2S_DIN_IO diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/i2s_es8311_example.c b/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/i2s_es8311_example.c deleted file mode 100644 index b1508b08356..00000000000 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/i2s_es8311_example.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: CC0-1.0 - */ - -#include -#include -#include "sdkconfig.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "driver/i2s_std.h" -#include "driver/i2c_master.h" -#include "driver/gpio.h" -#include "esp_system.h" -#include "esp_codec_dev_defaults.h" -#include "esp_codec_dev.h" -#include "esp_codec_dev_vol.h" -#include "esp_check.h" -#include "example_config.h" - -static const char *TAG = "i2s_es8311"; -static const char err_reason[][30] = {"input param is invalid", - "operation timeout" - }; -static i2s_chan_handle_t tx_handle = NULL; -static i2s_chan_handle_t rx_handle = NULL; - -/* Import music file as buffer */ -#if CONFIG_EXAMPLE_MODE_MUSIC -extern const uint8_t music_pcm_start[] asm("_binary_canon_pcm_start"); -extern const uint8_t music_pcm_end[] asm("_binary_canon_pcm_end"); -#endif - -static esp_err_t es8311_codec_init(void) -{ - /* Initialize I2C peripheral */ - i2c_master_bus_handle_t i2c_bus_handle = NULL; - i2c_master_bus_config_t i2c_mst_cfg = { - .i2c_port = I2C_NUM, - .sda_io_num = I2C_SDA_IO, - .scl_io_num = I2C_SCL_IO, - .clk_source = I2C_CLK_SRC_DEFAULT, - .glitch_ignore_cnt = 7, - /* Pull-up internally for no external pull-up case. - Suggest to use external pull-up to ensure a strong enough pull-up. */ - .flags.enable_internal_pullup = true, - }; - ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_cfg, &i2c_bus_handle)); - - /* Create control interface with I2C bus handle */ - audio_codec_i2c_cfg_t i2c_cfg = { - .port = I2C_NUM, - .addr = ES8311_CODEC_DEFAULT_ADDR, - .bus_handle = i2c_bus_handle, - }; - const audio_codec_ctrl_if_t *ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg); - assert(ctrl_if); - - /* Create data interface with I2S bus handle */ - audio_codec_i2s_cfg_t i2s_cfg = { - .port = I2S_NUM, - .rx_handle = rx_handle, - .tx_handle = tx_handle, - }; - const audio_codec_data_if_t *data_if = audio_codec_new_i2s_data(&i2s_cfg); - assert(data_if); - - /* Create ES8311 interface handle */ - const audio_codec_gpio_if_t *gpio_if = audio_codec_new_gpio(); - assert(gpio_if); - es8311_codec_cfg_t es8311_cfg = { - .ctrl_if = ctrl_if, - .gpio_if = gpio_if, - .codec_mode = ESP_CODEC_DEV_WORK_MODE_BOTH, - .master_mode = false, - .use_mclk = I2S_MCK_IO >= 0, - .pa_pin = EXAMPLE_PA_CTRL_IO, - .pa_reverted = false, - .hw_gain = { - .pa_voltage = 5.0, - .codec_dac_voltage = 3.3, - }, - .mclk_div = EXAMPLE_MCLK_MULTIPLE, - }; - const audio_codec_if_t *es8311_if = es8311_codec_new(&es8311_cfg); - assert(es8311_if); - - /* Create the top codec handle with ES8311 interface handle and data interface */ - esp_codec_dev_cfg_t dev_cfg = { - .dev_type = ESP_CODEC_DEV_TYPE_IN_OUT, - .codec_if = es8311_if, - .data_if = data_if, - }; - esp_codec_dev_handle_t codec_handle = esp_codec_dev_new(&dev_cfg); - assert(codec_handle); - - /* Specify the sample configurations and open the device */ - esp_codec_dev_sample_info_t sample_cfg = { - .bits_per_sample = I2S_DATA_BIT_WIDTH_16BIT, - .channel = 2, - .channel_mask = 0x03, - .sample_rate = EXAMPLE_SAMPLE_RATE, - .mclk_multiple = EXAMPLE_MCLK_MULTIPLE, - }; - if (esp_codec_dev_open(codec_handle, &sample_cfg) != ESP_CODEC_DEV_OK) { - ESP_LOGE(TAG, "Open codec device failed"); - return ESP_FAIL; - } - - /* Set the initial volume and gain */ - if (esp_codec_dev_set_out_vol(codec_handle, EXAMPLE_VOICE_VOLUME) != ESP_CODEC_DEV_OK) { - ESP_LOGE(TAG, "set output volume failed"); - return ESP_FAIL; - } -#if CONFIG_EXAMPLE_MODE_ECHO - if (esp_codec_dev_set_in_gain(codec_handle, EXAMPLE_MIC_GAIN) != ESP_CODEC_DEV_OK) { - ESP_LOGE(TAG, "set input gain failed"); - return ESP_FAIL; - } -#endif - return ESP_OK; -} - -static esp_err_t i2s_driver_init(void) -{ - i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM, I2S_ROLE_MASTER); - chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA buffer - ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle)); - i2s_std_config_t std_cfg = { - .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(EXAMPLE_SAMPLE_RATE), - .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), - .gpio_cfg = { - .mclk = I2S_MCK_IO, - .bclk = I2S_BCK_IO, - .ws = I2S_WS_IO, - .dout = I2S_DO_IO, - .din = I2S_DI_IO, - .invert_flags = { - .mclk_inv = false, - .bclk_inv = false, - .ws_inv = false, - }, - }, - }; - - ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &std_cfg)); - ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); - ESP_ERROR_CHECK(i2s_channel_enable(tx_handle)); - ESP_ERROR_CHECK(i2s_channel_enable(rx_handle)); - return ESP_OK; -} - -#if CONFIG_EXAMPLE_MODE_MUSIC -static void i2s_music(void *args) -{ - esp_err_t ret = ESP_OK; - size_t bytes_write = 0; - uint8_t *data_ptr = (uint8_t *)music_pcm_start; - - /* (Optional) Disable TX channel and preload the data before enabling the TX channel, - * so that the valid data can be transmitted immediately */ - ESP_ERROR_CHECK(i2s_channel_disable(tx_handle)); - ESP_ERROR_CHECK(i2s_channel_preload_data(tx_handle, data_ptr, music_pcm_end - data_ptr, &bytes_write)); - data_ptr += bytes_write; // Move forward the data pointer - - /* Enable the TX channel */ - ESP_ERROR_CHECK(i2s_channel_enable(tx_handle)); - while (1) { - /* Write music to earphone */ - ret = i2s_channel_write(tx_handle, data_ptr, music_pcm_end - data_ptr, &bytes_write, portMAX_DELAY); - if (ret != ESP_OK) { - /* Since we set timeout to 'portMAX_DELAY' in 'i2s_channel_write' - so you won't reach here unless you set other timeout value, - if timeout detected, it means write operation failed. */ - ESP_LOGE(TAG, "[music] i2s write failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]); - abort(); - } - if (bytes_write > 0) { - ESP_LOGI(TAG, "[music] i2s music played, %d bytes are written.", bytes_write); - } else { - ESP_LOGE(TAG, "[music] i2s music play failed."); - abort(); - } - data_ptr = (uint8_t *)music_pcm_start; - vTaskDelay(1000 / portTICK_PERIOD_MS); - } - vTaskDelete(NULL); -} - -#else -static void i2s_echo(void *args) -{ - int *mic_data = malloc(EXAMPLE_RECV_BUF_SIZE); - if (!mic_data) { - ESP_LOGE(TAG, "[echo] No memory for read data buffer"); - abort(); - } - esp_err_t ret = ESP_OK; - size_t bytes_read = 0; - size_t bytes_write = 0; - ESP_LOGI(TAG, "[echo] Echo start"); - - while (1) { - memset(mic_data, 0, EXAMPLE_RECV_BUF_SIZE); - /* Read sample data from mic */ - ret = i2s_channel_read(rx_handle, mic_data, EXAMPLE_RECV_BUF_SIZE, &bytes_read, 1000); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "[echo] i2s read failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]); - abort(); - } - /* Write sample data to earphone */ - ret = i2s_channel_write(tx_handle, mic_data, EXAMPLE_RECV_BUF_SIZE, &bytes_write, 1000); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "[echo] i2s write failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]); - abort(); - } - if (bytes_read != bytes_write) { - ESP_LOGW(TAG, "[echo] %d bytes read but only %d bytes are written", bytes_read, bytes_write); - } - } - vTaskDelete(NULL); -} -#endif - -void app_main(void) -{ - printf("i2s es8311 codec example start\n-----------------------------\n"); - /* Initialize i2s peripheral */ - if (i2s_driver_init() != ESP_OK) { - ESP_LOGE(TAG, "i2s driver init failed"); - abort(); - } else { - ESP_LOGI(TAG, "i2s driver init success"); - } - /* Initialize i2c peripheral and config es8311 codec by i2c */ - if (es8311_codec_init() != ESP_OK) { - ESP_LOGE(TAG, "es8311 codec init failed"); - abort(); - } else { - ESP_LOGI(TAG, "es8311 codec init success"); - } - -#if CONFIG_EXAMPLE_MODE_MUSIC - /* Play a piece of music in music mode */ - xTaskCreate(i2s_music, "i2s_music", 4096, NULL, 5, NULL); -#else - /* Echo the sound from MIC in echo mode */ - xTaskCreate(i2s_echo, "i2s_echo", 8192, NULL, 5, NULL); -#endif -} diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/idf_component.yml b/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/idf_component.yml deleted file mode 100644 index 3dfafda15bd..00000000000 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/main/idf_component.yml +++ /dev/null @@ -1,5 +0,0 @@ -## IDF Component Manager Manifest File -dependencies: - espressif/esp_codec_dev: ^1.6.0 - i2s_examples_common: - path: ${IDF_PATH}/examples/peripherals/i2s/i2s_examples_common diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/pytest_i2s_es8311.py b/examples/peripherals/i2s/i2s_codec/i2s_es8311/pytest_i2s_es8311.py deleted file mode 100644 index 50e3141bd31..00000000000 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/pytest_i2s_es8311.py +++ /dev/null @@ -1,36 +0,0 @@ -# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD -# SPDX-License-Identifier: CC0-1.0 -import pytest -from pytest_embedded import Dut -from pytest_embedded_idf.utils import idf_parametrize -from pytest_embedded_idf.utils import soc_filtered_targets - - -@pytest.mark.generic -@idf_parametrize( - 'target', - soc_filtered_targets('SOC_I2S_SUPPORTED == 1'), - indirect=['target'], -) -@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners') -def test_i2s_es8311_example_generic(dut: Dut) -> None: - dut.expect('i2s es8311 codec example start') - dut.expect('-----------------------------') - dut.expect('i2s_es8311: i2s driver init success') - - -@pytest.mark.es8311 -@pytest.mark.parametrize( - 'config', - [ - 's3_korvo2_v3', - ], - indirect=True, -) -@idf_parametrize('target', ['esp32s3'], indirect=['target']) -def test_i2s_es8311_example_korvo2_v3(dut: Dut) -> None: - dut.expect(r'i2s es8311 codec example start') - dut.expect(r'-----------------------------') - dut.expect(r'i2s_es8311: i2s driver init success') - dut.expect(r'i2s_es8311: es8311 codec init success') - dut.expect(r'Returned from app_main\(\)') diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/sdkconfig.ci b/examples/peripherals/i2s/i2s_codec/i2s_es8311/sdkconfig.ci deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/sdkconfig.ci.s3_korvo2_v3 b/examples/peripherals/i2s/i2s_codec/i2s_es8311/sdkconfig.ci.s3_korvo2_v3 deleted file mode 100644 index 2a5d5607844..00000000000 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/sdkconfig.ci.s3_korvo2_v3 +++ /dev/null @@ -1,8 +0,0 @@ -CONFIG_EXAMPLE_PA_CTRL_IO=48 -CONFIG_EXAMPLE_I2C_SDA_IO=17 -CONFIG_EXAMPLE_I2C_SCL_IO=18 -CONFIG_EXAMPLE_I2S_MCLK_IO=16 -CONFIG_EXAMPLE_I2S_BCLK_IO=9 -CONFIG_EXAMPLE_I2S_WS_IO=45 -CONFIG_EXAMPLE_I2S_DIN_IO=10 -CONFIG_EXAMPLE_I2S_DOUT_IO=8 diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/sdkconfig.defaults b/examples/peripherals/i2s/i2s_codec/i2s_es8311/sdkconfig.defaults deleted file mode 100644 index ab6f1e2f6b2..00000000000 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/sdkconfig.defaults +++ /dev/null @@ -1 +0,0 @@ -CONFIG_CODEC_I2C_BACKWARD_COMPATIBLE=n diff --git a/examples/peripherals/i2s/mic_recorder/main/Kconfig.projbuild b/examples/peripherals/i2s/mic_recorder/main/Kconfig.projbuild index 82c2056f2df..dca590e3e1f 100644 --- a/examples/peripherals/i2s/mic_recorder/main/Kconfig.projbuild +++ b/examples/peripherals/i2s/mic_recorder/main/Kconfig.projbuild @@ -72,7 +72,7 @@ menu "Example Configuration" config EXAMPLE_I2S_MCLK_IO int "I2S MCLK GPIO (set -1 if the codec does not use an external MCLK)" - default 2 + default -1 help Set the GPIO number used for the I2S MCLK signal. When set to -1, no MCLK is generated and the ES8389 derives its clock from BCLK. 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 2680e5c0572..882bd7adddc 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 @@ -132,10 +132,36 @@ static void record_from_pdm_microphone(uint8_t *pcm_data, size_t pcm_size) #endif #if CONFIG_EXAMPLE_MIC_TYPE_AMIC +static i2s_chan_handle_t i2s_rx_init(void) +{ + /* Simplex RX. I2S_ROLE_MASTER: the SoC drives BCLK/WS (and optional MCLK) + * so the ES8389 can run as I2S slave. */ + i2s_chan_handle_t rx_handle = NULL; + 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(EXAMPLE_SAMPLE_RATE), + .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(EXAMPLE_BITS_PER_SAMPLE, EXAMPLE_CHANNEL_COUNT), + .gpio_cfg = { + .mclk = CONFIG_EXAMPLE_I2S_MCLK_IO, + .bclk = CONFIG_EXAMPLE_I2S_BCLK_IO, + .ws = CONFIG_EXAMPLE_I2S_WS_IO, + .din = CONFIG_EXAMPLE_I2S_DIN_IO, + .dout = GPIO_NUM_NC, + }, + }; + + ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); + /* Clocks must be running before the codec PLL is started over I2C. */ + ESP_ERROR_CHECK(i2s_channel_enable(rx_handle)); + return rx_handle; +} + static void record_from_es8389_microphone(uint8_t *pcm_data, size_t pcm_size) { - /* The analog signal is sampled by the ES8389 ADC. I2S RX receives its digital samples - * and, as bus master, generates the BCLK/WS (and optional MCLK) required by the codec. */ + i2s_chan_handle_t rx_handle = i2s_rx_init(); + i2c_master_bus_handle_t i2c_bus_handle = NULL; i2c_master_bus_config_t i2c_bus_cfg = { .clk_source = I2C_CLK_SRC_DEFAULT, @@ -149,7 +175,6 @@ static void record_from_es8389_microphone(uint8_t *pcm_data, size_t pcm_size) }; ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_handle)); - /* I2C configures codec registers; PCM samples use I2S. */ audio_codec_i2c_cfg_t i2c_cfg = { .bus_handle = i2c_bus_handle, .addr = ES8389_CODEC_DEFAULT_ADDR, @@ -162,33 +187,12 @@ static void record_from_es8389_microphone(uint8_t *pcm_data, size_t pcm_size) .ctrl_if = ctrl_if, .codec_mode = ESP_CODEC_DEV_WORK_MODE_ADC, .pa_pin = GPIO_NUM_NC, - /* When MCLK is unused, the ES8389 derives its clock from BCLK. */ .use_mclk = CONFIG_EXAMPLE_I2S_MCLK_IO >= 0, .mclk_div = EXAMPLE_MCLK_MULTIPLE, }; const audio_codec_if_t *codec_if = es8389_codec_new(&es8389_cfg); ESP_ERROR_CHECK(codec_if ? ESP_OK : ESP_FAIL); - /* Recording needs only an RX channel. In master mode, RX also drives BCLK/WS. */ - i2s_chan_handle_t rx_handle = NULL; - 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(EXAMPLE_SAMPLE_RATE), - .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(EXAMPLE_BITS_PER_SAMPLE, EXAMPLE_CHANNEL_COUNT), - .gpio_cfg = { - .mclk = CONFIG_EXAMPLE_I2S_MCLK_IO, - .bclk = CONFIG_EXAMPLE_I2S_BCLK_IO, - .ws = CONFIG_EXAMPLE_I2S_WS_IO, - .dout = GPIO_NUM_NC, - .din = CONFIG_EXAMPLE_I2S_DIN_IO, - }, - }; - ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); - ESP_ERROR_CHECK(i2s_channel_enable(rx_handle)); - - /* Pass the already-configured RX channel to the codec data interface. */ audio_codec_i2s_cfg_t i2s_cfg = { .rx_handle = rx_handle, }; @@ -200,8 +204,8 @@ static void record_from_es8389_microphone(uint8_t *pcm_data, size_t pcm_size) .codec_if = codec_if, .data_if = data_if, }; - esp_codec_dev_handle_t codec_handle = esp_codec_dev_new(&dev_cfg); - ESP_ERROR_CHECK(codec_handle ? ESP_OK : ESP_FAIL); + esp_codec_dev_handle_t codec_dev = esp_codec_dev_new(&dev_cfg); + ESP_ERROR_CHECK(codec_dev ? ESP_OK : ESP_FAIL); esp_codec_dev_sample_info_t sample_cfg = { .bits_per_sample = EXAMPLE_BITS_PER_SAMPLE, @@ -210,8 +214,8 @@ static void record_from_es8389_microphone(uint8_t *pcm_data, size_t pcm_size) .sample_rate = EXAMPLE_SAMPLE_RATE, .mclk_multiple = EXAMPLE_MCLK_MULTIPLE, }; - ESP_ERROR_CHECK(esp_codec_dev_open(codec_handle, &sample_cfg)); - ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(codec_handle, CONFIG_EXAMPLE_MIC_GAIN)); + ESP_ERROR_CHECK(esp_codec_dev_open(codec_dev, &sample_cfg)); + ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(codec_dev, CONFIG_EXAMPLE_MIC_GAIN)); ESP_LOGI(TAG, "ES8389 codec initialized"); /* Discard the startup PCM to skip the microphone or codec startup transient. */ @@ -219,9 +223,8 @@ static void record_from_es8389_microphone(uint8_t *pcm_data, size_t pcm_size) ESP_LOGI(TAG, "Starting ES8389 recording for %d seconds!", EXAMPLE_RECORD_TIME_SECONDS); capture_pcm(rx_handle, pcm_data, pcm_size); - /* Closing the input device disables RX before its channel is deleted. */ - ESP_ERROR_CHECK(esp_codec_dev_close(codec_handle)); - esp_codec_dev_delete(codec_handle); + ESP_ERROR_CHECK(esp_codec_dev_close(codec_dev)); + esp_codec_dev_delete(codec_dev); ESP_ERROR_CHECK(audio_codec_delete_codec_if(codec_if)); ESP_ERROR_CHECK(audio_codec_delete_data_if(data_if)); ESP_ERROR_CHECK(audio_codec_delete_ctrl_if(ctrl_if)); diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/CMakeLists.txt b/examples/peripherals/i2s/wav_player/CMakeLists.txt similarity index 92% rename from examples/peripherals/i2s/i2s_codec/i2s_es8311/CMakeLists.txt rename to examples/peripherals/i2s/wav_player/CMakeLists.txt index bee278af491..83db1eda554 100644 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/CMakeLists.txt +++ b/examples/peripherals/i2s/wav_player/CMakeLists.txt @@ -6,4 +6,4 @@ include($ENV{IDF_PATH}/tools/cmake/project.cmake) # "Trim" the build. Include the minimal set of components, main, and anything it depends on. idf_build_set_property(MINIMAL_BUILD ON) -project(i2s-es8311-example) +project(wav_player_example) diff --git a/examples/peripherals/i2s/wav_player/README.md b/examples/peripherals/i2s/wav_player/README.md new file mode 100644 index 00000000000..08e2187fa28 --- /dev/null +++ b/examples/peripherals/i2s/wav_player/README.md @@ -0,0 +1,122 @@ +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | + +# I2S WAV Player Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example plays an embedded WAV file through a codec DAC over I2S STD TX. It supports two codecs, selectable in menuconfig: + +* **ES8311** — low-power mono ADC/DAC codec (for example ESP-BOX and ESP32-S3-Korvo-2). +* **ES8389** — stereo ADC/DAC codec (for example ESP32-S31-Korvo-1). + +The firmware embeds `assets/music.wav` in flash and loops it on the TX channel. A standard PCM WAV is a short RIFF header plus little-endian signed PCM; the example finds the `data` chunk and hands that payload to I2S. The clip stays mapped in flash and is copied in DMA-sized pieces, not into a RAM buffer. There is no microphone path. For recording, see [mic_recorder](../mic_recorder). + +| Audio Setting | Value | +|:---:|:---:| +| Sample Rate |16000 Hz| +| Bits per Sample |16 bits| +| Channels |Stereo| +| Source |Embedded `assets/music.wav`| + +These settings are defined as macros at the top of `main/wav_player_example_main.c` (see `EXAMPLE_SAMPLE_RATE`, `EXAMPLE_BITS_PER_SAMPLE`, etc.). **A replacement WAV must be uncompressed signed 16-bit PCM with the same rate, width, and channel count.** + +`music.wav` is an excerpt of *Canon in D Major (piano only)* by [Ava](https://freemusicarchive.org/music/ava-drumm/single/canon-in-d-major-piano-only), released on the Free Music Archive under [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/). The clip was resampled for this example. See [assets/README.md](assets/README.md) for the full provenance. + +## How to Use Example + +### Hardware Required + +* A development board with a SoC that supports I2S STD and I2C (see `Supported Targets` table above). +* A USB cable for power supply and programming. +* A board or module with an ES8311 or ES8389 codec and a headphone or speaker output. + +### Connection +``` +┌─────────────────┐ ┌──────────────────────────┐ +│ ESP │ │ ES8311 / ES8389 │ +│ │ │ │ +│ I2S_MCK_IO├──────────►│MCLK │ +│ │ │ │ ┌─────────┐ +│ I2S_BCK_IO├──────────►│BCLK analog out├───────────┤ │ +│ │ │ │ │ EARPHONE│ +│ I2S_WS_IO├──────────►│LRCK / WS │ │ / SPK │ +│ │ │ │ └─────────┘ +│ I2S_DOUT_IO├──────────►│SDIN │ +│ │ │ │ +│ I2C_SCL_IO├──────────►│SCL / CCLK │ +│ │ │ │ +│ I2C_SDA_IO│◄─────────►│SDA / CDATA │ +│ │ │ │ +│ PA_CTRL ├──────────►│amp EN / CTRL (optional) │ +│ │ │ │ +│ VCC 3.3├───────────┤VCC │ +│ GND├───────────┤GND │ +└─────────────────┘ └──────────────────────────┘ +``` + +The codec chip has no amplifier pin. `PA_CTRL` is the MCU GPIO that enables the board's speaker amplifier (HT8691, NS4150, and similar). Check the schematic: the enable is often labeled `EN`, `CTRL`, `PA`, or even `INT`. Set `Power amplifier enable IO` in menuconfig to that GPIO so the codec driver raises it when the DAC starts. Set it to `-1` if the enable is already strapped high or the board has no amplifier. A disabled amplifier is a common reason for silent speakers while headphones still work. + +Assign every signal in the diagram to your board's GPIOs under `Example Configuration` → `Example IO Configuration` in menuconfig. Some targets also ship extra defaults in `sdkconfig.defaults.`; `idf.py set-target` applies those automatically. + +### Dependency + +This example is based on [esp_codec_dev](https://components.espressif.com/components/espressif/esp_codec_dev). The component is already listed in `main/idf_component.yml` and is fetched by the [IDF Component Manager](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html) on the first build. + +To add the same dependency to another project: + +``` +idf.py add-dependency "espressif/esp_codec_dev^1.6.0" +``` + +### Configure the Project + +``` +idf.py menuconfig +``` + +In the `Example Configuration` menu: + +* Use `DAC / codec type` to select ES8311 or ES8389. +* Use `Example IO Configuration` to assign the shared I2C, I2S, and amplifier-enable GPIOs. +* Use `Voice volume` to set the output volume (0 to 100). + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +* [ESP-IDF Getting Started Guide on ESP32](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html) + +## Example Output + +``` +wav player example start +-------------------------- +I (...) wav_player: i2s driver init success +I (...) wav_player: ES8311 codec init success +I (...) wav_player: i2s music played, ... bytes are written. +I (...) wav_player: i2s music played, ... bytes are written. +...... +``` + +An ES8389 run looks the same, except the codec init line names ES8389. + +If you have a logic analyzer, probe the I2S signals on the GPIOs you set in `Example IO Configuration`. + +## Troubleshooting + +* No sound from the speaker or headphone + + * Confirm `DAC / codec type` and the I2C/I2S GPIOs match the board. Playback data goes to the codec **SDI** (SDIN) pin, not SDO. + * If the board has no MCLK pin (ESP32-S31-Korvo-1 does not), set `I2S MCLK IO` to -1 so the codec derives its clock from BCLK. Driving an unconnected MCLK GPIO while the codec waits for external MCLK produces silence. + * Check the schematic and set `Power amplifier enable IO` to the speaker-amplifier enable (`EN` / `CTRL` / `PA` / `INT`). Set the option to -1 if that pin is already strapped high. + +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/wav_player/assets/README.md b/examples/peripherals/i2s/wav_player/assets/README.md new file mode 100644 index 00000000000..83786fc41b9 --- /dev/null +++ b/examples/peripherals/i2s/wav_player/assets/README.md @@ -0,0 +1,16 @@ +# Audio clip provenance + +`music.wav` is a short excerpt of the following recording, converted for this example to 16 kHz, signed 16-bit, stereo PCM: + +| Field | Value | +| --- | --- | +| Title | Canon in D Major (piano only) | +| Artist | Ava | +| Source | https://freemusicarchive.org/music/ava-drumm/single/canon-in-d-major-piano-only | +| Released | 12 August 2021 | +| License | [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/) | + +The recording is a piano performance of Johann Pachelbel's *Canon in D*. +Pachelbel's composition is in the public domain. Ava released this performance under CC0 1.0, dedicating it to the public domain. + +The example firmware only embeds this file; it does not change the license of the recording. diff --git a/examples/peripherals/i2s/wav_player/assets/music.wav b/examples/peripherals/i2s/wav_player/assets/music.wav new file mode 100644 index 00000000000..92f92abd281 Binary files /dev/null and b/examples/peripherals/i2s/wav_player/assets/music.wav differ diff --git a/examples/peripherals/i2s/wav_player/main/CMakeLists.txt b/examples/peripherals/i2s/wav_player/main/CMakeLists.txt new file mode 100644 index 00000000000..6b6e4f860fc --- /dev/null +++ b/examples/peripherals/i2s/wav_player/main/CMakeLists.txt @@ -0,0 +1,8 @@ +idf_component_register(SRCS "wav_player_example_main.c" + PRIV_REQUIRES esp_driver_i2s esp_driver_i2c esp_driver_gpio + INCLUDE_DIRS .) + +# Embed the WAV as-is. The firmware skips the RIFF header and plays the signed +# 16-bit PCM payload from flash; no build-time conversion and no RAM copy of the clip. +target_add_binary_data(${COMPONENT_LIB} "${CMAKE_CURRENT_LIST_DIR}/../assets/music.wav" + BINARY RENAME_TO "music_wav") diff --git a/examples/peripherals/i2s/wav_player/main/Kconfig.projbuild b/examples/peripherals/i2s/wav_player/main/Kconfig.projbuild new file mode 100644 index 00000000000..18543f21cf3 --- /dev/null +++ b/examples/peripherals/i2s/wav_player/main/Kconfig.projbuild @@ -0,0 +1,79 @@ +menu "Example Configuration" + + choice EXAMPLE_DAC_TYPE + prompt "DAC / codec type" + default EXAMPLE_DAC_TYPE_ES8311 + help + Select the DAC codec connected to the board. Both options use I2S STD TX + to send PCM and I2C to configure the codec: + + - ES8311: low-power mono ADC/DAC codec used on boards such as ESP-BOX + and ESP32-S3-Korvo-2. + - ES8389: stereo ADC/DAC codec used on boards such as ESP32-S31-Korvo-1. + + config EXAMPLE_DAC_TYPE_ES8311 + bool "ES8311 codec" + select CODEC_ES8311_SUPPORT + + config EXAMPLE_DAC_TYPE_ES8389 + bool "ES8389 codec" + select CODEC_ES8389_SUPPORT + endchoice + + menu "Example IO Configuration" + config EXAMPLE_PA_CTRL_IO + int "Power amplifier enable IO" + default -1 + help + GPIO connected to the board's speaker-amplifier enable + (often labeled EN, CTRL, PA, or INT). This is not a pin + on the ES8311 or ES8389. The codec driver raises it when + the DAC starts. Set -1 if the board has no amplifier + enable, or if that pin is already strapped high. + + config EXAMPLE_I2C_SDA_IO + int "I2C SDA IO" + default 0 + help + Set the GPIO number used for the I2C SDA signal towards the codec. + + config EXAMPLE_I2C_SCL_IO + int "I2C SCL IO" + default 1 + help + Set the GPIO number used for the I2C SCL signal towards the codec. + + config EXAMPLE_I2S_MCLK_IO + int "I2S MCLK IO (set -1 if the codec does not use an external MCLK)" + default -1 + help + Set the GPIO number used for the I2S MCLK signal. When set to -1, no MCLK + is generated and the codec derives its clock from BCLK. + + config EXAMPLE_I2S_BCLK_IO + int "I2S BCLK IO" + default 3 + help + Set the GPIO number used for the I2S BCLK signal towards the codec. + + config EXAMPLE_I2S_WS_IO + int "I2S WS/LRCK IO" + default 4 + help + Set the GPIO number used for the I2S WS/LRCK signal towards the codec. + + config EXAMPLE_I2S_DOUT_IO + int "I2S DOUT IO" + default 7 + help + Set the GPIO number used for sending PCM data to the codec. + endmenu + + config EXAMPLE_VOICE_VOLUME + int "Voice volume" + range 0 100 + default 60 + help + Set the codec output volume. + +endmenu diff --git a/examples/peripherals/i2s/wav_player/main/idf_component.yml b/examples/peripherals/i2s/wav_player/main/idf_component.yml new file mode 100644 index 00000000000..d2ad161975e --- /dev/null +++ b/examples/peripherals/i2s/wav_player/main/idf_component.yml @@ -0,0 +1,3 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/esp_codec_dev: "^1.6.0" diff --git a/examples/peripherals/i2s/wav_player/main/wav_player_example_main.c b/examples/peripherals/i2s/wav_player/main/wav_player_example_main.c new file mode 100644 index 00000000000..53e4c798830 --- /dev/null +++ b/examples/peripherals/i2s/wav_player/main/wav_player_example_main.c @@ -0,0 +1,289 @@ +/* + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/i2s_std.h" +#include "driver/i2c_master.h" +#include "driver/gpio.h" + +#include "esp_codec_dev.h" +#include "esp_codec_dev_defaults.h" + +static const char *TAG = "wav_player"; + +/* These four values are the I2S slot format AND the WAV / codec format. They must match. */ +#define EXAMPLE_SAMPLE_RATE 16000 +#define EXAMPLE_BITS_PER_SAMPLE 16 +#define EXAMPLE_CHANNEL_COUNT 2 +#define EXAMPLE_STEREO_CHANNEL_MASK 0x03 /* Bit0 = left, bit1 = right. */ + +/* Most codecs expect MCLK = 256 * LRCK (sample rate) when an external MCLK pin is wired. */ +#define EXAMPLE_MCLK_MULTIPLE 256 +#define EXAMPLE_I2C_CLOCK_HZ 100000 + +#if CONFIG_EXAMPLE_DAC_TYPE_ES8311 +#define EXAMPLE_CODEC_I2C_ADDR ES8311_CODEC_DEFAULT_ADDR +#define EXAMPLE_CODEC_NAME "ES8311" +#else +#define EXAMPLE_CODEC_I2C_ADDR ES8389_CODEC_DEFAULT_ADDR +#define EXAMPLE_CODEC_NAME "ES8389" +#endif + +/* CMake embeds the WAV in flash as a binary blob (target_add_binary_data). */ +extern const uint8_t music_wav_start[] asm("_binary_music_wav_start"); +extern const uint8_t music_wav_end[] asm("_binary_music_wav_end"); + +static bool fourcc_eq(const uint8_t *p, const char *id) +{ + return memcmp(p, id, 4) == 0; +} + +static uint16_t read_le16(const uint8_t *p) +{ + return (uint16_t)p[0] | ((uint16_t)p[1] << 8); +} + +static uint32_t read_le32(const uint8_t *p) +{ + return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); +} + +/* I2S transmits raw PCM only. A WAV file is a RIFF container: skip "fmt " / "data" + * chunks until the little-endian PCM payload, and reject compressed encodings. */ +static esp_err_t wav_get_pcm(const uint8_t *wav, size_t wav_len, const uint8_t **pcm, size_t *pcm_len) +{ + if (wav_len < 12 || !fourcc_eq(wav, "RIFF") || !fourcc_eq(wav + 8, "WAVE")) { + ESP_LOGE(TAG, "not a RIFF/WAVE file"); + return ESP_ERR_INVALID_ARG; + } + + const uint8_t *fmt = NULL; + uint32_t fmt_size = 0; + const uint8_t *data = NULL; + uint32_t data_size = 0; + + for (size_t off = 12; off + 8 <= wav_len;) { + uint32_t size = read_le32(wav + off + 4); + size_t payload = off + 8; + if (size > wav_len - payload) { + ESP_LOGE(TAG, "WAV chunk overruns file"); + return ESP_ERR_INVALID_SIZE; + } + if (fourcc_eq(wav + off, "fmt ")) { + fmt = wav + payload; + fmt_size = size; + } else if (fourcc_eq(wav + off, "data")) { + data = wav + payload; + data_size = size; + break; + } + off = payload + size + (size & 1U); + } + + if (fmt == NULL || fmt_size < 16 || data == NULL || data_size == 0) { + ESP_LOGE(TAG, "WAV missing fmt or data chunk"); + return ESP_ERR_NOT_FOUND; + } + + uint16_t audio_format = read_le16(fmt); + uint16_t channels = read_le16(fmt + 2); + uint32_t sample_rate = read_le32(fmt + 4); + uint16_t bits = read_le16(fmt + 14); + if (audio_format != 1) { + ESP_LOGE(TAG, "WAV is not uncompressed PCM (format %u)", audio_format); + return ESP_ERR_NOT_SUPPORTED; + } + if (channels != EXAMPLE_CHANNEL_COUNT || + sample_rate != EXAMPLE_SAMPLE_RATE || + bits != EXAMPLE_BITS_PER_SAMPLE) { + ESP_LOGE(TAG, "WAV is %u Hz / %u-bit / %u ch, expected %u / %u / %u", + (unsigned)sample_rate, bits, channels, + EXAMPLE_SAMPLE_RATE, EXAMPLE_BITS_PER_SAMPLE, EXAMPLE_CHANNEL_COUNT); + return ESP_ERR_INVALID_ARG; + } + + *pcm = data; + *pcm_len = data_size; + ESP_LOGI(TAG, "WAV PCM payload %u bytes", (unsigned)data_size); + return ESP_OK; +} + +static const audio_codec_if_t *create_dac_codec_if(const audio_codec_ctrl_if_t *ctrl_if, + const audio_codec_gpio_if_t *gpio_if) +{ + /* The codec is the I2S slave: it receives BCLK/WS (and optional MCLK) from the SoC. + * pa_pin is the board amplifier enable, not a pin on the codec die. */ +#if CONFIG_EXAMPLE_DAC_TYPE_ES8311 + es8311_codec_cfg_t dac_cfg = { + .ctrl_if = ctrl_if, + .gpio_if = gpio_if, + .codec_mode = ESP_CODEC_DEV_WORK_MODE_DAC, + .master_mode = false, + .use_mclk = CONFIG_EXAMPLE_I2S_MCLK_IO >= 0, + .pa_pin = CONFIG_EXAMPLE_PA_CTRL_IO, + .hw_gain = { + .pa_voltage = 5.0, + .codec_dac_voltage = 3.3, + }, + .mclk_div = EXAMPLE_MCLK_MULTIPLE, + }; + return es8311_codec_new(&dac_cfg); +#else + es8389_codec_cfg_t dac_cfg = { + .ctrl_if = ctrl_if, + .gpio_if = gpio_if, + .codec_mode = ESP_CODEC_DEV_WORK_MODE_DAC, + .master_mode = false, + .use_mclk = CONFIG_EXAMPLE_I2S_MCLK_IO >= 0, + .pa_pin = CONFIG_EXAMPLE_PA_CTRL_IO, + .pa_reverted = false, + .hw_gain = { + .pa_voltage = 5.0, + .codec_dac_voltage = 3.3, + }, + .mclk_div = EXAMPLE_MCLK_MULTIPLE, + }; + return es8389_codec_new(&dac_cfg); +#endif +} + +static i2s_chan_handle_t i2s_driver_init(void) +{ + /* Simplex TX: only a transmit channel. I2S_ROLE_MASTER means the SoC generates + * BCLK and WS. The codec must be configured as I2S slave (see create_dac_codec_if). + * auto_clear writes zeros if the DMA ring underruns, which avoids a stuck last sample. */ + i2s_chan_handle_t tx_handle = NULL; + i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); + chan_cfg.auto_clear = true; + ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, NULL)); + + /* Standard (Philips) I2S: WS low = left slot, WS high = right slot. + * Each slot is EXAMPLE_BITS_PER_SAMPLE bits. Stereo 16-bit uses + * BCLK = sample_rate * 32. MCLK, if used, is sample_rate * EXAMPLE_MCLK_MULTIPLE. */ + i2s_std_config_t std_cfg = { + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(EXAMPLE_SAMPLE_RATE), + .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(EXAMPLE_BITS_PER_SAMPLE, EXAMPLE_CHANNEL_COUNT), + .gpio_cfg = { + .mclk = CONFIG_EXAMPLE_I2S_MCLK_IO, + .bclk = CONFIG_EXAMPLE_I2S_BCLK_IO, + .ws = CONFIG_EXAMPLE_I2S_WS_IO, + .dout = CONFIG_EXAMPLE_I2S_DOUT_IO, + .din = GPIO_NUM_NC, + }, + }; + + ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &std_cfg)); + /* Enable now so BCLK/WS (and MCLK) are already running when the codec PLL starts. */ + ESP_ERROR_CHECK(i2s_channel_enable(tx_handle)); + return tx_handle; +} + +static void dac_codec_init(i2s_chan_handle_t tx_handle) +{ + /* I2C programs codec registers (volume, mute, clock source, PA). PCM is still + * written with i2s_channel_write(); the handle is only handed to the codec + * so esp_codec_dev_open() can match the slot format already set on I2S. */ + i2c_master_bus_handle_t i2c_bus_handle = NULL; + i2c_master_bus_config_t i2c_bus_cfg = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = -1, /* Let the driver select a free I2C port */ + .sda_io_num = CONFIG_EXAMPLE_I2C_SDA_IO, + .scl_io_num = CONFIG_EXAMPLE_I2C_SCL_IO, + .glitch_ignore_cnt = 7, + /* Enable the internal pull-ups in case there is no external pull-up on the board. + * External pull-ups are recommended to make the bus more robust. */ + .flags.enable_internal_pullup = true, + }; + ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_handle)); + + audio_codec_i2c_cfg_t i2c_cfg = { + .bus_handle = i2c_bus_handle, + .addr = EXAMPLE_CODEC_I2C_ADDR, + .clock_speed_hz = EXAMPLE_I2C_CLOCK_HZ, + }; + const audio_codec_ctrl_if_t *ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg); + ESP_ERROR_CHECK(ctrl_if ? ESP_OK : ESP_FAIL); + + const audio_codec_gpio_if_t *gpio_if = audio_codec_new_gpio(); + ESP_ERROR_CHECK(gpio_if ? ESP_OK : ESP_FAIL); + + const audio_codec_if_t *codec_if = create_dac_codec_if(ctrl_if, gpio_if); + ESP_ERROR_CHECK(codec_if ? ESP_OK : ESP_FAIL); + + audio_codec_i2s_cfg_t i2s_cfg = { + .tx_handle = tx_handle, + }; + const audio_codec_data_if_t *data_if = audio_codec_new_i2s_data(&i2s_cfg); + ESP_ERROR_CHECK(data_if ? ESP_OK : ESP_FAIL); + + esp_codec_dev_cfg_t dev_cfg = { + .dev_type = ESP_CODEC_DEV_TYPE_OUT, + .codec_if = codec_if, + .data_if = data_if, + }; + esp_codec_dev_handle_t codec_dev = esp_codec_dev_new(&dev_cfg); + ESP_ERROR_CHECK(codec_dev ? ESP_OK : ESP_FAIL); + + /* open() applies the same sample format to the codec (and keeps the I2S + * channel in sync), then enables the DAC and the board PA. */ + esp_codec_dev_sample_info_t sample_cfg = { + .bits_per_sample = EXAMPLE_BITS_PER_SAMPLE, + .channel = EXAMPLE_CHANNEL_COUNT, + .channel_mask = EXAMPLE_STEREO_CHANNEL_MASK, + .sample_rate = EXAMPLE_SAMPLE_RATE, + .mclk_multiple = EXAMPLE_MCLK_MULTIPLE, + }; + ESP_ERROR_CHECK(esp_codec_dev_open(codec_dev, &sample_cfg)); + ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(codec_dev, CONFIG_EXAMPLE_VOICE_VOLUME)); + ESP_LOGI(TAG, "%s codec init success", EXAMPLE_CODEC_NAME); +} + +void app_main(void) +{ + printf("wav player example start\n--------------------------\n"); + + const uint8_t *pcm = NULL; + size_t pcm_len = 0; + ESP_ERROR_CHECK(wav_get_pcm(music_wav_start, music_wav_end - music_wav_start, &pcm, &pcm_len)); + + i2s_chan_handle_t tx_handle = i2s_driver_init(); + ESP_LOGI(TAG, "i2s driver init success"); + + dac_codec_init(tx_handle); + + /* Disable TX, preload the DMA descriptors, then enable. Otherwise the first + * frames on the wire are zeros or stale SRAM (a click at the start of playback). */ + size_t bytes_write = 0; + const uint8_t *data_ptr = pcm; + ESP_ERROR_CHECK(i2s_channel_disable(tx_handle)); + ESP_ERROR_CHECK(i2s_channel_preload_data(tx_handle, data_ptr, pcm_len, &bytes_write)); + data_ptr += bytes_write; + ESP_ERROR_CHECK(i2s_channel_enable(tx_handle)); + + while (1) { + size_t remain = (size_t)(pcm + pcm_len - data_ptr); + while (remain > 0) { + ESP_ERROR_CHECK(i2s_channel_write(tx_handle, data_ptr, remain, &bytes_write, portMAX_DELAY)); + if (bytes_write == 0) { + ESP_LOGE(TAG, "i2s music play failed."); + abort(); + } + data_ptr += bytes_write; + remain -= bytes_write; + } + ESP_LOGI(TAG, "i2s music played, %d bytes are written.", (int)pcm_len); + data_ptr = pcm; + vTaskDelay(pdMS_TO_TICKS(1000)); + } +} diff --git a/examples/peripherals/i2s/wav_player/pytest_wav_player.py b/examples/peripherals/i2s/wav_player/pytest_wav_player.py new file mode 100644 index 00000000000..cb979e96701 --- /dev/null +++ b/examples/peripherals/i2s/wav_player/pytest_wav_player.py @@ -0,0 +1,35 @@ +# SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import os + +import pytest +from pytest_embedded import Dut +from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets + +I2S_TARGETS = soc_filtered_targets('SOC_I2S_SUPPORTED == 1') + + +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'es8311', + 'es8389', + ], + indirect=True, +) +@idf_parametrize( + 'target', + I2S_TARGETS, + indirect=['target'], +) +def test_wav_player_example(dut: Dut, config: str) -> None: + dut.expect_exact('wav player example start') + dut.expect_exact('wav_player: i2s driver init success') + + # Generic CI runners have no codec; only check the rest when running locally. + if os.getenv('CI_JOB_ID'): + return + + dut.expect_exact(f'wav_player: {config.upper()} codec init success', timeout=10) diff --git a/examples/peripherals/i2s/wav_player/sdkconfig.ci.es8311 b/examples/peripherals/i2s/wav_player/sdkconfig.ci.es8311 new file mode 100644 index 00000000000..7e55ee17439 --- /dev/null +++ b/examples/peripherals/i2s/wav_player/sdkconfig.ci.es8311 @@ -0,0 +1 @@ +CONFIG_EXAMPLE_DAC_TYPE_ES8311=y diff --git a/examples/peripherals/i2s/wav_player/sdkconfig.ci.es8389 b/examples/peripherals/i2s/wav_player/sdkconfig.ci.es8389 new file mode 100644 index 00000000000..9b92e5a35d8 --- /dev/null +++ b/examples/peripherals/i2s/wav_player/sdkconfig.ci.es8389 @@ -0,0 +1 @@ +CONFIG_EXAMPLE_DAC_TYPE_ES8389=y diff --git a/examples/peripherals/i2s/wav_player/sdkconfig.defaults b/examples/peripherals/i2s/wav_player/sdkconfig.defaults new file mode 100644 index 00000000000..4f6a105ad1e --- /dev/null +++ b/examples/peripherals/i2s/wav_player/sdkconfig.defaults @@ -0,0 +1,3 @@ +# This file must exist. CMake only loads sdkconfig.defaults. +# as a companion of each file listed in SDKCONFIG_DEFAULTS, which +# defaults to this path. diff --git a/examples/peripherals/i2s/wav_player/sdkconfig.defaults.esp32 b/examples/peripherals/i2s/wav_player/sdkconfig.defaults.esp32 new file mode 100644 index 00000000000..dfcbb7e7a25 --- /dev/null +++ b/examples/peripherals/i2s/wav_player/sdkconfig.defaults.esp32 @@ -0,0 +1,5 @@ +CONFIG_EXAMPLE_I2C_SDA_IO=21 +CONFIG_EXAMPLE_I2C_SCL_IO=22 +CONFIG_EXAMPLE_I2S_BCLK_IO=4 +CONFIG_EXAMPLE_I2S_WS_IO=5 +CONFIG_EXAMPLE_I2S_DOUT_IO=18 diff --git a/examples/peripherals/i2s/wav_player/sdkconfig.defaults.esp32s31 b/examples/peripherals/i2s/wav_player/sdkconfig.defaults.esp32s31 new file mode 100644 index 00000000000..2c667d8a2cf --- /dev/null +++ b/examples/peripherals/i2s/wav_player/sdkconfig.defaults.esp32s31 @@ -0,0 +1,6 @@ +CONFIG_EXAMPLE_I2C_SDA_IO=0 +CONFIG_EXAMPLE_I2C_SCL_IO=1 +CONFIG_EXAMPLE_I2S_BCLK_IO=3 +CONFIG_EXAMPLE_I2S_WS_IO=4 +CONFIG_EXAMPLE_I2S_DOUT_IO=5 +CONFIG_EXAMPLE_PA_CTRL_IO=7 diff --git a/pytest.ini b/pytest.ini index 883561adfec..ea6b5f844ea 100644 --- a/pytest.ini +++ b/pytest.ini @@ -106,7 +106,6 @@ env_markers = httpbin: runner for tests that need to access the httpbin service flash_4mb: C2 runners with 4 MB flash jtag_re_enable: Runner to re-enable jtag which is softly disabled by burning bit SOFT_DIS_JTAG on eFuse - es8311: Development board that carries es8311 codec camera: Runner with camera ov5647: Runner with camera ov5647 esp32s3_eye: Runner for esp32s3_eye and camera ov2640