diff --git a/components/esp_driver_i2s/i2s_common.c b/components/esp_driver_i2s/i2s_common.c index 981ae04dd0..fef2b69fb5 100644 --- a/components/esp_driver_i2s/i2s_common.c +++ b/components/esp_driver_i2s/i2s_common.c @@ -792,6 +792,17 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag) gdma_trigger_t trig = {0}; switch (port_id) { +#if I2S_LL_SUPPORT(GDMA_RECOMB) + // Minimum support for GDMA channels on esp32s31 + case I2S_NUM_0: + trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S0CH0; + trig.bus_id = SOC_GDMA_TRIG_PERIPH_I2S0CH0_BUS; + break; + case I2S_NUM_1: + trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S1CH0; + trig.bus_id = SOC_GDMA_TRIG_PERIPH_I2S1CH0_BUS; + break; +#else #if I2S_LL_GET(INST_NUM) > 2 case I2S_NUM_2: trig = GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_I2S, 2); @@ -805,6 +816,7 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag) case I2S_NUM_0: trig = GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_I2S, 0); break; +#endif default: ESP_LOGE(TAG, "Unsupported I2S port number"); return ESP_ERR_NOT_SUPPORTED; @@ -882,15 +894,38 @@ static uint64_t s_i2s_get_pair_chan_gpio_mask(i2s_chan_handle_t handle) return handle->controller->tx_chan ? handle->controller->tx_chan->reserve_gpio_mask : 0; } +static bool s_i2s_gpio_used_by_pair_chan(i2s_chan_handle_t handle, int gpio_num) +{ + if (!handle->controller->full_duplex) { + return false; + } + return !!(s_i2s_get_pair_chan_gpio_mask(handle) & BIT64(gpio_num)); +} + +/** + * @note Call before IO_MUX/matrix reconfiguration. Input pins are not added to the + * global GPIO reserve map (no esp_gpio_reserve), to avoid esp_gpio_revoke() + * clearing bits that MSPI or other subsystems already own. + */ +static void s_i2c_input_gpio_reserve_check(i2s_chan_handle_t handle, int gpio_num) +{ + if (s_i2s_gpio_used_by_pair_chan(handle, gpio_num)) { + return; + } + if (esp_gpio_is_reserved(BIT64(gpio_num))) { + ESP_LOGW(TAG, "GPIO %d is already reserved; selecting GPIO matrix input on this pin may conflict (e.g. MSPI/Flash)", gpio_num); + } +} + void i2s_output_gpio_reserve(i2s_chan_handle_t handle, int gpio_num) { - bool used_by_pair_chan = false; /* If the gpio is used by the pair channel do not show warning for this case */ - if (handle->controller->full_duplex) { - used_by_pair_chan = !!(s_i2s_get_pair_chan_gpio_mask(handle) & BIT64(gpio_num)); + if (s_i2s_gpio_used_by_pair_chan(handle, gpio_num)) { + handle->reserve_gpio_mask |= BIT64(gpio_num); + return; } /* reserve the GPIO output path, because we don't expect another peripheral to signal to the same GPIO */ - if (!used_by_pair_chan && (esp_gpio_reserve(BIT64(gpio_num)) & BIT64(gpio_num))) { + if (esp_gpio_reserve(BIT64(gpio_num)) & BIT64(gpio_num)) { ESP_LOGW(TAG, "GPIO %d is not usable, maybe conflict with others", gpio_num); } handle->reserve_gpio_mask |= BIT64(gpio_num); @@ -913,14 +948,15 @@ void i2s_gpio_check_and_set(i2s_chan_handle_t handle, int gpio, uint32_t signal_ { /* Ignore the pin if pin = I2S_GPIO_UNUSED */ if (gpio != (int)I2S_GPIO_UNUSED) { - gpio_func_sel(gpio, PIN_FUNC_GPIO); + /* Reserve / warn before IO_MUX changes so e.g. MSPI pads are not remuxed with no prior notice */ if (is_input) { - /* Enable the input, for some GPIOs, the input function are not enabled as default */ + s_i2c_input_gpio_reserve_check(handle, gpio); + gpio_func_sel(gpio, PIN_FUNC_GPIO); gpio_input_enable(gpio); esp_rom_gpio_connect_in_signal(gpio, signal_idx, is_invert); } else { i2s_output_gpio_reserve(handle, gpio); - /* output will be enabled in esp_rom_gpio_connect_out_signal */ + gpio_func_sel(gpio, PIN_FUNC_GPIO); esp_rom_gpio_connect_out_signal(gpio, signal_idx, is_invert, 0); } } diff --git a/components/esp_driver_i2s/test_apps/.build-test-rules.yml b/components/esp_driver_i2s/test_apps/.build-test-rules.yml index 61cacfd048..56bba802ec 100644 --- a/components/esp_driver_i2s/test_apps/.build-test-rules.yml +++ b/components/esp_driver_i2s/test_apps/.build-test-rules.yml @@ -19,6 +19,9 @@ components/esp_driver_i2s/test_apps/i2s_multi_dev: - if: IDF_TARGET in ["esp32c61"] # TODO: [ESP32C61] IDF-11442 temporary: true reason: lack of runners + - if: IDF_TARGET in ["esp32s31"] + temporary: true + reason: lack of s31 multi-device runner depends_components: - esp_driver_i2s - esp_driver_dma diff --git a/components/esp_driver_i2s/test_apps/i2s/README.md b/components/esp_driver_i2s/test_apps/i2s/README.md index 889cb58939..4dc85ef7a0 100644 --- a/components/esp_driver_i2s/test_apps/i2s/README.md +++ b/components/esp_driver_i2s/test_apps/i2s/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | diff --git a/components/esp_driver_i2s/test_apps/i2s/main/test_app_main.c b/components/esp_driver_i2s/test_apps/i2s/main/test_app_main.c index 9e1f7b5a6c..c05ad2830a 100644 --- a/components/esp_driver_i2s/test_apps/i2s/main/test_app_main.c +++ b/components/esp_driver_i2s/test_apps/i2s/main/test_app_main.c @@ -9,7 +9,7 @@ #include "esp_heap_caps.h" // Some resources are lazy allocated in I2S driver, the threshold is left for that case -#define TEST_MEMORY_LEAK_THRESHOLD (-350) +#define TEST_MEMORY_LEAK_THRESHOLD (-360) static size_t before_free_8bit; static size_t before_free_32bit; diff --git a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c index 070281eb10..61db387616 100644 --- a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c +++ b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c @@ -931,7 +931,7 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_c // 196000 Hz sample rate doesn't support on PLL_96M target case_cnt = 15; #endif -#if I2S_LL_SUPPORT_XTAL +#if I2S_LL_SUPPORT(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; @@ -982,7 +982,7 @@ TEST_CASE("I2S_default_PLL_clock_test", "[i2s]") std_cfg.clk_cfg.clk_src = I2S_LL_DEFAULT_CLK_SRC; #endif i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg); -#if I2S_LL_SUPPORT_XTAL +#if I2S_LL_SUPPORT(XTAL) std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_XTAL; i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg); #endif @@ -1046,6 +1046,9 @@ TEST_CASE("I2S_package_lost_test", "[i2s]") .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO), .gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN, }; +#if CONFIG_IDF_TARGET_ESP32S31 // esp32s31 doesn't support PLL as clock source, use APLL instead + std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_APLL; +#endif TEST_ESP_OK(i2s_new_channel(&chan_cfg, NULL, &rx_handle)); TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); diff --git a/components/esp_driver_i2s/test_apps/i2s/pytest_i2s.py b/components/esp_driver_i2s/test_apps/i2s/pytest_i2s.py index ebb7b9b727..ef6bf48ad7 100644 --- a/components/esp_driver_i2s/test_apps/i2s/pytest_i2s.py +++ b/components/esp_driver_i2s/test_apps/i2s/pytest_i2s.py @@ -3,6 +3,7 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic @@ -16,9 +17,10 @@ from pytest_embedded_idf.utils import idf_parametrize ) @idf_parametrize( 'target', - ['esp32', 'esp32s2', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32c61'], + soc_filtered_targets('SOC_I2S_SUPPORTED == 1 and IDF_TARGET not in ["esp32c5", "esp32s3"]'), indirect=['target'], ) +@pytest.mark.temp_skip_ci(targets=['esp32h21', 'esp32h4'], reason='lack of runners') def test_i2s(dut: Dut) -> None: dut.run_all_single_board_cases() diff --git a/components/esp_driver_i2s/test_apps/i2s_multi_dev/README.md b/components/esp_driver_i2s/test_apps/i2s_multi_dev/README.md index db50040499..a2f5950a53 100644 --- a/components/esp_driver_i2s/test_apps/i2s_multi_dev/README.md +++ b/components/esp_driver_i2s/test_apps/i2s_multi_dev/README.md @@ -1,3 +1,3 @@ -| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | --------- | diff --git a/components/esp_driver_i2s/test_apps/i2s_multi_dev/pytest_i2s_multi_dev.py b/components/esp_driver_i2s/test_apps/i2s_multi_dev/pytest_i2s_multi_dev.py index b0390555a1..b1826704a0 100644 --- a/components/esp_driver_i2s/test_apps/i2s_multi_dev/pytest_i2s_multi_dev.py +++ b/components/esp_driver_i2s/test_apps/i2s_multi_dev/pytest_i2s_multi_dev.py @@ -7,6 +7,7 @@ from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic_multi_device @pytest.mark.temp_skip_ci(targets=['esp32c61'], reason='p4 rev3 migration # TODO: IDF-11442') +@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='lack of s31 multi-device runner # TODO: IDFCI-10334') @pytest.mark.parametrize('count', [2], indirect=True) @idf_parametrize('target', soc_filtered_targets('SOC_I2S_SUPPORTS_TDM == 1'), indirect=['target']) def test_i2s_multi_dev(case_tester) -> None: # type: ignore diff --git a/components/esp_driver_i2s/test_apps/test_inc/test_i2s.h b/components/esp_driver_i2s/test_apps/test_inc/test_i2s.h index 0be715c450..61180ed706 100644 --- a/components/esp_driver_i2s/test_apps/test_inc/test_i2s.h +++ b/components/esp_driver_i2s/test_apps/test_inc/test_i2s.h @@ -22,7 +22,7 @@ extern "C" { #define SLAVE_WS_IO 22 #define DATA_IN_IO 19 #define DATA_OUT_IO 18 -#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H4 #define MASTER_MCK_IO 0 #define MASTER_BCK_IO 4 #define MASTER_WS_IO 5 diff --git a/components/esp_hal_clock/esp32s31/include/hal/clk_tree_ll.h b/components/esp_hal_clock/esp32s31/include/hal/clk_tree_ll.h index 19a2de8b69..829dbe7a3c 100644 --- a/components/esp_hal_clock/esp32s31/include/hal/clk_tree_ll.h +++ b/components/esp_hal_clock/esp32s31/include/hal/clk_tree_ll.h @@ -16,6 +16,8 @@ #include "soc/lp_clkrst_struct.h" #include "soc/hp_alive_sys_reg.h" #include "soc/hp_alive_sys_struct.h" +#include "hal/regi2c_ctrl.h" +#include "soc/regi2c_apll.h" #include "soc/pmu_reg.h" #include "hal/clkout_channel.h" #include "hal/assert.h" @@ -463,7 +465,12 @@ static inline __attribute__((always_inline)) bool clk_ll_mpll_calibration_is_don */ static inline __attribute__((always_inline)) void clk_ll_apll_get_config(uint32_t *o_div, uint32_t *sdm0, uint32_t *sdm1, uint32_t *sdm2) { - // TODO: IDF-14771, IDF-14750 + uint32_t apll_sdm = HAL_FORCE_READ_U32_REG_FIELD(LP_CLKRST.apll_sdm, apll_sdm); + + *o_div = HAL_FORCE_READ_U32_REG_FIELD(LP_CLKRST.apll_div, apll_out_div); + *sdm0 = apll_sdm & 0xFF; + *sdm1 = (apll_sdm >> 8) & 0xFF; + *sdm2 = (apll_sdm >> 16) & 0x3F; } /** @@ -476,7 +483,8 @@ static inline __attribute__((always_inline)) void clk_ll_apll_get_config(uint32_ */ static inline __attribute__((always_inline)) void clk_ll_apll_set_config(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2) { - // TODO: IDF-14771, IDF-14750 + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_CLKRST.apll_div, apll_out_div, o_div); + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_CLKRST.apll_sdm, apll_sdm, (sdm2 << 16) | (sdm1 << 8) | sdm0); } /** @@ -484,7 +492,9 @@ static inline __attribute__((always_inline)) void clk_ll_apll_set_config(uint32_ */ static inline __attribute__((always_inline)) void clk_ll_apll_set_calibration(void) { - // TODO: IDF-14771, IDF-14750 + REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_1); + REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_2); + REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_3); } /** @@ -494,8 +504,7 @@ static inline __attribute__((always_inline)) void clk_ll_apll_set_calibration(vo */ static inline __attribute__((always_inline)) bool clk_ll_apll_calibration_is_done(void) { - // TODO: IDF-14771, IDF-14750 - return 0; + return REG_GET_BIT(HP_SYS_CLKRST_ANA_PLL_CTRL0_REG, HP_SYS_CLKRST_REG_PLLA_CAL_END); } /** diff --git a/components/esp_hal_i2s/esp32/include/hal/i2s_ll.h b/components/esp_hal_i2s/esp32/include/hal/i2s_ll.h index 3318f55321..97836b2650 100644 --- a/components/esp_hal_i2s/esp32/include/hal/i2s_ll.h +++ b/components/esp_hal_i2s/esp32/include/hal/i2s_ll.h @@ -22,6 +22,7 @@ #include "hal/hal_utils.h" #define I2S_LL_GET(_attr) I2S_LL_ ## _attr +#define I2S_LL_SUPPORT(_feat) I2S_LL_SUPPORT_ ## _feat #define I2S_LL_BUS_WIDTH 24 #define I2S_LL_INST_NUM 2 #define I2S_LL_TRANS_SIZE_ALIGN_WORD 1 // I2S DMA transfer size must be aligned to word diff --git a/components/esp_hal_i2s/esp32c3/include/hal/i2s_ll.h b/components/esp_hal_i2s/esp32c3/include/hal/i2s_ll.h index e758b5a93c..655d91917a 100644 --- a/components/esp_hal_i2s/esp32c3/include/hal/i2s_ll.h +++ b/components/esp_hal_i2s/esp32c3/include/hal/i2s_ll.h @@ -21,6 +21,7 @@ #include "hal/hal_utils.h" #define I2S_LL_GET(_attr) I2S_LL_ ## _attr +#define I2S_LL_SUPPORT(_feat) I2S_LL_SUPPORT_ ## _feat #define I2S_LL_INST_NUM 1 #ifdef __cplusplus diff --git a/components/esp_hal_i2s/esp32c5/include/hal/i2s_ll.h b/components/esp_hal_i2s/esp32c5/include/hal/i2s_ll.h index b1e88d686b..b0e21bf67a 100644 --- a/components/esp_hal_i2s/esp32c5/include/hal/i2s_ll.h +++ b/components/esp_hal_i2s/esp32c5/include/hal/i2s_ll.h @@ -23,6 +23,7 @@ #include "hal/hal_utils.h" #define I2S_LL_GET(_attr) I2S_LL_ ## _attr +#define I2S_LL_SUPPORT(_feat) I2S_LL_SUPPORT_ ## _feat #define I2S_LL_INST_NUM 1 #ifdef __cplusplus diff --git a/components/esp_hal_i2s/esp32c6/include/hal/i2s_ll.h b/components/esp_hal_i2s/esp32c6/include/hal/i2s_ll.h index 1073bb537a..635a3a8c3e 100644 --- a/components/esp_hal_i2s/esp32c6/include/hal/i2s_ll.h +++ b/components/esp_hal_i2s/esp32c6/include/hal/i2s_ll.h @@ -22,6 +22,7 @@ #include "hal/hal_utils.h" #define I2S_LL_GET(_attr) I2S_LL_ ## _attr +#define I2S_LL_SUPPORT(_feat) I2S_LL_SUPPORT_ ## _feat #define I2S_LL_INST_NUM 1 #ifdef __cplusplus diff --git a/components/esp_hal_i2s/esp32c61/include/hal/i2s_ll.h b/components/esp_hal_i2s/esp32c61/include/hal/i2s_ll.h index a8fa36a487..dcdc92860e 100644 --- a/components/esp_hal_i2s/esp32c61/include/hal/i2s_ll.h +++ b/components/esp_hal_i2s/esp32c61/include/hal/i2s_ll.h @@ -23,6 +23,7 @@ #include "hal/hal_utils.h" #define I2S_LL_GET(_attr) I2S_LL_ ## _attr +#define I2S_LL_SUPPORT(_feat) I2S_LL_SUPPORT_ ## _feat #define I2S_LL_INST_NUM 1 #ifdef __cplusplus diff --git a/components/esp_hal_i2s/esp32h2/include/hal/i2s_ll.h b/components/esp_hal_i2s/esp32h2/include/hal/i2s_ll.h index 394ea78c26..c2d9fd3311 100644 --- a/components/esp_hal_i2s/esp32h2/include/hal/i2s_ll.h +++ b/components/esp_hal_i2s/esp32h2/include/hal/i2s_ll.h @@ -22,6 +22,7 @@ #include "hal/hal_utils.h" #define I2S_LL_GET(_attr) I2S_LL_ ## _attr +#define I2S_LL_SUPPORT(_feat) I2S_LL_SUPPORT_ ## _feat #define I2S_LL_INST_NUM 1 #ifdef __cplusplus diff --git a/components/esp_hal_i2s/esp32h21/include/hal/i2s_ll.h b/components/esp_hal_i2s/esp32h21/include/hal/i2s_ll.h index c35b6e6606..70ac93a0c6 100644 --- a/components/esp_hal_i2s/esp32h21/include/hal/i2s_ll.h +++ b/components/esp_hal_i2s/esp32h21/include/hal/i2s_ll.h @@ -22,6 +22,7 @@ #include "hal/hal_utils.h" #define I2S_LL_GET(_attr) I2S_LL_ ## _attr +#define I2S_LL_SUPPORT(_feat) I2S_LL_SUPPORT_ ## _feat #define I2S_LL_INST_NUM 1 #ifdef __cplusplus @@ -247,9 +248,9 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) 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; + case I2S_CLK_SRC_XTAL_X2: + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 2; + break; case I2S_CLK_SRC_EXTERNAL: PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 3; break; @@ -275,9 +276,9 @@ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) 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; + case I2S_CLK_SRC_XTAL_X2: + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 2; + break; case I2S_CLK_SRC_EXTERNAL: PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 3; break; diff --git a/components/esp_hal_i2s/esp32h4/include/hal/i2s_ll.h b/components/esp_hal_i2s/esp32h4/include/hal/i2s_ll.h index 987f73969d..c53f55a10c 100644 --- a/components/esp_hal_i2s/esp32h4/include/hal/i2s_ll.h +++ b/components/esp_hal_i2s/esp32h4/include/hal/i2s_ll.h @@ -23,6 +23,7 @@ #include "hal/hal_utils.h" #define I2S_LL_GET(_attr) I2S_LL_ ## _attr +#define I2S_LL_SUPPORT(_feat) I2S_LL_SUPPORT_ ## _feat #define I2S_LL_INST_NUM 1 #ifdef __cplusplus @@ -251,9 +252,9 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) 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; + case I2S_CLK_SRC_XTAL_X2: + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 2; + break; case I2S_CLK_SRC_EXTERNAL: PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 3; break; @@ -279,9 +280,9 @@ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) 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; + case I2S_CLK_SRC_XTAL_X2: + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 2; + break; case I2S_CLK_SRC_EXTERNAL: PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 3; break; diff --git a/components/esp_hal_i2s/esp32p4/include/hal/i2s_ll.h b/components/esp_hal_i2s/esp32p4/include/hal/i2s_ll.h index 504f816ffe..b8e54de7f2 100644 --- a/components/esp_hal_i2s/esp32p4/include/hal/i2s_ll.h +++ b/components/esp_hal_i2s/esp32p4/include/hal/i2s_ll.h @@ -25,6 +25,7 @@ #include "hal/config.h" #define I2S_LL_GET(_attr) I2S_LL_ ## _attr +#define I2S_LL_SUPPORT(_feat) I2S_LL_SUPPORT_ ## _feat #define I2S_LL_INST_NUM 3 #ifdef __cplusplus diff --git a/components/esp_hal_i2s/esp32s2/include/hal/i2s_ll.h b/components/esp_hal_i2s/esp32s2/include/hal/i2s_ll.h index ce7a406022..6d78b9ae11 100644 --- a/components/esp_hal_i2s/esp32s2/include/hal/i2s_ll.h +++ b/components/esp_hal_i2s/esp32s2/include/hal/i2s_ll.h @@ -24,6 +24,7 @@ #include "hal/assert.h" #define I2S_LL_GET(_attr) I2S_LL_ ## _attr +#define I2S_LL_SUPPORT(_feat) I2S_LL_SUPPORT_ ## _feat #define I2S_LL_BUS_WIDTH 24 #define I2S_LL_INST_NUM 1 diff --git a/components/esp_hal_i2s/esp32s3/include/hal/i2s_ll.h b/components/esp_hal_i2s/esp32s3/include/hal/i2s_ll.h index a353aadcf6..92becdc9cc 100644 --- a/components/esp_hal_i2s/esp32s3/include/hal/i2s_ll.h +++ b/components/esp_hal_i2s/esp32s3/include/hal/i2s_ll.h @@ -21,6 +21,7 @@ #include "hal/hal_utils.h" #define I2S_LL_GET(_attr) I2S_LL_ ## _attr +#define I2S_LL_SUPPORT(_feat) I2S_LL_SUPPORT_ ## _feat #define I2S_LL_INST_NUM 2 #ifdef __cplusplus diff --git a/components/esp_hal_i2s/esp32s31/i2s_periph.c b/components/esp_hal_i2s/esp32s31/i2s_periph.c new file mode 100644 index 0000000000..b7d9884b16 --- /dev/null +++ b/components/esp_hal_i2s/esp32s31/i2s_periph.c @@ -0,0 +1,112 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "hal/i2s_periph.h" +#include "soc/i2s_reg.h" +#include "soc/gpio_sig_map.h" +#include "soc/lp_gpio_sig_map.h" + +/* + Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc +*/ +const i2s_signal_conn_t i2s_periph_signal[I2S_LL_GET(INST_NUM)] = { + [0] = { + .mck_out_sig = I2S0_MCLK_PAD_OUT_IDX, + .mck_in_sig = I2S0_MCLK_PAD_IN_IDX, + + .m_tx_bck_sig = I2S0_O_BCK_PAD_OUT_IDX, + .m_rx_bck_sig = I2S0_I_BCK_PAD_OUT_IDX, + .m_tx_ws_sig = I2S0_O_WS_PAD_OUT_IDX, + .m_rx_ws_sig = I2S0_I_WS_PAD_OUT_IDX, + + .s_tx_bck_sig = I2S0_O_BCK_PAD_IN_IDX, + .s_rx_bck_sig = I2S0_I_BCK_PAD_IN_IDX, + .s_tx_ws_sig = I2S0_O_WS_PAD_IN_IDX, + .s_rx_ws_sig = I2S0_I_WS_PAD_IN_IDX, + + .data_out_sigs[0] = I2S0_O_SD_PAD_OUT_IDX, + .data_out_sigs[1] = I2S0_O_SD1_PAD_OUT_IDX, + .data_in_sigs[0] = I2S0_I_SD_PAD_IN_IDX, + .data_in_sigs[1] = I2S0_I_SD1_PAD_IN_IDX, + .data_in_sigs[2] = I2S0_I_SD2_PAD_IN_IDX, + .data_in_sigs[3] = I2S0_I_SD3_PAD_IN_IDX, + + .irq = ETS_I2S0_INTR_SOURCE, + }, + [1] = { + .mck_out_sig = I2S1_MCLK_PAD_OUT_IDX, + .mck_in_sig = I2S1_MCLK_PAD_IN_IDX, + + .m_tx_bck_sig = I2S1_O_BCK_PAD_OUT_IDX, + .m_rx_bck_sig = I2S1_I_BCK_PAD_OUT_IDX, + .m_tx_ws_sig = I2S1_O_WS_PAD_OUT_IDX, + .m_rx_ws_sig = I2S1_I_WS_PAD_OUT_IDX, + + .s_tx_bck_sig = I2S1_O_BCK_PAD_IN_IDX, + .s_rx_bck_sig = I2S1_I_BCK_PAD_IN_IDX, + .s_tx_ws_sig = I2S1_O_WS_PAD_IN_IDX, + .s_rx_ws_sig = I2S1_I_WS_PAD_IN_IDX, + + .data_out_sigs[0] = I2S1_O_SD_PAD_OUT_IDX, + .data_out_sigs[1] = -1, + .data_in_sigs[0] = I2S1_I_SD_PAD_IN_IDX, + .data_in_sigs[1] = -1, + .data_in_sigs[2] = -1, + .data_in_sigs[3] = -1, + + .irq = ETS_I2S1_INTR_SOURCE, + }, +}; + +/** + * I2S Registers to be saved during sleep retention + * - I2S_RX_CONF_REG + * - I2S_TX_CONF_REG + * - I2S_RX_CONF1_REG + * - I2S_TX_CONF1_REG + * - I2S_RX_RECOMB_CTRL_REG + * - I2S_RX_RECOMB_DMA_CH0_REG + * - I2S_RX_RECOMB_DMA_CH1_REG + * - I2S_RX_RECOMB_DMA_CH2_REG + * - I2S_RX_RECOMB_DMA_CH3_REG + * - I2S_TX_PCM2PDM_CONF_REG + * - I2S_TX_PCM2PDM_CONF1_REG + * - I2S_RX_PDM2PCM_CONF_REG + * - I2S_RX_TDM_CTRL_REG + * - I2S_TX_TDM_CTRL_REG + * - I2S_RXEOF_NUM_REG + * - I2S_ETM_CONF_REG +*/ +#define I2S_RETENTION_REGS_CNT 16 +#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG(i) +static const uint32_t i2s_regs_map[4] = {0x123fff, 0x0, 0x0, 0x0}; +#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \ + /* Save/restore the register values */ \ + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \ + REGDMA_I2S_LINK(0x00), \ + I2S_RETENTION_REGS_BASE(i2s_port), \ + I2S_RETENTION_REGS_BASE(i2s_port), \ + I2S_RETENTION_REGS_CNT, 0, 0, \ + i2s_regs_map[0], i2s_regs_map[1], \ + i2s_regs_map[2], i2s_regs_map[3]), \ + .owner = ENTRY(0)}, \ +}; + +static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(0); +static const regdma_entries_config_t i2s1_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(1); + +const i2s_reg_retention_info_t i2s_reg_retention_info[I2S_LL_GET(INST_NUM)] = { + [0] = { + .retention_module = SLEEP_RETENTION_MODULE_I2S0, + .entry_array = i2s0_regs_retention, + .array_size = ARRAY_SIZE(i2s0_regs_retention) + }, + [1] = { + .retention_module = SLEEP_RETENTION_MODULE_I2S1, + .entry_array = i2s1_regs_retention, + .array_size = ARRAY_SIZE(i2s1_regs_retention) + }, +}; diff --git a/components/esp_hal_i2s/esp32s31/include/hal/i2s_ll.h b/components/esp_hal_i2s/esp32s31/include/hal/i2s_ll.h new file mode 100644 index 0000000000..08cfd4d51a --- /dev/null +++ b/components/esp_hal_i2s/esp32s31/include/hal/i2s_ll.h @@ -0,0 +1,1820 @@ +/* + * SPDX-FileCopyrightText: 2026 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_struct.h" +#include "soc/soc_etm_struct.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "soc/hp_alive_sys_struct.h" +#include "soc/soc_etm_source.h" +#include "hal/i2s_types.h" +#include "hal/hal_utils.h" +#include "hal/config.h" + +#define I2S_LL_GET(_attr) I2S_LL_ ## _attr +#define I2S_LL_SUPPORT(_feat) I2S_LL_SUPPORT_ ## _feat +#define I2S_LL_INST_NUM 2 // ESP32S31 has 2 I2S instances + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2S_LL_GET_HW(num) (((num) == 0)? (&I2S0) : ((num) == 1) ? (&I2S1) : NULL) +#define I2S_LL_GET_ID(hw) (((hw) == &I2S0)? 0 : ((hw) == &I2S1) ? 1 : -1) + +#define I2S_LL_TDM_CH_MASK (0xffff) +#define I2S_LL_PDM_BCK_FACTOR (64) + +#define I2S_LL_CLK_FRAC_DIV_N_MAX 256 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the N register is 8 bit-width +#define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width +#define I2S_LL_SLOT_FRAME_BIT_MAX 512 // Up-to 512 bits in one frame, determined by MAX(half_sample_bits) * 2 + +#define I2S_LL_XTAL_CLK_FREQ (40 * 1000000) // XTAL_CLK: 40MHz +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_XTAL_CLK_FREQ +#define I2S_LL_DEFAULT_CLK_SRC I2S_CLK_SRC_XTAL +#define I2S_LL_SUPPORT_XTAL 1 // Support XTAL as I2S clock source +/* ESP32S31 hardware provides 4 GDMA trigger channels per I2S instance. */ +#define I2S_LL_SUPPORT_GDMA_RECOMB 1 + +#define I2S_LL_ETM_EVENT_TABLE(i2s_port, chan_dir, event) \ + (uint32_t[I2S_LL_GET(INST_NUM)][2][I2S_ETM_EVENT_MAX]){ \ + [0] = { \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S0_EVT_RX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S0_EVT_X_WORDS_RECEIVED, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S0_EVT_TX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S0_EVT_X_WORDS_SENT, \ + }, \ + }, \ + [1] = { \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S1_EVT_RX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S1_EVT_X_WORDS_RECEIVED, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S1_EVT_TX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S1_EVT_X_WORDS_SENT, \ + }, \ + }, \ + }[i2s_port][(chan_dir) - 1][event] + +#define I2S_LL_ETM_TASK_TABLE(i2s_port, chan_dir, task) \ + (uint32_t[I2S_LL_GET(INST_NUM)][2][I2S_ETM_TASK_MAX]){ \ + [0] = { \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_TASK_START] = I2S0_TASK_START_RX, \ + [I2S_ETM_TASK_STOP] = I2S0_TASK_STOP_RX, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_TASK_START] = I2S0_TASK_START_TX, \ + [I2S_ETM_TASK_STOP] = I2S0_TASK_STOP_TX, \ + }, \ + }, \ + [1] = { \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_TASK_START] = I2S1_TASK_START_RX, \ + [I2S_ETM_TASK_STOP] = I2S1_TASK_STOP_RX, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_TASK_START] = I2S1_TASK_START_TX, \ + [I2S_ETM_TASK_STOP] = I2S1_TASK_STOP_TX, \ + }, \ + }, \ + }[i2s_port][(chan_dir) - 1][task] + +#define I2S_LL_ETM_MAX_THRESH_NUM (0x3FFFUL) + +/** + * @brief Enable the bus clock for I2S module + * + * @param i2s_id The port id of I2S + * @param enable Set true to enable the buf clock + */ +static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable) +{ + switch (i2s_id) { + case 0: + HP_SYS_CLKRST.i2s0_ctrl0.reg_i2s0_apb_clk_en = enable; + HP_ALIVE_SYS.hp_pad_i2s0_ctrl.hp_pad_i2s0_mclk_en = enable; + return; + case 1: + HP_SYS_CLKRST.i2s1_ctrl0.reg_i2s1_apb_clk_en = enable; + HP_ALIVE_SYS.hp_pad_i2s1_ctrl.hp_pad_i2s1_mclk_en = enable; + return; + } +} + +/** + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + switch (i2s_id) { + case 0: + HP_SYS_CLKRST.i2s0_ctrl0.reg_i2s0_apb_rst_en = 1; + HP_SYS_CLKRST.i2s0_ctrl0.reg_i2s0_apb_rst_en = 0; + return; + case 1: + HP_SYS_CLKRST.i2s1_ctrl0.reg_i2s1_apb_rst_en = 1; + HP_SYS_CLKRST.i2s1_ctrl0.reg_i2s1_apb_rst_en = 0; + return; + } +} + +/** + * @brief I2S module general init, enable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + * @param enable set true to enable the core clock + */ +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) +{ + (void)hw; + (void)enable; + // No need to do anything +} + +/** + * @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) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.i2s0_tx_ctrl0.reg_i2s0_tx_clk_en = 1; + return; + case 1: + HP_SYS_CLKRST.i2s1_tx_ctrl0.reg_i2s1_tx_clk_en = 1; + return; + } +} + +/** + * @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) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.i2s0_rx_ctrl0.reg_i2s0_rx_clk_en = 1; + return; + case 1: + HP_SYS_CLKRST.i2s1_rx_ctrl0.reg_i2s1_rx_clk_en = 1; + return; + } +} + +/** + * @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) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.i2s0_tx_ctrl0.reg_i2s0_tx_clk_en = 0; + return; + case 1: + HP_SYS_CLKRST.i2s1_tx_ctrl0.reg_i2s1_tx_clk_en = 0; + return; + } +} + +/** + * @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) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.i2s0_rx_ctrl0.reg_i2s0_rx_clk_en = 0; + return; + case 1: + HP_SYS_CLKRST.i2s1_rx_ctrl0.reg_i2s1_rx_clk_en = 0; + return; + } +} + +/** + * @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) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + // Special on S31, set mst_clk_sel to 1 means attach the mclk signal to TX module + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.i2s0_rx_ctrl0.reg_i2s0_mst_clk_sel = 1; + return; + case 1: + HP_SYS_CLKRST.i2s1_rx_ctrl0.reg_i2s1_mst_clk_sel = 1; + return; + } +} + +/** + * @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) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + // Special on S31, set mst_clk_sel to 0 means attach the mclk signal to RX module + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.i2s0_rx_ctrl0.reg_i2s0_mst_clk_sel = 0; + return; + case 1: + HP_SYS_CLKRST.i2s1_rx_ctrl0.reg_i2s1_mst_clk_sel = 0; + return; + } +} + +/** + * @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) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + switch (src) { + case I2S_CLK_SRC_XTAL: + HP_SYS_CLKRST.i2s0_tx_ctrl0.reg_i2s0_tx_clk_src_sel = 0; + return; + case I2S_CLK_SRC_APLL: + HP_SYS_CLKRST.i2s0_tx_ctrl0.reg_i2s0_tx_clk_src_sel = 1; + return; + case I2S_CLK_SRC_RTC_FAST: + HP_SYS_CLKRST.i2s0_tx_ctrl0.reg_i2s0_tx_clk_src_sel = 2; + return; + case I2S_CLK_SRC_EXTERNAL: + HP_SYS_CLKRST.i2s0_tx_ctrl0.reg_i2s0_tx_clk_src_sel = 3; + return; + default: + HAL_ASSERT(false && "unsupported clock source"); + return; + } + case 1: + switch (src) { + case I2S_CLK_SRC_XTAL: + HP_SYS_CLKRST.i2s1_tx_ctrl0.reg_i2s1_tx_clk_src_sel = 0; + return; + case I2S_CLK_SRC_APLL: + HP_SYS_CLKRST.i2s1_tx_ctrl0.reg_i2s1_tx_clk_src_sel = 1; + return; + case I2S_CLK_SRC_RTC_FAST: + HP_SYS_CLKRST.i2s1_tx_ctrl0.reg_i2s1_tx_clk_src_sel = 2; + return; + case I2S_CLK_SRC_EXTERNAL: + HP_SYS_CLKRST.i2s1_tx_ctrl0.reg_i2s1_tx_clk_src_sel = 3; + return; + default: + HAL_ASSERT(false && "unsupported clock source"); + return; + } + default: + return; + } +} + +/** + * @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) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + switch (src) { + case I2S_CLK_SRC_XTAL: + HP_SYS_CLKRST.i2s0_rx_ctrl0.reg_i2s0_rx_clk_src_sel = 0; + return; + case I2S_CLK_SRC_APLL: + HP_SYS_CLKRST.i2s0_rx_ctrl0.reg_i2s0_rx_clk_src_sel = 1; + return; + case I2S_CLK_SRC_RTC_FAST: + HP_SYS_CLKRST.i2s0_rx_ctrl0.reg_i2s0_rx_clk_src_sel = 2; + return; + case I2S_CLK_SRC_EXTERNAL: + HP_SYS_CLKRST.i2s0_rx_ctrl0.reg_i2s0_rx_clk_src_sel = 3; + return; + default: + HAL_ASSERT(false && "unsupported clock source"); + return; + } + case 1: + switch (src) { + case I2S_CLK_SRC_XTAL: + HP_SYS_CLKRST.i2s1_rx_ctrl0.reg_i2s1_rx_clk_src_sel = 0; + return; + case I2S_CLK_SRC_APLL: + HP_SYS_CLKRST.i2s1_rx_ctrl0.reg_i2s1_rx_clk_src_sel = 1; + return; + case I2S_CLK_SRC_RTC_FAST: + HP_SYS_CLKRST.i2s1_rx_ctrl0.reg_i2s1_rx_clk_src_sel = 2; + return; + case I2S_CLK_SRC_EXTERNAL: + HP_SYS_CLKRST.i2s1_rx_ctrl0.reg_i2s1_rx_clk_src_sel = 3; + return; + default: + HAL_ASSERT(false && "unsupported clock source"); + return; + } + default: + return; + } +} + +/** + * @brief Get TX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @return Current TX clock source (i2s_clock_src_t). + */ +static inline i2s_clock_src_t i2s_ll_tx_clk_get_src(i2s_dev_t *hw) +{ + uint32_t clk_src; + switch (I2S_LL_GET_ID(hw)) { + case 0: + clk_src = HP_SYS_CLKRST.i2s0_tx_ctrl0.reg_i2s0_tx_clk_src_sel; + break; + case 1: + clk_src = HP_SYS_CLKRST.i2s1_tx_ctrl0.reg_i2s1_tx_clk_src_sel; + break; + default: + return (i2s_clock_src_t)I2S_CLK_SRC_DEFAULT; + } + switch (clk_src) { + case 0: + return (i2s_clock_src_t)I2S_CLK_SRC_XTAL; + case 1: + return (i2s_clock_src_t)I2S_CLK_SRC_APLL; + case 2: + return (i2s_clock_src_t)I2S_CLK_SRC_RTC_FAST; + case 3: + return (i2s_clock_src_t)I2S_CLK_SRC_EXTERNAL; + default: + return (i2s_clock_src_t)I2S_CLK_SRC_DEFAULT; + } +} + +/** + * @brief Get RX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @return Current RX clock source (i2s_clock_src_t). + */ +static inline i2s_clock_src_t i2s_ll_rx_clk_get_src(i2s_dev_t *hw) +{ + uint32_t clk_src; + switch (I2S_LL_GET_ID(hw)) { + case 0: + clk_src = HP_SYS_CLKRST.i2s0_rx_ctrl0.reg_i2s0_rx_clk_src_sel; + break; + case 1: + clk_src = HP_SYS_CLKRST.i2s1_rx_ctrl0.reg_i2s1_rx_clk_src_sel; + break; + default: + return (i2s_clock_src_t)I2S_CLK_SRC_DEFAULT; + } + switch (clk_src) { + case 0: + return (i2s_clock_src_t)I2S_CLK_SRC_XTAL; + case 1: + return (i2s_clock_src_t)I2S_CLK_SRC_APLL; + case 2: + return (i2s_clock_src_t)I2S_CLK_SRC_RTC_FAST; + case 3: + return (i2s_clock_src_t)I2S_CLK_SRC_EXTERNAL; + default: + return (i2s_clock_src_t)I2S_CLK_SRC_DEFAULT; + } +} + +/** + * @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 div_int Integer part of division + * @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 div_int, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + /* Workaround for the double division issue. + * The division coefficients must be set in particular sequence. + * And it has to switch to a small division first before setting the target division. */ + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.i2s0_tx_ctrl0, reg_i2s0_tx_div_n, 2); + HP_SYS_CLKRST.i2s0_tx_div_ctrl0.reg_i2s0_tx_div_yn1 = 0; + HP_SYS_CLKRST.i2s0_tx_div_ctrl0.reg_i2s0_tx_div_y = 1; + HP_SYS_CLKRST.i2s0_tx_div_ctrl0.reg_i2s0_tx_div_z = 0; + HP_SYS_CLKRST.i2s0_tx_div_ctrl0.reg_i2s0_tx_div_x = 0; + /* Set the target mclk division coefficients */ + HP_SYS_CLKRST.i2s0_tx_div_ctrl0.reg_i2s0_tx_div_yn1 = yn1; + HP_SYS_CLKRST.i2s0_tx_div_ctrl0.reg_i2s0_tx_div_z = z; + HP_SYS_CLKRST.i2s0_tx_div_ctrl0.reg_i2s0_tx_div_y = y; + HP_SYS_CLKRST.i2s0_tx_div_ctrl0.reg_i2s0_tx_div_x = x; + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.i2s0_tx_ctrl0, reg_i2s0_tx_div_n, div_int); + return; + case 1: + /* Workaround for the double division issue. + * The division coefficients must be set in particular sequence. + * And it has to switch to a small division first before setting the target division. */ + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.i2s1_tx_ctrl0, reg_i2s1_tx_div_n, 2); + HP_SYS_CLKRST.i2s1_tx_div_ctrl0.reg_i2s1_tx_div_yn1 = 0; + HP_SYS_CLKRST.i2s1_tx_div_ctrl0.reg_i2s1_tx_div_y = 1; + HP_SYS_CLKRST.i2s1_tx_div_ctrl0.reg_i2s1_tx_div_z = 0; + HP_SYS_CLKRST.i2s1_tx_div_ctrl0.reg_i2s1_tx_div_x = 0; + /* Set the target mclk division coefficients */ + HP_SYS_CLKRST.i2s1_tx_div_ctrl0.reg_i2s1_tx_div_yn1 = yn1; + HP_SYS_CLKRST.i2s1_tx_div_ctrl0.reg_i2s1_tx_div_z = z; + HP_SYS_CLKRST.i2s1_tx_div_ctrl0.reg_i2s1_tx_div_y = y; + HP_SYS_CLKRST.i2s1_tx_div_ctrl0.reg_i2s1_tx_div_x = x; + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.i2s1_tx_ctrl0, reg_i2s1_tx_div_n, div_int); + return; + } +} + +/** + * @brief Set I2S rx raw clock division + * + * @param hw Peripheral I2S hardware instance address. + * @param div_int Integer part of division + * @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 div_int, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + /* Workaround for the double division issue. + * The division coefficients must be set in particular sequence. + * And it has to switch to a small division first before setting the target division. */ + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.i2s0_rx_ctrl0, reg_i2s0_rx_div_n, 2); + HP_SYS_CLKRST.i2s0_rx_div_ctrl0.reg_i2s0_rx_div_yn1 = 0; + HP_SYS_CLKRST.i2s0_rx_div_ctrl0.reg_i2s0_rx_div_y = 1; + HP_SYS_CLKRST.i2s0_rx_div_ctrl0.reg_i2s0_rx_div_z = 0; + HP_SYS_CLKRST.i2s0_rx_div_ctrl0.reg_i2s0_rx_div_x = 0; + /* Set the target mclk division coefficients */ + HP_SYS_CLKRST.i2s0_rx_div_ctrl0.reg_i2s0_rx_div_yn1 = yn1; + HP_SYS_CLKRST.i2s0_rx_div_ctrl0.reg_i2s0_rx_div_z = z; + HP_SYS_CLKRST.i2s0_rx_div_ctrl0.reg_i2s0_rx_div_y = y; + HP_SYS_CLKRST.i2s0_rx_div_ctrl0.reg_i2s0_rx_div_x = x; + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.i2s0_rx_ctrl0, reg_i2s0_rx_div_n, div_int); + return; + case 1: + /* Workaround for the double division issue. + * The division coefficients must be set in particular sequence. + * And it has to switch to a small division first before setting the target division. */ + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.i2s1_rx_ctrl0, reg_i2s1_rx_div_n, 2); + HP_SYS_CLKRST.i2s1_rx_div_ctrl0.reg_i2s1_rx_div_yn1 = 0; + HP_SYS_CLKRST.i2s1_rx_div_ctrl0.reg_i2s1_rx_div_y = 1; + HP_SYS_CLKRST.i2s1_rx_div_ctrl0.reg_i2s1_rx_div_z = 0; + HP_SYS_CLKRST.i2s1_rx_div_ctrl0.reg_i2s1_rx_div_x = 0; + /* Set the target mclk division coefficients */ + HP_SYS_CLKRST.i2s1_rx_div_ctrl0.reg_i2s1_rx_div_yn1 = yn1; + HP_SYS_CLKRST.i2s1_rx_div_ctrl0.reg_i2s1_rx_div_z = z; + HP_SYS_CLKRST.i2s1_rx_div_ctrl0.reg_i2s1_rx_div_y = y; + HP_SYS_CLKRST.i2s1_rx_div_ctrl0.reg_i2s1_rx_div_x = x; + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.i2s1_rx_ctrl0, reg_i2s1_rx_div_n, div_int); + return; + } +} + +/** + * @brief Configure I2S TX module clock divider + * + * @param hw Peripheral I2S hardware instance address. + * @param mclk_div The mclk division coefficients + */ +static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div) +{ + uint32_t div_x = 0; + uint32_t div_y = 0; + uint32_t div_z = 0; + uint32_t div_yn1 = 0; + /* If any of denominator and numerator is 0, set all the coefficients to 0 */ + if (mclk_div->denominator && mclk_div->numerator) { + div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator; + div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator; + div_x = mclk_div->denominator / div_z - 1; + div_y = mclk_div->denominator % div_z; + } + i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1); +} + +/** + * @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 ESP32S31 is shared by both TX and RX channel + * + * @param hw Peripheral I2S hardware instance address. + * @param mclk_div The mclk division coefficients + */ +static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div) +{ + uint32_t div_x = 0; + uint32_t div_y = 0; + uint32_t div_z = 0; + uint32_t div_yn1 = 0; + /* If any of denominator and numerator is 0, set all the coefficients to 0 */ + if (mclk_div->denominator && mclk_div->numerator) { + div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator; + div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator; + div_x = mclk_div->denominator / div_z - 1; + div_y = mclk_div->denominator % div_z; + } + i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1); +} + +/** + * @brief Update the TX configuration + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_update(i2s_dev_t *hw) +{ + hw->tx_conf.tx_update = 1; + while (hw->tx_conf.tx_update); +} + +/** + * @brief Update the RX configuration + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_update(i2s_dev_t *hw) +{ + hw->rx_conf.rx_update = 1; + while (hw->rx_conf.rx_update); +} + +/** + * @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 + i2s_ll_tx_update(hw); + 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 + i2s_ll_rx_update(hw); + 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) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rxeof_num, rx_eof_num, eof_num); +} + +/** + * @brief Configure 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 Configure 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) +{ + uint32_t tdm_ctrl = hw->tx_tdm_ctrl.val; + tdm_ctrl &= 0xFFFF0000; + tdm_ctrl |= chan_mask; + hw->tx_tdm_ctrl.val = tdm_ctrl; +} + +/** + * @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) +{ + uint32_t tdm_ctrl = hw->rx_tdm_ctrl.val; + tdm_ctrl &= 0xFFFF0000; + tdm_ctrl |= chan_mask; + hw->rx_tdm_ctrl.val = tdm_ctrl; +} + +/** + * @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 + uint32_t chan_mask = 0; + switch (slot_mask) { + case I2S_STD_SLOT_LEFT: + chan_mask |= 0x01; + break; + case I2S_STD_SLOT_RIGHT: + chan_mask |= 0x02; + break; + case I2S_STD_SLOT_BOTH: + chan_mask |= 0x03; + break; + default: + break; + } + i2s_ll_tx_set_active_chan_mask(hw, chan_mask); +} + +/** + * @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 + uint32_t chan_mask = 0; + switch (slot_mask) { + case I2S_STD_SLOT_LEFT: + chan_mask |= 0x01; + break; + case I2S_STD_SLOT_RIGHT: + chan_mask |= 0x02; + break; + case I2S_STD_SLOT_BOTH: + chan_mask |= 0x03; + break; + default: + break; + } + i2s_ll_rx_set_active_chan_mask(hw, chan_mask); +} + +/** + * @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; + hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = false; +} + +/** + * @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 I2S TX PDM mode + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm2pdm_en Set true to enable TX PCM to PDM filter + */ +static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en) +{ + hw->tx_conf.tx_pdm_en = true; + hw->tx_conf.tx_tdm_en = false; + hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pcm2pdm_en; +} + +/** + * @brief Enable I2S RX PDM mode + * + * @param hw Peripheral I2S hardware instance address. + * @param pdm2pcm_en Set true to enable RX PDM to PCM filter + * @note On ESP32S31, only I2S0 supports PDM2PCM + */ +static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm_en) +{ + hw->rx_conf.rx_pdm_en = true; + hw->rx_conf.rx_tdm_en = false; + // On ESP32S31, only I2S0 supports PDM2PCM + if (I2S_LL_GET_ID(hw) == 0) { + hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = pdm2pcm_en; + } else { + HAL_ASSERT(!pdm2pcm_en && "PDM2PCM is only supported on I2S0"); + hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = false; + } +} + +/** + * @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) +{ + // This target does not support bypassing the PDM TX high-pass filter. + HAL_ASSERT(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 parameter + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - fp configuration parameter + */ +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 parameter + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - fs configuration parameter + */ +static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) +{ + return hw->tx_pcm2pdm_conf1.tx_pdm_fs; +} + +/** + * @brief Configure RX PDM downsample + * + * @param hw Peripheral I2S hardware instance address. + * @param dsr PDM downsample configuration parameter + */ +static inline void i2s_ll_rx_set_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) +{ + hw->rx_pdm2pcm_conf.rx_pdm_sinc_dsr_16_en = dsr; +} + +/** + * @brief Get RX PDM downsample configuration + * + * @param hw Peripheral I2S hardware instance address. + * @param dsr Pointer to accept PDM downsample configuration + */ +static inline void i2s_ll_rx_get_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) +{ + *dsr = (i2s_pdm_dsr_t)hw->rx_pdm2pcm_conf.rx_pdm_sinc_dsr_16_en; +} + +/** + * @brief Configure RX PDM amplify number + * @note This is the amplification number of the digital amplifier, + * which is added after the PDM to PCM conversion result and mainly used for + * amplify the small PDM signal under the VAD scenario + * pcm_result = pdm_input * amplify_num + * pcm_result = 0 if amplify_num = 0 + * + * @param hw Peripheral I2S hardware instance address. + * @param amp_num PDM RX amplify number + */ +static inline void i2s_ll_rx_set_pdm_amplify_num(i2s_dev_t *hw, uint32_t amp_num) +{ + hw->rx_pdm2pcm_conf.rx_pdm2pcm_amplify_num = amp_num; +} + +/** + * @brief Set I2S RX PDM high pass filter param0 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM RX IIR_HP filter stage 1 is (504 + I2S_RX_IIR_HP_MULT12_0[2:0]) + */ +static inline void i2s_ll_rx_set_pdm_hp_filter_param0(i2s_dev_t *hw, uint32_t param) +{ + hw->rx_pdm2pcm_conf.rx_iir_hp_mult12_0 = param; +} + +/** + * @brief Set I2S RX PDM high pass filter param5 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM RX IIR_HP filter stage 2 is (504 + I2S_RX_IIR_HP_MULT12_5[2:0]) + */ +static inline void i2s_ll_rx_set_pdm_hp_filter_param5(i2s_dev_t *hw, uint32_t param) +{ + hw->rx_pdm2pcm_conf.rx_iir_hp_mult12_5 = param; +} + +/** + * @brief Enable I2S RX PDM high pass filter + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable I2S RX PDM high pass filter, set false to bypass it + */ +static inline void i2s_ll_rx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) +{ + hw->rx_pdm2pcm_conf.rx_pdm_hp_bypass = !enable; +} + +/** + * @brief Configura TX a/u-law decompress or compress + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm_cfg PCM configuration parameter + */ +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 parameter + */ +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_sigle_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 select 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; +} + +/** + * @brief Reset TX FIFO synchronization counter + * + * @param hw Peripheral I2S hardware instance address. + */ +__attribute__((always_inline)) +static inline void i2s_ll_tx_reset_fifo_sync_counter(i2s_dev_t *hw) +{ + hw->fifo_cnt.tx_fifo_cnt_rst = 1; + hw->fifo_cnt.tx_fifo_cnt_rst = 0; +} + +/** + * @brief Get TX FIFO synchronization count value + * + * @param hw Peripheral I2S hardware instance address. + * @return + * bclk count value + */ +__attribute__((always_inline)) +static inline uint32_t i2s_ll_tx_get_fifo_sync_count(i2s_dev_t *hw) +{ + return hw->fifo_cnt.tx_fifo_cnt; +} + +/** + * @brief Reset TX bclk synchronization counter + * + * @param hw Peripheral I2S hardware instance address. + */ +__attribute__((always_inline)) +static inline void i2s_ll_tx_reset_bclk_sync_counter(i2s_dev_t *hw) +{ + hw->bck_cnt.tx_bck_cnt_rst = 1; + hw->bck_cnt.tx_bck_cnt_rst = 0; +} + +/** + * @brief Get TX bclk synchronization count value + * + * @param hw Peripheral I2S hardware instance address. + * @return + * fifo count value + */ +__attribute__((always_inline)) +static inline uint32_t i2s_ll_tx_get_bclk_sync_count(i2s_dev_t *hw) +{ + return hw->bck_cnt.tx_bck_cnt; +} + +/** + * @brief Set the TX ETM threshold of REACH_THRESH event + * + * @param hw Peripheral I2S hardware instance address. + * @param thresh The threshold that send + */ +static inline void i2s_ll_tx_set_etm_threshold(i2s_dev_t *hw, uint32_t thresh) +{ + hw->etm_conf.etm_tx_send_word_num = thresh; +} + +/** + * @brief Set the RX ETM threshold of REACH_THRESH event + * + * @param hw Peripheral I2S hardware instance address. + * @param thresh The threshold that received + */ +static inline void i2s_ll_rx_set_etm_threshold(i2s_dev_t *hw, uint32_t thresh) +{ + hw->etm_conf.etm_rx_receive_word_num = thresh; +} + +/** + * @brief Get I2S ETM TX done event status + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - true TX done event triggered + * - false TX done event not triggered + */ +static inline bool i2s_ll_get_etm_tx_done_event_status(i2s_dev_t *hw) +{ + uint32_t i2s_id = I2S_LL_GET_ID(hw); + switch (i2s_id) { + case 0: + return SOC_ETM.evt_st8.i2s0_evt_tx_done_st; + case 1: + return SOC_ETM.evt_st8.i2s1_evt_tx_done_st; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Get I2S ETM TX done event status + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - true TX done event triggered + * - false TX done event not triggered + */ +static inline bool i2s_ll_get_etm_rx_done_event_status(i2s_dev_t *hw) +{ + uint32_t i2s_id = I2S_LL_GET_ID(hw); + switch (i2s_id) { + case 0: + return SOC_ETM.evt_st8.i2s0_evt_rx_done_st; + case 1: + return SOC_ETM.evt_st8.i2s1_evt_rx_done_st; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Get I2S ETM TX done event status + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - true TX done event triggered + * - false TX done event not triggered + */ +static inline bool i2s_ll_get_etm_tx_threshold_event_status(i2s_dev_t *hw) +{ + uint32_t i2s_id = I2S_LL_GET_ID(hw); + switch (i2s_id) { + case 0: + return SOC_ETM.evt_st8.i2s0_evt_x_words_sent_st; + case 1: + return SOC_ETM.evt_st8.i2s1_evt_x_words_sent_st; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Get I2S ETM TX done event status + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - true TX done event triggered + * - false TX done event not triggered + */ +static inline bool i2s_ll_get_etm_rx_threshold_event_status(i2s_dev_t *hw) +{ + uint32_t i2s_id = I2S_LL_GET_ID(hw); + switch (i2s_id) { + case 0: + return SOC_ETM.evt_st8.i2s0_evt_x_words_received_st; + case 1: + return SOC_ETM.evt_st8.i2s1_evt_x_words_received_st; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Enable RX recomb function for DMA data format reorganization + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable RX recomb + */ +static inline void i2s_ll_rx_enable_recomb(i2s_dev_t *hw, bool enable) +{ + hw->rx_recomb_ctrl.rx_recomb_en = enable; +} + +/** + * @brief Set RX recomb external channel number + * + * @param hw Peripheral I2S hardware instance address. + * @param ch_num External channel number (0-3) + */ +static inline void i2s_ll_rx_set_recomb_ext_ch_num(i2s_dev_t *hw, uint32_t ch_num) +{ + hw->rx_recomb_ctrl.rx_recomb_ext_ch_num = ch_num; +} + +/** + * @brief Update RX recomb configuration + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_recomb_update(i2s_dev_t *hw) +{ + hw->rx_recomb_ctrl.rx_recomb_update = 1; + while (hw->rx_recomb_ctrl.rx_recomb_update); +} + +/** + * @brief Configure RX recomb DMA channel + * + * @param hw Peripheral I2S hardware instance address. + * @param ch_id DMA channel ID (0-3) + * @param valid Set true to enable this DMA channel + * @param style Recomb style + * @param order Recomb order + * @param eof_num EOF number for this channel + */ +static inline void i2s_ll_rx_set_recomb_dma_ch(i2s_dev_t *hw, uint32_t ch_id, bool valid, uint32_t style, uint32_t order, uint32_t eof_num) +{ + switch (ch_id) { + case 0: + hw->rx_recomb_dma_ch0.rx_recomb_dma_ch0_valid = valid; + hw->rx_recomb_dma_ch0.rx_recomb_dma_ch0_style = style; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_recomb_dma_ch0, rx_recomb_dma_ch0_order, order); + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_recomb_dma_ch0, rx_recomb_dma_ch0_eof_num, eof_num); + return; + case 1: + hw->rx_recomb_dma_ch1.rx_recomb_dma_ch1_valid = valid; + hw->rx_recomb_dma_ch1.rx_recomb_dma_ch1_style = style; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_recomb_dma_ch1, rx_recomb_dma_ch1_order, order); + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_recomb_dma_ch1, rx_recomb_dma_ch1_eof_num, eof_num); + return; + case 2: + hw->rx_recomb_dma_ch2.rx_recomb_dma_ch2_valid = valid; + hw->rx_recomb_dma_ch2.rx_recomb_dma_ch2_style = style; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_recomb_dma_ch2, rx_recomb_dma_ch2_order, order); + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_recomb_dma_ch2, rx_recomb_dma_ch2_eof_num, eof_num); + return; + case 3: + hw->rx_recomb_dma_ch3.rx_recomb_dma_ch3_valid = valid; + hw->rx_recomb_dma_ch3.rx_recomb_dma_ch3_style = style; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_recomb_dma_ch3, rx_recomb_dma_ch3_order, order); + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_recomb_dma_ch3, rx_recomb_dma_ch3_eof_num, eof_num); + return; + } +} + +/** + * @brief Set the TX ETM synchronization ideal count + * + * @param hw Peripheral I2S hardware instance address. + * @param ideal_cnt The ideal FIFO count when I2S_ETM_TASK_SYNC_FIFO triggered. + */ +__attribute__((always_inline)) +static inline void i2s_ll_tx_set_etm_sync_ideal_cnt(i2s_dev_t *hw, uint32_t ideal_cnt) +{ + hw->ideal_cnt.tx_ideal_cnt = ideal_cnt; +} + +/** + * @brief Get TX ideal count + * + * @param hw Peripheral I2S hardware instance address. + * @return TX ideal count value + */ +static inline uint32_t i2s_ll_tx_get_ideal_cnt(i2s_dev_t *hw) +{ + return hw->ideal_cnt.tx_ideal_cnt; +} + +/** + * @brief Set TX sync software threshold + * + * @param hw Peripheral I2S hardware instance address. + * @param thres Software threshold value + */ +static inline void i2s_ll_tx_set_sync_sw_thres(i2s_dev_t *hw, uint32_t thres) +{ + hw->sync_sw_thres.tx_cnt_diff_sw_thres = thres; +} + +/** + * @brief Set TX sync hardware threshold + * + * @param hw Peripheral I2S hardware instance address. + * @param thres Hardware threshold value + */ +static inline void i2s_ll_tx_set_sync_hw_thres(i2s_dev_t *hw, uint32_t thres) +{ + hw->sync_hw_thres.tx_cnt_diff_hw_thres = thres; +} + +/** + * @brief Enable TX hardware sync + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable hardware sync + */ +static inline void i2s_ll_tx_enable_hw_sync(i2s_dev_t *hw, bool enable) +{ + hw->hw_sync_conf.tx_hw_sync_en = enable; +} + +/** + * @brief Set TX hardware sync supplement mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mode Supplement mode: 0 = last data, 1 = configured data + */ +static inline void i2s_ll_tx_set_hw_sync_suppl_mode(i2s_dev_t *hw, bool mode) +{ + hw->hw_sync_conf.tx_hw_sync_suppl_mode = mode; +} + +/** + * @brief Set TX hardware sync supplement data + * + * @param hw Peripheral I2S hardware instance address. + * @param data Supplement data value + */ +static inline void i2s_ll_tx_set_hw_sync_suppl_data(i2s_dev_t *hw, uint32_t data) +{ + hw->hw_sync_data.tx_hw_sync_suppl_data = data; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/port/esp32s31/esp_clk_tree.c b/components/esp_hw_support/port/esp32s31/esp_clk_tree.c index d9fa5a4590..d12369dd53 100644 --- a/components/esp_hw_support/port/esp32s31/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32s31/esp_clk_tree.c @@ -5,6 +5,7 @@ */ #include +#include #include "esp_clk_tree.h" #include "esp_err.h" #include "esp_check.h" @@ -16,6 +17,9 @@ ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree"); +static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 }; +static bool s_clk_tree_initialized = false; + esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision, uint32_t *freq_value) { @@ -52,6 +56,9 @@ esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_sr case SOC_MOD_CLK_MPLL: clk_src_freq = clk_ll_mpll_get_freq_mhz(clk_hal_xtal_get_freq_mhz()) * MHZ; break; + case SOC_MOD_CLK_APLL: + clk_src_freq = clk_hal_apll_get_freq_hz(); + break; case SOC_MOD_CLK_RTC_SLOW: clk_src_freq = esp_clk_tree_lp_slow_get_freq_hz(precision); break; @@ -82,9 +89,22 @@ esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_sr esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value) { - /* TODO: [ESP32S31] IDF-14733 */ - (void)clk_src; (void)expt_freq_value; (void)ret_freq_value; - return ESP_ERR_NOT_SUPPORTED; + ESP_RETURN_ON_FALSE(clk_src > 0 && clk_src < SOC_MOD_CLK_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown clk src"); + ESP_RETURN_ON_FALSE(expt_freq_value > 0, ESP_ERR_INVALID_ARG, TAG, "invalid frequency"); + + uint32_t real_freq_value = 0; + esp_err_t ret = ESP_OK; + switch (clk_src) { + case SOC_MOD_CLK_APLL: + ret = esp_clk_tree_apll_freq_set(expt_freq_value, &real_freq_value); + break; + default: + return ESP_ERR_NOT_SUPPORTED; + } + if (ret_freq_value) { + *ret_freq_value = real_freq_value; + } + return ret; } static int16_t s_cpll_ref_cnt = 0; @@ -102,6 +122,7 @@ void esp_clk_tree_initialize(void) // Gating // flash clock source is set to BBPLL in bootloader + s_clk_tree_initialized = true; } bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable) @@ -134,6 +155,49 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable) esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable) { + if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) { + // some conditions is legal, e.g. -1 means external clock source + return ESP_OK; + } + + if (!s_clk_tree_initialized) { + return ESP_OK; + } + + // These clock sources have their own reference counting + switch (clk_src) { + case SOC_MOD_CLK_APLL: + if (enable) { + esp_clk_tree_apll_acquire(); + } else { + esp_clk_tree_apll_release(); + } + return ESP_OK; + case SOC_MOD_CLK_MPLL: + if (enable) { + return esp_clk_tree_mpll_acquire(); + } else { + esp_clk_tree_mpll_release(); + } + return ESP_OK; + default: + break; + } + + // Other clock sources use the global reference counting + int16_t prev_ref_cnt = 0; + if (enable) { + prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1); + } else { + prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1); + if (prev_ref_cnt <= 0) { + ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src); + atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0); + return ESP_OK; + } + } + // TODO: IDF-15502 + return ESP_OK; } diff --git a/components/esp_hw_support/port/esp32s31/rtc_clk.c b/components/esp_hw_support/port/esp32s31/rtc_clk.c index 6f98ad29e6..d463ec6e35 100644 --- a/components/esp_hw_support/port/esp32s31/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s31/rtc_clk.c @@ -592,7 +592,18 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2) { - // TODO: IDF-14771, IDF-14750 + clk_ll_apll_set_config(o_div, sdm0, sdm1, sdm2); + + /* calibration */ + ANALOG_CLOCK_ENABLE(); + clk_ll_apll_set_calibration(); + + /* wait for calibration end */ + while (!clk_ll_apll_calibration_is_done()) { + /* use esp_rom_delay_us so the RTC bus doesn't get flooded */ + esp_rom_delay_us(1); + } + ANALOG_CLOCK_DISABLE(); } void rtc_dig_clk8m_enable(void) diff --git a/components/esp_lcd/test_apps/rgb_lcd/main/test_rgb_panel.c b/components/esp_lcd/test_apps/rgb_lcd/main/test_rgb_panel.c index 1d3f90ad9f..2fd3da4f44 100644 --- a/components/esp_lcd/test_apps/rgb_lcd/main/test_rgb_panel.c +++ b/components/esp_lcd/test_apps/rgb_lcd/main/test_rgb_panel.c @@ -308,7 +308,7 @@ TEST_CASE("lcd_rgb_panel_use_apll", "[lcd]") printf("set APLL frequency\r\n"); uint32_t real_freq = 0; - TEST_ESP_OK(esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_APLL, 160 * 1000 * 1000, &real_freq)); + TEST_ESP_OK(esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_APLL, 120 * 1000 * 1000, &real_freq)); printf("APLL frequency: %"PRIu32" Hz\r\n", real_freq); printf("initialize RGB panel with stream mode\r\n"); diff --git a/components/soc/esp32h21/include/soc/clk_tree_defs.h b/components/soc/esp32h21/include/soc/clk_tree_defs.h index 7e0b834c98..98d490478a 100644 --- a/components/soc/esp32h21/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h21/include/soc/clk_tree_defs.h @@ -486,7 +486,7 @@ typedef enum { typedef enum { I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_F96M as the default source clock */ I2S_CLK_SRC_PLL_96M = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_F96M as the source clock */ - I2S_CLK_SRC_PLL_64M = SOC_MOD_CLK_XTAL_X2_F64M, /*!< Select XTAL_X2_F64M as the source clock */ + I2S_CLK_SRC_XTAL_X2 = SOC_MOD_CLK_XTAL_X2_F64M, /*!< Select XTAL_X2_F64M as the source clock */ I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */ } soc_periph_i2s_clk_src_t; diff --git a/components/soc/esp32h4/include/soc/clk_tree_defs.h b/components/soc/esp32h4/include/soc/clk_tree_defs.h index e5adcd5b73..f406b1995c 100644 --- a/components/soc/esp32h4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h4/include/soc/clk_tree_defs.h @@ -452,7 +452,7 @@ typedef enum { typedef enum { I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_F96M as the default source clock */ I2S_CLK_SRC_PLL_96M = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_F96M as the source clock */ - I2S_CLK_SRC_PLL_64M = SOC_MOD_CLK_XTAL_X2_F64M, /*!< Select XTAL_X2_F64M as the source clock */ + I2S_CLK_SRC_XTAL_X2 = SOC_MOD_CLK_XTAL_X2_F64M, /*!< Select XTAL_X2_F64M as the source clock */ I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */ } soc_periph_i2s_clk_src_t; diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 3bf8650671..00d406c870 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -111,6 +111,10 @@ config SOC_RMT_SUPPORTED bool default y +config SOC_I2S_SUPPORTED + bool + default y + config SOC_SDM_SUPPORTED bool default y @@ -911,6 +915,10 @@ config SOC_CLK_RC_FAST_SUPPORT_CALIBRATION bool default y +config SOC_CLK_APLL_SUPPORTED + bool + default y + config SOC_CLK_MPLL_SUPPORTED bool default y @@ -927,6 +935,10 @@ config SOC_CLK_LP_FAST_SUPPORT_XTAL bool default y +config SOC_CLK_ANA_I2C_MST_HAS_ROOT_GATE + bool + default y + config SOC_RCC_IS_INDEPENDENT bool default y @@ -1198,3 +1210,75 @@ config SOC_BLE_SUBRATE_SUPPORTED config SOC_BLE_PERIODIC_ADV_WITH_RESPONSE bool default y + +config SOC_I2S_NUM + int + default 2 + +config SOC_I2S_HW_VERSION_2 + bool + default y + +config SOC_I2S_SUPPORTS_ETM + bool + default y + +config SOC_I2S_SUPPORTS_APLL + bool + default y + +config SOC_I2S_SUPPORTS_RTC_FAST + bool + default y + +config SOC_I2S_SUPPORTS_EXTERNAL + 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 + +config SOC_I2S_SUPPORTS_PCM2PDM + bool + default y + +config SOC_I2S_SUPPORTS_PDM_RX + bool + default y + +config SOC_I2S_SUPPORTS_PDM2PCM + bool + default y + +config SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + bool + default y + +config SOC_I2S_SUPPORTS_TX_SYNC_CNT + bool + default y + +config SOC_I2S_SUPPORTS_RX_RECOMB + bool + default y + +config SOC_I2S_SUPPORTS_TDM + bool + default y + +config SOC_I2S_PDM_MAX_TX_LINES + int + default 2 + +config SOC_I2S_PDM_MAX_RX_LINES + int + default 4 diff --git a/components/soc/esp32s31/include/soc/clk_tree_defs.h b/components/soc/esp32s31/include/soc/clk_tree_defs.h index ff5b0791b9..71fa6d1fd5 100644 --- a/components/soc/esp32s31/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s31/include/soc/clk_tree_defs.h @@ -476,6 +476,25 @@ typedef enum { MCPWM_CARRIER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default choice */ } soc_periph_mcpwm_carrier_clk_src_t; +//////////////////////////////////////////////////I2S///////////////////////////////////////////////////////////////// + +/** + * @brief I2S clock source + */ +#define SOC_I2S_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_APLL, SOC_MOD_CLK_RTC_FAST, I2S_CLK_SRC_EXTERNAL} + +/** + * @brief I2S clock source enum + * @note Enum values are matched with the register field values on purpose + */ +typedef enum { + I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Auto select maximum clock source as default source clock */ + I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + I2S_CLK_SRC_APLL = SOC_MOD_CLK_APLL, /*!< Select APLL as the source clock */ + I2S_CLK_SRC_RTC_FAST = SOC_MOD_CLK_RTC_FAST, /*!< Select RTC_FAST as the source clock */ + I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */ +} soc_periph_i2s_clk_src_t; + //////////////////////////////////////////////CLOCK OUTPUT/////////////////////////////////////////////////////////// typedef enum { CLKOUT_SIG_MPLL_500M = 0, /*!< MPLL output at 500MHz */ diff --git a/components/soc/esp32s31/include/soc/regi2c_apll.h b/components/soc/esp32s31/include/soc/regi2c_apll.h new file mode 100644 index 0000000000..ced0ee131f --- /dev/null +++ b/components/soc/esp32s31/include/soc/regi2c_apll.h @@ -0,0 +1,131 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + */ + +#pragma once + +/** + * @file regi2c_apll.h + * @brief Register definitions for audio PLL (APLL) + * + * This file lists register fields of APLL, located on an internal configuration + * bus. These definitions are used via macros defined in regi2c_ctrl.h, by + * rtc_clk_apll_freq_set and rtc_clk_apll_enable function in rtc_clk.c. + */ + +#define I2C_APLL 0X0C +#define I2C_APLL_HOSTID 0 + +#define I2C_APLL_IR_CAL_DELAY 0 +#define I2C_APLL_IR_CAL_DELAY_MSB 3 +#define I2C_APLL_IR_CAL_DELAY_LSB 0 + +#define I2C_APLL_IR_CAL_RSTB 0 +#define I2C_APLL_IR_CAL_RSTB_MSB 4 +#define I2C_APLL_IR_CAL_RSTB_LSB 4 + +#define I2C_APLL_IR_CAL_START 0 +#define I2C_APLL_IR_CAL_START_MSB 5 +#define I2C_APLL_IR_CAL_START_LSB 5 + +#define I2C_APLL_IR_CAL_UNSTOP 0 +#define I2C_APLL_IR_CAL_UNSTOP_MSB 6 +#define I2C_APLL_IR_CAL_UNSTOP_LSB 6 + +#define I2C_APLL_OC_ENB_FCAL 0 +#define I2C_APLL_OC_ENB_FCAL_MSB 7 +#define I2C_APLL_OC_ENB_FCAL_LSB 7 + +#define I2C_APLL_IR_CAL_EXT_CAP 1 +#define I2C_APLL_IR_CAL_EXT_CAP_MSB 4 +#define I2C_APLL_IR_CAL_EXT_CAP_LSB 0 + +#define I2C_APLL_IR_CAL_ENX_CAP 1 +#define I2C_APLL_IR_CAL_ENX_CAP_MSB 5 +#define I2C_APLL_IR_CAL_ENX_CAP_LSB 5 + +#define I2C_APLL_OC_LBW 1 +#define I2C_APLL_OC_LBW_MSB 6 +#define I2C_APLL_OC_LBW_LSB 6 + +#define I2C_APLL_IR_CAL_CK_DIV 2 +#define I2C_APLL_IR_CAL_CK_DIV_MSB 3 +#define I2C_APLL_IR_CAL_CK_DIV_LSB 0 + +#define I2C_APLL_OC_DCHGP 2 +#define I2C_APLL_OC_DCHGP_MSB 6 +#define I2C_APLL_OC_DCHGP_LSB 4 + +#define I2C_APLL_OC_ENB_VCON 2 +#define I2C_APLL_OC_ENB_VCON_MSB 7 +#define I2C_APLL_OC_ENB_VCON_LSB 7 + +#define I2C_APLL_OR_CAL_CAP 3 +#define I2C_APLL_OR_CAL_CAP_MSB 4 +#define I2C_APLL_OR_CAL_CAP_LSB 0 + +#define I2C_APLL_OR_CAL_UDF 3 +#define I2C_APLL_OR_CAL_UDF_MSB 5 +#define I2C_APLL_OR_CAL_UDF_LSB 5 + +#define I2C_APLL_OR_CAL_OVF 3 +#define I2C_APLL_OR_CAL_OVF_MSB 6 +#define I2C_APLL_OR_CAL_OVF_LSB 6 + +#define I2C_APLL_OR_CAL_END 3 +#define I2C_APLL_OR_CAL_END_MSB 7 +#define I2C_APLL_OR_CAL_END_LSB 7 + +#define I2C_APLL_OR_OUTPUT_DIV 4 +#define I2C_APLL_OR_OUTPUT_DIV_MSB 4 +#define I2C_APLL_OR_OUTPUT_DIV_LSB 0 + +#define I2C_APLL_OC_TSCHGP 4 +#define I2C_APLL_OC_TSCHGP_MSB 6 +#define I2C_APLL_OC_TSCHGP_LSB 6 + +#define I2C_APLL_EN_FAST_CAL 4 +#define I2C_APLL_EN_FAST_CAL_MSB 7 +#define I2C_APLL_EN_FAST_CAL_LSB 7 + +#define I2C_APLL_OC_DHREF_SEL 5 +#define I2C_APLL_OC_DHREF_SEL_MSB 1 +#define I2C_APLL_OC_DHREF_SEL_LSB 0 + +#define I2C_APLL_OC_DLREF_SEL 5 +#define I2C_APLL_OC_DLREF_SEL_MSB 3 +#define I2C_APLL_OC_DLREF_SEL_LSB 2 + +#define I2C_APLL_SDM_DITHER 5 +#define I2C_APLL_SDM_DITHER_MSB 4 +#define I2C_APLL_SDM_DITHER_LSB 4 + +#define I2C_APLL_SDM_STOP 5 +#define I2C_APLL_SDM_STOP_MSB 5 +#define I2C_APLL_SDM_STOP_LSB 5 + +#define I2C_APLL_SDM_RSTB 5 +#define I2C_APLL_SDM_RSTB_MSB 6 +#define I2C_APLL_SDM_RSTB_LSB 6 + +#define I2C_APLL_OC_DVDD 6 +#define I2C_APLL_OC_DVDD_MSB 4 +#define I2C_APLL_OC_DVDD_LSB 0 + +#define I2C_APLL_OC_REF_DIV 6 +#define I2C_APLL_OC_REF_DIV_MSB 7 +#define I2C_APLL_OC_REF_DIV_LSB 5 + +#define I2C_APLL_DSDM2 7 +#define I2C_APLL_DSDM2_MSB 5 +#define I2C_APLL_DSDM2_LSB 0 + +#define I2C_APLL_DSDM1 8 +#define I2C_APLL_DSDM1_MSB 7 +#define I2C_APLL_DSDM1_LSB 0 + +#define I2C_APLL_DSDM0 9 +#define I2C_APLL_DSDM0_MSB 7 +#define I2C_APLL_DSDM0_LSB 0 diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index 7093186646..0cd971d731 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -58,7 +58,7 @@ #define SOC_RTC_FAST_MEM_SUPPORTED 1 #define SOC_RTC_MEM_SUPPORTED 1 // TODO: [ESP32S31] IDF-14645 #define SOC_RMT_SUPPORTED 1 -// #define SOC_I2S_SUPPORTED 1 // TODO: [ESP32S31] IDF-14771 +#define SOC_I2S_SUPPORTED 1 #define SOC_SDM_SUPPORTED 1 #define SOC_GPSPI_SUPPORTED 1 #define SOC_LEDC_SUPPORTED 1 @@ -390,13 +390,15 @@ #define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (1) -// #define SOC_CLK_APLL_SUPPORTED (1) /*!< Support Audio PLL */ // TODO: IDF-14771, IDF-14750 +#define SOC_CLK_APLL_SUPPORTED (1) /*!< Support Audio PLL */ #define SOC_CLK_MPLL_SUPPORTED (1) /*!< Support MSPI PLL */ // TODO: IDF-14718 #define SOC_CLK_XTAL32K_SUPPORTED (1) /*!< Support to connect an external low frequency crystal */ #define SOC_CLK_RC32K_SUPPORTED (1) /*!< Support an internal 32kHz RC oscillator */ #define SOC_CLK_LP_FAST_SUPPORT_XTAL (1) /*!< Support XTAL clock as the LP_FAST clock source */ +#define SOC_CLK_ANA_I2C_MST_HAS_ROOT_GATE (1) /*!< Any regi2c operation needs enable the analog i2c master clock first */ + #define SOC_RCC_IS_INDEPENDENT 1 /*!< Reset and Clock Control has own registers for each module */ /*-------------------------- Memory CAPS --------------------------*/ #define SOC_ASYNCHRONOUS_BUS_ERROR_MODE (1) @@ -501,3 +503,23 @@ #define SOC_BLE_SUBRATE_SUPPORTED (1) /*!< Support Bluetooth LE Connection Subrating */ #define SOC_BLE_PERIODIC_ADV_WITH_RESPONSE (1) /*!< Support Bluetooth LE Periodic Advertising with Response (PAwR) */ // #define SOC_BLE_ISO_SUPPORTED (1) /*!< Support Bluetooth ISO */ + +/*-------------------------- I2S CAPS ----------------------------------------*/ +#define SOC_I2S_NUM (2U) +#define SOC_I2S_HW_VERSION_2 (1) +#define SOC_I2S_SUPPORTS_ETM (1) +#define SOC_I2S_SUPPORTS_APLL (1) +#define SOC_I2S_SUPPORTS_RTC_FAST (1) // Support RTC_FAST as I2S clock source +#define SOC_I2S_SUPPORTS_EXTERNAL (1) // Support External clock source +#define SOC_I2S_SUPPORTS_PCM (1) +#define SOC_I2S_SUPPORTS_PDM (1) +#define SOC_I2S_SUPPORTS_PDM_TX (1) // Support to output raw PDM format data +#define SOC_I2S_SUPPORTS_PCM2PDM (1) // Support to write PCM format but output PDM format data with the help of PCM to PDM filter +#define SOC_I2S_SUPPORTS_PDM_RX (1) // Support to input raw PDM format data +#define SOC_I2S_SUPPORTS_PDM2PCM (1) // Support to input PDM format but read PCM format data with the help of PDM to PCM filter (only on I2S0) +#define SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER (1) +#define SOC_I2S_SUPPORTS_TX_SYNC_CNT (1) // Support TX synchronization count (ideal_cnt) +#define SOC_I2S_SUPPORTS_RX_RECOMB (1) // Support RX recomb for DMA data format reorganization +#define SOC_I2S_SUPPORTS_TDM (1) +#define SOC_I2S_PDM_MAX_TX_LINES (2) // On I2S0 +#define SOC_I2S_PDM_MAX_RX_LINES (4) // On I2S0 diff --git a/components/soc/esp32s31/register/soc/i2s_reg.h b/components/soc/esp32s31/register/soc/i2s_reg.h index 7be00b1c80..e6241612e5 100644 --- a/components/soc/esp32s31/register/soc/i2s_reg.h +++ b/components/soc/esp32s31/register/soc/i2s_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -10,10 +10,12 @@ extern "C" { #endif -/** I2S_INT_RAW_REG register +#define REG_I2S_BASE(i) (DR_REG_I2S_BASE + (i) * 0x1000) + +/** I2S_INT_RAW_REG(i) register * I2S interrupt raw register, valid in level. */ -#define I2S_INT_RAW_REG (DR_REG_I2S_BASE + 0xc) +#define I2S_INT_RAW_REG(i) (REG_I2S_BASE(i) + 0xc) /** I2S_RX_DONE_INT_RAW : RO/WTC/SS; bitpos: [0]; default: 0; * The raw interrupt status bit for the i2s_rx_done_int interrupt */ @@ -50,10 +52,10 @@ extern "C" { #define I2S_TX_SYNC_INT_RAW_V 0x00000001U #define I2S_TX_SYNC_INT_RAW_S 4 -/** I2S_INT_ST_REG register +/** I2S_INT_ST_REG(i) register * I2S interrupt status register. */ -#define I2S_INT_ST_REG (DR_REG_I2S_BASE + 0x10) +#define I2S_INT_ST_REG(i) (REG_I2S_BASE(i) + 0x10) /** I2S_RX_DONE_INT_ST : RO; bitpos: [0]; default: 0; * The masked interrupt status bit for the i2s_rx_done_int interrupt */ @@ -90,10 +92,10 @@ extern "C" { #define I2S_TX_SYNC_INT_ST_V 0x00000001U #define I2S_TX_SYNC_INT_ST_S 4 -/** I2S_INT_ENA_REG register +/** I2S_INT_ENA_REG(i) register * I2S interrupt enable register. */ -#define I2S_INT_ENA_REG (DR_REG_I2S_BASE + 0x14) +#define I2S_INT_ENA_REG(i) (REG_I2S_BASE(i) + 0x14) /** I2S_RX_DONE_INT_ENA : R/W; bitpos: [0]; default: 0; * The interrupt enable bit for the i2s_rx_done_int interrupt */ @@ -130,10 +132,10 @@ extern "C" { #define I2S_TX_SYNC_INT_ENA_V 0x00000001U #define I2S_TX_SYNC_INT_ENA_S 4 -/** I2S_INT_CLR_REG register +/** I2S_INT_CLR_REG(i) register * I2S interrupt clear register. */ -#define I2S_INT_CLR_REG (DR_REG_I2S_BASE + 0x18) +#define I2S_INT_CLR_REG(i) (REG_I2S_BASE(i) + 0x18) /** I2S_RX_DONE_INT_CLR : WT; bitpos: [0]; default: 0; * Set this bit to clear the i2s_rx_done_int interrupt */ @@ -170,10 +172,10 @@ extern "C" { #define I2S_TX_SYNC_INT_CLR_V 0x00000001U #define I2S_TX_SYNC_INT_CLR_S 4 -/** I2S_RX_CONF_REG register +/** I2S_RX_CONF_REG(i) register * I2S RX configure register */ -#define I2S_RX_CONF_REG (DR_REG_I2S_BASE + 0x20) +#define I2S_RX_CONF_REG(i) (REG_I2S_BASE(i) + 0x20) /** I2S_RX_RESET : WT; bitpos: [0]; default: 0; * Set this bit to reset receiver */ @@ -322,10 +324,10 @@ extern "C" { #define I2S_RX_BCK_DIV_NUM_V 0x0000003FU #define I2S_RX_BCK_DIV_NUM_S 21 -/** I2S_TX_CONF_REG register +/** I2S_TX_CONF_REG(i) register * I2S TX configure register */ -#define I2S_TX_CONF_REG (DR_REG_I2S_BASE + 0x24) +#define I2S_TX_CONF_REG(i) (REG_I2S_BASE(i) + 0x24) /** I2S_TX_RESET : WT; bitpos: [0]; default: 0; * Set this bit to reset transmitter */ @@ -498,10 +500,10 @@ extern "C" { #define I2S_SIG_LOOPBACK_V 0x00000001U #define I2S_SIG_LOOPBACK_S 30 -/** I2S_RX_CONF1_REG register +/** I2S_RX_CONF1_REG(i) register * I2S RX configure register 1 */ -#define I2S_RX_CONF1_REG (DR_REG_I2S_BASE + 0x28) +#define I2S_RX_CONF1_REG(i) (REG_I2S_BASE(i) + 0x28) /** I2S_RX_TDM_WS_WIDTH : R/W; bitpos: [8:0]; default: 0; * The width of rx_ws_out at idle level in TDM mode is (I2S_RX_TDM_WS_WIDTH[8:0] +1) * * T_bck @@ -535,10 +537,10 @@ extern "C" { #define I2S_RX_TDM_CHAN_BITS_V 0x0000001FU #define I2S_RX_TDM_CHAN_BITS_S 27 -/** I2S_TX_CONF1_REG register +/** I2S_TX_CONF1_REG(i) register * I2S TX configure register 1 */ -#define I2S_TX_CONF1_REG (DR_REG_I2S_BASE + 0x2c) +#define I2S_TX_CONF1_REG(i) (REG_I2S_BASE(i) + 0x2c) /** I2S_TX_TDM_WS_WIDTH : R/W; bitpos: [8:0]; default: 0; * The width of tx_ws_out at idle level in TDM mode is (I2S_TX_TDM_WS_WIDTH[8:0] +1) * * T_bck @@ -572,10 +574,10 @@ extern "C" { #define I2S_TX_TDM_CHAN_BITS_V 0x0000001FU #define I2S_TX_TDM_CHAN_BITS_S 27 -/** I2S_RX_RECOMB_CTRL_REG register +/** I2S_RX_RECOMB_CTRL_REG(i) register * I2S RX configure register 1 */ -#define I2S_RX_RECOMB_CTRL_REG (DR_REG_I2S_BASE + 0x30) +#define I2S_RX_RECOMB_CTRL_REG(i) (REG_I2S_BASE(i) + 0x30) /** I2S_RX_RECOMB_EN : R/W; bitpos: [0]; default: 0; * Set this bit to enable i2s rx data recombination. */ @@ -599,10 +601,10 @@ extern "C" { #define I2S_RX_RECOMB_UPDATE_V 0x00000001U #define I2S_RX_RECOMB_UPDATE_S 31 -/** I2S_RX_RECOMB_DMA_CH0_REG register +/** I2S_RX_RECOMB_DMA_CH0_REG(i) register * I2S RX recombined-dma-channel configuration register */ -#define I2S_RX_RECOMB_DMA_CH0_REG (DR_REG_I2S_BASE + 0x34) +#define I2S_RX_RECOMB_DMA_CH0_REG(i) (REG_I2S_BASE(i) + 0x34) /** I2S_RX_RECOMB_DMA_CH0_VALID : R/W; bitpos: [0]; default: 0; * Set this bit to enable the adc-dma-channel. */ @@ -634,10 +636,10 @@ extern "C" { #define I2S_RX_RECOMB_DMA_CH0_EOF_NUM_V 0x0000FFFFU #define I2S_RX_RECOMB_DMA_CH0_EOF_NUM_S 13 -/** I2S_RX_RECOMB_DMA_CH1_REG register +/** I2S_RX_RECOMB_DMA_CH1_REG(i) register * I2S RX recombined-dma-channel configuration register */ -#define I2S_RX_RECOMB_DMA_CH1_REG (DR_REG_I2S_BASE + 0x38) +#define I2S_RX_RECOMB_DMA_CH1_REG(i) (REG_I2S_BASE(i) + 0x38) /** I2S_RX_RECOMB_DMA_CH1_VALID : R/W; bitpos: [0]; default: 0; * Set this bit to enable the adc-dma-channel. */ @@ -669,10 +671,10 @@ extern "C" { #define I2S_RX_RECOMB_DMA_CH1_EOF_NUM_V 0x0000FFFFU #define I2S_RX_RECOMB_DMA_CH1_EOF_NUM_S 13 -/** I2S_RX_RECOMB_DMA_CH2_REG register +/** I2S_RX_RECOMB_DMA_CH2_REG(i) register * I2S RX recombined-dma-channel configuration register */ -#define I2S_RX_RECOMB_DMA_CH2_REG (DR_REG_I2S_BASE + 0x3c) +#define I2S_RX_RECOMB_DMA_CH2_REG(i) (REG_I2S_BASE(i) + 0x3c) /** I2S_RX_RECOMB_DMA_CH2_VALID : R/W; bitpos: [0]; default: 0; * Set this bit to enable the adc-dma-channel. */ @@ -704,10 +706,10 @@ extern "C" { #define I2S_RX_RECOMB_DMA_CH2_EOF_NUM_V 0x0000FFFFU #define I2S_RX_RECOMB_DMA_CH2_EOF_NUM_S 13 -/** I2S_RX_RECOMB_DMA_CH3_REG register +/** I2S_RX_RECOMB_DMA_CH3_REG(i) register * I2S RX recombined-dma-channel configuration register */ -#define I2S_RX_RECOMB_DMA_CH3_REG (DR_REG_I2S_BASE + 0x40) +#define I2S_RX_RECOMB_DMA_CH3_REG(i) (REG_I2S_BASE(i) + 0x40) /** I2S_RX_RECOMB_DMA_CH3_VALID : R/W; bitpos: [0]; default: 0; * Set this bit to enable the adc-dma-channel. */ @@ -739,10 +741,10 @@ extern "C" { #define I2S_RX_RECOMB_DMA_CH3_EOF_NUM_V 0x0000FFFFU #define I2S_RX_RECOMB_DMA_CH3_EOF_NUM_S 13 -/** I2S_TX_PCM2PDM_CONF_REG register +/** I2S_TX_PCM2PDM_CONF_REG(i) register * I2S TX PCM2PDM configuration register */ -#define I2S_TX_PCM2PDM_CONF_REG (DR_REG_I2S_BASE + 0x44) +#define I2S_TX_PCM2PDM_CONF_REG(i) (REG_I2S_BASE(i) + 0x44) /** I2S_TX_PDM_SINC_OSR2 : R/W; bitpos: [4:1]; default: 2; * I2S TX PDM OSR2 value */ @@ -821,10 +823,10 @@ extern "C" { #define I2S_PCM2PDM_CONV_EN_V 0x00000001U #define I2S_PCM2PDM_CONV_EN_S 25 -/** I2S_TX_PCM2PDM_CONF1_REG register +/** I2S_TX_PCM2PDM_CONF1_REG(i) register * I2S TX PCM2PDM configuration register */ -#define I2S_TX_PCM2PDM_CONF1_REG (DR_REG_I2S_BASE + 0x48) +#define I2S_TX_PCM2PDM_CONF1_REG(i) (REG_I2S_BASE(i) + 0x48) /** I2S_TX_PDM_FP : R/W; bitpos: [9:0]; default: 960; * I2S TX PDM Fp */ @@ -856,10 +858,10 @@ extern "C" { #define I2S_TX_IIR_HP_MULT12_0_V 0x00000007U #define I2S_TX_IIR_HP_MULT12_0_S 23 -/** I2S_RX_PDM2PCM_CONF_REG register +/** I2S_RX_PDM2PCM_CONF_REG(i) register * I2S RX configure register */ -#define I2S_RX_PDM2PCM_CONF_REG (DR_REG_I2S_BASE + 0x4c) +#define I2S_RX_PDM2PCM_CONF_REG(i) (REG_I2S_BASE(i) + 0x4c) /** I2S_RX_PDM2PCM_EN : R/W; bitpos: [19]; default: 0; * 1: Enable PDM2PCM RX mode. 0: DIsable. */ @@ -906,10 +908,10 @@ extern "C" { #define I2S_RX_IIR_HP_MULT12_0_V 0x00000007U #define I2S_RX_IIR_HP_MULT12_0_S 29 -/** I2S_RX_TDM_CTRL_REG register +/** I2S_RX_TDM_CTRL_REG(i) register * I2S TX TDM mode control register */ -#define I2S_RX_TDM_CTRL_REG (DR_REG_I2S_BASE + 0x50) +#define I2S_RX_TDM_CTRL_REG(i) (REG_I2S_BASE(i) + 0x50) /** I2S_RX_TDM_PDM_CHAN0_EN : R/W; bitpos: [0]; default: 1; * 1: Enable the valid data input of I2S RX TDM or PDM channel $n. 0: Disable, just * input 0 in this channel. @@ -1053,10 +1055,10 @@ extern "C" { #define I2S_RX_TDM_BITS_MODE_DET_EN_V 0x00000001U #define I2S_RX_TDM_BITS_MODE_DET_EN_S 20 -/** I2S_TX_TDM_CTRL_REG register +/** I2S_TX_TDM_CTRL_REG(i) register * I2S TX TDM mode control register */ -#define I2S_TX_TDM_CTRL_REG (DR_REG_I2S_BASE + 0x54) +#define I2S_TX_TDM_CTRL_REG(i) (REG_I2S_BASE(i) + 0x54) /** I2S_TX_TDM_CHAN0_EN : R/W; bitpos: [0]; default: 1; * 1: Enable the valid data output of I2S TX TDM channel $n. 0: Disable, just output * 0 in this channel. @@ -1209,10 +1211,10 @@ extern "C" { #define I2S_TX_TDM_BITS_MODE_DET_EN_V 0x00000001U #define I2S_TX_TDM_BITS_MODE_DET_EN_S 21 -/** I2S_RX_TIMING_REG register +/** I2S_RX_TIMING_REG(i) register * I2S RX timing control register */ -#define I2S_RX_TIMING_REG (DR_REG_I2S_BASE + 0x58) +#define I2S_RX_TIMING_REG(i) (REG_I2S_BASE(i) + 0x58) /** I2S_RX_SD_IN_DM : R/W; bitpos: [1:0]; default: 0; * The delay mode of I2S Rx SD input signal. 0: bypass. 1: delay by pos edge. 2: * delay by neg edge. 3: not used. @@ -1278,10 +1280,10 @@ extern "C" { #define I2S_RX_BCK_IN_DM_V 0x00000003U #define I2S_RX_BCK_IN_DM_S 28 -/** I2S_TX_TIMING_REG register +/** I2S_TX_TIMING_REG(i) register * I2S TX timing control register */ -#define I2S_TX_TIMING_REG (DR_REG_I2S_BASE + 0x5c) +#define I2S_TX_TIMING_REG(i) (REG_I2S_BASE(i) + 0x5c) /** I2S_TX_SD_OUT_DM : R/W; bitpos: [1:0]; default: 0; * The delay mode of I2S TX SD output signal. 0: bypass. 1: delay by pos edge. 2: * delay by neg edge. 3: not used. @@ -1331,10 +1333,10 @@ extern "C" { #define I2S_TX_BCK_IN_DM_V 0x00000003U #define I2S_TX_BCK_IN_DM_S 28 -/** I2S_LC_HUNG_CONF_REG register +/** I2S_LC_HUNG_CONF_REG(i) register * I2S HUNG configure register. */ -#define I2S_LC_HUNG_CONF_REG (DR_REG_I2S_BASE + 0x60) +#define I2S_LC_HUNG_CONF_REG(i) (REG_I2S_BASE(i) + 0x60) /** I2S_LC_FIFO_TIMEOUT : R/W; bitpos: [7:0]; default: 16; * the i2s_tx_hung_int interrupt or the i2s_rx_hung_int interrupt will be triggered * when fifo hung counter is equal to this value @@ -1359,10 +1361,10 @@ extern "C" { #define I2S_LC_FIFO_TIMEOUT_ENA_V 0x00000001U #define I2S_LC_FIFO_TIMEOUT_ENA_S 11 -/** I2S_RXEOF_NUM_REG register +/** I2S_RXEOF_NUM_REG(i) register * I2S RX data number control register. */ -#define I2S_RXEOF_NUM_REG (DR_REG_I2S_BASE + 0x64) +#define I2S_RXEOF_NUM_REG(i) (REG_I2S_BASE(i) + 0x64) /** I2S_RX_EOF_NUM : R/W; bitpos: [15:0]; default: 64; * The receive data bit length is (I2S_RX_BITS_MOD[4:0] + 1) * (REG_RX_EOF_NUM[15:0]) * . It will trigger in_suc_eof interrupt in the configured DMA RX channel. @@ -1372,10 +1374,10 @@ extern "C" { #define I2S_RX_EOF_NUM_V 0x0000FFFFU #define I2S_RX_EOF_NUM_S 0 -/** I2S_CONF_SIGLE_DATA_REG register +/** I2S_CONF_SIGLE_DATA_REG(i) register * I2S signal data register */ -#define I2S_CONF_SIGLE_DATA_REG (DR_REG_I2S_BASE + 0x68) +#define I2S_CONF_SIGLE_DATA_REG(i) (REG_I2S_BASE(i) + 0x68) /** I2S_SINGLE_DATA : R/W; bitpos: [31:0]; default: 0; * The configured constant channel data to be sent out. */ @@ -1384,10 +1386,10 @@ extern "C" { #define I2S_SINGLE_DATA_V 0xFFFFFFFFU #define I2S_SINGLE_DATA_S 0 -/** I2S_STATE_REG register +/** I2S_STATE_REG(i) register * I2S TX status register */ -#define I2S_STATE_REG (DR_REG_I2S_BASE + 0x6c) +#define I2S_STATE_REG(i) (REG_I2S_BASE(i) + 0x6c) /** I2S_TX_IDLE : RO; bitpos: [0]; default: 1; * 1: i2s_tx is idle state. 0: i2s_tx is working. */ @@ -1396,10 +1398,10 @@ extern "C" { #define I2S_TX_IDLE_V 0x00000001U #define I2S_TX_IDLE_S 0 -/** I2S_ETM_CONF_REG register +/** I2S_ETM_CONF_REG(i) register * I2S ETM configure register */ -#define I2S_ETM_CONF_REG (DR_REG_I2S_BASE + 0x70) +#define I2S_ETM_CONF_REG(i) (REG_I2S_BASE(i) + 0x70) /** I2S_ETM_TX_SEND_WORD_NUM : R/W; bitpos: [13:0]; default: 64; * I2S ETM send x words event. When sending word number of * reg_etm_tx_send_word_num[13:0], i2s will trigger an etm event. @@ -1417,10 +1419,10 @@ extern "C" { #define I2S_ETM_RX_RECEIVE_WORD_NUM_V 0x00003FFFU #define I2S_ETM_RX_RECEIVE_WORD_NUM_S 14 -/** I2S_IDEAL_CNT_REG register +/** I2S_IDEAL_CNT_REG(i) register * I2S sync counter register */ -#define I2S_IDEAL_CNT_REG (DR_REG_I2S_BASE + 0x74) +#define I2S_IDEAL_CNT_REG(i) (REG_I2S_BASE(i) + 0x74) /** I2S_TX_IDEAL_CNT : R/W; bitpos: [30:0]; default: 0; * tx fifo counter ideal value. */ @@ -1429,10 +1431,10 @@ extern "C" { #define I2S_TX_IDEAL_CNT_V 0x7FFFFFFFU #define I2S_TX_IDEAL_CNT_S 0 -/** I2S_FIFO_CNT_REG register +/** I2S_FIFO_CNT_REG(i) register * I2S sync counter register */ -#define I2S_FIFO_CNT_REG (DR_REG_I2S_BASE + 0x78) +#define I2S_FIFO_CNT_REG(i) (REG_I2S_BASE(i) + 0x78) /** I2S_TX_FIFO_CNT : RO; bitpos: [30:0]; default: 0; * tx fifo counter value. */ @@ -1448,10 +1450,10 @@ extern "C" { #define I2S_TX_FIFO_CNT_RST_V 0x00000001U #define I2S_TX_FIFO_CNT_RST_S 31 -/** I2S_BCK_CNT_REG register +/** I2S_BCK_CNT_REG(i) register * I2S sync counter register */ -#define I2S_BCK_CNT_REG (DR_REG_I2S_BASE + 0x7c) +#define I2S_BCK_CNT_REG(i) (REG_I2S_BASE(i) + 0x7c) /** I2S_TX_BCK_CNT : RO; bitpos: [30:0]; default: 0; * tx bck counter value. */ @@ -1467,10 +1469,10 @@ extern "C" { #define I2S_TX_BCK_CNT_RST_V 0x00000001U #define I2S_TX_BCK_CNT_RST_S 31 -/** I2S_CNT_DIFF_REG register +/** I2S_CNT_DIFF_REG(i) register * I2S sync counter register */ -#define I2S_CNT_DIFF_REG (DR_REG_I2S_BASE + 0x80) +#define I2S_CNT_DIFF_REG(i) (REG_I2S_BASE(i) + 0x80) /** I2S_TX_CNT_DIFF : RO; bitpos: [30:0]; default: 0; * tx bck counter value. */ @@ -1486,10 +1488,10 @@ extern "C" { #define I2S_TX_CNT_DIFF_RST_V 0x00000001U #define I2S_TX_CNT_DIFF_RST_S 31 -/** I2S_SYNC_SW_THRES_REG register +/** I2S_SYNC_SW_THRES_REG(i) register * I2S sync counter register */ -#define I2S_SYNC_SW_THRES_REG (DR_REG_I2S_BASE + 0x84) +#define I2S_SYNC_SW_THRES_REG(i) (REG_I2S_BASE(i) + 0x84) /** I2S_TX_CNT_DIFF_SW_THRES : R/W; bitpos: [30:0]; default: 0; * tx fifo counter difference software threshold value, when difference larger than * this threshold, interrupt will occur and hardware sync will not be executed. @@ -1499,10 +1501,10 @@ extern "C" { #define I2S_TX_CNT_DIFF_SW_THRES_V 0x7FFFFFFFU #define I2S_TX_CNT_DIFF_SW_THRES_S 0 -/** I2S_SYNC_HW_THRES_REG register +/** I2S_SYNC_HW_THRES_REG(i) register * I2S sync counter register */ -#define I2S_SYNC_HW_THRES_REG (DR_REG_I2S_BASE + 0x88) +#define I2S_SYNC_HW_THRES_REG(i) (REG_I2S_BASE(i) + 0x88) /** I2S_TX_CNT_DIFF_HW_THRES : R/W; bitpos: [30:0]; default: 0; * tx fifo counter difference hardware threshold value, which means that only when * difference larger than this threshold will hardware start hardware sync. @@ -1512,10 +1514,10 @@ extern "C" { #define I2S_TX_CNT_DIFF_HW_THRES_V 0x7FFFFFFFU #define I2S_TX_CNT_DIFF_HW_THRES_S 0 -/** I2S_HW_SYNC_CONF_REG register +/** I2S_HW_SYNC_CONF_REG(i) register * I2S TX hardware sync function configuration register */ -#define I2S_HW_SYNC_CONF_REG (DR_REG_I2S_BASE + 0x8c) +#define I2S_HW_SYNC_CONF_REG(i) (REG_I2S_BASE(i) + 0x8c) /** I2S_TX_HW_SYNC_EN : R/W; bitpos: [0]; default: 0; * Configure whether enable i2s tx hardware sync function. 1: Enable. 0: Disable */ @@ -1532,10 +1534,10 @@ extern "C" { #define I2S_TX_HW_SYNC_SUPPL_MODE_V 0x00000001U #define I2S_TX_HW_SYNC_SUPPL_MODE_S 1 -/** I2S_HW_SYNC_DATA_REG register +/** I2S_HW_SYNC_DATA_REG(i) register * I2S TX hardware sync function configuration register */ -#define I2S_HW_SYNC_DATA_REG (DR_REG_I2S_BASE + 0x90) +#define I2S_HW_SYNC_DATA_REG(i) (REG_I2S_BASE(i) + 0x90) /** I2S_TX_HW_SYNC_SUPPL_DATA : R/W; bitpos: [31:0]; default: 0; * Configure the i2s tx hardware sync supplementation data when * I2S_TX_HW_SYNC_SUPPL_MODE is 1. @@ -1545,10 +1547,10 @@ extern "C" { #define I2S_TX_HW_SYNC_SUPPL_DATA_V 0xFFFFFFFFU #define I2S_TX_HW_SYNC_SUPPL_DATA_S 0 -/** I2S_DESTINATION_REG register +/** I2S_DESTINATION_REG(i) register * I2S TX status register */ -#define I2S_DESTINATION_REG (DR_REG_I2S_BASE + 0xf4) +#define I2S_DESTINATION_REG(i) (REG_I2S_BASE(i) + 0xf4) /** I2S_RX_DESTINATION : R/W; bitpos: [0]; default: 0; * Set this bit to configure the data destination of i2s rx. 1: ble. 0: gdma. */ @@ -1564,10 +1566,10 @@ extern "C" { #define I2S_TX_DESTINATION_V 0x00000001U #define I2S_TX_DESTINATION_S 1 -/** I2S_CLK_GATE_REG register +/** I2S_CLK_GATE_REG(i) register * Clock gate register */ -#define I2S_CLK_GATE_REG (DR_REG_I2S_BASE + 0xf8) +#define I2S_CLK_GATE_REG(i) (REG_I2S_BASE(i) + 0xf8) /** I2S_CLK_EN : R/W; bitpos: [0]; default: 0; * set this bit to enable clock gate */ @@ -1576,10 +1578,10 @@ extern "C" { #define I2S_CLK_EN_V 0x00000001U #define I2S_CLK_EN_S 0 -/** I2S_DATE_REG register +/** I2S_DATE_REG(i) register * Version control register */ -#define I2S_DATE_REG (DR_REG_I2S_BASE + 0xfc) +#define I2S_DATE_REG(i) (REG_I2S_BASE(i) + 0xfc) /** I2S_DATE : R/W; bitpos: [27:0]; default: 38813744; * I2S version control register */ diff --git a/components/soc/esp32s31/register/soc/i2s_struct.h b/components/soc/esp32s31/register/soc/i2s_struct.h index 2e78a613a0..73878564a0 100644 --- a/components/soc/esp32s31/register/soc/i2s_struct.h +++ b/components/soc/esp32s31/register/soc/i2s_struct.h @@ -1282,6 +1282,8 @@ typedef struct { volatile i2s_date_reg_t date; } i2s_dev_t; +extern i2s_dev_t I2S0; +extern i2s_dev_t I2S1; #ifndef __cplusplus _Static_assert(sizeof(i2s_dev_t) == 0x100, "Invalid size of i2s_dev_t structure"); diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index 686b888de1..f7b51644b7 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -3,7 +3,7 @@ Inter-IC Sound (I2S) :link_to_translation:`zh_CN:[中文]` -{IDF_TARGET_I2S_NUM:default="one", esp32="two", esp32s3="two", esp32p4="three"} +{IDF_TARGET_I2S_NUM:default="one", esp32="two", esp32s3="two", esp32p4="three", esp32s31="two"} {IDF_TARGET_I2S_STD_TDM:default="standard and TDM", esp32="standard", esp32s2="standard"} Introduction @@ -55,12 +55,14 @@ Clock Source .. list:: - - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_DEFAULT`: Default PLL clock. + - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_DEFAULT`: Default clock source. The actual source clock depends on the chip. See chip's Technical Reference Manual for details. :SOC_I2S_SUPPORTS_PLL_F160M: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_160M`: 160 MHz PLL clock. :SOC_I2S_SUPPORTS_PLL_F120M: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_120M`: 120 MHz PLL clock. :SOC_I2S_SUPPORTS_PLL_F96M: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_96M`: 96 MHz PLL clock. :SOC_I2S_SUPPORTS_PLL_F240M: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_240M`: 240 MHz PLL clock. - :SOC_I2S_SUPPORTS_APLL: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_APLL`: Audio PLL clock, which is more precise than ``I2S_CLK_SRC_PLL_160M`` in high sample rate applications. Its frequency is configurable according to the sample rate. However, if APLL has been occupied by EMAC or other channels, the APLL frequency cannot be changed, and the driver will try to work under this APLL frequency. If this frequency cannot meet the requirements of I2S, the clock configuration will fail. + :SOC_I2S_SUPPORTS_APLL: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_APLL`: Audio PLL clock. Its frequency is configurable according to the sample rate, which makes it more precise in high sample rate applications. However, if APLL has been occupied by EMAC or other channels, the APLL frequency cannot be changed, and the driver will try to work under this APLL frequency. If this frequency cannot meet the requirements of I2S, the clock configuration will fail. + :SOC_I2S_SUPPORTS_RTC_FAST: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_RTC_FAST`: RTC_FAST clock source. + :SOC_I2S_SUPPORTS_EXTERNAL: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_EXTERNAL`: External clock source. Clock Terminology ^^^^^^^^^^^^^^^^^ diff --git a/docs/zh_CN/api-reference/peripherals/i2s.rst b/docs/zh_CN/api-reference/peripherals/i2s.rst index bf25ec7868..5a0a0abc17 100644 --- a/docs/zh_CN/api-reference/peripherals/i2s.rst +++ b/docs/zh_CN/api-reference/peripherals/i2s.rst @@ -3,7 +3,7 @@ I2S :link_to_translation:`en:[English]` -{IDF_TARGET_I2S_NUM:default="1", esp32="2", esp32s3="2", esp32p4="3"} +{IDF_TARGET_I2S_NUM:default="1", esp32="2", esp32s3="2", esp32p4="3", esp32s31="2"} {IDF_TARGET_I2S_STD_TDM:default="标准和 TDM", esp32="标准", esp32s2="标准"} 简介 @@ -55,12 +55,14 @@ I2S 时钟 .. list:: - - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_DEFAULT`:默认 PLL 时钟。 + - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_DEFAULT`:默认时钟源。实际时钟源取决于具体芯片,详情请参阅芯片技术参考手册。 :SOC_I2S_SUPPORTS_PLL_F160M: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_160M`:160 MHz PLL 时钟。 :SOC_I2S_SUPPORTS_PLL_F120M: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_120M`:120 MHz PLL 时钟。 :SOC_I2S_SUPPORTS_PLL_F96M: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_96M`:96 MHz PLL 时钟。 :SOC_I2S_SUPPORTS_PLL_F240M: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_240M`:240 MHz PLL 时钟。 - :SOC_I2S_SUPPORTS_APLL: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_APLL`:音频 PLL 时钟,在高采样率应用中比 ``I2S_CLK_SRC_PLL_160M`` 更精确。其频率可根据采样率进行配置,但如果 APLL 已经被 EMAC 或其他通道占用,则无法更改 APLL 频率,驱动程序将尝试在原有 APLL 频率下工作。如果原有 APLL 频率无法满足 I2S 的需求,时钟配置将失败。 + :SOC_I2S_SUPPORTS_APLL: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_APLL`:音频 PLL 时钟。其频率可根据采样率进行配置,在高采样率应用中精度更高。但如果 APLL 已经被 EMAC 或其他通道占用,则无法更改 APLL 频率,驱动程序将尝试在原有 APLL 频率下工作。如果原有 APLL 频率无法满足 I2S 的需求,时钟配置将失败。 + :SOC_I2S_SUPPORTS_RTC_FAST: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_RTC_FAST`:RTC_FAST 时钟源。 + :SOC_I2S_SUPPORTS_EXTERNAL: - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_EXTERNAL`:外部时钟源。 时钟术语 ^^^^^^^^ diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 3488af71af..e17c4588ca 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -231,10 +231,6 @@ examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm: disable: - if: SOC_I2S_SUPPORTS_TDM != 1 or (SOC_I2C_SUPPORTED != 1 or SOC_GPSPI_SUPPORTED != 1) reason: rely on I2S TDM mode to receive audio, I2C to config es7210 and SPI to save audio to SD card - disable_test: - - if: IDF_TARGET in ["esp32p4", "esp32c61"] - temporary: true - reason: lack of runners depends_components: - esp_driver_i2s - esp_driver_dma diff --git a/examples/peripherals/i2s/i2s_basic/i2s_pdm/README.md b/examples/peripherals/i2s/i2s_basic/i2s_pdm/README.md index c8957a485a..2ba6613bce 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-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | --------- | # 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 2a7529f44e..66db55ac98 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 @@ -3,15 +3,17 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic @pytest.mark.parametrize('config', ['pdm_tx'], indirect=True) @idf_parametrize( 'target', - ['esp32', 'esp32s3', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32c61'], + soc_filtered_targets('SOC_I2S_SUPPORTS_PDM == 1'), indirect=['target'], ) +@pytest.mark.temp_skip_ci(targets=['esp32h21', 'esp32h4'], reason='lack of runners') def test_i2s_pdm_tx_example(dut: Dut) -> None: dut.expect(r'I2S PDM TX example start', timeout=5) dut.expect(r'---------------------------', timeout=5) @@ -33,7 +35,7 @@ def test_i2s_pdm_tx_example(dut: Dut) -> None: @pytest.mark.generic @pytest.mark.parametrize('config', ['pdm_rx'], indirect=True) -@idf_parametrize('target', ['esp32', 'esp32s3', 'esp32p4'], indirect=['target']) +@idf_parametrize('target', ['esp32', 'esp32s3', 'esp32s31', 'esp32p4'], indirect=['target']) def test_i2s_pdm_rx_example(dut: Dut) -> None: dut.expect(r'I2S PDM RX example start', timeout=5) dut.expect(r'---------------------------', timeout=5) diff --git a/examples/peripherals/i2s/i2s_basic/i2s_std/README.md b/examples/peripherals/i2s/i2s_basic/i2s_std/README.md index dcd4cd8ea0..e8603e463c 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-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # 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 9d7fbbbd5b..92076291dc 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 @@ -3,14 +3,16 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic @idf_parametrize( 'target', - ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32c61'], + soc_filtered_targets('SOC_I2S_SUPPORTED == 1'), indirect=['target'], ) +@pytest.mark.temp_skip_ci(targets=['esp32h21', 'esp32h4'], reason='lack of runners') def test_i2s_basic_example(dut: Dut) -> None: dut.expect(r'i2s_common: tx channel is registered on I2S0 successfully', timeout=5) dut.expect(r'i2s_common: rx channel is registered on I2S0 successfully', timeout=5) diff --git a/examples/peripherals/i2s/i2s_basic/i2s_tdm/README.md b/examples/peripherals/i2s/i2s_basic/i2s_tdm/README.md index 09f2b37138..04b63d8a85 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-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | --------- | # I2S Basic TDM Mode Example 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 65bf9da7be..98e796a9f6 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 @@ -3,12 +3,16 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic @idf_parametrize( - 'target', ['esp32s3', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32c61'], indirect=['target'] + 'target', + soc_filtered_targets('SOC_I2S_SUPPORTS_TDM == 1'), + indirect=['target'], ) +@pytest.mark.temp_skip_ci(targets=['esp32h21', 'esp32h4'], reason='lack of runners') def test_i2s_tdm_example(dut: Dut) -> None: dut.expect(r'i2s_common: tx channel is registered on I2S0 successfully', timeout=5) dut.expect(r'i2s_common: rx channel is registered on I2S0 successfully', timeout=5) 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 e524b76d2f..3a73321ec6 100644 --- a/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md +++ b/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | --------- | # I2S TDM Example -- ES7210 4-Ch ADC Codec 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 0fda2176f5..a2fd0ac5b7 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 @@ -3,10 +3,12 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic -@idf_parametrize('target', ['esp32s3', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2'], indirect=['target']) +@idf_parametrize('target', soc_filtered_targets('SOC_I2S_SUPPORTS_TDM == 1'), indirect=['target']) +@pytest.mark.temp_skip_ci(targets=['esp32h21', 'esp32h4'], reason='lack of runners') def test_i2s_es7210_tdm_example(dut: Dut) -> None: dut.expect_exact('example: Create I2S receive channel') dut.expect_exact('example: Configure I2S receive channel to TDM mode') diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md b/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md index d2089962b8..1d30dbb9f6 100644 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md +++ b/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # I2S ES8311 Example 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 664840b019..ee50455b6c 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 @@ -3,14 +3,16 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic @idf_parametrize( 'target', - ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32c61'], + soc_filtered_targets('SOC_I2S_SUPPORTED == 1'), indirect=['target'], ) +@pytest.mark.temp_skip_ci(targets=['esp32h21', 'esp32h4'], reason='lack of runners') def test_i2s_es8311_example_generic(dut: Dut) -> None: dut.expect('i2s es8311 codec example start') dut.expect('-----------------------------') diff --git a/examples/peripherals/i2s/i2s_examples_common/i2s_example_pins.h b/examples/peripherals/i2s/i2s_examples_common/i2s_example_pins.h index e2109d0cf8..4d0cfbf0f9 100644 --- a/examples/peripherals/i2s/i2s_examples_common/i2s_example_pins.h +++ b/examples/peripherals/i2s/i2s_examples_common/i2s_example_pins.h @@ -38,7 +38,7 @@ extern "C" { #define EXAMPLE_I2S_DOUT_IO2 GPIO_NUM_22 // I2S data out io number #define EXAMPLE_I2S_DIN_IO2 GPIO_NUM_23 // I2S data in io number -#elif CONFIG_IDF_TARGET_ESP32S3 +#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32S31 #define EXAMPLE_I2S_BCLK_IO1 GPIO_NUM_2 // I2S bit clock io number #define EXAMPLE_I2S_WS_IO1 GPIO_NUM_3 // I2S word select io number #define EXAMPLE_I2S_DOUT_IO1 GPIO_NUM_4 // I2S data out io number