Explorar el Código

i2s: support esp32h2

laokaiyao hace 3 años
padre
commit
92ea22fe81

+ 1 - 1
components/driver/CMakeLists.txt

@@ -116,7 +116,7 @@ else()
     idf_component_register(SRCS "${srcs}"
                         INCLUDE_DIRS ${includes}
                         PRIV_INCLUDE_DIRS "include/driver"
-                        PRIV_REQUIRES efuse esp_timer esp_adc
+                        PRIV_REQUIRES efuse esp_timer esp_adc esp_psram
                         REQUIRES esp_pm esp_ringbuf freertos soc hal esp_hw_support
                         LDFRAGMENTS linker.lf)
 endif()

+ 20 - 5
components/driver/i2s/i2s_common.c

@@ -46,6 +46,9 @@
 #include "esp_attr.h"
 
 #include "esp_rom_gpio.h"
+#if CONFIG_SPIRAM && !CONFIG_IDF_TARGET_ESP32
+#include "esp_psram.h"
+#endif
 
 #define I2S_DMA_BUFFER_MAX_SIZE     (4092)
 
@@ -59,6 +62,7 @@
 #define I2S_MEM_ALLOC_CAPS      MALLOC_CAP_DEFAULT
 #endif //CONFIG_I2S_ISR_IRAM_SAFE
 #define I2S_DMA_ALLOC_CAPS      (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
+#define I2S_PSRAM_ALLOC_CAPS    (MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)
 
 /**
  * @brief Global i2s platform object
@@ -204,7 +208,6 @@ static i2s_controller_t *i2s_acquire_controller_obj(int id)
         portENTER_CRITICAL(&g_i2s.spinlock);
         if (g_i2s.controller[id]) {
             i2s_obj = g_i2s.controller[id];
-        } else {
         }
         portEXIT_CRITICAL(&g_i2s.spinlock);
         if (i2s_obj == NULL) {
@@ -407,12 +410,22 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
     handle->dma.desc_num = num;
     handle->dma.buf_size = bufsize;
 
-    handle->dma.desc = (lldesc_t **)heap_caps_calloc(num, sizeof(lldesc_t *), I2S_MEM_ALLOC_CAPS);
+    uint32_t dma_alloc_caps = I2S_DMA_ALLOC_CAPS;
+    uint32_t mem_alloc_caps = I2S_MEM_ALLOC_CAPS;
+
+#if (CONFIG_SPIRAM_USE_MALLOC || CONFIG_SPIRAM_USE_CAPS_ALLOC) && !CONFIG_IDF_TARGET_ESP32
+    if (handle->dma.psram_en && esp_psram_is_initialized()) {
+        ESP_LOGD(TAG, "DMA buffer will be allocate in the psram");
+        dma_alloc_caps = I2S_PSRAM_ALLOC_CAPS;
+        mem_alloc_caps = I2S_PSRAM_ALLOC_CAPS;
+    }
+#endif
+    handle->dma.desc = (lldesc_t **)heap_caps_aligned_calloc(4, num, sizeof(lldesc_t *), mem_alloc_caps);
     ESP_GOTO_ON_FALSE(handle->dma.desc, ESP_ERR_NO_MEM, err, TAG, "create I2S DMA decriptor array failed");
-    handle->dma.bufs = (uint8_t **)heap_caps_calloc(num, sizeof(uint8_t *), I2S_MEM_ALLOC_CAPS);
+    handle->dma.bufs = (uint8_t **)heap_caps_aligned_calloc(4, num, sizeof(uint8_t *), mem_alloc_caps);
     for (int i = 0; i < num; i++) {
         /* Allocate DMA descriptor */
-        handle->dma.desc[i] = (lldesc_t *) heap_caps_calloc(1, sizeof(lldesc_t), I2S_DMA_ALLOC_CAPS);
+        handle->dma.desc[i] = (lldesc_t *) heap_caps_aligned_calloc(4, 1, sizeof(lldesc_t), dma_alloc_caps);
         ESP_GOTO_ON_FALSE(handle->dma.desc[i], ESP_ERR_NO_MEM, err, TAG,  "allocate DMA description failed");
         handle->dma.desc[i]->owner = 1;
         handle->dma.desc[i]->eof = 1;
@@ -420,7 +433,7 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
         handle->dma.desc[i]->length = bufsize;
         handle->dma.desc[i]->size = bufsize;
         handle->dma.desc[i]->offset = 0;
-        handle->dma.bufs[i] = (uint8_t *) heap_caps_calloc(1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS);
+        handle->dma.bufs[i] = (uint8_t *) heap_caps_aligned_calloc(4, 1, bufsize * sizeof(uint8_t), dma_alloc_caps);
         handle->dma.desc[i]->buf = handle->dma.bufs[i];
         ESP_GOTO_ON_FALSE(handle->dma.desc[i]->buf, ESP_ERR_NO_MEM, err, TAG,  "allocate DMA buffer failed");
     }
@@ -782,6 +795,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
                           err, TAG, "register I2S tx channel failed");
         i2s_obj->tx_chan->role = chan_cfg->role;
         i2s_obj->tx_chan->dma.auto_clear = chan_cfg->auto_clear;
+        i2s_obj->tx_chan->dma.psram_en = chan_cfg->dma_buf_in_psram;
         i2s_obj->tx_chan->dma.desc_num = chan_cfg->dma_desc_num;
         i2s_obj->tx_chan->dma.frame_num = chan_cfg->dma_frame_num;
         i2s_obj->tx_chan->start = i2s_tx_channel_start;
@@ -794,6 +808,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
         ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_RX, chan_cfg->dma_desc_num),
                           err, TAG, "register I2S rx channel failed");
         i2s_obj->rx_chan->role = chan_cfg->role;
+        i2s_obj->rx_chan->dma.psram_en = chan_cfg->dma_buf_in_psram;
         i2s_obj->rx_chan->dma.desc_num = chan_cfg->dma_desc_num;
         i2s_obj->rx_chan->dma.frame_num = chan_cfg->dma_frame_num;
         i2s_obj->rx_chan->start = i2s_rx_channel_start;

+ 2 - 0
components/driver/i2s/i2s_pdm.c

@@ -67,8 +67,10 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
     portENTER_CRITICAL(&g_i2s.spinlock);
     /* Set clock configurations in HAL*/
     i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
+#if SOC_I2S_HW_VERSION_2
     /* Work aroud for PDM TX clock, set the raw division directly to reduce the noise */
     i2s_ll_tx_set_raw_clk_div(handle->controller->hal.dev, 1, 1, 0, 0);
+#endif
     portEXIT_CRITICAL(&g_i2s.spinlock);
 
     /* Update the mode info: clock configuration */

+ 1 - 0
components/driver/i2s/i2s_private.h

@@ -47,6 +47,7 @@ typedef struct {
     uint32_t                desc_num;       /*!< I2S DMA buffer number, it is also the number of DMA descriptor */
     uint32_t                frame_num;      /*!< I2S frame number in one DMA buffer. One frame means one-time sample data in all slots */
     uint32_t                buf_size;       /*!< dma buffer size */
+    bool                    psram_en;       /*!< Whether prefer to allocate the DMA buffers in the psram */
     bool                    auto_clear;     /*!< Set to auto clear DMA TX descriptor, i2s will always send zero automatically if no data to send */
     uint32_t                rw_pos;         /*!< reading/writing pointer position */
     void                    *curr_ptr;      /*!< Pointer to current dma buffer */

+ 26 - 23
components/driver/include/driver/i2s_common.h

@@ -24,6 +24,7 @@ extern "C" {
     .role = i2s_role, \
     .dma_desc_num = 6, \
     .dma_frame_num = 250, \
+    .dma_buf_in_psram = false, \
     .auto_clear = false, \
 }
 
@@ -36,43 +37,45 @@ extern "C" {
  *       The variables used in the function should be in the SRAM as well.
  */
 typedef struct {
-    i2s_isr_callback_t on_recv;         /**< Callback of data received event, only for rx channel
-                                         *   The event data includes DMA buffer address and size that just finished receiving data
-                                         */
-    i2s_isr_callback_t on_recv_q_ovf;   /**< Callback of receiving queue overflowed event, only for rx channel
-                                         *   The event data includes buffer size that has been overwritten
-                                         */
-    i2s_isr_callback_t on_sent;         /**< Callback of data sent event, only for tx channel
-                                         *   The event data includes DMA buffer address and size that just finished sending data
-                                         */
-    i2s_isr_callback_t on_send_q_ovf;   /**< Callback of sending queue overflowed evnet, only for tx channel
-                                         *   The event data includes buffer size that has been overwritten
-                                         */
+    i2s_isr_callback_t on_recv;             /**< Callback of data received event, only for rx channel
+                                             *   The event data includes DMA buffer address and size that just finished receiving data
+                                             */
+    i2s_isr_callback_t on_recv_q_ovf;       /**< Callback of receiving queue overflowed event, only for rx channel
+                                             *   The event data includes buffer size that has been overwritten
+                                             */
+    i2s_isr_callback_t on_sent;             /**< Callback of data sent event, only for tx channel
+                                             *   The event data includes DMA buffer address and size that just finished sending data
+                                             */
+    i2s_isr_callback_t on_send_q_ovf;       /**< Callback of sending queue overflowed evnet, only for tx channel
+                                             *   The event data includes buffer size that has been overwritten
+                                             */
 } i2s_event_callbacks_t;
 
 /**
  * @brief I2S controller channel configuration
 */
 typedef struct {
-    i2s_port_t              id;             /*!< I2S port id */
-    i2s_role_t              role;           /*!< I2S role, I2S_ROLE_MASTER or I2S_ROLE_SLAVE */
+    i2s_port_t          id;                 /*!< I2S port id */
+    i2s_role_t          role;               /*!< I2S role, I2S_ROLE_MASTER or I2S_ROLE_SLAVE */
 
     /* DMA configurations */
-    uint32_t                dma_desc_num;   /*!< I2S DMA buffer number, it is also the number of DMA descriptor */
-    uint32_t                dma_frame_num;  /*!< I2S frame number in one DMA buffer. One frame means one-time sample data in all slots */
-    bool                    auto_clear;     /*!< Set to auto clear DMA TX buffer, i2s will always send zero automatically if no data to send */
-
+    uint32_t            dma_desc_num;       /*!< I2S DMA buffer number, it is also the number of DMA descriptor */
+    uint32_t            dma_frame_num;      /*!< I2S frame number in one DMA buffer. One frame means one-time sample data in all slots */
+    bool                dma_buf_in_psram;   /*!< Prefer to allocate the DMA buffers in the psram (not supported on ESP32)
+                                             *   To allocate the DMA buffers in the psram, SPIRAM should be enabled in menuconfig
+                                             */
+    bool                auto_clear;         /*!< Set to auto clear DMA TX buffer, i2s will always send zero automatically if no data to send */
 } i2s_chan_config_t;
 
 /**
  * @brief I2S channel information
  */
 typedef struct {
-    i2s_port_t              id;             /*!< I2S port id */
-    i2s_role_t              role;           /*!< I2S role, I2S_ROLE_MASTER or I2S_ROLE_SLAVE */
-    i2s_dir_t               dir;            /*!< I2S channel direction */
-    i2s_comm_mode_t         mode;           /*!< I2S channel communication mode */
-    i2s_chan_handle_t       pair_chan;      /*!< I2S pair channel handle in duplex mode, always NULL in simplex mode */
+    i2s_port_t          id;                 /*!< I2S port id */
+    i2s_role_t          role;               /*!< I2S role, I2S_ROLE_MASTER or I2S_ROLE_SLAVE */
+    i2s_dir_t           dir;                /*!< I2S channel direction */
+    i2s_comm_mode_t     mode;               /*!< I2S channel communication mode */
+    i2s_chan_handle_t   pair_chan;          /*!< I2S pair channel handle in duplex mode, always NULL in simplex mode */
 } i2s_chan_info_t;
 
 /**

+ 2 - 2
components/driver/test_apps/i2s_test_apps/i2s/README.md

@@ -1,2 +1,2 @@
-| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
-| ----------------- | ----- | -------- | -------- | -------- |
+| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 | ESP32-H2 |
+| ----------------- | ----- | -------- | -------- | -------- | -------- |

+ 2 - 2
components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md

@@ -1,2 +1,2 @@
-| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
-| ----------------- | ----- | -------- | -------- | -------- |
+| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 | ESP32-H2 |
+| ----------------- | ----- | -------- | -------- | -------- | -------- |

+ 8 - 0
components/driver/test_apps/i2s_test_apps/test_inc/test_i2s.h

@@ -44,6 +44,14 @@ extern "C" {
 #define SLAVE_WS_IO 15
 #define DATA_IN_IO 19
 #define DATA_OUT_IO 18
+#elif CONFIG_IDF_TARGET_ESP32H2
+#define MASTER_MCK_IO 0
+#define MASTER_BCK_IO 4
+#define MASTER_WS_IO 5
+#define SLAVE_BCK_IO 2
+#define SLAVE_WS_IO 3
+#define DATA_IN_IO 6
+#define DATA_OUT_IO 7
 #endif
 
 #ifdef __cplusplus

+ 2 - 2
examples/peripherals/i2s/i2s_basic/i2s_pdm/README.md

@@ -1,5 +1,5 @@
-| Supported Targets | ESP32 | ESP32-C3 | ESP32-S3 |
-| ----------------- | ----- | -------- | -------- |
+| Supported Targets | ESP32 | ESP32-C3 | ESP32-S3 | ESP32-H2 |
+| ----------------- | ----- | -------- | -------- | -------- |
 
 # I2S Basic Standard Mode Example
 

+ 2 - 2
examples/peripherals/i2s/i2s_basic/i2s_std/README.md

@@ -1,5 +1,5 @@
-| Supported Targets | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 |
-| ----------------- | ----- | -------- | -------- | -------- |
+| Supported Targets | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 | ESP32-H2 |
+| ----------------- | ----- | -------- | -------- | -------- | -------- |
 
 # I2S Basic Standard Mode Example
 

+ 2 - 2
examples/peripherals/i2s/i2s_basic/i2s_tdm/README.md

@@ -1,5 +1,5 @@
-| Supported Targets | ESP32-C3 | ESP32-S3 |
-| ----------------- | -------- | -------- |
+| Supported Targets | ESP32-C3 | ESP32-S3 | ESP32-H2 |
+| ----------------- | -------- | -------- | -------- |
 
 # I2S Basic TDM Mode Example
 

+ 9 - 9
examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md

@@ -1,5 +1,5 @@
-| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
-| ----------------- | ----- | -------- | -------- | -------- |
+| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 | ESP32-H2 |
+| ----------------- | ----- | -------- | -------- | -------- | -------- |
 
 # I2S ES8311 Example
 
@@ -41,20 +41,20 @@ For more details, see [ES8311 datasheet](http://www.everest-semi.com/pdf/ES8311%
 │       WS-GPIO 5 ├──────────►│PIN8-LRCK       PIN13-OUTN├───────────┤         │
 │                 │           │                          │           └─────────┘
 │    SDOUT-GPIO 18├──────────►│PIN9-SDIN                 │
-│                 │           │                          │
+│         (GPIO 2)│           │                          │
 │     SDIN-GPIO 19│◄──────────┤PIN7-SDOUT                │
-│                 │           │                          │           ┌─────────┐
+│         (GPIO 3)│           │                          │           ┌─────────┐
 │                 │           │               PIN18-MIC1P├───────────┤         │
 │      SCL-GPIO 16├──────────►│PIN1 -CCLK                │           │  MIC    │
-│         (GPIO 7)│           │               PIN17-MIC1N├───────────┤         │
+│         (GPIO 6)│           │               PIN17-MIC1N├───────────┤         │
 │      SDA-GPIO 17│◄─────────►│PIN19-CDATA               │           └─────────┘
-│         (GPIO 8)│           │                          │
+│         (GPIO 7)│           │                          │
 │          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.
+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 & ESP32-H2 and GPIO 16/17 for other chips, same as GPIO 18/19, we use GPIO 2/3 instead.
 
 ### Dependency
 
@@ -123,8 +123,8 @@ If you have a logic analyzer, you can use a logic analyzer to grab GPIO signal d
 | 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 |
+| SDOUT |serial data out| GPIO_NUM_18/2 |
+| SDIN  |serial data in | GPIO_NUM_19/3 |
 
 ### Customize your own music
 

+ 20 - 11
examples/peripherals/i2s/i2s_codec/i2s_es8311/main/i2s_es8311_example.c

@@ -15,12 +15,12 @@
 
 /* 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)
+#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
+#define I2C_SCL_IO      (GPIO_NUM_6)
+#define I2C_SDA_IO      (GPIO_NUM_7)
 #else
-#define I2C_SDA_IO      (GPIO_NUM_15)
-#define I2C_SCL_IO      (GPIO_NUM_14)
+#define I2C_SCL_IO      (GPIO_NUM_16)
+#define I2C_SDA_IO      (GPIO_NUM_17)
 #endif
 
 /* I2S port and GPIOs */
@@ -28,13 +28,18 @@
 #define I2S_MCK_IO      (GPIO_NUM_0)
 #define I2S_BCK_IO      (GPIO_NUM_4)
 #define I2S_WS_IO       (GPIO_NUM_5)
+#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
+#define I2S_DO_IO       (GPIO_NUM_2)
+#define I2S_DI_IO       (GPIO_NUM_3)
+#else
 #define I2S_DO_IO       (GPIO_NUM_18)
 #define I2S_DI_IO       (GPIO_NUM_19)
-
+#endif
 /* Example configurations */
 #define EXAMPLE_RECV_BUF_SIZE   (2048)
 #define EXAMPLE_SAMPLE_RATE     (16000)
 #define EXAMPLE_MCLK_MULTIPLE   (256)
+#define EXAMPLE_MCLK_FREQ_HZ    (EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE)
 #define EXAMPLE_VOICE_VOLUME    CONFIG_EXAMPLE_VOICE_VOLUME
 #if CONFIG_EXAMPLE_MODE_ECHO
 #define EXAMPLE_MIC_GAIN        CONFIG_EXAMPLE_MIC_GAIN
@@ -71,7 +76,10 @@ static esp_err_t es8311_codec_init(void)
     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_inverted = false,
+        .sclk_inverted = false,
         .mclk_from_mclk_pin = true,
+        .mclk_frequency = EXAMPLE_MCLK_FREQ_HZ,
         .sample_frequency = EXAMPLE_SAMPLE_RATE
     };
 
@@ -88,16 +96,17 @@ static esp_err_t es8311_codec_init(void)
 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_PHILIP_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
         .gpio_cfg = {
-            .mclk = GPIO_NUM_0,
-            .bclk = GPIO_NUM_4,
-            .ws = GPIO_NUM_5,
-            .dout = GPIO_NUM_18,
-            .din = GPIO_NUM_19,
+            .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,

+ 9 - 8
examples/peripherals/i2s/i2s_codec/i2s_es8311/main/idf_component.yml

@@ -1,16 +1,17 @@
 ## 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"
+  espressif/es8311: "==1.0.0"
   ## Required IDF version
   idf:
-    version: "^5.0"
+    version: ">=4.1.0"
   # # Put list of dependencies here
   # # For components maintained by Espressif:
-  # component:
-  #   version: "~1.0.0"
+  # component: "~1.0.0"
   # # For 3rd party components:
-  # username/component:
+  # username/component: ">=1.0.0,<2.0.0"
+  # username2/component2:
   #   version: "~1.0.0"
+  #   # For transient dependencies `public` flag can be set.
+  #   # `public` flag doesn't have an effect dependencies of the `main` component.
+  #   # All dependencies of `main` are public by default.
+  #   public: true