Explorar o código

example/i2s: add es8311 example and i2s loop unit-test

laokaiyao %!s(int64=4) %!d(string=hai) anos
pai
achega
3eb09287f9

+ 82 - 2
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 <string.h>
 #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,

+ 6 - 0
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)

+ 147 - 0
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.

+ 2 - 0
examples/peripherals/i2s/i2s_es8311/main/CMakeLists.txt

@@ -0,0 +1,2 @@
+idf_component_register(SRCS "i2s_es8311_example.c"
+                    EMBED_FILES "canon.pcm")

+ 58 - 0
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

BIN=BIN
examples/peripherals/i2s/i2s_es8311/main/canon.pcm


+ 204 - 0
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 <stdio.h>
+#include <string.h>
+#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
+}

+ 16 - 0
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"

+ 1 - 0
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