diff --git a/components/driver/.build-test-rules.yml b/components/driver/.build-test-rules.yml index 5c6a32371d..92ea5c9780 100644 --- a/components/driver/.build-test-rules.yml +++ b/components/driver/.build-test-rules.yml @@ -27,10 +27,6 @@ components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac: components/driver/test_apps/i2s_test_apps/legacy_i2s_driver: disable: - if: SOC_I2S_SUPPORTED != 1 - disable_test: - - if: IDF_TARGET == "esp32c6" - temporary: true - reason: target esp32c6 is not supported yet components/driver/test_apps/ledc: disable: diff --git a/components/driver/i2s/i2s_common.c b/components/driver/i2s/i2s_common.c index ed2dcb8363..b7df13f663 100644 --- a/components/driver/i2s/i2s_common.c +++ b/components/driver/i2s/i2s_common.c @@ -497,6 +497,11 @@ uint32_t i2s_get_source_clk_freq(i2s_clock_src_t clk_src, uint32_t mclk_freq_hz) case I2S_CLK_SRC_PLL_96M: (void)mclk_freq_hz; return I2S_LL_PLL_F96M_CLK_FREQ; +#endif +#if SOC_I2S_SUPPORTS_PLL_F64M + case I2S_CLK_SRC_PLL_64M: + (void)mclk_freq_hz; + return I2S_LL_PLL_F64M_CLK_FREQ; #endif default: // Invalid clock source diff --git a/components/driver/test_apps/i2s_test_apps/i2s/README.md b/components/driver/test_apps/i2s_test_apps/i2s/README.md index 6f026d8e9e..19f1d19a54 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s/README.md +++ b/components/driver/test_apps/i2s_test_apps/i2s/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c index e242a09ebf..b8aaa01570 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c +++ b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c @@ -748,16 +748,21 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_c /* Test common sample rate * Workaround: set 12000 as 12001 to bypass the unknown failure, TODO: IDF-6705 */ - uint32_t test_freq[] = {8000, 10000, 11025, 12001, 16000, 22050, 24000, - 32000, 44100, 48000, 64000, 88200, 96000, - 128000, 144000, 196000}; + const uint32_t test_freq[] = { + 8000, 10000, 11025, 12001, 16000, 22050, + 24000, 32000, 44100, 48000, 64000, 88200, + 96000, 128000,144000,196000}; int real_pulse = 0; int case_cnt = sizeof(test_freq) / sizeof(uint32_t); -#if SOC_I2S_HW_VERSION_2 +#if SOC_I2S_SUPPORTS_XTAL // Can't support a very high sample rate while using XTAL as clock source if (clk_cfg->clk_src == I2S_CLK_SRC_XTAL) { case_cnt = 10; } +#endif +#if CONFIG_IDF_ENV_FPGA + // Limit the test sample rate on FPGA platform due to the low frequency it supports. + case_cnt = 10; #endif for (int i = 0; i < case_cnt; i++) { int expt_pulse = (int)((float)test_freq[i] * (TEST_I2S_PERIOD_MS / 1000.0)); @@ -797,7 +802,7 @@ TEST_CASE("I2S_default_PLL_clock_test", "[i2s]") TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg); -#if SOC_I2S_HW_VERSION_2 +#if SOC_I2S_SUPPORTS_XTAL std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_XTAL; i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg); #endif diff --git a/components/driver/test_apps/i2s_test_apps/i2s/pytest_i2s.py b/components/driver/test_apps/i2s_test_apps/i2s/pytest_i2s.py index 5e28269b5c..8920052d55 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s/pytest_i2s.py +++ b/components/driver/test_apps/i2s_test_apps/i2s/pytest_i2s.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import pytest @@ -10,6 +10,7 @@ from pytest_embedded import Dut @pytest.mark.esp32c3 @pytest.mark.esp32c6 @pytest.mark.esp32s3 +@pytest.mark.esp32h2 @pytest.mark.generic @pytest.mark.parametrize( 'config', diff --git a/components/driver/test_apps/i2s_test_apps/i2s_tdm/README.md b/components/driver/test_apps/i2s_test_apps/i2s_tdm/README.md index 721d4348d7..541c8b1e9a 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s_tdm/README.md +++ b/components/driver/test_apps/i2s_test_apps/i2s_tdm/README.md @@ -1,3 +1,3 @@ -| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/i2s_test_apps/i2s_tdm/pytest_i2s_tdm_full_duplex.py b/components/driver/test_apps/i2s_test_apps/i2s_tdm/pytest_i2s_tdm_full_duplex.py index 25d4dce7b7..458e6aa28a 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s_tdm/pytest_i2s_tdm_full_duplex.py +++ b/components/driver/test_apps/i2s_test_apps/i2s_tdm/pytest_i2s_tdm_full_duplex.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 import pytest @@ -6,6 +6,7 @@ import pytest @pytest.mark.esp32s3 @pytest.mark.esp32c3 @pytest.mark.esp32c6 +@pytest.mark.esp32h2 @pytest.mark.generic_multi_device @pytest.mark.parametrize('count', [ 2, diff --git a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md index 6f026d8e9e..19f1d19a54 100644 --- a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md +++ b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/main/test_legacy_i2s.c b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/main/test_legacy_i2s.c index 26b0c97306..c6f8ea9e9f 100644 --- a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/main/test_legacy_i2s.c +++ b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/main/test_legacy_i2s.c @@ -876,11 +876,17 @@ static void i2s_test_common_sample_rate(i2s_port_t id) /* Test common sample rate * Workaround: set 12000 as 12001 to bypass the unknown failure, TODO: IDF-6705 */ - uint32_t test_freq[] = {8000, 10000, 11025, 12001, 16000, 22050, 24000, - 32000, 44100, 48000, 64000, 88200, 96000, - 128000, 144000, 196000}; - int case_cnt = sizeof(test_freq) / sizeof(uint32_t); + const uint32_t test_freq[] = { + 8000, 10000, 11025, 12001, 16000, 22050, + 24000, 32000, 44100, 48000, 64000, 88200, + 96000, 128000, 144000,196000}; int real_pulse = 0; +#if CONFIG_IDF_ENV_FPGA + // Limit the test sample rate on FPGA platform due to the low frequency it supports. + int case_cnt = 10; +#else + int case_cnt = sizeof(test_freq) / sizeof(uint32_t); +#endif // Acquire the PM lock incase Dynamic Frequency Scaling(DFS) lower the frequency #ifdef CONFIG_PM_ENABLE diff --git a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/pytest_legacy_i2s.py b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/pytest_legacy_i2s.py index e3777b1045..0efdd44a40 100644 --- a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/pytest_legacy_i2s.py +++ b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/pytest_legacy_i2s.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import pytest @@ -9,6 +9,8 @@ from pytest_embedded import Dut @pytest.mark.esp32s2 @pytest.mark.esp32c3 @pytest.mark.esp32s3 +@pytest.mark.esp32c6 +@pytest.mark.esp32h2 @pytest.mark.generic @pytest.mark.parametrize( 'config', diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index c6ef55a6a8..ab1fb68cdc 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -936,6 +936,8 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) */ static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) { + // Due to the lack of `PDM to PCM` module on ESP32-C3, PDM RX is not available + HAL_ASSERT(!pdm_enable); hw->rx_conf.rx_pdm_en = 0; hw->rx_conf.rx_tdm_en = 1; } diff --git a/components/hal/esp32c6/include/hal/i2s_ll.h b/components/hal/esp32c6/include/hal/i2s_ll.h index e3d9cfd404..a3a763a2ea 100644 --- a/components/hal/esp32c6/include/hal/i2s_ll.h +++ b/components/hal/esp32c6/include/hal/i2s_ll.h @@ -951,6 +951,8 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) */ static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) { + // Due to the lack of `PDM to PCM` module on ESP32-C6, PDM RX is not available + HAL_ASSERT(!pdm_enable); hw->rx_conf.rx_pdm_en = 0; hw->rx_conf.rx_tdm_en = 1; } diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h new file mode 100644 index 0000000000..df18b690e7 --- /dev/null +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -0,0 +1,1190 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for I2S register operations +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in hal/include/hal/readme.md + ******************************************************************************/ + +#pragma once +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "soc/i2s_periph.h" +#include "soc/i2s_struct.h" +#include "soc/pcr_struct.h" +#include "hal/i2s_types.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2S_LL_GET_HW(num) (((num) == 0)? (&I2S0) : NULL) + +#define I2S_LL_TDM_CH_MASK (0xffff) +#define I2S_LL_PDM_BCK_FACTOR (64) + +#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9) +#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) + +#define I2S_LL_PLL_F96M_CLK_FREQ (96 * 1000000) // PLL_F96M_CLK: 96MHz +#define I2S_LL_PLL_F64M_CLK_FREQ (64 * 1000000) // PLL_F64M_CLK: 64MHz +#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT + +/* I2S clock configuration structure */ +typedef struct { + uint16_t mclk_div; // I2S module clock divider, Fmclk = Fsclk /(mclk_div+b/a) + uint16_t a; + uint16_t b; // The decimal part of module clock divider, the decimal is: b/a +} i2s_ll_mclk_div_t; + +/** + * @brief I2S module general init, enable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_enable_clock(i2s_dev_t *hw) +{ + // The clock gate enabling is moved to `periph_module_enable` + (void)hw; +} + +/** + * @brief I2S module disable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_disable_clock(i2s_dev_t *hw) +{ + // The clock gate disabling is moved to `periph_module_disable` + (void)hw; +} + +/** + * @brief Enable I2S tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_en = 1; +} + +/** + * @brief Enable I2S rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 1; +} + +/** + * @brief Disable I2S tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_en = 0; +} + +/** + * @brief Disable I2S rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 0; +} + +/** + * @brief I2S mclk use tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_mclk_bind_to_tx_clk(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_rx_clkm_conf.i2s_mclk_sel = 0; +} + +/** + * @brief I2S mclk use rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_mclk_bind_to_rx_clk(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_rx_clkm_conf.i2s_mclk_sel = 1; +} + +/** + * @brief Enable I2S TX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->tx_conf.tx_slave_mod = slave_en; +} + +/** + * @brief Enable I2S RX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->rx_conf.rx_slave_mod = slave_en; +} + +/** + * @brief Reset I2S TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_reset(i2s_dev_t *hw) +{ + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; +} + +/** + * @brief Reset I2S RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_reset(i2s_dev_t *hw) +{ + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; +} + +/** + * @brief Reset I2S TX FIFO + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw) +{ + hw->tx_conf.tx_fifo_reset = 1; + hw->tx_conf.tx_fifo_reset = 0; +} + +/** + * @brief Reset I2S RX FIFO + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) +{ + hw->rx_conf.rx_fifo_reset = 1; + hw->rx_conf.rx_fifo_reset = 0; +} + +/** + * @brief Set TX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock. + */ +static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + (void)hw; + switch (src) + { + case I2S_CLK_SRC_XTAL: + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 0; + break; + case I2S_CLK_SRC_PLL_96M: + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 1; + break; + case I2S_CLK_SRC_PLL_64M: + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 2; + break; + default: + HAL_ASSERT(false && "unsupported clock source"); + break; + } +} + +/** + * @brief Set RX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock + */ +static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + (void)hw; + switch (src) + { + case I2S_CLK_SRC_XTAL: + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 0; + break; + case I2S_CLK_SRC_PLL_96M: + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 1; + break; + case I2S_CLK_SRC_PLL_64M: + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 2; + break; + default: + HAL_ASSERT(false && "unsupported clock source"); + break; + } +} + +/** + * @brief Set I2S tx bck div num + * + * @param hw Peripheral I2S hardware instance address. + * @param val value to set tx bck div num + */ +static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) +{ + hw->tx_conf.tx_bck_div_num = val - 1; +} + +/** + * @brief Set I2S tx raw clock division + * + * @param hw Peripheral I2S hardware instance address. + * @param x div x + * @param y div y + * @param z div z + * @param yn1 yn1 + */ +static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1) +{ + (void)hw; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = x; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = y; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = z; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = yn1; +} + +/** + * @brief Set I2S rx raw clock division + * + * @param hw Peripheral I2S hardware instance address. + * @param x div x + * @param y div y + * @param z div z + * @param yn1 yn1 + */ +static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1) +{ + (void)hw; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = x; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = y; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = z; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = yn1; +} + +/** + * @brief Configure I2S TX module clock divider + * + * @param hw Peripheral I2S hardware instance address. + * @param sclk system clock + * @param mclk module clock + * @param mclk_div integer part of the division from sclk to mclk + */ +static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mclk, uint32_t mclk_div) +{ + (void)hw; + int ma = 0; + int mb = 0; + int denominator = 1; + int numerator = 0; + + uint32_t freq_diff = abs((int)sclk - (int)(mclk * mclk_div)); + if (!freq_diff) { + goto finish; + } + float decimal = freq_diff / (float)mclk; + // Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 / 126.0 + if (decimal > 125.0 / 126.0) { + mclk_div++; + goto finish; + } + uint32_t min = ~0; + for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) { + int b = (int)(a * (freq_diff / (double)mclk) + 0.5); + ma = freq_diff * a; + mb = mclk * b; + if (ma == mb) { + denominator = a; + numerator = b; + goto finish; + } + if (abs((mb - ma)) < min) { + denominator = a; + numerator = b; + min = abs(mb - ma); + } + } +finish: + if (denominator == 0 || numerator == 0) { + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = 0; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = 0; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = 0; + } else { + if (numerator > denominator / 2) { + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = denominator / (denominator - numerator) - 1; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = denominator % (denominator - numerator); + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = denominator - numerator; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = 1; + } else { + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = denominator / numerator - 1; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = denominator % numerator; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = numerator; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = 0; + } + } + HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_tx_clkm_conf, i2s_tx_clkm_div_num, mclk_div); +} + +/** + * @brief Set I2S rx bck div num + * + * @param hw Peripheral I2S hardware instance address. + * @param val value to set rx bck div num + */ +static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) +{ + hw->rx_conf.rx_bck_div_num = val - 1; +} + +/** + * @brief Configure I2S RX module clock divider + * @note mclk on ESP32 is shared by both TX and RX channel + * + * @param hw Peripheral I2S hardware instance address. + * @param sclk system clock, 0 means use apll + * @param mclk module clock + * @param mclk_div integer part of the division from sclk to mclk + */ +static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mclk, uint32_t mclk_div) +{ + (void)hw; + int ma = 0; + int mb = 0; + int denominator = 1; + int numerator = 0; + + uint32_t freq_diff = abs((int)sclk - (int)(mclk * mclk_div)); + if (!freq_diff) { + goto finish; + } + float decimal = freq_diff / (float)mclk; + // Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 / 126.0 + if (decimal > 125.0 / 126.0) { + mclk_div++; + goto finish; + } + uint32_t min = ~0; + for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) { + int b = (int)(a * (freq_diff / (double)mclk) + 0.5); + ma = freq_diff * a; + mb = mclk * b; + if (ma == mb) { + denominator = a; + numerator = b; + goto finish; + } + if (abs((mb - ma)) < min) { + denominator = a; + numerator = b; + min = abs(mb - ma); + } + } +finish: + if (denominator == 0 || numerator == 0) { + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = 0; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = 0; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = 0; + } else { + if (numerator > denominator / 2) { + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = denominator / (denominator - numerator) - 1; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = denominator % (denominator - numerator); + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = denominator - numerator; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = 1; + } else { + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = denominator / numerator - 1; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = denominator % numerator; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = numerator; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = 0; + } + } + HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_rx_clkm_conf, i2s_rx_clkm_div_num, mclk_div); +} + +/** + * @brief Start I2S TX + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_start(i2s_dev_t *hw) +{ + // Have to update registers before start + hw->tx_conf.tx_update = 1; + while (hw->tx_conf.tx_update); + hw->tx_conf.tx_start = 1; +} + +/** + * @brief Start I2S RX + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_start(i2s_dev_t *hw) +{ + // Have to update registers before start + hw->rx_conf.rx_update = 1; + while (hw->rx_conf.rx_update); + hw->rx_conf.rx_start = 1; +} + +/** + * @brief Stop I2S TX + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_stop(i2s_dev_t *hw) +{ + hw->tx_conf.tx_start = 0; +} + +/** + * @brief Stop I2S RX + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_stop(i2s_dev_t *hw) +{ + hw->rx_conf.rx_start = 0; +} + +/** + * @brief Configure TX WS signal width + * + * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle + */ +static inline void i2s_ll_tx_set_ws_width(i2s_dev_t *hw, int width) +{ + hw->tx_conf1.tx_tdm_ws_width = width - 1; +} + +/** + * @brief Configure RX WS signal width + * + * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle + */ +static inline void i2s_ll_rx_set_ws_width(i2s_dev_t *hw, int width) +{ + hw->rx_conf1.rx_tdm_ws_width = width - 1; +} + +/** + * @brief Configure the received length to trigger in_suc_eof interrupt + * + * @param hw Peripheral I2S hardware instance address. + * @param eof_num the byte length to trigger in_suc_eof interrupt + */ +static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num) +{ + hw->rx_eof_num.rx_eof_num = eof_num; +} + +/** + * @brief Congfigure TX chan bit and audio data bit + * + * @param hw Peripheral I2S hardware instance address. + * @param chan_bit The chan bit width + * @param data_bit The audio data bit width + */ +static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) +{ + hw->tx_conf1.tx_bits_mod = data_bit - 1; + hw->tx_conf1.tx_tdm_chan_bits = chan_bit - 1; +} + +/** + * @brief Congfigure RX chan bit and audio data bit + * + * @param hw Peripheral I2S hardware instance address. + * @param chan_bit The chan bit width + * @param data_bit The audio data bit width + */ +static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) +{ + hw->rx_conf1.rx_bits_mod = data_bit - 1; + hw->rx_conf1.rx_tdm_chan_bits = chan_bit - 1; +} + +/** + * @brief Configure RX half_sample_bit + * + * @param hw Peripheral I2S hardware instance address. + * @param half_sample_bits half sample bit width + */ +static inline void i2s_ll_tx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_conf1, tx_half_sample_bits, half_sample_bits - 1); +} + +/** + * @brief Configure RX half_sample_bit + * + * @param hw Peripheral I2S hardware instance address. + * @param half_sample_bits half sample bit width + */ +static inline void i2s_ll_rx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_conf1, rx_half_sample_bits, half_sample_bits - 1); +} + +/** + * @brief Enable TX MSB shift, the data will be launch at the first BCK clock + * + * @param hw Peripheral I2S hardware instance address. + * @param msb_shift_enable Set true to enable MSB shift + */ +static inline void i2s_ll_tx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) +{ + hw->tx_conf.tx_msb_shift = msb_shift_enable; +} + +/** + * @brief Enable RX MSB shift, the data will be launch at the first BCK clock + * + * @param hw Peripheral I2S hardware instance address. + * @param msb_shift_enable Set true to enable MSB shift + */ +static inline void i2s_ll_rx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) +{ + hw->rx_conf.rx_msb_shift = msb_shift_enable; +} + +/** + * @brief Configure TX total chan number + * + * @param hw Peripheral I2S hardware instance address. + * @param total_num Total chan number + */ +static inline void i2s_ll_tx_set_chan_num(i2s_dev_t *hw, int total_num) +{ + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; +} + +/** + * @brief Configure RX total chan number + * + * @param hw Peripheral I2S hardware instance address. + * @param total_num Total chan number + */ +static inline void i2s_ll_rx_set_chan_num(i2s_dev_t *hw, int total_num) +{ + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; +} + +/** + * @brief Set the bimap of the active TX chan, only the active chan can launch audio data. + * + * @param hw Peripheral I2S hardware instance address. + * @param chan_mask mask of tx active chan + */ +static inline void i2s_ll_tx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) +{ + typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; + hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; +} + +/** + * @brief Set the bimap of the active RX chan, only the active chan can receive audio data. + * + * @param hw Peripheral I2S hardware instance address. + * @param chan_mask mask of rx active chan + */ +static inline void i2s_ll_rx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) +{ + typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; + hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; +} + +/** + * @brief Set I2S tx chan mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slot_mask select slot to send data + */ +static inline void i2s_ll_tx_select_std_slot(i2s_dev_t *hw, i2s_std_slot_mask_t slot_mask) +{ + /* In mono mode, there only should be one slot enabled, another inactive slot will transmit same data as enabled slot + * Otherwise always enable the first two slots */ + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = 1; // tx_tdm_tot_chan_num = 2 slots - 1 = 1 + hw->tx_tdm_ctrl.val &= ~I2S_LL_TDM_CH_MASK; + switch (slot_mask) + { + case I2S_STD_SLOT_LEFT: + hw->tx_tdm_ctrl.val |= 0x01; + break; + case I2S_STD_SLOT_RIGHT: + hw->tx_tdm_ctrl.val |= 0x02; + break; + case I2S_STD_SLOT_BOTH: + hw->tx_tdm_ctrl.val |= 0x03; + break; + default: + break; + } +} + +/** + * @brief Set I2S rx chan mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slot_mask select slot to receive data + */ +static inline void i2s_ll_rx_select_std_slot(i2s_dev_t *hw, i2s_std_slot_mask_t slot_mask) +{ + /* In mono mode, there only should be one slot enabled, another inactive slot will transmit same data as enabled slot + * Otherwise always enable the first two slots */ + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = 1; // rx_tdm_tot_chan_num = 2 slots - 1 = 1 + hw->rx_tdm_ctrl.val &= ~I2S_LL_TDM_CH_MASK; + switch (slot_mask) + { + case I2S_STD_SLOT_LEFT: + hw->rx_tdm_ctrl.val |= 0x01; + break; + case I2S_STD_SLOT_RIGHT: + hw->rx_tdm_ctrl.val |= 0x02; + break; + case I2S_STD_SLOT_BOTH: + hw->rx_tdm_ctrl.val |= 0x03; + break; + default: + break; + } +} + +/** + * @brief PDM slot mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mod Channel mode + * while tx_ws_idle_pol = 0: + * 0: stereo + * 1: Both slots transmit left + * 2: Both slots transmit right + * 3: Left transmits `conf_single_data` right transmits data + * 4: Right transmits `conf_single_data` left transmits data + * while tx_ws_idle_pol = 1: + 0: stereo + * 1: Both slots transmit right + * 2: Both slots transmit left + * 3: Right transmits `conf_single_data` left transmits data + * 4: Left transmits `conf_single_data` right transmits data + */ +static inline void i2s_ll_tx_set_pdm_chan_mod(i2s_dev_t *hw, uint32_t mod) +{ + hw->tx_conf.tx_chan_mod = mod; +} + +/** + * @brief Set TX WS signal pol level + * + * @param hw Peripheral I2S hardware instance address. + * @param ws_pol_level pin level of WS(output) when receiving left channel data + */ +static inline void i2s_ll_tx_set_ws_idle_pol(i2s_dev_t *hw, bool ws_pol_level) +{ + hw->tx_conf.tx_ws_idle_pol = ws_pol_level; +} + +/** + * @brief Set RX WS signal pol level + * + * @param hw Peripheral I2S hardware instance address. + * @param ws_pol_level pin level of WS(input) when receiving left channel data + */ +static inline void i2s_ll_rx_set_ws_idle_pol(i2s_dev_t *hw, bool ws_pol_level) +{ + hw->rx_conf.rx_ws_idle_pol = ws_pol_level; +} + +/** + * @brief Enable I2S TX TDM mode + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_enable_tdm(i2s_dev_t *hw) +{ + hw->tx_conf.tx_pdm_en = false; + hw->tx_conf.tx_tdm_en = true; + hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = false; +} + +/** + * @brief Enable I2S RX TDM mode + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_enable_tdm(i2s_dev_t *hw) +{ + hw->rx_conf.rx_pdm_en = false; + hw->rx_conf.rx_tdm_en = true; +} + +/** + * @brief Enable I2S TX STD mode + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_enable_std(i2s_dev_t *hw) +{ + i2s_ll_tx_enable_tdm(hw); +} + +/** + * @brief Enable I2S RX STD mode + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw) +{ + i2s_ll_rx_enable_tdm(hw); +} + +/** + * @brief Enable TX PDM mode. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw) +{ + hw->tx_conf.tx_pdm_en = true; + hw->tx_conf.tx_tdm_en = false; + hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = true; +} + +/** + * @brief Set I2S TX PDM prescale + * + * @param hw Peripheral I2S hardware instance address. + * @param prescale I2S TX PDM prescale + */ +static inline void i2s_ll_tx_set_pdm_prescale(i2s_dev_t *hw, bool prescale) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_pcm2pdm_conf, tx_pdm_prescale, prescale); +} + +/** + * @brief Set I2S TX PDM high pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_hp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_hp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM low pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_lp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_lp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sinc filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sinc_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sinc_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sigma-delta filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sd_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM high pass filter param0 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 + I2S_TX_IIR_HP_MULT12_0[2:0]) + */ +static inline void i2s_ll_tx_set_pdm_hp_filter_param0(i2s_dev_t *hw, uint32_t param) +{ + hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_0 = param; +} + +/** + * @brief Set I2S TX PDM high pass filter param5 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 + I2S_TX_IIR_HP_MULT12_5[2:0]) + */ +static inline void i2s_ll_tx_set_pdm_hp_filter_param5(i2s_dev_t *hw, uint32_t param) +{ + hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_5 = param; +} + +/** + * @brief Enable I2S TX PDM high pass filter + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable I2S TX PDM high pass filter, set false to bypass it + */ +static inline void i2s_ll_tx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) +{ + hw->tx_pcm2pdm_conf.tx_pdm_hp_bypass = !enable; +} + +/** + * @brief Set I2S TX PDM sigma-delta codec dither + * + * @param hw Peripheral I2S hardware instance address. + * @param dither I2S TX PDM sigmadelta dither value + */ +static inline void i2s_ll_tx_set_pdm_sd_dither(i2s_dev_t *hw, uint32_t dither) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither = dither; +} + +/** + * @brief Set I2S TX PDM sigma-delta codec dither + * + * @param hw Peripheral I2S hardware instance address. + * @param dither2 I2S TX PDM sigmadelta dither2 value + */ +static inline void i2s_ll_tx_set_pdm_sd_dither2(i2s_dev_t *hw, uint32_t dither2) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither2 = dither2; +} + +/** + * @brief Set the PDM TX over sampling ratio + * + * @param hw Peripheral I2S hardware instance address. + * @param ovr Over sampling ratio + */ +static inline void i2s_ll_tx_set_pdm_over_sample_ratio(i2s_dev_t *hw, uint32_t ovr) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = ovr; +} + +/** + * @brief Configure I2S TX PDM sample rate + * Fpdm = 64*Fpcm*fp/fs + * + * @param hw Peripheral I2S hardware instance address. + * @param fp The fp value of TX PDM filter module group0. + * @param fs The fs value of TX PDM filter module group0. + */ +static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) +{ + hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp; + hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs; +} + +/** + * @brief Get I2S TX PDM fp configuration paramater + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - fp configuration paramater + */ +static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) +{ + return hw->tx_pcm2pdm_conf1.tx_pdm_fp; +} + +/** + * @brief Get I2S TX PDM fs configuration paramater + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - fs configuration paramater + */ +static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) +{ + return hw->tx_pcm2pdm_conf1.tx_pdm_fs; +} + +/** + * @brief Enable RX PDM mode. + * @note ESP32-H2 doesn't support pdm in rx mode, disable anyway + * + * @param hw Peripheral I2S hardware instance address. + * @param pdm_enable Set true to RX enable PDM mode (ignored) + */ +static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) +{ + // Due to the lack of `PDM to PCM` module on ESP32-H2, PDM RX is not available + HAL_ASSERT(!pdm_enable); + hw->rx_conf.rx_pdm_en = 0; + hw->rx_conf.rx_tdm_en = 1; +} + +/** + * @brief Configura TX a/u-law decompress or compress + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm_cfg PCM configuration paramater + */ +static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) +{ + hw->tx_conf.tx_pcm_conf = pcm_cfg; + hw->tx_conf.tx_pcm_bypass = !pcm_cfg; +} + +/** + * @brief Configure RX a/u-law decompress or compress + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm_cfg PCM configuration paramater + */ +static inline void i2s_ll_rx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) +{ + hw->rx_conf.rx_pcm_conf = pcm_cfg; + hw->rx_conf.rx_pcm_bypass = !pcm_cfg; +} + +/** + * @brief Enable TX audio data left alignment + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable left alignment + */ +static inline void i2s_ll_tx_enable_left_align(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.tx_left_align = ena; +} + +/** + * @brief Enable RX audio data left alignment + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable left alignment + */ +static inline void i2s_ll_rx_enable_left_align(i2s_dev_t *hw, bool ena) +{ + hw->rx_conf.rx_left_align = ena; +} + +/** + * @brief Enable TX big endian mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable big endian mode + */ +static inline void i2s_ll_rx_enable_big_endian(i2s_dev_t *hw, bool ena) +{ + hw->rx_conf.rx_big_endian = ena; +} + +/** + * @brief Enable RX big endian mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable big endian mode + */ +static inline void i2s_ll_tx_enable_big_endian(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.tx_big_endian = ena; +} + +/** + * @brief Configure TX bit order + * + * @param hw Peripheral I2S hardware instance address. + * @param lsb_order_ena Set true to enable LSB bit order + */ +static inline void i2s_ll_tx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) +{ + hw->tx_conf.tx_bit_order = lsb_order_ena; +} + +/** + * @brief Configure RX bit order + * + * @param hw Peripheral I2S hardware instance address. + * @param lsb_order_ena Set true to enable LSB bit order + */ +static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) +{ + hw->rx_conf.rx_bit_order = lsb_order_ena; +} + +/** + * @brief Configure TX skip mask enable + * + * @param hw Peripheral I2S hardware instance address. + * @param skip_mask_ena Set true to skip inactive channels. + */ +static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena) +{ + hw->tx_tdm_ctrl.tx_tdm_skip_msk_en = skip_mask_ena; +} + + +/** + * @brief Configure single data + * + * @param hw Peripheral I2S hardware instance address. + * @param data Single data to be set + */ +static inline void i2s_ll_set_single_data(i2s_dev_t *hw, uint32_t data) +{ + hw->conf_single_data.val = data; +} + +/** + * @brief Enable TX mono mode + * @note MONO in hardware means only one channel got data, but another doesn't + * MONO in software means two channel share same data + * This function aims to use MONO in software meaning + * so 'tx_mono' and 'tx_chan_equal' should be enabled at the same time + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + hw->tx_conf.tx_mono = mono_ena; + hw->tx_conf.tx_chan_equal = mono_ena; +} + +/** + * @brief Enable RX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + hw->rx_conf.rx_mono = mono_ena; + hw->rx_conf.rx_mono_fst_vld = mono_ena; +} + +/** + * @brief Enable loopback mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to share BCK and WS signal for tx module and rx module. + */ +static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.sig_loopback = ena; +} + +/** + * @brief PDM TX DMA data take mode + * + * @param hw Peripheral I2S hardware instance address. + * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) + * @param is_fst_valid Whether take the DMA data at the first half period + * Only take effet when 'is_mono' is true + */ +static inline void i2s_ll_tx_pdm_dma_take_mode(i2s_dev_t *hw, bool is_mono, bool is_fst_valid) +{ + hw->tx_conf.tx_mono = is_mono; + hw->tx_conf.tx_mono_fst_vld = is_fst_valid; +} + +/** + * @brief PDM TX slot mode + * @note Mode Left Slot Right Slot Chan Mode WS Pol + * ----------------------------------------------------------------- + * Stereo Left Right 0 x + * ----------------------------------------------------------------- + * Mono Left Left 1 0 + * Mono Right Right 2 0 + * Mono Single Right 3 0 + * Mono Left Single 4 0 + * ----------------------------------------------------------------- + * Mono Right Right 1 1 + * Mono Left Left 2 1 + * Mono Left Single 3 1 + * Mono Single Right 4 1 + * @note The 'Single' above means always sending the value of `conf_single_data` reg + * The default value of `conf_single_data` reg is '0', it is not public for now + * + * @param hw Peripheral I2S hardware instance address. + * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) + * @param is_copy Whether the un-selected slot copies the data from the selected one + * If not, the un-selected slot will transmit the data from 'conf_single_data' + * @param mask The slot mask to selet the slot + */ +static inline void i2s_ll_tx_pdm_slot_mode(i2s_dev_t *hw, bool is_mono, bool is_copy, i2s_pdm_slot_mask_t mask) +{ + if (is_mono) { + /* The default tx_ws_idle_pol is false */ + if (is_copy) { + hw->tx_conf.tx_chan_mod = mask == I2S_PDM_SLOT_LEFT ? 1 : 2; + } else { + hw->tx_conf.tx_chan_mod = mask == I2S_PDM_SLOT_LEFT ? 4 : 3; + } + } else { + hw->tx_conf.tx_chan_mod = 0; + } +} + +/** + * @brief PDM TX line mode + * @note Mode DAC Mode 2 lines output + * ------------------------------------------- + * PDM codec 0 1 + * DAC 1-line 1 0 + * DAC 2-line 1 1 + * + * @param hw Peripheral I2S hardware instance address. + * @param line_mode PDM TX line mode + */ +static inline void i2s_ll_tx_pdm_line_mode(i2s_dev_t *hw, i2s_pdm_tx_line_mode_t line_mode) +{ + hw->tx_pcm2pdm_conf.tx_pdm_dac_mode_en = line_mode > I2S_PDM_TX_ONE_LINE_CODEC; + hw->tx_pcm2pdm_conf.tx_pdm_dac_2out_en = line_mode != I2S_PDM_TX_ONE_LINE_DAC; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h4/include/hal/i2s_ll.h b/components/hal/esp32h4/include/hal/i2s_ll.h index 841d0e798a..c715ad426a 100644 --- a/components/hal/esp32h4/include/hal/i2s_ll.h +++ b/components/hal/esp32h4/include/hal/i2s_ll.h @@ -936,6 +936,8 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) */ static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) { + // Due to the lack of `PDM to PCM` module on ESP32-H4, PDM RX is not available + HAL_ASSERT(!pdm_enable); hw->rx_conf.rx_pdm_en = pdm_enable; hw->rx_conf.rx_tdm_en = !pdm_enable; } diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index d3fdf2e32a..db80787dc3 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -376,8 +376,8 @@ config SOC_I2C_SUPPORT_RTC default y config SOC_I2S_NUM - bool - default y + int + default 1 config SOC_I2S_HW_VERSION_2 bool diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 0619126970..d68a455cdf 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -185,7 +185,7 @@ #define SOC_I2C_SUPPORT_RTC (1) /*-------------------------- I2S CAPS ----------------------------------------*/ -#define SOC_I2S_NUM (1) +#define SOC_I2S_NUM (1U) #define SOC_I2S_HW_VERSION_2 (1) #define SOC_I2S_SUPPORTS_XTAL (1) #define SOC_I2S_SUPPORTS_PLL_F160M (1) diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 48e42ffbc0..b001779a7c 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -428,8 +428,8 @@ config SOC_I2C_SUPPORT_RTC default y config SOC_I2S_NUM - bool - default y + int + default 1 config SOC_I2S_HW_VERSION_2 bool diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index b4be8c1bdd..ec98b49af0 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -212,7 +212,7 @@ #define SOC_I2C_SUPPORT_RTC (1) /*-------------------------- I2S CAPS ----------------------------------------*/ -#define SOC_I2S_NUM (1) +#define SOC_I2S_NUM (1U) #define SOC_I2S_HW_VERSION_2 (1) #define SOC_I2S_SUPPORTS_XTAL (1) #define SOC_I2S_SUPPORTS_PLL_F160M (1) diff --git a/components/soc/esp32h2/CMakeLists.txt b/components/soc/esp32h2/CMakeLists.txt index 25599a01ee..2288fc49c8 100644 --- a/components/soc/esp32h2/CMakeLists.txt +++ b/components/soc/esp32h2/CMakeLists.txt @@ -21,7 +21,6 @@ list(REMOVE_ITEM srcs "adc_periph.c" "dedic_gpio_periph.c" "ledc_periph.c" - "i2s_periph.c" "i2c_periph.c" "temperature_sensor_periph.c" "adc_periph.c" diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 941a546958..ea0fff2c5b 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -39,6 +39,10 @@ config SOC_RTC_MEM_SUPPORTED bool default y +config SOC_I2S_SUPPORTED + bool + default y + config SOC_SDM_SUPPORTED bool default y @@ -272,8 +276,8 @@ config SOC_I2C_SUPPORT_RTC default y config SOC_I2S_NUM - bool - default y + int + default 1 config SOC_I2S_HW_VERSION_2 bool @@ -283,10 +287,22 @@ config SOC_I2S_SUPPORTS_XTAL bool default y +config SOC_I2S_SUPPORTS_PLL_F96M + bool + default y + +config SOC_I2S_SUPPORTS_PLL_F64M + bool + default y + config SOC_I2S_SUPPORTS_PCM bool default y +config SOC_I2S_SUPPORTS_PDM + bool + default y + config SOC_I2S_SUPPORTS_PDM_TX bool default y @@ -295,6 +311,14 @@ config SOC_I2S_PDM_MAX_TX_LINES int default 2 +config SOC_I2S_SUPPORTS_TDM + bool + default y + +config SOC_I2S_TDM_FULL_DATA_WIDTH + bool + default y + config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK bool default y diff --git a/components/soc/esp32h2/include/soc/i2s_struct.h b/components/soc/esp32h2/include/soc/i2s_struct.h index 6d257e9f5c..f4ac17a3b0 100644 --- a/components/soc/esp32h2/include/soc/i2s_struct.h +++ b/components/soc/esp32h2/include/soc/i2s_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -448,7 +448,7 @@ typedef union { uint32_t val; } i2s_rx_tdm_ctrl_reg_t; -/** Type of rxeof_num register +/** Type of rx_eof_num register * I2S RX data number control register. */ typedef union { @@ -461,7 +461,7 @@ typedef union { uint32_t reserved_12:20; }; uint32_t val; -} i2s_rxeof_num_reg_t; +} i2s_rx_eof_num_reg_t; /** Group: TX Control and configuration registers */ @@ -912,7 +912,7 @@ typedef union { uint32_t val; } i2s_lc_hung_conf_reg_t; -/** Type of conf_sigle_data register +/** Type of conf_single_data register * I2S signal data register */ typedef union { @@ -923,7 +923,7 @@ typedef union { uint32_t single_data:32; }; uint32_t val; -} i2s_conf_sigle_data_reg_t; +} i2s_conf_single_data_reg_t; /** Group: TX status registers */ @@ -1003,8 +1003,8 @@ typedef struct { volatile i2s_rx_timing_reg_t rx_timing; volatile i2s_tx_timing_reg_t tx_timing; volatile i2s_lc_hung_conf_reg_t lc_hung_conf; - volatile i2s_rxeof_num_reg_t rxeof_num; - volatile i2s_conf_sigle_data_reg_t conf_sigle_data; + volatile i2s_rx_eof_num_reg_t rx_eof_num; + volatile i2s_conf_single_data_reg_t conf_single_data; volatile i2s_state_reg_t state; volatile i2s_etm_conf_reg_t etm_conf; uint32_t reserved_074[3]; diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 76c06a8574..3826a37869 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -44,7 +44,7 @@ #define SOC_EFUSE_HAS_EFUSE_RST_BUG 1 #define SOC_RTC_FAST_MEM_SUPPORTED 1 #define SOC_RTC_MEM_SUPPORTED 1 -// #define SOC_I2S_SUPPORTED 1 // TODO: IDF-6219 +#define SOC_I2S_SUPPORTED 1 #define SOC_SDM_SUPPORTED 1 #define SOC_RMT_SUPPORTED 1 // #define SOC_GPSPI_SUPPORTED 1 // TODO: IDF-6264 @@ -183,16 +183,18 @@ #define SOC_I2C_SUPPORT_XTAL (1) #define SOC_I2C_SUPPORT_RTC (1) -// TODO: IDF-6219 /*-------------------------- I2S CAPS ----------------------------------------*/ -#define SOC_I2S_NUM (1) +#define SOC_I2S_NUM (1U) #define SOC_I2S_HW_VERSION_2 (1) #define SOC_I2S_SUPPORTS_XTAL (1) +#define SOC_I2S_SUPPORTS_PLL_F96M (1) +#define SOC_I2S_SUPPORTS_PLL_F64M (1) #define SOC_I2S_SUPPORTS_PCM (1) -// #define SOC_I2S_SUPPORTS_PDM (1) +#define SOC_I2S_SUPPORTS_PDM (1) #define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_PDM_MAX_TX_LINES (2) -// #define SOC_I2S_SUPPORTS_TDM (1) +#define SOC_I2S_SUPPORTS_TDM (1) +#define SOC_I2S_TDM_FULL_DATA_WIDTH (1) /*!< No limitation to data bit width when using multiple slots */ // TODO: IDF-6235 (Copy from esp32c6, need check) /*-------------------------- LEDC CAPS ---------------------------------------*/ diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 3e9b68f742..90ad7fee72 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -356,8 +356,8 @@ config SOC_I2C_SUPPORT_RTC default y config SOC_I2S_NUM - bool - default y + int + default 1 config SOC_I2S_HW_VERSION_2 bool diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 14783455af..c7da987f9d 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -193,7 +193,7 @@ #define SOC_I2C_SUPPORT_RTC (1) /*-------------------------- I2S CAPS ----------------------------------------*/ -#define SOC_I2S_NUM (1) +#define SOC_I2S_NUM (1U) #define SOC_I2S_HW_VERSION_2 (1) #define SOC_I2S_SUPPORTS_XTAL (1) #define SOC_I2S_SUPPORTS_PLL_F96M (1) diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 75d3182dba..906b715b8b 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -187,7 +187,7 @@ #define SOC_I2C_SUPPORT_RTC (1) /*-------------------------- I2S CAPS ----------------------------------------*/ -#define SOC_I2S_NUM (2) +#define SOC_I2S_NUM (2U) #define SOC_I2S_HW_VERSION_2 (1) #define SOC_I2S_SUPPORTS_XTAL (1) #define SOC_I2S_SUPPORTS_PLL_F160M (1) diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index 3204820129..61eaa67160 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -160,7 +160,15 @@ Standard mode always has left and right two sound channels which are called 'slo TDM Mode ^^^^^^^^ - TDM(Time Division Multiplexing) mode supports upto 16 slots, these slots can be enabled by :cpp:member:`i2s_tdm_slot_config_t::slot_mask`. But due to the hardware limitation, only upto 4 slots are supported while the slot is set to 32 bit-width, and 8 slots for 16 bit-width, 16 slots for 8 bit-width. The slot communication format of TDM is almost same as standard mode, but there are some small differences between them. + TDM(Time Division Multiplexing) mode supports up to 16 slots, these slots can be enabled by :cpp:member:`i2s_tdm_slot_config_t::slot_mask`. + + .. only:: SOC_I2S_TDM_FULL_DATA_WIDTH + + Any data bit-width is supported no matter how many slots are enabled, that means there can be up to ``32 bit-width * 16 slots = 512 bit`` in one frame. + + .. only:: not SOC_I2S_TDM_FULL_DATA_WIDTH + + But due to the hardware limitation, only up to 4 slots are supported while the slot is set to 32 bit-width, and 8 slots for 16 bit-width, 16 slots for 8 bit-width. The slot communication format of TDM is almost same as standard mode, but there are some small differences between them. - **Philips Format**: Data signal have one bit shift comparing to the WS(word select) signal. And no matter how many slots are contained in one frame, the duty of WS signal will always keep 50%. diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 83c30957bc..24f0060d6d 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -41,10 +41,6 @@ examples/peripherals/i2s/i2s_adc_dac: examples/peripherals/i2s/i2s_basic/i2s_pdm: disable: - if: SOC_I2S_SUPPORTS_PDM != 1 - disable_test: - - if: IDF_TARGET == "esp32c6" - temporary: true - reason: target esp32c6 is not supported yet examples/peripherals/i2s/i2s_basic/i2s_std: disable: @@ -56,11 +52,13 @@ examples/peripherals/i2s/i2s_basic/i2s_tdm: examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm: disable: - - if: SOC_I2S_SUPPORTS_TDM != 1 + - if: SOC_I2S_SUPPORTS_TDM != 1 or SOC_I2C_SUPPORTED != 1 + reason: rely on I2S TDM mode and I2C support examples/peripherals/i2s/i2s_codec/i2s_es8311: disable: - - if: SOC_I2S_SUPPORTED != 1 + - if: SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1 + reason: rely on I2S STD mode and I2C support examples/peripherals/i2s/i2s_recorder: enable: diff --git a/examples/peripherals/i2s/i2s_basic/i2s_pdm/README.md b/examples/peripherals/i2s/i2s_basic/i2s_pdm/README.md index 897dbcab0e..1c951cdeb9 100644 --- a/examples/peripherals/i2s/i2s_basic/i2s_pdm/README.md +++ b/examples/peripherals/i2s/i2s_basic/i2s_pdm/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | # I2S Basic PDM Mode Example diff --git a/examples/peripherals/i2s/i2s_basic/i2s_pdm/pytest_i2s_pdm.py b/examples/peripherals/i2s/i2s_basic/i2s_pdm/pytest_i2s_pdm.py index c31210811f..561ee109dd 100644 --- a/examples/peripherals/i2s/i2s_basic/i2s_pdm/pytest_i2s_pdm.py +++ b/examples/peripherals/i2s/i2s_basic/i2s_pdm/pytest_i2s_pdm.py @@ -8,6 +8,8 @@ from pytest_embedded import Dut @pytest.mark.esp32 @pytest.mark.esp32s3 @pytest.mark.esp32c3 +@pytest.mark.esp32c6 +@pytest.mark.esp32h2 @pytest.mark.generic @pytest.mark.parametrize( 'config', diff --git a/examples/peripherals/i2s/i2s_basic/i2s_std/README.md b/examples/peripherals/i2s/i2s_basic/i2s_std/README.md index 5c1dc1ada8..048907dc7e 100644 --- a/examples/peripherals/i2s/i2s_basic/i2s_std/README.md +++ b/examples/peripherals/i2s/i2s_basic/i2s_std/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | # I2S Basic Standard Mode Example diff --git a/examples/peripherals/i2s/i2s_basic/i2s_std/pytest_i2s_std.py b/examples/peripherals/i2s/i2s_basic/i2s_std/pytest_i2s_std.py index 92f93a1936..9ee532dab2 100644 --- a/examples/peripherals/i2s/i2s_basic/i2s_std/pytest_i2s_std.py +++ b/examples/peripherals/i2s/i2s_basic/i2s_std/pytest_i2s_std.py @@ -10,6 +10,7 @@ from pytest_embedded import Dut @pytest.mark.esp32s3 @pytest.mark.esp32c3 @pytest.mark.esp32c6 +@pytest.mark.esp32h2 @pytest.mark.generic def test_i2s_basic_example(dut: Dut) -> None: diff --git a/examples/peripherals/i2s/i2s_basic/i2s_tdm/README.md b/examples/peripherals/i2s/i2s_basic/i2s_tdm/README.md index f58024c0dd..23181e6f30 100644 --- a/examples/peripherals/i2s/i2s_basic/i2s_tdm/README.md +++ b/examples/peripherals/i2s/i2s_basic/i2s_tdm/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # I2S Basic TDM Mode Example diff --git a/examples/peripherals/i2s/i2s_basic/i2s_tdm/main/i2s_tdm_example_main.c b/examples/peripherals/i2s/i2s_basic/i2s_tdm/main/i2s_tdm_example_main.c index fb3475bcbb..b89fdfe342 100644 --- a/examples/peripherals/i2s/i2s_basic/i2s_tdm/main/i2s_tdm_example_main.c +++ b/examples/peripherals/i2s/i2s_basic/i2s_tdm/main/i2s_tdm_example_main.c @@ -102,9 +102,12 @@ static void i2s_example_init_tdm_duplex(void) * They can help to specify the slot and clock configurations for initialization or re-configuring */ i2s_tdm_config_t tdm_cfg = { .clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(16000), - /* Limited by the hardware, the number of bit clock can't exceed 128 in one frame, + /* For the target that not support full data bit-width in multiple slots (e.g. ESP32C3, ESP32S3, ESP32C6) + * The maximum bits in one frame is limited by the hardware, the number of bit clock can't exceed 128 in one frame, * which is to say, TDM mode can only support 32 bit-width data upto 4 slots, - * 16 bit-width data upto 8 slots and 8 bit-width data upto 16 slots */ + * 16 bit-width data upto 8 slots and 8 bit-width data upto 16 slots + * But for the target that support full data bit-width in multiple slots (e.g. ESP32H2) + * There is no such limitation, it can support up to 32 bit-width with 16 slots */ .slot_cfg = I2S_TDM_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3), .gpio_cfg = { diff --git a/examples/peripherals/i2s/i2s_basic/i2s_tdm/pytest_i2s_tdm.py b/examples/peripherals/i2s/i2s_basic/i2s_tdm/pytest_i2s_tdm.py index a585cd3d22..cd59107d90 100644 --- a/examples/peripherals/i2s/i2s_basic/i2s_tdm/pytest_i2s_tdm.py +++ b/examples/peripherals/i2s/i2s_basic/i2s_tdm/pytest_i2s_tdm.py @@ -8,6 +8,7 @@ from pytest_embedded import Dut @pytest.mark.esp32s3 @pytest.mark.esp32c3 @pytest.mark.esp32c6 +@pytest.mark.esp32h2 @pytest.mark.generic def test_i2s_tdm_example(dut: Dut) -> None: diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/pytest_i2s_es7210_tdm.py b/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/pytest_i2s_es7210_tdm.py index 0dac05ea90..618c700bfd 100644 --- a/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/pytest_i2s_es7210_tdm.py +++ b/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/pytest_i2s_es7210_tdm.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 import pytest from pytest_embedded import Dut @@ -7,6 +7,7 @@ from pytest_embedded import Dut @pytest.mark.esp32s3 @pytest.mark.esp32c3 @pytest.mark.esp32c6 +@pytest.mark.esp32h2 @pytest.mark.generic def test_i2s_es7210_tdm_example(dut: Dut) -> None: dut.expect_exact('example: Create I2S receive channel') 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 index d6b46ddd91..65b07d7df2 100644 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/pytest_i2s_es8311.py +++ b/examples/peripherals/i2s/i2s_codec/i2s_es8311/pytest_i2s_es8311.py @@ -10,6 +10,7 @@ from pytest_embedded import Dut @pytest.mark.esp32s3 @pytest.mark.esp32c3 @pytest.mark.esp32c6 +@pytest.mark.esp32h2 @pytest.mark.generic def test_i2s_es8311_example_generic(dut: Dut) -> None: dut.expect('i2s es8311 codec example start')