From 409397f181e15dba32737747ebaa559e370f4f85 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 31 Dec 2024 18:32:30 +0800 Subject: [PATCH 1/2] fix(i2s): lock APB when using apll with DFS feature Closes https://github.com/espressif/esp-idf/issues/14707 Append to the commit ad9021a844c8922f69f9214571e52f9181871f66. --- components/driver/deprecated/i2s_legacy.c | 5 +++++ components/esp_driver_dac/dac_continuous.c | 2 +- components/esp_driver_i2s/i2s_pdm.c | 21 +++++++++++++++---- components/esp_driver_i2s/i2s_std.c | 13 ++++++++++-- components/esp_driver_i2s/i2s_tdm.c | 11 +++++++++- components/esp_lcd/i80/esp_lcd_panel_io_i2s.c | 2 +- docs/en/api-reference/peripherals/dac.rst | 2 +- docs/en/api-reference/peripherals/i2s.rst | 2 +- docs/zh_CN/api-reference/peripherals/dac.rst | 2 +- docs/zh_CN/api-reference/peripherals/i2s.rst | 2 +- 10 files changed, 49 insertions(+), 13 deletions(-) diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index bc7c0b3cb9..5b5148fedd 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -1479,6 +1479,11 @@ static esp_err_t i2s_init_legacy(i2s_port_t i2s_num, int intr_alloc_flag) /* Create power management lock */ #ifdef CONFIG_PM_ENABLE esp_pm_lock_type_t pm_lock = ESP_PM_APB_FREQ_MAX; +#if SOC_I2S_SUPPORTS_APLL + if (p_i2s[i2s_num]->use_apll) { + pm_lock = ESP_PM_NO_LIGHT_SLEEP; + } +#endif // SOC_I2S_SUPPORTS_APLL ESP_RETURN_ON_ERROR(esp_pm_lock_create(pm_lock, 0, "i2s_driver", &p_i2s[i2s_num]->pm_lock), TAG, "I2S pm lock error"); #endif //CONFIG_PM_ENABLE diff --git a/components/esp_driver_dac/dac_continuous.c b/components/esp_driver_dac/dac_continuous.c index c7e4ffb5ea..b3f8f9c25e 100644 --- a/components/esp_driver_dac/dac_continuous.c +++ b/components/esp_driver_dac/dac_continuous.c @@ -228,7 +228,7 @@ esp_err_t dac_continuous_new_channels(const dac_continuous_config_t *cont_cfg, d /* Create PM lock */ #if CONFIG_PM_ENABLE - esp_pm_lock_type_t pm_lock_type = ESP_PM_APB_FREQ_MAX; + esp_pm_lock_type_t pm_lock_type = cont_cfg->clk_src == DAC_DIGI_CLK_SRC_APLL ? ESP_PM_NO_LIGHT_SLEEP : ESP_PM_APB_FREQ_MAX; ESP_GOTO_ON_ERROR(esp_pm_lock_create(pm_lock_type, 0, "dac_driver", &handle->pm_lock), err3, TAG, "Failed to create DAC pm lock"); #endif handle->chan_cnt = __builtin_popcount(cont_cfg->chan_mask); diff --git a/components/esp_driver_i2s/i2s_pdm.c b/components/esp_driver_i2s/i2s_pdm.c index 615fc5b17c..3773537409 100644 --- a/components/esp_driver_i2s/i2s_pdm.c +++ b/components/esp_driver_i2s/i2s_pdm.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -202,6 +202,13 @@ esp_err_t i2s_channel_init_pdm_tx_mode(i2s_chan_handle_t handle, const i2s_pdm_t #ifdef CONFIG_PM_ENABLE esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX; +#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2 + if (pdm_tx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) { + /* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source + * HW 1 will have timing issue because the DMA and I2S are under different clock domains */ + pm_type = ESP_PM_NO_LIGHT_SLEEP; + } +#endif // SOC_I2S_SUPPORTS_APLL ESP_RETURN_ON_ERROR(esp_pm_lock_create(pm_type, 0, "i2s_driver", &handle->pm_lock), TAG, "I2S pm lock create failed"); #endif @@ -249,8 +256,10 @@ esp_err_t i2s_channel_reconfig_pdm_tx_clock(i2s_chan_handle_t handle, const i2s_ if (pdm_tx_cfg->clk_cfg.clk_src != clk_cfg->clk_src) { ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed"); esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX; -#if SOC_I2S_SUPPORTS_APLL +#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2 if (clk_cfg->clk_src == I2S_CLK_SRC_APLL) { + /* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source + * HW 1 will have timing issue because the DMA and I2S are under different clock domains */ pm_type = ESP_PM_NO_LIGHT_SLEEP; } #endif // SOC_I2S_SUPPORTS_APLL @@ -488,8 +497,10 @@ esp_err_t i2s_channel_init_pdm_rx_mode(i2s_chan_handle_t handle, const i2s_pdm_r #ifdef CONFIG_PM_ENABLE esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX; -#if SOC_I2S_SUPPORTS_APLL +#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2 if (pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) { + /* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source + * HW 1 will have timing issue because the DMA and I2S are under different clock domains */ pm_type = ESP_PM_NO_LIGHT_SLEEP; } #endif // SOC_I2S_SUPPORTS_APLL @@ -540,8 +551,10 @@ esp_err_t i2s_channel_reconfig_pdm_rx_clock(i2s_chan_handle_t handle, const i2s_ if (pdm_rx_cfg->clk_cfg.clk_src != clk_cfg->clk_src) { ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed"); esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX; -#if SOC_I2S_SUPPORTS_APLL +#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2 if (clk_cfg->clk_src == I2S_CLK_SRC_APLL) { + /* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source + * HW 1 will have timing issue because the DMA and I2S are under different clock domains */ pm_type = ESP_PM_NO_LIGHT_SLEEP; } #endif // SOC_I2S_SUPPORTS_APLL diff --git a/components/esp_driver_i2s/i2s_std.c b/components/esp_driver_i2s/i2s_std.c index 5b2d34dc87..d4965ede2c 100644 --- a/components/esp_driver_i2s/i2s_std.c +++ b/components/esp_driver_i2s/i2s_std.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -245,6 +245,13 @@ esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_conf #ifdef CONFIG_PM_ENABLE esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX; +#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2 + if (std_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) { + /* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source + * HW 1 will have timing issue because the DMA and I2S are under different clock domains */ + pm_type = ESP_PM_NO_LIGHT_SLEEP; + } +#endif // SOC_I2S_SUPPORTS_APLL ESP_RETURN_ON_ERROR(esp_pm_lock_create(pm_type, 0, "i2s_driver", &handle->pm_lock), TAG, "I2S pm lock create failed"); #endif @@ -293,8 +300,10 @@ esp_err_t i2s_channel_reconfig_std_clock(i2s_chan_handle_t handle, const i2s_std if (std_cfg->clk_cfg.clk_src != clk_cfg->clk_src) { ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed"); esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX; -#if SOC_I2S_SUPPORTS_APLL +#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2 if (clk_cfg->clk_src == I2S_CLK_SRC_APLL) { + /* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source + * HW 1 will have timing issue because the DMA and I2S are under different clock domains */ pm_type = ESP_PM_NO_LIGHT_SLEEP; } #endif // SOC_I2S_SUPPORTS_APLL diff --git a/components/esp_driver_i2s/i2s_tdm.c b/components/esp_driver_i2s/i2s_tdm.c index d840825b50..c5fd8d6480 100644 --- a/components/esp_driver_i2s/i2s_tdm.c +++ b/components/esp_driver_i2s/i2s_tdm.c @@ -254,6 +254,13 @@ esp_err_t i2s_channel_init_tdm_mode(i2s_chan_handle_t handle, const i2s_tdm_conf #endif #ifdef CONFIG_PM_ENABLE esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX; +#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2 + if (tdm_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) { + /* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source + * HW 1 will have timing issue because the DMA and I2S are under different clock domains */ + pm_type = ESP_PM_NO_LIGHT_SLEEP; + } +#endif // SOC_I2S_SUPPORTS_APLL ESP_RETURN_ON_ERROR(esp_pm_lock_create(pm_type, 0, "i2s_driver", &handle->pm_lock), TAG, "I2S pm lock create failed"); #endif @@ -302,8 +309,10 @@ esp_err_t i2s_channel_reconfig_tdm_clock(i2s_chan_handle_t handle, const i2s_tdm if (tdm_cfg->clk_cfg.clk_src != clk_cfg->clk_src) { ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed"); esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX; -#if SOC_I2S_SUPPORTS_APLL +#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2 if (clk_cfg->clk_src == I2S_CLK_SRC_APLL) { + /* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source + * HW 1 will have timing issue because the DMA and I2S are under different clock domains */ pm_type = ESP_PM_NO_LIGHT_SLEEP; } #endif // SOC_I2S_SUPPORTS_APLL diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c b/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c index ac520a6ed9..a73ba64c25 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c @@ -667,7 +667,7 @@ static esp_err_t i2s_lcd_select_periph_clock(esp_lcd_i80_bus_handle_t bus, lcd_c // create pm lock based on different clock source // clock sources like PLL and XTAL will be turned off in light sleep #if CONFIG_PM_ENABLE - ESP_RETURN_ON_ERROR(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "i80_bus_lcd", &bus->pm_lock), TAG, "create pm lock failed"); + ESP_RETURN_ON_ERROR(esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i80_bus_lcd", &bus->pm_lock), TAG, "create pm lock failed"); #endif return ESP_OK; } diff --git a/docs/en/api-reference/peripherals/dac.rst b/docs/en/api-reference/peripherals/dac.rst index 06b5cc55f0..4cb3eb12b3 100644 --- a/docs/en/api-reference/peripherals/dac.rst +++ b/docs/en/api-reference/peripherals/dac.rst @@ -96,7 +96,7 @@ Power Management When the power management is enabled (i.e., :ref:`CONFIG_PM_ENABLE` is on), the system will adjust or stop the clock source of DAC before entering Light-sleep mode, thus potential influence to the DAC signals may lead to false data conversion. -When using DAC driver in continuous mode, it can prevent the system from changing or stopping the clock source in DMA or cosine mode by acquiring a power management lock. The power lock type will be set to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`. Whenever the DAC is converting (i.e., DMA or cosine wave generator is working), the driver guarantees that the power management lock is acquired after calling :cpp:func:`dac_continuous_enable`. Likewise, the driver will release the lock when :cpp:func:`dac_continuous_disable` is called. +When using DAC driver in continuous mode, it can prevent the system from changing or stopping the clock source in DMA or cosine mode by acquiring a power management lock. When the clock source is generated from APB, the lock type will be set to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`. When the clock source is APLL (only in DMA mode), it will be set to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_NO_LIGHT_SLEEP`. Whenever the DAC is converting (i.e., DMA or cosine wave generator is working), the driver guarantees that the power management lock is acquired after calling :cpp:func:`dac_continuous_enable`. Likewise, the driver will release the lock when :cpp:func:`dac_continuous_disable` is called. IRAM Safe ^^^^^^^^^ diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index 47a8e73756..a0ac096885 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -243,7 +243,7 @@ Power Management When the power management is enabled (i.e., :ref:`CONFIG_PM_ENABLE` is on), the system will adjust or stop the source clock of I2S before entering Light-sleep, thus potentially changing the I2S signals and leading to transmitting or receiving invalid data. -The I2S driver can prevent the system from changing or stopping the source clock by acquiring a power management lock. The power lock type will be set to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`. Whenever the user is reading or writing via I2S (i.e., calling :cpp:func:`i2s_channel_read` or :cpp:func:`i2s_channel_write`), the driver guarantees that the power management lock is acquired. Likewise, the driver releases the lock after the reading or writing finishes. +The I2S driver can prevent the system from changing or stopping the source clock by acquiring a power management lock. When the source clock is generated from APB, the lock type will be set to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX` and when the source clock is APLL (if supported), it will be set to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_NO_LIGHT_SLEEP`. Whenever the user is reading or writing via I2S (i.e., calling :cpp:func:`i2s_channel_read` or :cpp:func:`i2s_channel_write`), the driver guarantees that the power management lock is acquired. Likewise, the driver releases the lock after the reading or writing finishes. .. only:: SOC_I2S_SUPPORT_SLEEP_RETENTION diff --git a/docs/zh_CN/api-reference/peripherals/dac.rst b/docs/zh_CN/api-reference/peripherals/dac.rst index d96ce61213..1c45cbf8c5 100644 --- a/docs/zh_CN/api-reference/peripherals/dac.rst +++ b/docs/zh_CN/api-reference/peripherals/dac.rst @@ -96,7 +96,7 @@ DAC 外设中包含一个余弦波发生器,可以在通道上产生余弦波 启用电源管理时(即开启 :ref:`CONFIG_PM_ENABLE`),系统会在进入 Light-sleep 模式前调整或停止 DAC 时钟源,这可能会影响 DAC 信号,从而导致数据无法正确转换。 -在连续模式下使用 DAC 驱动时,可以通过获取电源管理锁来防止系统在 DMA 或余弦波模式下改变或停止时钟源。电源锁的类型将被设置为 :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`。在进行 DAC 转换时(即 DMA 或余弦波发生器运行时),驱动程序会保证在调用 :cpp:func:`dac_continuous_enable` 后获取电源管理锁。同样地,在调用 :cpp:func:`dac_continuous_disable` 时,驱动程序会释放锁。 +在连续模式下使用 DAC 驱动时,可以通过获取电源管理锁来防止系统在 DMA 或余弦波模式下改变或停止时钟源。时钟源为 APB 时,锁的类型将被设置为 :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`。时钟源为 APLL 时(仅在 DMA 模式下),锁的类型将被设置为 :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_NO_LIGHT_SLEEP`。在进行 DAC 转换时(即 DMA 或余弦波发生器运行时),驱动程序会保证在调用 :cpp:func:`dac_continuous_enable` 后获取电源管理锁。同样地,在调用 :cpp:func:`dac_continuous_disable` 时,驱动程序会释放锁。 IRAM 安全 ^^^^^^^^^ diff --git a/docs/zh_CN/api-reference/peripherals/i2s.rst b/docs/zh_CN/api-reference/peripherals/i2s.rst index a5697022f9..81c73af8bd 100644 --- a/docs/zh_CN/api-reference/peripherals/i2s.rst +++ b/docs/zh_CN/api-reference/peripherals/i2s.rst @@ -237,7 +237,7 @@ I2S 驱动中的资源可分为三个级别: 电源管理启用(即开启 :ref:`CONFIG_PM_ENABLE`)时,系统将在进入 Light-sleep 前调整或停止 I2S 时钟源,这可能会影响 I2S 信号,从而导致传输或接收的数据无效。 -I2S 驱动可以获取电源管理锁,从而防止系统设置更改或时钟源被禁用。电源锁的类型将被设置为 :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`。用户通过 I2S 读写时(即调用 :cpp:func:`i2s_channel_read` 或 :cpp:func:`i2s_channel_write`),驱动程序将获取电源管理锁,并在读写完成后释放锁。 +I2S 驱动可以获取电源管理锁,从而防止系统设置更改或时钟源被禁用。时钟源为 APB 时,锁的类型将被设置为 :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`。时钟源为 APLL(若支持)时,锁的类型将被设置为 :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_NO_LIGHT_SLEEP`。用户通过 I2S 读写时(即调用 :cpp:func:`i2s_channel_read` 或 :cpp:func:`i2s_channel_write`),驱动程序将获取电源管理锁,并在读写完成后释放锁。 .. only:: SOC_I2S_SUPPORT_SLEEP_RETENTION From 6f40f190477e5e51da098d56ce87ba06076319aa Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 7 Jan 2025 19:23:30 +0800 Subject: [PATCH 2/2] docs(i2s): add application notes to es7210 example --- .../i2s/i2s_codec/i2s_es7210_tdm/README.md | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md b/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md index 85cc1c9486..dab5455536 100644 --- a/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md +++ b/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md @@ -5,7 +5,7 @@ (See the README.md file in the upper level 'examples' directory for more information about examples.) -I2S on `ESP32S3` and `ESP32C3` supports [TDM mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/i2s.html#tdm-mode), in which multiple slots can be transmitted by standard I2S connection. +The targets that listed on the top support [TDM mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/i2s.html#tdm-mode), in which multiple slots can be transmitted by standard I2S connection. This example demonstrates how to use I2S TDM mode to record 4 MICs connected to [ES7210](http://www.everest-semi.com/pdf/ES7210%20PB.pdf) codec. ES7210 has 4 TDM modes, which are `ES7210_I2S_FMT_I2S` `ES7210_I2S_FMT_LJ` `ES7210_I2S_FMT_DSP_A` and `ES7210_I2S_FMT_DSP_B`, and they are all supported by I2S TDM driver. Relation between ES7210 TDM modes and I2S Driver TDM modes is shown in the following table. @@ -91,6 +91,63 @@ I (10431) gpio: GPIO[4]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulld I (10431) example: You can now safely remove the card, recorded file is /RECORD.WAV ``` +## Application Notes + +TDM mode is widely used in multi-channel scenario. Some ADC/DAC (e.g., ES7210 and ES7243) that supports TDM can be cascaded to sample more channels synchronously. + +Take ES7210 for example, it is a 4-channel audio ADC that supports TDM. And we can chain upto four ES7210 to form a 16-channel recorder, meanwhile it only needs one I2S port. + +You can refer to the connection as follow: + +``` +┌───────────────┐ +│ ESP │ +│ │ +│ MCLK ├───────────┬──────────────────────────────┬──────────────────────────────┬──────────────────────────────┐ +│ │ │ │ │ │ +│ BCLK ├────────┬──┼───────────────────────────┬──┼───────────────────────────┬──┼───────────────────────────┐ │ +│ │ │ │ │ │ │ │ │ │ +│ WS ├─────┬──┼──┼────────────────────────┬──┼──┼────────────────────────┬──┼──┼────────────────────────┐ │ │ +│ │ │ │ │ │ │ │ │ │ │ │ │ │ +│ DOUT │ │ │ │ ┌───────────────┐ │ │ │ ┌───────────────┐ │ │ │ ┌───────────────┐ │ │ │ ┌───────────────┐ +│ │ │ │ │ │ ES7210_0 │ │ │ │ │ ES7210_1 │ │ │ │ │ ES7210_2 │ │ │ │ │ ES7210_3 │ +│ DIN │◄─┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ +└───────────────┘ │ │ │ └───►│ MCLK │ │ │ └───►│ MCLK │ │ │ └───►│ MCLK │ │ │ └───►│ MCLK │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ └──────►│ SCLK │ │ └──────►│ SCLK │ │ └──────►│ SCLK │ │ └──────►│ SCLK │ + │ │ │ │ │ │ │ │ │ │ │ │ │ + │ └─────────►│ LRCK │ └─────────►│ LRCK │ └─────────►│ LRCK │ └─────────►│ LRCK │ + │ │ │ │ │ │ │ │ │ + └─────────────┤ TDMOUT │ ┌──────────┤ TDMOUT │ ┌──────────┤ TDMOUT │ ┌──────────┤ TDMOUT │ + │ │ │ │ │ │ │ │ │ │ │ + ┌───►│ TDMIN │ │ ┌───►│ TDMIN │ │ ┌───►│ TDMIN │ │ │ TDMIN │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ └───────────────┘ │ │ └───────────────┘ │ │ └───────────────┘ │ └───────────────┘ + │ │ │ │ │ │ + └────────────────────────┘ └────────────────────────┘ └────────────────────────┘ +``` + +### How A Frame Formed in This Cascaded Case + +Generally, all the ES7210 will send the data that sampled by itself at the beginning of a frame, and then catenate the backward ES7210 data behind. In another word, ES7210_0 will send the data in the order ES7210_0 -> ES7210_1 -> ES7210_2 -> ES7210_3. + +See the detailed steps as follows: + +1. First 4 channels of the 16 channels: + - ES7210_3 send data that sampled by itself to ES7210_2; + - ES7210_2 send data that sampled by itself to ES7210_1, store the data sent from ES7210_3; + - ES7210_1 send data that sampled by itself to ES7210_0, store the data sent from ES7210_2; + - ES7210_0 send data that sampled by itself to ESP, store the data sent from ES7210_1; +2. Second 4 channels of the 16 channels: + - ES7210_2 send the stored data (i.e., sampled by ES7210_3) to ES7210_1; + - ES7210_1 send the stored data (i.e., sampled by ES7210_2) to ES7210_0, and store the data from ES7210_2 (i.e., sampled by ES7210_3); + - ES7210_0 send the stored data (i.e., sampled by ES7210_1) to ESP, and store the data sent from ES7210_1 (i.e., sampled by ES7210_2); +3. Third 4 channels of the 16 channels: + - ES7210_1 send the stored data (i.e., sampled by ES7210_3) to ES7210_0; + - ES7210_0 send the stored data (i.e., sampled by ES7210_2) to ESP, and store the data from ES7210_1 (i.e., sampled by ES7210_3); +4. Last 4 channels of the 16 channels: + - ES7210_0 send the stored data (i.e., sampled by ES7210_3) to ESP; + ## Troubleshooting For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.