diff --git a/components/esp_driver_i2s/i2s_common.c b/components/esp_driver_i2s/i2s_common.c index 4e1c51519f..614396a92a 100644 --- a/components/esp_driver_i2s/i2s_common.c +++ b/components/esp_driver_i2s/i2s_common.c @@ -881,10 +881,12 @@ esp_err_t i2s_del_channel(i2s_chan_handle_t handle) /* Must switch back to D2CLK on ESP32-S2, * because the clock of some registers are bound to APLL, * otherwise, once APLL is disabled, the registers can't be updated anymore */ - if (handle->dir == I2S_DIR_TX) { - i2s_ll_tx_clk_set_src(handle->controller->hal.dev, I2S_CLK_SRC_DEFAULT); - } else { - i2s_ll_rx_clk_set_src(handle->controller->hal.dev, I2S_CLK_SRC_DEFAULT); + I2S_CLOCK_SRC_ATOMIC() { + if (handle->dir == I2S_DIR_TX) { + i2s_ll_tx_clk_set_src(handle->controller->hal.dev, I2S_CLK_SRC_DEFAULT); + } else { + i2s_ll_rx_clk_set_src(handle->controller->hal.dev, I2S_CLK_SRC_DEFAULT); + } } periph_rtc_apll_release(); } diff --git a/components/esp_driver_i2s/i2s_pdm.c b/components/esp_driver_i2s/i2s_pdm.c index e545ad08f8..c358d6b5cd 100644 --- a/components/esp_driver_i2s/i2s_pdm.c +++ b/components/esp_driver_i2s/i2s_pdm.c @@ -151,7 +151,9 @@ static esp_err_t i2s_pdm_tx_set_gpio(i2s_chan_handle_t handle, const i2s_pdm_tx_ i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].m_tx_ws_sig, false, gpio_cfg->invert_flags.clk_inv); } #if SOC_I2S_HW_VERSION_2 - i2s_ll_mclk_bind_to_tx_clk(handle->controller->hal.dev); + I2S_CLOCK_SRC_ATOMIC() { + i2s_ll_mclk_bind_to_tx_clk(handle->controller->hal.dev); + } #endif /* Update the mode info: gpio configuration */ memcpy(&(pdm_tx_cfg->gpio_cfg), gpio_cfg, sizeof(i2s_pdm_tx_gpio_config_t)); @@ -438,7 +440,9 @@ static esp_err_t i2s_pdm_rx_set_gpio(i2s_chan_handle_t handle, const i2s_pdm_rx_ } } #if SOC_I2S_HW_VERSION_2 - i2s_ll_mclk_bind_to_rx_clk(handle->controller->hal.dev); + I2S_CLOCK_SRC_ATOMIC() { + i2s_ll_mclk_bind_to_rx_clk(handle->controller->hal.dev); + } #endif /* Update the mode info: gpio configuration */ memcpy(&(pdm_rx_cfg->gpio_cfg), gpio_cfg, sizeof(i2s_pdm_rx_gpio_config_t)); diff --git a/components/esp_driver_i2s/i2s_std.c b/components/esp_driver_i2s/i2s_std.c index 73354e0c0f..1594b04ee0 100644 --- a/components/esp_driver_i2s/i2s_std.c +++ b/components/esp_driver_i2s/i2s_std.c @@ -164,7 +164,9 @@ static esp_err_t i2s_std_set_gpio(i2s_chan_handle_t handle, const i2s_std_gpio_c /* For "tx + slave" mode, select TX signal index for ws and bck */ if (handle->dir == I2S_DIR_TX && !handle->controller->full_duplex) { #if SOC_I2S_HW_VERSION_2 - i2s_ll_mclk_bind_to_tx_clk(handle->controller->hal.dev); + I2S_CLOCK_SRC_ATOMIC() { + i2s_ll_mclk_bind_to_tx_clk(handle->controller->hal.dev); + } #endif i2s_gpio_check_and_set(gpio_cfg->ws, i2s_periph_signal[id].s_tx_ws_sig, true, gpio_cfg->invert_flags.ws_inv); i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].s_tx_bck_sig, true, gpio_cfg->invert_flags.bclk_inv); @@ -177,7 +179,9 @@ static esp_err_t i2s_std_set_gpio(i2s_chan_handle_t handle, const i2s_std_gpio_c /* For "rx + master" mode, select RX signal index for ws and bck */ if (handle->dir == I2S_DIR_RX && !handle->controller->full_duplex) { #if SOC_I2S_HW_VERSION_2 - i2s_ll_mclk_bind_to_rx_clk(handle->controller->hal.dev); + I2S_CLOCK_SRC_ATOMIC() { + i2s_ll_mclk_bind_to_rx_clk(handle->controller->hal.dev); + } #endif i2s_gpio_check_and_set(gpio_cfg->ws, i2s_periph_signal[id].m_rx_ws_sig, false, gpio_cfg->invert_flags.ws_inv); i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].m_rx_bck_sig, false, gpio_cfg->invert_flags.bclk_inv); diff --git a/components/esp_driver_i2s/i2s_tdm.c b/components/esp_driver_i2s/i2s_tdm.c index f9c8cc25ef..5dcdb50114 100644 --- a/components/esp_driver_i2s/i2s_tdm.c +++ b/components/esp_driver_i2s/i2s_tdm.c @@ -169,7 +169,9 @@ static esp_err_t i2s_tdm_set_gpio(i2s_chan_handle_t handle, const i2s_tdm_gpio_c /* For "tx + slave" mode, select TX signal index for ws and bck */ if (handle->dir == I2S_DIR_TX && !handle->controller->full_duplex) { #if SOC_I2S_HW_VERSION_2 - i2s_ll_mclk_bind_to_tx_clk(handle->controller->hal.dev); + I2S_CLOCK_SRC_ATOMIC() { + i2s_ll_mclk_bind_to_tx_clk(handle->controller->hal.dev); + } #endif i2s_gpio_check_and_set(gpio_cfg->ws, i2s_periph_signal[id].s_tx_ws_sig, true, gpio_cfg->invert_flags.ws_inv); i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].s_tx_bck_sig, true, gpio_cfg->invert_flags.bclk_inv); @@ -182,7 +184,9 @@ static esp_err_t i2s_tdm_set_gpio(i2s_chan_handle_t handle, const i2s_tdm_gpio_c /* For "rx + master" mode, select RX signal index for ws and bck */ if (handle->dir == I2S_DIR_RX && !handle->controller->full_duplex) { #if SOC_I2S_HW_VERSION_2 - i2s_ll_mclk_bind_to_rx_clk(handle->controller->hal.dev); + I2S_CLOCK_SRC_ATOMIC() { + i2s_ll_mclk_bind_to_rx_clk(handle->controller->hal.dev); + } #endif i2s_gpio_check_and_set(gpio_cfg->ws, i2s_periph_signal[id].m_rx_ws_sig, false, gpio_cfg->invert_flags.ws_inv); i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].m_rx_bck_sig, false, gpio_cfg->invert_flags.bclk_inv); diff --git a/components/hal/esp32p4/include/hal/i2s_ll.h b/components/hal/esp32p4/include/hal/i2s_ll.h index c3b69cf98d..a5fd58c118 100644 --- a/components/hal/esp32p4/include/hal/i2s_ll.h +++ b/components/hal/esp32p4/include/hal/i2s_ll.h @@ -112,7 +112,7 @@ static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw) +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)) { @@ -128,12 +128,16 @@ static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw) } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_tx_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_ll_tx_enable_clock(__VA_ARGS__) + /** * @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) +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)) { @@ -149,6 +153,10 @@ static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw) } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_rx_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_ll_rx_enable_clock(__VA_ARGS__) + /** * @brief Disable I2S tx module clock * @@ -204,9 +212,36 @@ static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_mclk_bind_to_tx_clk(i2s_dev_t *hw) +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 P4, 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.peri_clk_ctrl14.reg_i2s0_mst_clk_sel = 1; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_mst_clk_sel = 1; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_mst_clk_sel = 1; + return; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_mclk_bind_to_tx_clk(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_ll_mclk_bind_to_tx_clk(__VA_ARGS__) + +/** + * @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 P4, 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.peri_clk_ctrl14.reg_i2s0_mst_clk_sel = 0; @@ -220,26 +255,9 @@ static inline void i2s_ll_mclk_bind_to_tx_clk(i2s_dev_t *hw) } } -/** - * @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 - switch (I2S_LL_GET_ID(hw)) { - case 0: - HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_mst_clk_sel = 1; - return; - case 1: - HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_mst_clk_sel = 1; - return; - case 2: - HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_mst_clk_sel = 1; - return; - } -} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_mclk_bind_to_rx_clk(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_ll_mclk_bind_to_rx_clk(__VA_ARGS__) /** * @brief Enable I2S TX slave mode @@ -329,7 +347,7 @@ static inline uint32_t i2s_ll_get_clk_src(i2s_clock_src_t src) * @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) +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 uint32_t clk_src = i2s_ll_get_clk_src(src); @@ -346,13 +364,17 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_tx_clk_set_src(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_ll_tx_clk_set_src(__VA_ARGS__) + /** * @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) +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 uint32_t clk_src = i2s_ll_get_clk_src(src); @@ -369,6 +391,10 @@ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_rx_clk_set_src(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_ll_rx_clk_set_src(__VA_ARGS__) + /** * @brief Set I2S tx bck div num * @@ -462,7 +488,7 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui * @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) +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, @@ -484,6 +510,10 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t * i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1); } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_tx_set_mclk(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_ll_tx_set_mclk(__VA_ARGS__) + /** * @brief Set I2S rx bck div num * @@ -502,7 +532,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) * @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) +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, @@ -524,6 +554,10 @@ static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t * i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1); } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_rx_set_mclk(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_ll_rx_set_mclk(__VA_ARGS__) + /** * @brief Start I2S TX * diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index 56e7e225d5..274cef04b0 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -66,7 +66,42 @@ void i2s_hal_init(i2s_hal_context_t *hal, int port_id) hal->dev = I2S_LL_GET_HW(port_id); } +#if SOC_PERIPH_CLK_CTRL_SHARED void _i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src) +{ + if (clk_info) { + hal_utils_clk_div_t mclk_div = {}; +#if SOC_I2S_HW_VERSION_2 + _i2s_ll_tx_enable_clock(hal->dev); + _i2s_ll_mclk_bind_to_tx_clk(hal->dev); +#endif + _i2s_ll_tx_clk_set_src(hal->dev, clk_src); + i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, &mclk_div); + _i2s_ll_tx_set_mclk(hal->dev, &mclk_div); + i2s_ll_tx_set_bck_div_num(hal->dev, clk_info->bclk_div); + } else { + _i2s_ll_tx_clk_set_src(hal->dev, clk_src); + } +} + +void _i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src) +{ + if (clk_info) { + hal_utils_clk_div_t mclk_div = {}; +#if SOC_I2S_HW_VERSION_2 + _i2s_ll_rx_enable_clock(hal->dev); + _i2s_ll_mclk_bind_to_rx_clk(hal->dev); +#endif + _i2s_ll_rx_clk_set_src(hal->dev, clk_src); + i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, &mclk_div); + _i2s_ll_rx_set_mclk(hal->dev, &mclk_div); + i2s_ll_rx_set_bck_div_num(hal->dev, clk_info->bclk_div); + } else { + _i2s_ll_rx_clk_set_src(hal->dev, clk_src); + } +} +#else +void i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src) { if (clk_info) { hal_utils_clk_div_t mclk_div = {}; @@ -83,7 +118,7 @@ void _i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *c } } -void _i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src) +void i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src) { if (clk_info) { hal_utils_clk_div_t mclk_div = {}; @@ -99,6 +134,7 @@ void _i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *c i2s_ll_rx_clk_set_src(hal->dev, clk_src); } } +#endif // SOC_PERIPH_CLK_CTRL_SHARED /*------------------------------------------------------------------------- | STD Specific Slot Configurations | diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index 2be2180b9d..7b9d55649c 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -139,6 +139,7 @@ void i2s_hal_init(i2s_hal_context_t *hal, int port_id); */ void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, hal_utils_clk_div_t *mclk_div); +#if SOC_PERIPH_CLK_CTRL_SHARED /** * @brief Set tx channel clock * @@ -147,14 +148,19 @@ void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, hal_utils_ * @param clk_src clock source */ void _i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src); - -#if SOC_PERIPH_CLK_CTRL_SHARED /// use a macro to wrap the function, force the caller to use it in a critical section /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance #define i2s_hal_set_tx_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_hal_set_tx_clock(__VA_ARGS__) #else -#define i2s_hal_set_tx_clock(...) _i2s_hal_set_tx_clock(__VA_ARGS__) -#endif +/** + * @brief Set tx channel clock + * + * @param hal Context of the HAL layer + * @param clk_info clock information, if it is NULL, only set the clock source + * @param clk_src clock source + */ +void i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src); +#endif // SOC_PERIPH_CLK_CTRL_SHARED /** * @brief Set rx channel clock