diff --git a/components/driver/test/test_i2s.c b/components/driver/test/test_i2s.c index 7234164cc5..6e4140ad68 100644 --- a/components/driver/test/test_i2s.c +++ b/components/driver/test/test_i2s.c @@ -1,8 +1,9 @@ /* * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD * - * SPDX-License-Identifier: Apache-2.0 + * SPDX-License-Identifier: CC0-1.0 */ + /** * I2S test environment UT_T1_I2S: * We use internal signals instead of external wiring, but please keep the following IO connections, or connect nothing to prevent the signal from being disturbed. @@ -14,6 +15,7 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "freertos/queue.h" #include "driver/i2s.h" #include "driver/gpio.h" #include "hal/gpio_hal.h" @@ -157,12 +159,15 @@ TEST_CASE("I2S basic driver install, uninstall, set pin test", "[i2s]") // normal i2s i2s_pin_config_t pin_config = { + .mck_io_num = -1, .bck_io_num = MASTER_BCK_IO, .ws_io_num = MASTER_WS_IO, .data_out_num = DATA_OUT_IO, .data_in_num = -1 }; - TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); + QueueHandle_t evt_que; + TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 16, &evt_que)); + TEST_ASSERT(evt_que); TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config)); TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0)); @@ -199,6 +204,7 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]") #endif }; i2s_pin_config_t master_pin_config = { + .mck_io_num = -1, .bck_io_num = MASTER_BCK_IO, .ws_io_num = MASTER_WS_IO, .data_out_num = DATA_OUT_IO, @@ -247,6 +253,74 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]") i2s_driver_uninstall(I2S_NUM_0); } +#if SOC_I2S_SUPPORTS_TDM +TEST_CASE("I2S TDM Loopback test(master tx and rx)", "[i2s]") +{ + // master driver installed and send data + i2s_config_t master_i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_MULTIPLE, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .total_chan = 4, + .chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1 | I2S_TDM_ACTIVE_CH2 | I2S_TDM_ACTIVE_CH3, + .dma_buf_count = 6, + .dma_buf_len = 100, + .use_apll = 0, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, + }; + i2s_pin_config_t master_pin_config = { + .mck_io_num = -1, + .bck_io_num = MASTER_BCK_IO, + .ws_io_num = MASTER_WS_IO, + .data_out_num = DATA_OUT_IO, + .data_in_num = DATA_IN_IO + }; + TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &master_i2s_config, 0, NULL)); + TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &master_pin_config)); + i2s_test_io_config(I2S_TEST_MODE_LOOPBACK); + printf("\r\nheap size: %d\n", esp_get_free_heap_size()); + + uint8_t *data_wr = (uint8_t *)malloc(sizeof(uint8_t) * 400); + size_t i2s_bytes_write = 0; + size_t bytes_read = 0; + int length = 0; + uint8_t *i2s_read_buff = (uint8_t *)malloc(sizeof(uint8_t) * 10000); + + for (int i = 0; i < 100; i++) { + data_wr[i] = i + 1; + } + int flag = 0; // break loop flag + int end_position = 0; + // write data to slave + i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t) * 400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS); + while (!flag) { + if (length >= 10000 - 500) { + break; + } + i2s_read(I2S_NUM_0, i2s_read_buff + length, sizeof(uint8_t) * 500, &bytes_read, 1000 / portMAX_DELAY); + if (bytes_read > 0) { + for (int i = length; i < length + bytes_read; i++) { + if (i2s_read_buff[i] == 100) { + flag = 1; + end_position = i; + break; + } + } + } + length = length + bytes_read; + } + // test the read data right or not + for (int i = end_position - 99; i <= end_position; i++) { + TEST_ASSERT_EQUAL_UINT8((i - end_position + 100), *(i2s_read_buff + i)); + } + free(data_wr); + free(i2s_read_buff); + i2s_driver_uninstall(I2S_NUM_0); +} +#endif + #if SOC_I2S_NUM > 1 /* ESP32S2 and ESP32C3 has only single I2S port and hence following test cases are not applicable */ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") @@ -272,6 +346,7 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") #endif }; i2s_pin_config_t master_pin_config = { + .mck_io_num = -1, .bck_io_num = MASTER_BCK_IO, .ws_io_num = MASTER_WS_IO, .data_out_num = DATA_OUT_IO, @@ -302,6 +377,7 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") #endif }; i2s_pin_config_t slave_pin_config = { + .mck_io_num = -1, .bck_io_num = SLAVE_BCK_IO, .ws_io_num = SLAVE_WS_IO, .data_out_num = -1, @@ -374,6 +450,7 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") #endif }; i2s_pin_config_t master_pin_config = { + .mck_io_num = -1, .bck_io_num = MASTER_BCK_IO, .ws_io_num = MASTER_WS_IO, .data_out_num = -1, @@ -404,6 +481,7 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") #endif }; i2s_pin_config_t slave_pin_config = { + .mck_io_num = -1, .bck_io_num = SLAVE_BCK_IO, .ws_io_num = SLAVE_WS_IO, .data_out_num = DATA_OUT_IO, @@ -477,6 +555,7 @@ TEST_CASE("I2S memory leaking test", "[i2s]") #endif }; i2s_pin_config_t master_pin_config = { + .mck_io_num = -1, .bck_io_num = MASTER_BCK_IO, .ws_io_num = MASTER_WS_IO, .data_out_num = -1, @@ -507,6 +586,7 @@ TEST_CASE("I2S memory leaking test", "[i2s]") TEST_CASE("I2S APLL clock variation test", "[i2s]") { i2s_pin_config_t pin_config = { + .mck_io_num = -1, .bck_io_num = MASTER_BCK_IO, .ws_io_num = MASTER_WS_IO, .data_out_num = DATA_OUT_IO, diff --git a/examples/peripherals/i2s/i2s_es8311/CMakeLists.txt b/examples/peripherals/i2s/i2s_es8311/CMakeLists.txt new file mode 100644 index 0000000000..44b16d09c3 --- /dev/null +++ b/examples/peripherals/i2s/i2s_es8311/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(i2s-es8311-example) diff --git a/examples/peripherals/i2s/i2s_es8311/README.md b/examples/peripherals/i2s/i2s_es8311/README.md new file mode 100644 index 0000000000..35aca7fde2 --- /dev/null +++ b/examples/peripherals/i2s/i2s_es8311/README.md @@ -0,0 +1,147 @@ +# 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 + +* An ESP development board that support I2S. +* 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 │ +│ │ │ │ +│ MCLK-GPIO 0 ├──────────►│PIN2-MCLK │ +│ │ │ │ ┌─────────┐ +│ BCLK-GPIO 4 ├──────────►│PIN6-BCLK PIN12-OUTP├───────────┤ │ +│ │ │ │ │ EARPHONE│ +│ WS-GPIO 5 ├──────────►│PIN8-LRCK PIN13-OUTN├───────────┤ │ +│ │ │ │ └─────────┘ +│ SDOUT-GPIO 18├──────────►│PIN9-SDIN │ +│ │ │ │ +│ SDIN-GPIO 19│◄──────────┤PIN7-SDOUT │ +│ │ │ │ ┌─────────┐ +│ │ │ PIN18-MIC1P├───────────┤ │ +│ SCL-GPIO 16├──────────►│PIN1 -CCLK │ │ MIC │ +│ (GPIO 7)│ │ PIN17-MIC1N├───────────┤ │ +│ SDA-GPIO 17│◄─────────►│PIN19-CDATA │ └─────────┘ +│ (GPIO 8)│ │ │ +│ VCC 3.3├───────────┤VCC │ +│ │ │ │ +│ GND├───────────┤GND │ +└─────────────────┘ └──────────────────────────┘ +``` +Note: Since ESP32-C3 board does not have GPIO 16/17, you can use other available GPIOs instead. In this example, we set GPIO 7/8 as I2C pins for ESP32-C3 and GPIO 16/17 for other chips. + +### Dependency + +This example is based on [es8311 component](https://components.espressif.com/component/espressif/es8311) + +The component can be installed by esp component manager. Since this example already installed it, no need to re-installed it again, but if you want to install this component in your own project, you can input the following command: +``` +idf.py add-dependency espressif/es8311==0.0.2-alpha +``` + +If dependency is added, you can check `idf_component.yml` for more detail. When building this example or other project with managed-component in it, the component manager will search the componet online and download it under `managed_componets` folder. + +### Configure the Project + +``` +idf.py menuconfig +``` +You can find configurations for this example in 'Example Configutation' 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 volum between 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. + +## 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_buf_count=6 +I (348) I2S: DMA Malloc info, datalen=blocksize=1200, dma_buf_count=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_buf_count=6 +I (312) I2S: DMA Malloc info, datalen=blocksize=1200, dma_buf_count=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 | +| SDIN |serial data in | GPIO_NUM_19 | + +### 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 s16ls -ar 16000 -ac -1 -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_es9311_example.c`(line 46/47) +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. + +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_es8311/main/CMakeLists.txt b/examples/peripherals/i2s/i2s_es8311/main/CMakeLists.txt new file mode 100644 index 0000000000..6acf1972e2 --- /dev/null +++ b/examples/peripherals/i2s/i2s_es8311/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "i2s_es8311_example.c" + EMBED_FILES "canon.pcm") diff --git a/examples/peripherals/i2s/i2s_es8311/main/Kconfig.projbuild b/examples/peripherals/i2s/i2s_es8311/main/Kconfig.projbuild new file mode 100644 index 0000000000..dcfb7896af --- /dev/null +++ b/examples/peripherals/i2s/i2s_es8311/main/Kconfig.projbuild @@ -0,0 +1,58 @@ +menu "Example Configuration" + + 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 + bool "echo" + endchoice + + choice EXAMPLE_SELECT_MIC_GAIN + prompt "Set MIC gain" + depends on EXAMPLE_MODE_ECHO + default MIC_GAIN_18DB + help + Select mic gain for echo mode + + config MIC_GAIN_0DB + bool "0dB" + config MIC_GAIN_6DB + bool "6dB" + config MIC_GAIN_12DB + bool "12dB" + config MIC_GAIN_18DB + bool "18dB" + config MIC_GAIN_24DB + bool "24dB" + config MIC_GAIN_30DB + bool "30dB" + config MIC_GAIN_36DB + bool "36dB" + config MIC_GAIN_42DB + bool "42dB" + endchoice + + config EXAMPLE_MIC_GAIN + int + default 0 if MIC_GAIN_0DB + default 1 if MIC_GAIN_6DB + default 2 if MIC_GAIN_12DB + default 3 if MIC_GAIN_18DB + default 4 if MIC_GAIN_24DB + default 5 if MIC_GAIN_30DB + default 6 if MIC_GAIN_36DB + default 7 if MIC_GAIN_42DB + + config EXAMPLE_VOICE_VOLUME + int "Voice volume" + range 0 100 + default 60 + help + Set voice volume + +endmenu diff --git a/examples/peripherals/i2s/i2s_es8311/main/canon.pcm b/examples/peripherals/i2s/i2s_es8311/main/canon.pcm new file mode 100644 index 0000000000..71ccd2c772 Binary files /dev/null and b/examples/peripherals/i2s/i2s_es8311/main/canon.pcm differ diff --git a/examples/peripherals/i2s/i2s_es8311/main/i2s_es8311_example.c b/examples/peripherals/i2s/i2s_es8311/main/i2s_es8311_example.c new file mode 100644 index 0000000000..8df18c3b4d --- /dev/null +++ b/examples/peripherals/i2s/i2s_es8311/main/i2s_es8311_example.c @@ -0,0 +1,204 @@ +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/i2s.h" +#include "esp_system.h" +#include "esp_check.h" +#include "es8311.h" + +/* I2C port and GPIOs */ +#define I2C_NUM (0) +#ifdef CONFIG_IDF_TARGET_ESP32C3 +#define I2C_SDA_IO (GPIO_NUM_17) +#define I2C_SCL_IO (GPIO_NUM_16) +#else +#define I2C_SDA_IO (GPIO_NUM_15) +#define I2C_SCL_IO (GPIO_NUM_14) +#endif + +/* I2S port and GPIOs */ +#define I2S_NUM (0) +#define I2S_MCK_IO (GPIO_NUM_0) +#define I2S_BCK_IO (GPIO_NUM_4) +#define I2S_WS_IO (GPIO_NUM_5) +#define I2S_DO_IO (GPIO_NUM_18) +#define I2S_DI_IO (GPIO_NUM_19) + +/* Example configurations */ +#define EXAMPLE_RECV_BUF_SIZE (2048) +#define EXAMPLE_SAMPLE_RATE (16000) +#define EXAMPLE_MCLK_MULTIPLE I2S_MCLK_MULTIPLE_256 +#define EXAMPLE_VOICE_VOLUME CONFIG_EXAMPLE_VOICE_VOLUME +#if CONFIG_EXAMPLE_MODE_ECHO +#define EXAMPLE_MIC_GAIN CONFIG_EXAMPLE_MIC_GAIN +#endif + +static const char *TAG = "i2s_es8311"; +static const char err_reason[][30] = {"input param is invalid", + "operation timeout" + }; + +/* 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_config_t es_i2c_cfg = { + .sda_io_num = I2C_SDA_IO, + .scl_io_num = I2C_SCL_IO, + .mode = I2C_MODE_MASTER, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = 100000, + }; + ESP_RETURN_ON_ERROR(i2c_param_config(I2C_NUM, &es_i2c_cfg), TAG, "config i2c failed"); + ESP_RETURN_ON_ERROR(i2c_driver_install(I2C_NUM, I2C_MODE_MASTER, 0, 0, 0), TAG, "install i2c driver failed"); + + /* Initialize es8311 codec */ + es8311_handle_t es_handle = es8311_create(I2C_NUM, ES8311_ADDRRES_0); + ESP_RETURN_ON_FALSE(es_handle, ESP_FAIL, TAG, "es8311 create failed"); + es8311_clock_config_t es_clk = { + .mclk_from_mclk_pin = true, + .sample_frequency = EXAMPLE_SAMPLE_RATE + }; + + es8311_init(es_handle, &es_clk, ES8311_RESOLUTION_16, ES8311_RESOLUTION_16); + ESP_RETURN_ON_ERROR(es8311_sample_frequency_config(es_handle, EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE, EXAMPLE_SAMPLE_RATE), TAG, "set es8311 sample frequency failed"); + ESP_RETURN_ON_ERROR(es8311_voice_volume_set(es_handle, EXAMPLE_VOICE_VOLUME, NULL), TAG, "set es8311 volume failed"); + ESP_RETURN_ON_ERROR(es8311_microphone_config(es_handle, false), TAG, "set es8311 microphone failed"); +#if CONFIG_EXAMPLE_MODE_ECHO + ESP_RETURN_ON_ERROR(es8311_microphone_gain_set(es_handle, EXAMPLE_MIC_GAIN), TAG, "set es8311 microphone gain faield"); +#endif + return ESP_OK; +} + +static esp_err_t i2s_driver_init(void) +{ + i2s_config_t i2s_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX, + .sample_rate = EXAMPLE_SAMPLE_RATE, + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .tx_desc_auto_clear = true, +#if SOC_I2S_SUPPORTS_TDM + .total_chan = 2, + .chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align = false, + .big_edin = false, + .bit_order_msb = false, + .skip_msk = false, +#endif + .dma_buf_count = 8, + .dma_buf_len = 64, + .use_apll = false, + .mclk_multiple = EXAMPLE_MCLK_MULTIPLE, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, + }; + + ESP_RETURN_ON_ERROR(i2s_driver_install(I2S_NUM, &i2s_cfg, 0, NULL), TAG, "install i2s failed"); + i2s_pin_config_t i2s_pin_cfg = { + .mck_io_num = I2S_MCK_IO, + .bck_io_num = I2S_BCK_IO, + .ws_io_num = I2S_WS_IO, + .data_out_num = I2S_DO_IO, + .data_in_num = I2S_DI_IO + }; + ESP_RETURN_ON_ERROR(i2s_set_pin(I2S_NUM, &i2s_pin_cfg), TAG, "set i2s pins failed"); + 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; + while (1) { + /* Write music to earphone */ + ret = i2s_write(I2S_NUM, music_pcm_start, music_pcm_end - music_pcm_start, &bytes_write, portMAX_DELAY); + if (ret != ESP_OK) { + /* Since we set timeout to 'portMAX_DELAY' in 'i2s_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 read failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]); + abort(); + } + /* Clear DMA buffer to avoid noise from legacy data in buffer */ + i2s_zero_dma_buffer(I2S_NUM); + 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 falied."); + abort(); + } + vTaskDelay(1000 / portTICK_RATE_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_read(I2S_NUM, mic_data, EXAMPLE_RECV_BUF_SIZE, &bytes_read, 100); + 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_write(I2S_NUM, mic_data, EXAMPLE_RECV_BUF_SIZE, &bytes_write, 100); + 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) +{ + /* Initialize i2s peripheral */ + if (i2s_driver_init() != ESP_OK) { + ESP_LOGE(TAG, "i2s driver init failed"); + abort(); + } + /* Initialize i2c peripheral and config es8311 codec by i2c */ + if (es8311_codec_init() != ESP_OK) { + ESP_LOGE(TAG, "es8311 codec init failed"); + abort(); + } +#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_es8311/main/idf_component.yml b/examples/peripherals/i2s/i2s_es8311/main/idf_component.yml new file mode 100644 index 0000000000..4f7079020c --- /dev/null +++ b/examples/peripherals/i2s/i2s_es8311/main/idf_component.yml @@ -0,0 +1,16 @@ +## IDF Component Manager Manifest File +## Version of your project. Should conform Semantic Versioning 2.0 rules https://semver.org/ +version: "1.0.0" + +dependencies: + espressif/es8311: "==0.0.2-alpha" + ## Required IDF version + idf: + version: "^4.4" + # # Put list of dependencies here + # # For components maintained by Espressif: + # component: + # version: "~1.0.0" + # # For 3rd party components: + # username/component: + # version: "~1.0.0" diff --git a/tools/ci/check_examples_cmake_make-cmake_ignore.txt b/tools/ci/check_examples_cmake_make-cmake_ignore.txt index 592564da46..af00a26c0e 100644 --- a/tools/ci/check_examples_cmake_make-cmake_ignore.txt +++ b/tools/ci/check_examples_cmake_make-cmake_ignore.txt @@ -7,3 +7,4 @@ build_system/cmake/ mb_example_common/ examples/cxx/experimental/blink_cxx examples/peripherals/lcd/lvgl +examples/peripherals/i2s/i2s_es8311