diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index d36b2e2945..47951b5358 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -22,6 +22,7 @@ #include "soc/lldesc.h" #include "driver/gpio.h" +#include "esp_private/gpio.h" #include "hal/gpio_hal.h" #include "driver/i2s_types_legacy.h" #include "hal/i2s_hal.h" @@ -1849,7 +1850,7 @@ static void gpio_matrix_out_check_and_set(gpio_num_t gpio, uint32_t signal_idx, { //if pin = -1, do not need to configure if (gpio != -1) { - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); + gpio_func_sel(gpio, PIN_FUNC_GPIO); gpio_set_direction(gpio, GPIO_MODE_OUTPUT); esp_rom_gpio_connect_out_signal(gpio, signal_idx, out_inv, oen_inv); } @@ -1858,7 +1859,7 @@ static void gpio_matrix_out_check_and_set(gpio_num_t gpio, uint32_t signal_idx, static void gpio_matrix_in_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool inv) { if (gpio != -1) { - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); + gpio_func_sel(gpio, PIN_FUNC_GPIO); /* Set direction, for some GPIOs, the input function are not enabled as default */ gpio_set_direction(gpio, GPIO_MODE_INPUT); esp_rom_gpio_connect_in_signal(gpio, signal_idx, inv); diff --git a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/main/test_legacy_i2s.c b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/main/test_legacy_i2s.c index e8a3b5b4f9..bf008b44c3 100644 --- a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/main/test_legacy_i2s.c +++ b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/main/test_legacy_i2s.c @@ -22,6 +22,7 @@ #include "soc/i2s_periph.h" #include "soc/soc_caps.h" #include "driver/gpio.h" +#include "esp_private/gpio.h" #include "hal/gpio_hal.h" #include "unity.h" #include "math.h" @@ -47,9 +48,9 @@ static void i2s_test_io_config(int mode) { // Connect internal signals using IO matrix. - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[MASTER_BCK_IO], PIN_FUNC_GPIO); - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[MASTER_WS_IO], PIN_FUNC_GPIO); - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[DATA_OUT_IO], PIN_FUNC_GPIO); + gpio_func_sel(MASTER_BCK_IO, PIN_FUNC_GPIO); + gpio_func_sel(MASTER_WS_IO, PIN_FUNC_GPIO); + gpio_func_sel(DATA_OUT_IO, PIN_FUNC_GPIO); gpio_set_direction(MASTER_BCK_IO, GPIO_MODE_INPUT_OUTPUT); gpio_set_direction(MASTER_WS_IO, GPIO_MODE_INPUT_OUTPUT); @@ -869,7 +870,7 @@ static void i2s_test_common_sample_rate(i2s_port_t id) TEST_ESP_OK(pcnt_unit_enable(pcnt_unit)); // Reconfig GPIO signal - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[MASTER_WS_IO], PIN_FUNC_GPIO); + gpio_func_sel(MASTER_WS_IO, PIN_FUNC_GPIO); gpio_set_direction(MASTER_WS_IO, GPIO_MODE_INPUT_OUTPUT); esp_rom_gpio_connect_out_signal(MASTER_WS_IO, i2s_periph_signal[0].m_tx_ws_sig, 0, 0); esp_rom_gpio_connect_in_signal(MASTER_WS_IO, pcnt_periph_signals.groups[0].units[0].channels[0].pulse_sig, 0); diff --git a/components/esp_driver_i2s/i2s_common.c b/components/esp_driver_i2s/i2s_common.c index 7bd6cddd6d..d145a49004 100644 --- a/components/esp_driver_i2s/i2s_common.c +++ b/components/esp_driver_i2s/i2s_common.c @@ -42,6 +42,7 @@ #include "esp_private/esp_clk.h" #include "driver/gpio.h" +#include "esp_private/gpio.h" #include "driver/i2s_common.h" #include "i2s_private.h" @@ -789,7 +790,7 @@ 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_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); + gpio_func_sel(gpio, PIN_FUNC_GPIO); if (is_input) { /* Set direction, for some GPIOs, the input function are not enabled as default */ gpio_set_direction(gpio, GPIO_MODE_INPUT); @@ -806,7 +807,7 @@ void i2s_gpio_loopback_set(i2s_chan_handle_t handle, int gpio, uint32_t out_sig_ { if (gpio != (int)I2S_GPIO_UNUSED) { i2s_output_gpio_reserve(handle, gpio); - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); + gpio_func_sel(gpio, PIN_FUNC_GPIO); gpio_set_direction(gpio, GPIO_MODE_INPUT_OUTPUT); esp_rom_gpio_connect_out_signal(gpio, out_sig_idx, 0, 0); esp_rom_gpio_connect_in_signal(gpio, in_sig_idx, 0); 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 5cb9489b5d..e0e69c551b 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 @@ -14,6 +14,7 @@ #include "sdkconfig.h" #include "driver/gpio.h" #include "hal/gpio_hal.h" +#include "esp_private/gpio.h" #include "esp_err.h" #include "esp_attr.h" #include "unity.h" @@ -71,9 +72,9 @@ static void i2s_test_io_config(int mode) { // Connect internal signals using IO matrix. - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[MASTER_BCK_IO], PIN_FUNC_GPIO); - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[MASTER_WS_IO], PIN_FUNC_GPIO); - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[DATA_OUT_IO], PIN_FUNC_GPIO); + gpio_func_sel(MASTER_BCK_IO, PIN_FUNC_GPIO); + gpio_func_sel(MASTER_WS_IO, PIN_FUNC_GPIO); + gpio_func_sel(DATA_OUT_IO, PIN_FUNC_GPIO); gpio_set_direction(MASTER_BCK_IO, GPIO_MODE_INPUT_OUTPUT); gpio_set_direction(MASTER_WS_IO, GPIO_MODE_INPUT_OUTPUT); @@ -745,7 +746,7 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_c TEST_ESP_OK(pcnt_unit_enable(pcnt_unit)); // Reconfig GPIO signal - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[MASTER_WS_IO], PIN_FUNC_GPIO); + gpio_func_sel(MASTER_WS_IO, PIN_FUNC_GPIO); gpio_set_direction(MASTER_WS_IO, GPIO_MODE_INPUT_OUTPUT); esp_rom_gpio_connect_out_signal(MASTER_WS_IO, i2s_periph_signal[0].m_rx_ws_sig, 0, 0); esp_rom_gpio_connect_in_signal(MASTER_WS_IO, pcnt_periph_signals.groups[0].units[0].channels[0].pulse_sig, 0); 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 db546feb2f..c3b4522b9a 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 @@ -54,6 +54,14 @@ extern "C" { #define SLAVE_WS_IO 23 #define DATA_IN_IO 47 #define DATA_OUT_IO 48 +#elif CONFIG_IDF_TARGET_ESP32C5 +#define MASTER_MCK_IO 6 +#define MASTER_BCK_IO 8 +#define MASTER_WS_IO 9 +#define SLAVE_BCK_IO 23 +#define SLAVE_WS_IO 24 +#define DATA_IN_IO 10 +#define DATA_OUT_IO 25 #else #define MASTER_MCK_IO 0 #define MASTER_BCK_IO 4 diff --git a/components/hal/esp32c5/include/hal/i2s_ll.h b/components/hal/esp32c5/include/hal/i2s_ll.h new file mode 100644 index 0000000000..c14a4bf4ae --- /dev/null +++ b/components/hal/esp32c5/include/hal/i2s_ll.h @@ -0,0 +1,1196 @@ +/* + * SPDX-FileCopyrightText: 2024 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 "sdkconfig.h" +#include "hal/misc.h" +#include "hal/assert.h" +#include "soc/i2s_periph.h" +#include "soc/i2s_struct.h" +#include "soc/pcr_struct.h" +#include "hal/i2s_types.h" +#include "hal/hal_utils.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2S_LL_GET_HW(num) (((num) == 0)? (&I2S0) : NULL) + +#define I2S_LL_TDM_CH_MASK (0xffff) +#define I2S_LL_PDM_BCK_FACTOR (64) + +#define I2S_LL_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_XTAL_CLK_FREQ (CONFIG_XTAL_FREQ * 1000000) // XTAL_CLK: 40MHz or 48MHz +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_XTAL_CLK_FREQ // No PLL clock source on P4, use XTAL as default + +/** + * @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) +{ + (void)i2s_id; + PCR.i2s_conf.i2s_clk_en = enable; +} + +/** + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + (void)i2s_id; + PCR.i2s_conf.i2s_rst_en = 1; + PCR.i2s_conf.i2s_rst_en = 0; +} + +/** + * @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) +{ + (void)hw; + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_en = 1; +} + +/** + * @brief Enable I2S rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 1; +} + +/** + * @brief Disable I2S tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_en = 0; +} + +/** + * @brief Disable I2S rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 0; +} + +/** + * @brief I2S mclk use tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_mclk_bind_to_tx_clk(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_rx_clkm_conf.i2s_mclk_sel = 0; // TODO: need check +} + +/** + * @brief I2S mclk use rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_mclk_bind_to_rx_clk(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_rx_clkm_conf.i2s_mclk_sel = 1; +} + +/** + * @brief Enable I2S TX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->tx_conf.tx_slave_mod = slave_en; +} + +/** + * @brief Enable I2S RX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->rx_conf.rx_slave_mod = slave_en; +} + +/** + * @brief Reset I2S TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_reset(i2s_dev_t *hw) +{ + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; +} + +/** + * @brief Reset I2S RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_reset(i2s_dev_t *hw) +{ + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; +} + +/** + * @brief Reset I2S TX FIFO + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw) +{ + hw->tx_conf.tx_fifo_reset = 1; + hw->tx_conf.tx_fifo_reset = 0; +} + +/** + * @brief Reset I2S RX FIFO + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) +{ + hw->rx_conf.rx_fifo_reset = 1; + hw->rx_conf.rx_fifo_reset = 0; +} + +/** + * @brief Set TX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock. + */ +static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + (void)hw; + switch (src) + { + case I2S_CLK_SRC_XTAL: + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 0; + break; + case I2S_CLK_SRC_PLL_240M: + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 1; + break; + case I2S_CLK_SRC_PLL_160M: + 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; + default: + HAL_ASSERT(false && "unsupported clock source"); + break; + } +} + +/** + * @brief Set RX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock + */ +static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + (void)hw; + switch (src) + { + case I2S_CLK_SRC_XTAL: + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 0; + break; + case I2S_CLK_SRC_PLL_240M: + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 1; + break; + case I2S_CLK_SRC_PLL_160M: + 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; + default: + HAL_ASSERT(false && "unsupported clock source"); + break; + } +} + +/** + * @brief Set I2S tx bck div num + * + * @param hw Peripheral I2S hardware instance address. + * @param val value to set tx bck div num + */ +static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) +{ + hw->tx_conf.tx_bck_div_num = val - 1; +} + +/** + * @brief Set I2S tx raw clock division + * + * @param hw Peripheral I2S hardware instance address. + * @param 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) +{ + (void)hw; + HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_tx_clkm_conf, i2s_tx_clkm_div_num, div_int); + typeof(PCR.i2s_tx_clkm_div_conf) div = {}; + div.i2s_tx_clkm_div_x = x; + div.i2s_tx_clkm_div_y = y; + div.i2s_tx_clkm_div_z = z; + div.i2s_tx_clkm_div_yn1 = yn1; + PCR.i2s_tx_clkm_div_conf.val = div.val; +} + +/** + * @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) +{ + (void)hw; + HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_rx_clkm_conf, i2s_rx_clkm_div_num, div_int); + typeof(PCR.i2s_rx_clkm_div_conf) div = {}; + div.i2s_rx_clkm_div_x = x; + div.i2s_rx_clkm_div_y = y; + div.i2s_rx_clkm_div_z = z; + div.i2s_rx_clkm_div_yn1 = yn1; + PCR.i2s_rx_clkm_div_conf.val = div.val; +} + +/** + * @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) +{ + /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate + * Set to particular coefficients first then update to the target coefficients, + * otherwise the clock division might be inaccurate. + * the general idea is to set a value that impossible to calculate from the regular decimal */ + i2s_ll_tx_set_raw_clk_div(hw, 7, 317, 7, 3, 0); + + 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 ESP32 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) +{ + /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate + * Set to particular coefficients first then update to the target coefficients, + * otherwise the clock division might be inaccurate. + * the general idea is to set a value that impossible to calculate from the regular decimal */ + i2s_ll_rx_set_raw_clk_div(hw, 7, 317, 7, 3, 0); + + 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 Start I2S TX + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_start(i2s_dev_t *hw) +{ + // Have to update registers before start + hw->tx_conf.tx_update = 1; + while (hw->tx_conf.tx_update); + hw->tx_conf.tx_start = 1; +} + +/** + * @brief Start I2S RX + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_start(i2s_dev_t *hw) +{ + // Have to update registers before start + hw->rx_conf.rx_update = 1; + while (hw->rx_conf.rx_update); + hw->rx_conf.rx_start = 1; +} + +/** + * @brief Stop I2S TX + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_stop(i2s_dev_t *hw) +{ + hw->tx_conf.tx_start = 0; +} + +/** + * @brief Stop I2S RX + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_stop(i2s_dev_t *hw) +{ + hw->rx_conf.rx_start = 0; +} + +/** + * @brief Configure TX WS signal width + * + * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle + */ +static inline void i2s_ll_tx_set_ws_width(i2s_dev_t *hw, int width) +{ + hw->tx_conf1.tx_tdm_ws_width = width - 1; +} + +/** + * @brief Configure RX WS signal width + * + * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle + */ +static inline void i2s_ll_rx_set_ws_width(i2s_dev_t *hw, int width) +{ + hw->rx_conf1.rx_tdm_ws_width = width - 1; +} + +/** + * @brief Configure the received length to trigger in_suc_eof interrupt + * + * @param hw Peripheral I2S hardware instance address. + * @param eof_num the byte length to trigger in_suc_eof interrupt + */ +static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num) +{ + hw->rx_eof_num.rx_eof_num = eof_num; +} + +/** + * @brief 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 TX PDM mode. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw) +{ + hw->tx_conf.tx_pdm_en = true; + hw->tx_conf.tx_tdm_en = false; + hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = true; +} + +/** + * @brief Set I2S TX PDM prescale + * + * @param hw Peripheral I2S hardware instance address. + * @param prescale I2S TX PDM prescale + */ +static inline void i2s_ll_tx_set_pdm_prescale(i2s_dev_t *hw, bool prescale) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_pcm2pdm_conf, tx_pdm_prescale, prescale); +} + +/** + * @brief Set I2S TX PDM high pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_hp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_hp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM low pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_lp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_lp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sinc filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sinc_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sinc_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sigma-delta filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sd_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM high pass filter param0 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 + I2S_TX_IIR_HP_MULT12_0[2:0]) + */ +static inline void i2s_ll_tx_set_pdm_hp_filter_param0(i2s_dev_t *hw, uint32_t param) +{ + hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_0 = param; +} + +/** + * @brief Set I2S TX PDM high pass filter param5 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 + I2S_TX_IIR_HP_MULT12_5[2:0]) + */ +static inline void i2s_ll_tx_set_pdm_hp_filter_param5(i2s_dev_t *hw, uint32_t param) +{ + hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_5 = param; +} + +/** + * @brief Enable I2S TX PDM high pass filter + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable I2S TX PDM high pass filter, set false to bypass it + */ +static inline void i2s_ll_tx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) +{ + hw->tx_pcm2pdm_conf.tx_pdm_hp_bypass = !enable; +} + +/** + * @brief Set I2S TX PDM sigma-delta codec dither + * + * @param hw Peripheral I2S hardware instance address. + * @param dither I2S TX PDM sigmadelta dither value + */ +static inline void i2s_ll_tx_set_pdm_sd_dither(i2s_dev_t *hw, uint32_t dither) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither = dither; +} + +/** + * @brief Set I2S TX PDM sigma-delta codec dither + * + * @param hw Peripheral I2S hardware instance address. + * @param dither2 I2S TX PDM sigmadelta dither2 value + */ +static inline void i2s_ll_tx_set_pdm_sd_dither2(i2s_dev_t *hw, uint32_t dither2) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither2 = dither2; +} + +/** + * @brief Set the PDM TX over sampling ratio + * + * @param hw Peripheral I2S hardware instance address. + * @param ovr Over sampling ratio + */ +static inline void i2s_ll_tx_set_pdm_over_sample_ratio(i2s_dev_t *hw, uint32_t ovr) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = ovr; +} + +/** + * @brief Configure I2S TX PDM sample rate + * Fpdm = 64*Fpcm*fp/fs + * + * @param hw Peripheral I2S hardware instance address. + * @param fp The fp value of TX PDM filter module group0. + * @param fs The fs value of TX PDM filter module group0. + */ +static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) +{ + hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp; + hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs; +} + +/** + * @brief Get I2S TX PDM fp configuration 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 Enable RX PDM mode. + * @note ESP32-C5 doesn't support pdm in rx mode, disable anyway + * + * @param hw Peripheral I2S hardware instance address. + * @param pdm_enable Set true to RX enable PDM mode (ignored) + */ +static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) +{ + // Due to the lack of `PDM to PCM` module on ESP32-H2, PDM RX is not available + HAL_ASSERT(!pdm_enable); + hw->rx_conf.rx_pdm_en = 0; + hw->rx_conf.rx_tdm_en = 1; +} + +/** + * @brief Configura TX a/u-law decompress or compress + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm_cfg PCM configuration 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_single_data.val = data; +} + +/** + * @brief Enable TX mono mode + * @note MONO in hardware means only one channel got data, but another doesn't + * MONO in software means two channel share same data + * This function aims to use MONO in software meaning + * so 'tx_mono' and 'tx_chan_equal' should be enabled at the same time + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + hw->tx_conf.tx_mono = mono_ena; + hw->tx_conf.tx_chan_equal = mono_ena; +} + +/** + * @brief Enable RX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + hw->rx_conf.rx_mono = mono_ena; + hw->rx_conf.rx_mono_fst_vld = mono_ena; +} + +/** + * @brief Enable loopback mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to share BCK and WS signal for tx module and rx module. + */ +static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.sig_loopback = ena; +} + +/** + * @brief PDM TX DMA data take mode + * + * @param hw Peripheral I2S hardware instance address. + * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) + * @param is_fst_valid Whether take the DMA data at the first half period + * Only take effet when 'is_mono' is true + */ +static inline void i2s_ll_tx_pdm_dma_take_mode(i2s_dev_t *hw, bool is_mono, bool is_fst_valid) +{ + hw->tx_conf.tx_mono = is_mono; + hw->tx_conf.tx_mono_fst_vld = is_fst_valid; +} + +/** + * @brief PDM TX slot mode + * @note Mode Left Slot Right Slot Chan Mode WS Pol + * ----------------------------------------------------------------- + * Stereo Left Right 0 x + * ----------------------------------------------------------------- + * Mono Left Left 1 0 + * Mono Right Right 2 0 + * Mono Single Right 3 0 + * Mono Left Single 4 0 + * ----------------------------------------------------------------- + * Mono Right Right 1 1 + * Mono Left Left 2 1 + * Mono Left Single 3 1 + * Mono Single Right 4 1 + * @note The 'Single' above means always sending the value of `conf_single_data` reg + * The default value of `conf_single_data` reg is '0', it is not public for now + * + * @param hw Peripheral I2S hardware instance address. + * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) + * @param is_copy Whether the un-selected slot copies the data from the selected one + * If not, the un-selected slot will transmit the data from 'conf_single_data' + * @param mask The slot mask to 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; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index 7b9d55649c..8fa3a38434 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -40,7 +40,7 @@ typedef struct { i2s_std_slot_mask_t slot_mask; /*!< Select the left, right or both slot */ uint32_t ws_width; /*!< WS signal width (i.e. the number of bclk ticks that ws signal is high) */ bool ws_pol; /*!< WS signal polarity, set true to enable high lever first */ - bool bit_shift; /*!< Set to enbale bit shift in Philips mode */ + bool bit_shift; /*!< Set to enable bit shift in Philips mode */ #if SOC_I2S_HW_VERSION_1 // For esp32/esp32-s2 bool msb_right; /*!< Set to place right channel data at the MSB in the FIFO */ #else @@ -350,7 +350,7 @@ void i2s_hal_tdm_enable_rx_channel(i2s_hal_context_t *hal); #define i2s_hal_rx_reset_fifo(hal) i2s_ll_rx_reset_fifo((hal)->dev) -#if !SOC_I2S_SUPPORTS_GDMA +#if !SOC_GDMA_SUPPORTED /** * @brief Enable I2S TX DMA * diff --git a/components/soc/esp32c5/mp/i2s_periph.c b/components/soc/esp32c5/mp/i2s_periph.c new file mode 100644 index 0000000000..dbd1fdc816 --- /dev/null +++ b/components/soc/esp32c5/mp/i2s_periph.c @@ -0,0 +1,35 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/i2s_periph.h" +#include "soc/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[SOC_I2S_NUM] = { + { + .mck_out_sig = I2S_MCLK_OUT_IDX, + .mck_in_sig = I2S_MCLK_IN_IDX, + + .m_tx_bck_sig = I2SO_BCK_OUT_IDX, + .m_rx_bck_sig = I2SI_BCK_OUT_IDX, + .m_tx_ws_sig = I2SO_WS_OUT_IDX, + .m_rx_ws_sig = I2SI_WS_OUT_IDX, + + .s_tx_bck_sig = I2SO_BCK_IN_IDX, + .s_rx_bck_sig = I2SI_BCK_IN_IDX, + .s_tx_ws_sig = I2SO_WS_IN_IDX, + .s_rx_ws_sig = I2SI_WS_IN_IDX, + + .data_out_sigs[0] = I2SO_SD_OUT_IDX, + .data_out_sigs[1] = I2SO_SD1_OUT_IDX, + .data_in_sig = I2SI_SD_IN_IDX, + + .irq = ETS_I2S1_INTR_SOURCE, + .module = -1, + } +}; diff --git a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in index 160c29581f..438f227017 100644 --- a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in @@ -43,6 +43,10 @@ config SOC_RTC_MEM_SUPPORTED bool default y +config SOC_I2S_SUPPORTED + bool + default y + config SOC_GPSPI_SUPPORTED bool default y @@ -215,6 +219,54 @@ config SOC_HP_I2C_NUM int default 1 +config SOC_I2S_NUM + int + default 1 + +config SOC_I2S_HW_VERSION_2 + bool + default y + +config SOC_I2S_SUPPORTS_TX_SYNC_CNT + bool + default y + +config SOC_I2S_SUPPORTS_XTAL + bool + default y + +config SOC_I2S_SUPPORTS_PLL_F160M + bool + default y + +config SOC_I2S_SUPPORTS_PLL_F240M + 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_PDM_MAX_TX_LINES + int + default 2 + +config SOC_I2S_SUPPORTS_TDM + bool + default y + +config SOC_I2S_TDM_FULL_DATA_WIDTH + bool + default y + config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK bool default y diff --git a/components/soc/esp32c5/mp/include/soc/clk_tree_defs.h b/components/soc/esp32c5/mp/include/soc/clk_tree_defs.h index e1035c7d2c..eb04727cf8 100644 --- a/components/soc/esp32c5/mp/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c5/mp/include/soc/clk_tree_defs.h @@ -315,15 +315,16 @@ typedef enum { // TODO: [ESP32C5] IDF-8709 (inherit from C6) /** * @brief Array initializer for all supported clock sources of I2S */ -#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL, I2S_CLK_SRC_EXTERNAL} +#define SOC_I2S_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_PLL_F240M, I2S_CLK_SRC_EXTERNAL} /** * @brief I2S clock source enum */ -typedef enum { // TODO: [ESP32C5] IDF-8713 (inherit from C6) +typedef enum { I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default source clock */ - I2S_CLK_SRC_PLL_160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + I2S_CLK_SRC_PLL_240M = SOC_MOD_CLK_PLL_F240M, /*!< Select PLL_F240M as the source clock */ + I2S_CLK_SRC_PLL_160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M 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/esp32c5/mp/include/soc/i2s_struct.h b/components/soc/esp32c5/mp/include/soc/i2s_struct.h index ffd609f27e..3c6d1c9c18 100644 --- a/components/soc/esp32c5/mp/include/soc/i2s_struct.h +++ b/components/soc/esp32c5/mp/include/soc/i2s_struct.h @@ -267,117 +267,33 @@ typedef union { uint32_t val; } i2s_rx_recomb_ctrl_reg_t; -/** Type of rx_recomb_dma_ch0 register +/** Type of rx_recomb_dma_chn register * I2S RX recombined-dma-channel configuration register */ typedef union { struct { - /** rx_recomb_dma_ch0_valid : R/W; bitpos: [0]; default: 0; + /** rx_recomb_dma_ch_valid : R/W; bitpos: [0]; default: 0; * Set this bit to enable the adc-dma-channel. */ - uint32_t rx_recomb_dma_ch0_valid:1; - /** rx_recomb_dma_ch0_style : R/W; bitpos: [4:1]; default: 0; + uint32_t rx_recomb_dma_ch_valid:1; + /** rx_recomb_dma_ch_style : R/W; bitpos: [4:1]; default: 0; * Set this field to set the recombined-dma-channel style. If choose to use i2s * extracted ch 1&3 in 4 channels, the style should be: 6'b1010. */ - uint32_t rx_recomb_dma_ch0_style:4; - /** rx_recomb_dma_ch0_order : R/W; bitpos: [12:5]; default: 0; + uint32_t rx_recomb_dma_ch_style:4; + /** rx_recomb_dma_ch_order : R/W; bitpos: [12:5]; default: 0; * Set this field to set the recombined-dma-channel order. If choose to use the order * ch3 -> ch1, the order should be: 8'd7 = {2'd0,2'd0,2'd1,2'd3}. */ - uint32_t rx_recomb_dma_ch0_order:8; - /** rx_recomb_dma_ch0_eof_num : R/W; bitpos: [28:13]; default: 0; + uint32_t rx_recomb_dma_ch_order:8; + /** rx_recomb_dma_ch_eof_num : R/W; bitpos: [28:13]; default: 0; * Set this field to set the receive eof byte length of the recombined-dma-channel. */ - uint32_t rx_recomb_dma_ch0_eof_num:16; + uint32_t rx_recomb_dma_ch_eof_num:16; uint32_t reserved_29:3; }; uint32_t val; -} i2s_rx_recomb_dma_ch0_reg_t; - -/** Type of rx_recomb_dma_ch1 register - * I2S RX recombined-dma-channel configuration register - */ -typedef union { - struct { - /** rx_recomb_dma_ch1_valid : R/W; bitpos: [0]; default: 0; - * Set this bit to enable the adc-dma-channel. - */ - uint32_t rx_recomb_dma_ch1_valid:1; - /** rx_recomb_dma_ch1_style : R/W; bitpos: [4:1]; default: 0; - * Set this field to set the recombined-dma-channel style. If choose to use i2s - * extracted ch 1&3 in 4 channels, the style should be: 6'b1010. - */ - uint32_t rx_recomb_dma_ch1_style:4; - /** rx_recomb_dma_ch1_order : R/W; bitpos: [12:5]; default: 0; - * Set this field to set the recombined-dma-channel order. If choose to use the order - * ch3 -> ch1, the order should be: 8'd7 = {2'd0,2'd0,2'd1,2'd3}. - */ - uint32_t rx_recomb_dma_ch1_order:8; - /** rx_recomb_dma_ch1_eof_num : R/W; bitpos: [28:13]; default: 0; - * Set this field to set the receive eof byte length of the recombined-dma-channel. - */ - uint32_t rx_recomb_dma_ch1_eof_num:16; - uint32_t reserved_29:3; - }; - uint32_t val; -} i2s_rx_recomb_dma_ch1_reg_t; - -/** Type of rx_recomb_dma_ch2 register - * I2S RX recombined-dma-channel configuration register - */ -typedef union { - struct { - /** rx_recomb_dma_ch2_valid : R/W; bitpos: [0]; default: 0; - * Set this bit to enable the adc-dma-channel. - */ - uint32_t rx_recomb_dma_ch2_valid:1; - /** rx_recomb_dma_ch2_style : R/W; bitpos: [4:1]; default: 0; - * Set this field to set the recombined-dma-channel style. If choose to use i2s - * extracted ch 1&3 in 4 channels, the style should be: 6'b1010. - */ - uint32_t rx_recomb_dma_ch2_style:4; - /** rx_recomb_dma_ch2_order : R/W; bitpos: [12:5]; default: 0; - * Set this field to set the recombined-dma-channel order. If choose to use the order - * ch3 -> ch1, the order should be: 8'd7 = {2'd0,2'd0,2'd1,2'd3}. - */ - uint32_t rx_recomb_dma_ch2_order:8; - /** rx_recomb_dma_ch2_eof_num : R/W; bitpos: [28:13]; default: 0; - * Set this field to set the receive eof byte length of the recombined-dma-channel. - */ - uint32_t rx_recomb_dma_ch2_eof_num:16; - uint32_t reserved_29:3; - }; - uint32_t val; -} i2s_rx_recomb_dma_ch2_reg_t; - -/** Type of rx_recomb_dma_ch3 register - * I2S RX recombined-dma-channel configuration register - */ -typedef union { - struct { - /** rx_recomb_dma_ch3_valid : R/W; bitpos: [0]; default: 0; - * Set this bit to enable the adc-dma-channel. - */ - uint32_t rx_recomb_dma_ch3_valid:1; - /** rx_recomb_dma_ch3_style : R/W; bitpos: [4:1]; default: 0; - * Set this field to set the recombined-dma-channel style. If choose to use i2s - * extracted ch 1&3 in 4 channels, the style should be: 6'b1010. - */ - uint32_t rx_recomb_dma_ch3_style:4; - /** rx_recomb_dma_ch3_order : R/W; bitpos: [12:5]; default: 0; - * Set this field to set the recombined-dma-channel order. If choose to use the order - * ch3 -> ch1, the order should be: 8'd7 = {2'd0,2'd0,2'd1,2'd3}. - */ - uint32_t rx_recomb_dma_ch3_order:8; - /** rx_recomb_dma_ch3_eof_num : R/W; bitpos: [28:13]; default: 0; - * Set this field to set the receive eof byte length of the recombined-dma-channel. - */ - uint32_t rx_recomb_dma_ch3_eof_num:16; - uint32_t reserved_29:3; - }; - uint32_t val; -} i2s_rx_recomb_dma_ch3_reg_t; +} i2s_rx_recomb_dma_chn_reg_t; /** Type of rx_pdm2pcm_conf register * I2S RX configure register @@ -510,7 +426,7 @@ typedef union { uint32_t val; } i2s_rx_tdm_ctrl_reg_t; -/** Type of rxeof_num register +/** Type of rx_eof_num register * I2S RX data number control register. */ typedef union { @@ -523,7 +439,7 @@ typedef union { uint32_t reserved_16:16; }; uint32_t val; -} i2s_rxeof_num_reg_t; +} i2s_rx_eof_num_reg_t; /** Group: TX Control and configuration registers */ @@ -549,7 +465,7 @@ typedef union { */ uint32_t tx_slave_mod:1; /** tx_stop_en : R/W; bitpos: [4]; default: 1; - * Set this bit to stop disable output BCK signal and WS signal when tx FIFO is emtpy + * Set this bit to stop disable output BCK signal and WS signal when tx FIFO is empty */ uint32_t tx_stop_en:1; /** tx_chan_equal : R/W; bitpos: [5]; default: 0; @@ -987,7 +903,7 @@ typedef union { uint32_t val; } i2s_lc_hung_conf_reg_t; -/** Type of conf_sigle_data register +/** Type of conf_single_data register * I2S signal data register */ typedef union { @@ -998,7 +914,7 @@ typedef union { uint32_t single_data:32; }; uint32_t val; -} i2s_conf_sigle_data_reg_t; +} i2s_conf_single_data_reg_t; /** Group: TX status registers */ @@ -1119,10 +1035,7 @@ typedef struct { volatile i2s_rx_conf1_reg_t rx_conf1; volatile i2s_tx_conf1_reg_t tx_conf1; volatile i2s_rx_recomb_ctrl_reg_t rx_recomb_ctrl; - volatile i2s_rx_recomb_dma_ch0_reg_t rx_recomb_dma_ch0; - volatile i2s_rx_recomb_dma_ch1_reg_t rx_recomb_dma_ch1; - volatile i2s_rx_recomb_dma_ch2_reg_t rx_recomb_dma_ch2; - volatile i2s_rx_recomb_dma_ch3_reg_t rx_recomb_dma_ch3; + volatile i2s_rx_recomb_dma_chn_reg_t rx_recomb_dma_ch[4]; volatile i2s_tx_pcm2pdm_conf_reg_t tx_pcm2pdm_conf; volatile i2s_tx_pcm2pdm_conf1_reg_t tx_pcm2pdm_conf1; volatile i2s_rx_pdm2pcm_conf_reg_t rx_pdm2pcm_conf; @@ -1131,8 +1044,8 @@ typedef struct { volatile i2s_rx_timing_reg_t rx_timing; volatile i2s_tx_timing_reg_t tx_timing; volatile i2s_lc_hung_conf_reg_t lc_hung_conf; - volatile i2s_rxeof_num_reg_t rxeof_num; - volatile i2s_conf_sigle_data_reg_t conf_sigle_data; + volatile i2s_rx_eof_num_reg_t rx_eof_num; + volatile i2s_conf_single_data_reg_t conf_single_data; volatile i2s_state_reg_t state; volatile i2s_etm_conf_reg_t etm_conf; volatile i2s_fifo_cnt_reg_t fifo_cnt; @@ -1141,7 +1054,7 @@ typedef struct { volatile i2s_date_reg_t date; } i2s_dev_t; -extern i2s_dev_t I2S; +extern i2s_dev_t I2S0; #ifndef __cplusplus _Static_assert(sizeof(i2s_dev_t) == 0x84, "Invalid size of i2s_dev_t structure"); diff --git a/components/soc/esp32c5/mp/include/soc/soc_caps.h b/components/soc/esp32c5/mp/include/soc/soc_caps.h index 54ea441cd7..2595569523 100644 --- a/components/soc/esp32c5/mp/include/soc/soc_caps.h +++ b/components/soc/esp32c5/mp/include/soc/soc_caps.h @@ -38,7 +38,7 @@ #define SOC_EFUSE_SUPPORTED 1 #define SOC_RTC_FAST_MEM_SUPPORTED 1 #define SOC_RTC_MEM_SUPPORTED 1 -// #define SOC_I2S_SUPPORTED 1 // TODO: [ESP32C5] IDF-8713, IDF-8714 +#define SOC_I2S_SUPPORTED 1 // #define SOC_RMT_SUPPORTED 1 // TODO: [ESP32C5] IDF-8726 // #define SOC_SDM_SUPPORTED 1 // TODO: [ESP32C5] IDF-8687 #define SOC_GPSPI_SUPPORTED 1 @@ -259,15 +259,19 @@ // #define SOC_LP_I2C_FIFO_LEN (16) /*!< LP_I2C hardware FIFO depth */ /*-------------------------- I2S CAPS ----------------------------------------*/ -// #define SOC_I2S_NUM (1U) -// #define SOC_I2S_HW_VERSION_2 (1) -// #define SOC_I2S_SUPPORTS_XTAL (1) -// #define SOC_I2S_SUPPORTS_PLL_F160M (1) -// #define SOC_I2S_SUPPORTS_PCM (1) -// #define SOC_I2S_SUPPORTS_PDM (1) -// #define SOC_I2S_SUPPORTS_PDM_TX (1) -// #define SOC_I2S_PDM_MAX_TX_LINES (2) -// #define SOC_I2S_SUPPORTS_TDM (1) +#define SOC_I2S_NUM (1U) +#define SOC_I2S_HW_VERSION_2 (1) +#define SOC_I2S_SUPPORTS_TX_SYNC_CNT (1) +// #define SOC_I2S_SUPPORTS_RX_RECOMB (1) //TODO[C5] IDF-9966 +#define SOC_I2S_SUPPORTS_XTAL (1) +#define SOC_I2S_SUPPORTS_PLL_F160M (1) +#define SOC_I2S_SUPPORTS_PLL_F240M (1) +#define SOC_I2S_SUPPORTS_PCM (1) +#define SOC_I2S_SUPPORTS_PDM (1) +#define SOC_I2S_SUPPORTS_PDM_TX (1) +#define SOC_I2S_PDM_MAX_TX_LINES (2) +#define SOC_I2S_SUPPORTS_TDM (1) +#define SOC_I2S_TDM_FULL_DATA_WIDTH (1) /*!< No limitation to data bit width when using multiple slots */ /*-------------------------- LEDC CAPS ---------------------------------------*/ // TODO: [ESP32C5] 8684 diff --git a/components/soc/esp32c5/mp/ld/esp32c5.peripherals.ld b/components/soc/esp32c5/mp/ld/esp32c5.peripherals.ld index b7b8e4da40..b2c135337f 100644 --- a/components/soc/esp32c5/mp/ld/esp32c5.peripherals.ld +++ b/components/soc/esp32c5/mp/ld/esp32c5.peripherals.ld @@ -17,7 +17,7 @@ PROVIDE ( TIMERG0 = 0x60008000 ); PROVIDE ( TIMERG1 = 0x60009000 ); PROVIDE ( SYSTIMER = 0x6000A000 ); PROVIDE ( TWAI0 = 0x6000B000 ); -PROVIDE ( I2S = 0x6000C000 ); +PROVIDE ( I2S0 = 0x6000C000 ); PROVIDE ( TWAI1 = 0x6000D000 ); PROVIDE ( APB_SARADC = 0x6000E000 ); PROVIDE ( USB_SERIAL_JTAG = 0x6000F000 ); diff --git a/docs/docs_not_updated/esp32c5.txt b/docs/docs_not_updated/esp32c5.txt index 267b842c5e..84d814eb9d 100644 --- a/docs/docs_not_updated/esp32c5.txt +++ b/docs/docs_not_updated/esp32c5.txt @@ -111,7 +111,6 @@ api-reference/peripherals/usb_device.rst api-reference/peripherals/sdspi_host.rst api-reference/peripherals/spi_slave.rst api-reference/peripherals/etm.rst -api-reference/peripherals/i2s.rst api-reference/peripherals/gptimer.rst api-reference/peripherals/pcnt.rst api-reference/peripherals/touch_element.rst diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index 5a60b0116c..2659546bb7 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -74,14 +74,18 @@ Clock Source - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_DEFAULT`: Default PLL clock. -.. only:: not esp32h2 +.. only:: SOC_I2S_SUPPORTS_PLL_F160M - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_160M`: 160 MHz PLL clock. -.. only:: esp32h2 +.. only:: SOC_I2S_SUPPORTS_PLL_F96M - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_96M`: 96 MHz PLL clock. +.. only:: SOC_I2S_SUPPORTS_PLL_F240M + + - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_240M`: 240 MHz PLL clock. + .. only:: 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. @@ -117,6 +121,7 @@ ESP32-C6 I2S 0 I2S 0 none I2S 0 none none ESP32-S3 I2S 0/1 I2S 0 I2S 0 I2S 0/1 none none ESP32-H2 I2S 0 I2S 0 none I2S 0 none none ESP32-P4 I2S 0~2 I2S 0 I2S 0 I2S 0~2 none none +ESP32-C5 I2S 0 I2S 0 none I2S 0 none none ========= ======== ======== ======== ======== ======== ========== Standard Mode diff --git a/docs/zh_CN/api-reference/peripherals/i2s.rst b/docs/zh_CN/api-reference/peripherals/i2s.rst index 1c4103d045..3b70174581 100644 --- a/docs/zh_CN/api-reference/peripherals/i2s.rst +++ b/docs/zh_CN/api-reference/peripherals/i2s.rst @@ -74,14 +74,18 @@ I2S 时钟 - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_DEFAULT`:默认 PLL 时钟。 -.. only:: not esp32h2 +.. only:: SOC_I2S_SUPPORTS_PLL_F160M - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_160M`:160 MHz PLL 时钟。 -.. only:: esp32h2 +.. only:: SOC_I2S_SUPPORTS_PLL_F96M - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_96M`:96 MHz PLL 时钟。 +.. only:: SOC_I2S_SUPPORTS_PLL_F240M + + - :cpp:enumerator:`i2s_clock_src_t::I2S_CLK_SRC_PLL_240M`:240 MHz PLL 时钟。 + .. only:: 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 的需求,时钟配置将失败。 @@ -117,6 +121,7 @@ ESP32-C6 I2S 0 I2S 0 无 I2S 0 无 无 ESP32-S3 I2S 0/1 I2S 0 I2S 0 I2S 0/1 无 无 ESP32-H2 I2S 0 I2S 0 无 I2S 0 无 无 ESP32-P4 I2S 0~2 I2S 0 I2S 0 I2S 0~2 无 无 +ESP32-C5 I2S 0 I2S 0 无 I2S 0 无 无 ========= ======== ======== ======== ======== ======== ========== 标准模式