diff --git a/components/driver/test_apps/i2s_test_apps/i2s_multi_dev/main/test_i2s_multi_dev.c b/components/driver/test_apps/i2s_test_apps/i2s_multi_dev/main/test_i2s_multi_dev.c index 5581511554..f4611d9756 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s_multi_dev/main/test_i2s_multi_dev.c +++ b/components/driver/test_apps/i2s_test_apps/i2s_multi_dev/main/test_i2s_multi_dev.c @@ -23,7 +23,7 @@ static const char *TAG = "i2s_multi_dev_test"; #define TEST_I2S_FRAME_SIZE (128) // Frame numbers in every writing / reading #define TEST_I2S_ARRAY_LENGTH (1024) // The loop data length for verification -#define TEST_I2S_MAX_DATA (256) // The maximum data value in the data buffer +#define TEST_I2S_MAX_DATA (128) // The maximum data value in the data buffer #define TEST_I2S_MAX_FAIL_CNT (3) // Max broken packet count #define TEST_I2S_FRAME_TIMEOUT_SEC (10.0f) // Timeout seconds of waiting for a correct frame diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index a6a7a1b15f..53108247cd 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -74,7 +74,7 @@ static inline void i2s_ll_dma_enable_auto_write_back(i2s_dev_t *hw, bool en) } /** - * @brief I2S DMA generate EOF event on data in FIFO poped out + * @brief I2S DMA generate EOF event on data in FIFO popped out * * @param hw Peripheral I2S hardware instance address. * @param en True to enable, False to disable @@ -350,11 +350,6 @@ static inline void i2s_ll_set_raw_mclk_div(i2s_dev_t *hw, uint32_t mclk_div, uin */ 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 unlike to calculate from the regular decimal */ - i2s_ll_set_raw_mclk_div(hw, 7, 47, 3); i2s_ll_set_raw_mclk_div(hw, mclk_div->integer, mclk_div->denominator, mclk_div->numerator); } @@ -659,7 +654,7 @@ static inline void i2s_ll_tx_set_bits_mod(i2s_dev_t *hw, uint32_t val) } /** - * @brief Congfigure TX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit + * @brief Configure TX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width @@ -672,7 +667,7 @@ static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int } /** - * @brief Congfigure RX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit + * @brief Configure RX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index 1b7e9de0da..907324fdd0 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -285,15 +285,21 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) */ 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) { - /* Set the integer part of mclk division */ + /* 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(hw->tx_clkm_conf, tx_clkm_div_num, 2); + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0; + hw->tx_clkm_div_conf.tx_clkm_div_y = 1; + hw->tx_clkm_div_conf.tx_clkm_div_z = 0; + hw->tx_clkm_div_conf.tx_clkm_div_x = 0; + + /* Set the target mclk division coefficients */ + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = yn1; + hw->tx_clkm_div_conf.tx_clkm_div_z = z; + hw->tx_clkm_div_conf.tx_clkm_div_y = y; + hw->tx_clkm_div_conf.tx_clkm_div_x = x; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_clkm_conf, tx_clkm_div_num, div_int); - /* Set the decimal part of the mclk division */ - typeof(hw->tx_clkm_div_conf) div = {}; - div.tx_clkm_div_x = x; - div.tx_clkm_div_y = y; - div.tx_clkm_div_z = z; - div.tx_clkm_div_yn1 = yn1; - hw->tx_clkm_div_conf.val = div.val; } /** @@ -308,15 +314,21 @@ static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui */ 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) { - /* Set the integer part of mclk division */ + /* 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(hw->rx_clkm_conf, rx_clkm_div_num, 2); + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0; + hw->rx_clkm_div_conf.rx_clkm_div_y = 1; + hw->rx_clkm_div_conf.rx_clkm_div_z = 0; + hw->rx_clkm_div_conf.rx_clkm_div_x = 0; + + /* Set the target mclk division coefficients */ + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = yn1; + hw->rx_clkm_div_conf.rx_clkm_div_z = z; + hw->rx_clkm_div_conf.rx_clkm_div_y = y; + hw->rx_clkm_div_conf.rx_clkm_div_x = x; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_clkm_conf, rx_clkm_div_num, div_int); - /* Set the decimal part of the mclk division */ - typeof(hw->rx_clkm_div_conf) div = {}; - div.rx_clkm_div_x = x; - div.rx_clkm_div_y = y; - div.rx_clkm_div_z = z; - div.rx_clkm_div_yn1 = yn1; - hw->rx_clkm_div_conf.val = div.val; } /** @@ -327,12 +339,6 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui */ 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; @@ -367,12 +373,6 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) */ 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; @@ -467,7 +467,7 @@ static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num) } /** - * @brief Congfigure TX chan bit and audio data bit + * @brief Configure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width @@ -480,7 +480,7 @@ static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int } /** - * @brief Congfigure RX chan bit and audio data bit + * @brief Configure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width @@ -880,11 +880,11 @@ static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f } /** - * @brief Get I2S TX PDM fp configuration paramater + * @brief Get I2S TX PDM fp configuration parameter * * @param hw Peripheral I2S hardware instance address. * @return - * - fp configuration paramater + * - fp configuration parameter */ static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) { @@ -892,11 +892,11 @@ static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) } /** - * @brief Get I2S TX PDM fs configuration paramater + * @brief Get I2S TX PDM fs configuration parameter * * @param hw Peripheral I2S hardware instance address. * @return - * - fs configuration paramater + * - fs configuration parameter */ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) { @@ -922,7 +922,7 @@ static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) * @brief Configura TX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param pcm_cfg PCM configuration paramater + * @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) { @@ -934,7 +934,7 @@ static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_ * @brief Configure RX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param pcm_cfg PCM configuration paramater + * @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) { @@ -1106,7 +1106,7 @@ static inline void i2s_ll_tx_pdm_dma_take_mode(i2s_dev_t *hw, bool is_mono, bool * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) * @param is_copy Whether the un-selected slot copies the data from the selected one * If not, the un-selected slot will transmit the data from 'conf_single_data' - * @param mask The slot mask to selet the slot + * @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) { diff --git a/components/hal/esp32c6/include/hal/i2s_ll.h b/components/hal/esp32c6/include/hal/i2s_ll.h index 52c15d43f0..56b9a09423 100644 --- a/components/hal/esp32c6/include/hal/i2s_ll.h +++ b/components/hal/esp32c6/include/hal/i2s_ll.h @@ -281,13 +281,21 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) 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; + /* 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(PCR.i2s_tx_clkm_conf, i2s_tx_clkm_div_num, 2); + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = 0; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = 1; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = 0; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = 0; + + /* Set the target mclk division coefficients */ + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = yn1; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = z; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = y; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = x; 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; } /** @@ -303,13 +311,21 @@ static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui 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; + /* 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(PCR.i2s_rx_clkm_conf, i2s_rx_clkm_div_num, 2); + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = 0; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = 1; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = 0; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = 0; + + /* Set the target mclk division coefficients */ + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = yn1; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = z; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = y; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = x; 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; } /** @@ -320,12 +336,6 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui */ 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; @@ -360,12 +370,6 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) */ 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; diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index 0baf7101e5..02a9659bf2 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -288,13 +288,21 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) 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; + /* 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(PCR.i2s_tx_clkm_conf, i2s_tx_clkm_div_num, 2); + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = 0; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = 1; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = 0; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = 0; + + /* Set the target mclk division coefficients */ + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = yn1; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = z; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = y; + PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = x; 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; } /** @@ -310,13 +318,21 @@ static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui 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; + /* 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(PCR.i2s_rx_clkm_conf, i2s_rx_clkm_div_num, 2); + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = 0; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = 1; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = 0; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = 0; + + /* Set the target mclk division coefficients */ + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = yn1; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = z; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = y; + PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = x; 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; } /** @@ -327,12 +343,6 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui */ 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, 8, 1, 1, 73, 1); - uint32_t div_x = 0; uint32_t div_y = 0; uint32_t div_z = 0; @@ -367,12 +377,6 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) */ 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, 8, 1, 1, 73, 1); - uint32_t div_x = 0; uint32_t div_y = 0; uint32_t div_z = 0; diff --git a/components/hal/esp32p4/include/hal/i2s_ll.h b/components/hal/esp32p4/include/hal/i2s_ll.h index c3b69cf98d..94d02e3103 100644 --- a/components/hal/esp32p4/include/hal/i2s_ll.h +++ b/components/hal/esp32p4/include/hal/i2s_ll.h @@ -395,25 +395,52 @@ static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui // 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: - HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl13, reg_i2s0_tx_div_n, div_int); - HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_tx_div_x = x; - HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_tx_div_y = y; - HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_tx_div_z = z; + /* 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.peri_clk_ctrl13, reg_i2s0_tx_div_n, 2); + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_tx_div_yn1 = 0; + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_tx_div_y = 1; + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_tx_div_z = 0; + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_tx_div_x = 0; + /* Set the target mclk division coefficients */ HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_tx_div_yn1 = yn1; + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_tx_div_z = z; + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_tx_div_y = y; + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_tx_div_x = x; + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl13, reg_i2s0_tx_div_n, div_int); return; case 1: - HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl16, reg_i2s1_tx_div_n, div_int); - HP_SYS_CLKRST.peri_clk_ctrl16.reg_i2s1_tx_div_x = x; - HP_SYS_CLKRST.peri_clk_ctrl16.reg_i2s1_tx_div_y = y; - HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_tx_div_z = z; + /* 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.peri_clk_ctrl16, reg_i2s1_tx_div_n, 2); + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_tx_div_yn1 = 0; + HP_SYS_CLKRST.peri_clk_ctrl16.reg_i2s1_tx_div_y = 1; + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_tx_div_z = 0; + HP_SYS_CLKRST.peri_clk_ctrl16.reg_i2s1_tx_div_x = 0; + /* Set the target mclk division coefficients */ HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_tx_div_yn1 = yn1; + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_tx_div_z = z; + HP_SYS_CLKRST.peri_clk_ctrl16.reg_i2s1_tx_div_y = y; + HP_SYS_CLKRST.peri_clk_ctrl16.reg_i2s1_tx_div_x = x; + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl16, reg_i2s1_tx_div_n, div_int); return; case 2: - HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl18, reg_i2s2_tx_div_n, div_int); - HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_x = x; - HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_y = y; - HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_z = z; + /* 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.peri_clk_ctrl18, reg_i2s2_tx_div_n, 2); + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_yn1 = 0; + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_y = 1; + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_z = 0; + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_x = 0; + /* Set the target mclk division coefficients */ HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_yn1 = yn1; + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_z = z; + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_y = y; + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_x = x; + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl18, reg_i2s2_tx_div_n, div_int); return; } } @@ -433,25 +460,52 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui // 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: - HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl12, reg_i2s0_rx_div_n, div_int); - HP_SYS_CLKRST.peri_clk_ctrl12.reg_i2s0_rx_div_x = x; - HP_SYS_CLKRST.peri_clk_ctrl12.reg_i2s0_rx_div_y = y; - HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_rx_div_z = z; + /* 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.peri_clk_ctrl12, reg_i2s0_rx_div_n, 2); + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_rx_div_yn1 = 0; + HP_SYS_CLKRST.peri_clk_ctrl12.reg_i2s0_rx_div_y = 1; + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_rx_div_z = 0; + HP_SYS_CLKRST.peri_clk_ctrl12.reg_i2s0_rx_div_x = 0; + /* Set the target mclk division coefficients */ HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_rx_div_yn1 = yn1; + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_rx_div_z = z; + HP_SYS_CLKRST.peri_clk_ctrl12.reg_i2s0_rx_div_y = y; + HP_SYS_CLKRST.peri_clk_ctrl12.reg_i2s0_rx_div_x = x; + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl12, reg_i2s0_rx_div_n, div_int); return; case 1: - HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl14, reg_i2s1_rx_div_n, div_int); - HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_x = x; - HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_y = y; - HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_z = z; + /* 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.peri_clk_ctrl14, reg_i2s1_rx_div_n, 2); + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_yn1 = 0; + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_y = 1; + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_z = 0; + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_x = 0; + /* Set the target mclk division coefficients */ HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_yn1 = yn1; + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_z = z; + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_y = y; + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_x = x; + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl14, reg_i2s1_rx_div_n, div_int); return; case 2: - HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl17, reg_i2s2_rx_div_n, div_int); - HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s2_rx_div_x = x; - HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_rx_div_y = y; - HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_rx_div_z = z; + /* 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.peri_clk_ctrl17, reg_i2s2_rx_div_n, 2); + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_rx_div_yn1 = 0; + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_rx_div_y = 1; + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_rx_div_z = 0; + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s2_rx_div_x = 0; + /* Set the target mclk division coefficients */ HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_rx_div_yn1 = yn1; + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_rx_div_z = z; + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_rx_div_y = y; + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s2_rx_div_x = x; + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl17, reg_i2s2_rx_div_n, div_int); return; } } @@ -464,12 +518,6 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui */ 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; @@ -504,12 +552,6 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) */ 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; diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index 2c97bf157a..5953c93c34 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -72,7 +72,7 @@ static inline void i2s_ll_dma_enable_auto_write_back(i2s_dev_t *hw, bool en) } /** - * @brief I2S DMA generate EOF event on data in FIFO poped out + * @brief I2S DMA generate EOF event on data in FIFO popped out * * @param hw Peripheral I2S hardware instance address. * @param en True to enable, False to disable @@ -341,11 +341,6 @@ static inline void i2s_ll_set_raw_mclk_div(i2s_dev_t *hw, uint32_t mclk_div, uin */ 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 unlike to calculate from the regular decimal */ - i2s_ll_set_raw_mclk_div(hw, 7, 47, 3); i2s_ll_set_raw_mclk_div(hw, mclk_div->integer, mclk_div->denominator, mclk_div->numerator); } @@ -682,7 +677,7 @@ static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, uint32_t eof_num) } /** - * @brief Congfigure TX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit + * @brief Configure TX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width @@ -695,7 +690,7 @@ static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int } /** - * @brief Congfigure RX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit + * @brief Configure RX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 89b53f8c24..9f0ff7ec5a 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -291,15 +291,21 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) */ 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) { - /* Set the integer part of mclk division */ + /* 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(hw->tx_clkm_conf, tx_clkm_div_num, 2); + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0; + hw->tx_clkm_div_conf.tx_clkm_div_y = 1; + hw->tx_clkm_div_conf.tx_clkm_div_z = 0; + hw->tx_clkm_div_conf.tx_clkm_div_x = 0; + + /* Set the target mclk division coefficients */ + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = yn1; + hw->tx_clkm_div_conf.tx_clkm_div_z = z; + hw->tx_clkm_div_conf.tx_clkm_div_y = y; + hw->tx_clkm_div_conf.tx_clkm_div_x = x; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_clkm_conf, tx_clkm_div_num, div_int); - /* Set the decimal part of the mclk division */ - typeof(hw->tx_clkm_div_conf) div = {}; - div.tx_clkm_div_x = x; - div.tx_clkm_div_y = y; - div.tx_clkm_div_z = z; - div.tx_clkm_div_yn1 = yn1; - hw->tx_clkm_div_conf.val = div.val; } /** @@ -314,15 +320,21 @@ static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui */ 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) { - /* Set the integer part of mclk division */ + /* 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(hw->rx_clkm_conf, rx_clkm_div_num, 2); + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0; + hw->rx_clkm_div_conf.rx_clkm_div_y = 1; + hw->rx_clkm_div_conf.rx_clkm_div_z = 0; + hw->rx_clkm_div_conf.rx_clkm_div_x = 0; + + /* Set the target mclk division coefficients */ + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = yn1; + hw->rx_clkm_div_conf.rx_clkm_div_z = z; + hw->rx_clkm_div_conf.rx_clkm_div_y = y; + hw->rx_clkm_div_conf.rx_clkm_div_x = x; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_clkm_conf, rx_clkm_div_num, div_int); - /* Set the decimal part of the mclk division */ - typeof(hw->rx_clkm_div_conf) div = {}; - div.rx_clkm_div_x = x; - div.rx_clkm_div_y = y; - div.rx_clkm_div_z = z; - div.rx_clkm_div_yn1 = yn1; - hw->rx_clkm_div_conf.val = div.val; } /** @@ -333,12 +345,6 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui */ 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; @@ -373,12 +379,6 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) */ 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; @@ -474,7 +474,7 @@ static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num) } /** - * @brief Congfigure TX chan bit and audio data bit + * @brief Configure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width @@ -487,7 +487,7 @@ static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int } /** - * @brief Congfigure RX chan bit and audio data bit + * @brief Configure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width @@ -790,11 +790,11 @@ static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f } /** - * @brief Get I2S TX PDM fp configuration paramater + * @brief Get I2S TX PDM fp configuration parameter * * @param hw Peripheral I2S hardware instance address. * @return - * - fp configuration paramater + * - fp configuration parameter */ static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) { @@ -802,11 +802,11 @@ static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) } /** - * @brief Get I2S TX PDM fs configuration paramater + * @brief Get I2S TX PDM fs configuration parameter * * @param hw Peripheral I2S hardware instance address. * @return - * - fs configuration paramater + * - fs configuration parameter */ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) { @@ -927,7 +927,7 @@ static inline void i2s_ll_tx_set_pdm_sd_dither2(i2s_dev_t *hw, uint32_t dither2) * @brief Configure RX PDM downsample * * @param hw Peripheral I2S hardware instance address. - * @param dsr PDM downsample configuration paramater + * @param dsr PDM downsample configuration parameter */ static inline void i2s_ll_rx_set_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) { @@ -949,7 +949,7 @@ static inline void i2s_ll_rx_get_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) * @brief Configura TX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param pcm_cfg PCM configuration paramater + * @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) { @@ -961,7 +961,7 @@ static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_ * @brief Configure RX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param pcm_cfg PCM configuration paramater + * @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) { @@ -1133,7 +1133,7 @@ static inline void i2s_ll_tx_pdm_dma_take_mode(i2s_dev_t *hw, bool is_mono, bool * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) * @param is_copy Whether the un-selected slot copies the data from the selected one * If not, the un-selected slot will transmit the data from 'conf_single_data' - * @param mask The slot mask to selet the slot + * @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) {