From cf889f3c6d7b489409a15b32c06661b4e276b3ce Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Fri, 16 Jun 2023 15:15:23 +0800 Subject: [PATCH 1/4] feat(i2s): support i2s on esp32p4 --- components/driver/deprecated/i2s_legacy.c | 4 +- .../driver/i2s/include/driver/i2s_pdm.h | 24 + .../i2s_test_apps/i2s/main/test_i2s.c | 2 + .../esp_hw_support/port/esp32p4/rtc_clk.c | 16 + components/hal/esp32/include/hal/i2s_ll.h | 2 +- components/hal/esp32c3/include/hal/i2s_ll.h | 2 +- components/hal/esp32c6/include/hal/i2s_ll.h | 2 +- components/hal/esp32h2/include/hal/i2s_ll.h | 2 +- components/hal/esp32p4/include/i2s_ll.h | 1244 +++++++++++++++++ components/hal/esp32s2/include/hal/i2s_ll.h | 2 +- components/hal/esp32s3/include/hal/i2s_ll.h | 2 +- components/hal/i2s_hal.c | 49 +- components/hal/include/hal/i2s_hal.h | 8 +- .../soc/esp32c6/include/soc/i2s_struct.h | 124 +- .../soc/esp32h2/include/soc/i2s_struct.h | 124 +- components/soc/esp32p4/i2s_periph.c | 69 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 36 +- .../soc/esp32p4/include/soc/clk_tree_defs.h | 15 + .../soc/esp32p4/include/soc/i2s_struct.h | 184 +-- components/soc/esp32p4/include/soc/soc_caps.h | 19 +- examples/peripherals/.build-test-rules.yml | 10 +- 21 files changed, 1568 insertions(+), 372 deletions(-) create mode 100644 components/hal/esp32p4/include/i2s_ll.h diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index 9b7ded0144..f687cf9170 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -654,12 +654,12 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3 /* In APLL mode, there is no sclk but only mclk, so return 0 here to indicate APLL mode */ return real_freq; } - return I2S_LL_DEFAULT_PLL_CLK_FREQ; + return I2S_LL_DEFAULT_CLK_FREQ; #else if (use_apll) { ESP_LOGW(TAG, "APLL not supported on current chip, use I2S_CLK_SRC_DEFAULT as default clock source"); } - return I2S_LL_DEFAULT_PLL_CLK_FREQ; + return I2S_LL_DEFAULT_CLK_FREQ; #endif } diff --git a/components/driver/i2s/include/driver/i2s_pdm.h b/components/driver/i2s/include/driver/i2s_pdm.h index 2265c7908a..d8bd632c99 100644 --- a/components/driver/i2s/include/driver/i2s_pdm.h +++ b/components/driver/i2s/include/driver/i2s_pdm.h @@ -48,6 +48,24 @@ extern "C" { .bclk_div = 8, \ } +#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER +/** + * @brief PDM format in 2 slots(RX) + * @param bits_per_sample i2s data bit width, only support 16 bits for PDM mode + * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO + */ +#define I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \ + .data_bit_width = bits_per_sample, \ + .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \ + .slot_mode = mono_or_stereo, \ + .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \ + I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \ + .hp_en = true, \ + .hp_cut_off_freq_hz = 35.5, \ + .amplify_num = 1, \ /* TODO: maybe need an enum */ +} +#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + /** * @brief I2S slot configuration for pdm rx mode */ @@ -58,6 +76,12 @@ typedef struct { i2s_slot_mode_t slot_mode; /*!< Set mono or stereo mode with I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO */ /* Particular fields */ i2s_pdm_slot_mask_t slot_mask; /*!< Choose the slots to activate */ +#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + bool hp_en; /*!< High pass filter enable */ + float hp_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */ + uint32_t amplify_num; /*!< The amplification number of the final conversion result, range 1~15, default 1 */ +#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + } i2s_pdm_rx_slot_config_t; /** diff --git a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c index e9e81cde62..a419ea6c2e 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c +++ b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c @@ -803,7 +803,9 @@ TEST_CASE("I2S_default_PLL_clock_test", "[i2s]") TEST_ESP_OK(i2s_new_channel(&chan_cfg, NULL, &rx_handle)); TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); +#if SOC_I2S_SUPPORTS_PLL_F160M || SOC_I2S_SUPPORTS_PLL_F96M i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg); +#endif // SOC_I2S_SUPPORTS_PLL_F160M || SOC_I2S_SUPPORTS_PLL_F96M #if SOC_I2S_SUPPORTS_XTAL std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_XTAL; i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg); diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk.c b/components/esp_hw_support/port/esp32p4/rtc_clk.c index 2abac0e6fb..6c67021a9b 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk.c @@ -368,6 +368,22 @@ uint32_t rtc_clk_apb_freq_get(void) return rtc_clk_ahb_freq_get() / clk_ll_apb_get_divider() * MHZ; } +void rtc_clk_apll_enable(bool enable) +{ + // TODO: IDF-7526 +} + +uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2) +{ + // TODO: IDF-7526 + return 0; +} + +void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2) +{ + // TODO: IDF-7526 +} + void rtc_dig_clk8m_enable(void) { clk_ll_rc_fast_digi_enable(); diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index 8f621d92e2..c03f56ce02 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -48,7 +48,7 @@ extern "C" { #define I2S_LL_RX_EVENT_MASK I2S_LL_EVENT_RX_EOF #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz -#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT /** * @brief Enable DMA descriptor owner check diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index 6f8dac94ee..1bf9d1ecc4 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -34,7 +34,7 @@ extern "C" { #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_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz -#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT /** * @brief I2S module general init, enable I2S clock. diff --git a/components/hal/esp32c6/include/hal/i2s_ll.h b/components/hal/esp32c6/include/hal/i2s_ll.h index 687ef3162f..33da02f677 100644 --- a/components/hal/esp32c6/include/hal/i2s_ll.h +++ b/components/hal/esp32c6/include/hal/i2s_ll.h @@ -35,7 +35,7 @@ extern "C" { #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_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz -#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT /** * @brief I2S module general init, enable I2S clock. diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index 8ebfa8518b..c7cd73dd4f 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -36,7 +36,7 @@ extern "C" { #define I2S_LL_PLL_F96M_CLK_FREQ (96 * 1000000) // PLL_F96M_CLK: 96MHz #define I2S_LL_PLL_F64M_CLK_FREQ (64 * 1000000) // PLL_F64M_CLK: 64MHz -#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT /** * @brief I2S module general init, enable I2S clock. diff --git a/components/hal/esp32p4/include/i2s_ll.h b/components/hal/esp32p4/include/i2s_ll.h new file mode 100644 index 0000000000..c2ce486e04 --- /dev/null +++ b/components/hal/esp32p4/include/i2s_ll.h @@ -0,0 +1,1244 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for I2S register operations +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in hal/include/hal/readme.md + ******************************************************************************/ + +#pragma once +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "soc/i2s_periph.h" +#include "soc/i2s_struct.h" +#include "soc/pcr_struct.h" +#include "hal/i2s_types.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2S_LL_GET_HW(num) (((num) == 0)? (&I2S0) : ((num) == 1) ? (&I2S1) : (&I2S2)) + +#define I2S_LL_TDM_CH_MASK (0xffff) +#define I2S_LL_PDM_BCK_FACTOR (64) + +#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9) +#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) + +#define I2S_LL_XTAL_CLK_FREQ (40 * 1000000) // XTAL_CLK: 40MHz +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_XTAL_CLK_FREQ // No PLL clock source on P4, use XTAL as default + +/** + * @brief I2S clock configuration structure + * @note Fmclk = Fsclk /(integ+numer/denom) + */ +typedef struct { + uint16_t integ; // Integer part of I2S module clock divider + uint16_t denom; // Denominator part of I2S module clock divider + uint16_t numer; // Numerator part of I2S module clock divider +} i2s_ll_mclk_div_t; + +/** + * @brief I2S module general init, enable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_enable_clock(i2s_dev_t *hw) +{ + // The clock gate enabling is moved to `periph_module_enable` + (void)hw; +} + +/** + * @brief I2S module disable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_disable_clock(i2s_dev_t *hw) +{ + // The clock gate disabling is moved to `periph_module_disable` + (void)hw; +} + +/** + * @brief Enable I2S tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_en = 1; +} + +/** + * @brief Enable I2S rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 1; +} + +/** + * @brief Disable I2S tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_en = 0; +} + +/** + * @brief Disable I2S rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 0; +} + +/** + * @brief I2S mclk use tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_mclk_bind_to_tx_clk(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_rx_clkm_conf.i2s_mclk_sel = 0; +} + +/** + * @brief I2S mclk use rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_mclk_bind_to_rx_clk(i2s_dev_t *hw) +{ + (void)hw; + PCR.i2s_rx_clkm_conf.i2s_mclk_sel = 1; +} + +/** + * @brief Enable I2S TX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->tx_conf.tx_slave_mod = slave_en; +} + +/** + * @brief Enable I2S RX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->rx_conf.rx_slave_mod = slave_en; +} + +/** + * @brief Reset I2S TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_reset(i2s_dev_t *hw) +{ + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; +} + +/** + * @brief Reset I2S RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_reset(i2s_dev_t *hw) +{ + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; +} + +/** + * @brief Reset I2S TX FIFO + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw) +{ + hw->tx_conf.tx_fifo_reset = 1; + hw->tx_conf.tx_fifo_reset = 0; +} + +/** + * @brief Reset I2S RX FIFO + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) +{ + hw->rx_conf.rx_fifo_reset = 1; + hw->rx_conf.rx_fifo_reset = 0; +} + +/** + * @brief Set TX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock. + */ +static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + (void)hw; + switch (src) + { + case I2S_CLK_SRC_XTAL: + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 0; + break; + case I2S_CLK_SRC_APLL: + PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 1; + 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_APLL: + PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 1; + 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 i2s_ll_mclk_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->denom && mclk_div->numer) { + div_yn1 = mclk_div->numer * 2 > mclk_div->denom; + div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer; + div_x = mclk_div->denom / div_z - 1; + div_y = mclk_div->denom % div_z; + } + i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integ, 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 i2s_ll_mclk_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->denom && mclk_div->numer) { + div_yn1 = mclk_div->numer * 2 > mclk_div->denom; + div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer; + div_x = mclk_div->denom / div_z - 1; + div_y = mclk_div->denom % div_z; + } + i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integ, 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 Congfigure TX chan bit and audio data bit + * + * @param hw Peripheral I2S hardware instance address. + * @param chan_bit The chan bit width + * @param data_bit The audio data bit width + */ +static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) +{ + hw->tx_conf1.tx_bits_mod = data_bit - 1; + hw->tx_conf1.tx_tdm_chan_bits = chan_bit - 1; +} + +/** + * @brief Congfigure RX chan bit and audio data bit + * + * @param hw Peripheral I2S hardware instance address. + * @param chan_bit The chan bit width + * @param data_bit The audio data bit width + */ +static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) +{ + hw->rx_conf1.rx_bits_mod = data_bit - 1; + hw->rx_conf1.rx_tdm_chan_bits = chan_bit - 1; +} + +/** + * @brief Configure RX half_sample_bit + * + * @param hw Peripheral I2S hardware instance address. + * @param half_sample_bits half sample bit width + */ +static inline void i2s_ll_tx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_conf1, tx_half_sample_bits, half_sample_bits - 1); +} + +/** + * @brief Configure RX half_sample_bit + * + * @param hw Peripheral I2S hardware instance address. + * @param half_sample_bits half sample bit width + */ +static inline void i2s_ll_rx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_conf1, rx_half_sample_bits, half_sample_bits - 1); +} + +/** + * @brief Enable TX MSB shift, the data will be launch at the first BCK clock + * + * @param hw Peripheral I2S hardware instance address. + * @param msb_shift_enable Set true to enable MSB shift + */ +static inline void i2s_ll_tx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) +{ + hw->tx_conf.tx_msb_shift = msb_shift_enable; +} + +/** + * @brief Enable RX MSB shift, the data will be launch at the first BCK clock + * + * @param hw Peripheral I2S hardware instance address. + * @param msb_shift_enable Set true to enable MSB shift + */ +static inline void i2s_ll_rx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) +{ + hw->rx_conf.rx_msb_shift = msb_shift_enable; +} + +/** + * @brief Configure TX total chan number + * + * @param hw Peripheral I2S hardware instance address. + * @param total_num Total chan number + */ +static inline void i2s_ll_tx_set_chan_num(i2s_dev_t *hw, int total_num) +{ + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; +} + +/** + * @brief Configure RX total chan number + * + * @param hw Peripheral I2S hardware instance address. + * @param total_num Total chan number + */ +static inline void i2s_ll_rx_set_chan_num(i2s_dev_t *hw, int total_num) +{ + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; +} + +/** + * @brief Set the bimap of the active TX chan, only the active chan can launch audio data. + * + * @param hw Peripheral I2S hardware instance address. + * @param chan_mask mask of tx active chan + */ +static inline void i2s_ll_tx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) +{ + 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 paramater + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - fp configuration paramater + */ +static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) +{ + return hw->tx_pcm2pdm_conf1.tx_pdm_fp; +} + +/** + * @brief Get I2S TX PDM fs configuration paramater + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - fs configuration paramater + */ +static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) +{ + return hw->tx_pcm2pdm_conf1.tx_pdm_fs; +} + +/** + * @brief Enable RX PDM mode. + * + * @param hw Peripheral I2S hardware instance address. + * @param pdm_enable Set true to RX enable PDM mode + */ +static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) +{ + hw->rx_conf.rx_pdm_en = pdm_enable; + hw->rx_conf.rx_tdm_en = !pdm_enable; + hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = pdm_enable; +} + +/** + * @brief Configure RX PDM downsample + * + * @param hw Peripheral I2S hardware instance address. + * @param dsr PDM downsample configuration paramater + */ +static inline void i2s_ll_rx_set_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) +{ + hw->rx_pdm2pcm_conf.rx_pdm_sinc_dsr_16_en = dsr; +} + +/** + * @brief Get RX PDM downsample configuration + * + * @param hw Peripheral I2S hardware instance address. + * @param dsr Pointer to accept PDM downsample configuration + */ +static inline void i2s_ll_rx_get_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) +{ + *dsr = (i2s_pdm_dsr_t)hw->rx_pdm2pcm_conf.rx_pdm_sinc_dsr_16_en; +} + +/** + * @brief Configure RX PDM amplify number + * @note This is the amplification number of the digital amplifier, + * which is added after the PDM to PCM conversion result and mainly used for + * amplify the small PDM signal under the VAD scenario + * pcm_result = pdm_input * amplify_num + * pcm_result = 0 if amplify_num = 0 + * + * @param hw Peripheral I2S hardware instance address. + * @param amp_num PDM RX amplify number + */ +static inline void i2s_ll_rx_set_pdm_amplify_num(i2s_dev_t *hw, uint32_t amp_num) +{ + hw->rx_pdm2pcm_conf.rx_pdm2pcm_amplify_num = amp_num; +} + + +/** + * @brief Set I2S RX PDM high pass filter param0 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM RX IIR_HP filter stage 1 is (504 + I2S_RX_IIR_HP_MULT12_0[2:0]) + */ +static inline void i2s_ll_rx_set_pdm_hp_filter_param0(i2s_dev_t *hw, uint32_t param) +{ + hw->rx_pdm2pcm_conf.rx_iir_hp_mult12_0 = param; +} + +/** + * @brief Set I2S RX PDM high pass filter param5 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM RX IIR_HP filter stage 2 is (504 + I2S_RX_IIR_HP_MULT12_5[2:0]) + */ +static inline void i2s_ll_rx_set_pdm_hp_filter_param5(i2s_dev_t *hw, uint32_t param) +{ + hw->rx_pdm2pcm_conf.rx_iir_hp_mult12_5 = param; +} + +/** + * @brief Enable I2S RX PDM high pass filter + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable I2S RX PDM high pass filter, set false to bypass it + */ +static inline void i2s_ll_rx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) +{ + hw->rx_pdm2pcm_conf.rx_pdm_hp_bypass = !enable; +} + + +/** + * @brief Configura TX a/u-law decompress or compress + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm_cfg PCM configuration paramater + */ +static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) +{ + hw->tx_conf.tx_pcm_conf = pcm_cfg; + hw->tx_conf.tx_pcm_bypass = !pcm_cfg; +} + +/** + * @brief Configure RX a/u-law decompress or compress + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm_cfg PCM configuration paramater + */ +static inline void i2s_ll_rx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) +{ + hw->rx_conf.rx_pcm_conf = pcm_cfg; + hw->rx_conf.rx_pcm_bypass = !pcm_cfg; +} + +/** + * @brief Enable TX audio data left alignment + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable left alignment + */ +static inline void i2s_ll_tx_enable_left_align(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.tx_left_align = ena; +} + +/** + * @brief Enable RX audio data left alignment + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable left alignment + */ +static inline void i2s_ll_rx_enable_left_align(i2s_dev_t *hw, bool ena) +{ + hw->rx_conf.rx_left_align = ena; +} + +/** + * @brief Enable TX big endian mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable big endian mode + */ +static inline void i2s_ll_rx_enable_big_endian(i2s_dev_t *hw, bool ena) +{ + hw->rx_conf.rx_big_endian = ena; +} + +/** + * @brief Enable RX big endian mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable big endian mode + */ +static inline void i2s_ll_tx_enable_big_endian(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.tx_big_endian = ena; +} + +/** + * @brief Configure TX bit order + * + * @param hw Peripheral I2S hardware instance address. + * @param lsb_order_ena Set true to enable LSB bit order + */ +static inline void i2s_ll_tx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) +{ + hw->tx_conf.tx_bit_order = lsb_order_ena; +} + +/** + * @brief Configure RX bit order + * + * @param hw Peripheral I2S hardware instance address. + * @param lsb_order_ena Set true to enable LSB bit order + */ +static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) +{ + hw->rx_conf.rx_bit_order = lsb_order_ena; +} + +/** + * @brief Configure TX skip mask enable + * + * @param hw Peripheral I2S hardware instance address. + * @param skip_mask_ena Set true to skip inactive channels. + */ +static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena) +{ + hw->tx_tdm_ctrl.tx_tdm_skip_msk_en = skip_mask_ena; +} + + +/** + * @brief Configure single data + * + * @param hw Peripheral I2S hardware instance address. + * @param data Single data to be set + */ +static inline void i2s_ll_set_single_data(i2s_dev_t *hw, uint32_t data) +{ + hw->conf_single_data.val = data; +} + +/** + * @brief Enable TX mono mode + * @note MONO in hardware means only one channel got data, but another doesn't + * MONO in software means two channel share same data + * This function aims to use MONO in software meaning + * so 'tx_mono' and 'tx_chan_equal' should be enabled at the same time + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + hw->tx_conf.tx_mono = mono_ena; + hw->tx_conf.tx_chan_equal = mono_ena; +} + +/** + * @brief Enable RX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + hw->rx_conf.rx_mono = mono_ena; + hw->rx_conf.rx_mono_fst_vld = mono_ena; +} + +/** + * @brief Enable loopback mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to share BCK and WS signal for tx module and rx module. + */ +static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.sig_loopback = ena; +} + +/** + * @brief PDM TX DMA data take mode + * + * @param hw Peripheral I2S hardware instance address. + * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) + * @param is_fst_valid Whether take the DMA data at the first half period + * Only take effet when 'is_mono' is true + */ +static inline void i2s_ll_tx_pdm_dma_take_mode(i2s_dev_t *hw, bool is_mono, bool is_fst_valid) +{ + hw->tx_conf.tx_mono = is_mono; + hw->tx_conf.tx_mono_fst_vld = is_fst_valid; +} + +/** + * @brief PDM TX slot mode + * @note Mode Left Slot Right Slot Chan Mode WS Pol + * ----------------------------------------------------------------- + * Stereo Left Right 0 x + * ----------------------------------------------------------------- + * Mono Left Left 1 0 + * Mono Right Right 2 0 + * Mono Single Right 3 0 + * Mono Left Single 4 0 + * ----------------------------------------------------------------- + * Mono Right Right 1 1 + * Mono Left Left 2 1 + * Mono Left Single 3 1 + * Mono Single Right 4 1 + * @note The 'Single' above means always sending the value of `conf_single_data` reg + * The default value of `conf_single_data` reg is '0', it is not public for now + * + * @param hw Peripheral I2S hardware instance address. + * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) + * @param is_copy Whether the un-selected slot copies the data from the selected one + * If not, the un-selected slot will transmit the data from 'conf_single_data' + * @param mask The slot mask to selet the slot + */ +static inline void i2s_ll_tx_pdm_slot_mode(i2s_dev_t *hw, bool is_mono, bool is_copy, i2s_pdm_slot_mask_t mask) +{ + if (is_mono) { + /* The default tx_ws_idle_pol is false */ + if (is_copy) { + hw->tx_conf.tx_chan_mod = mask == I2S_PDM_SLOT_LEFT ? 1 : 2; + } else { + hw->tx_conf.tx_chan_mod = mask == I2S_PDM_SLOT_LEFT ? 4 : 3; + } + } else { + hw->tx_conf.tx_chan_mod = 0; + } +} + +/** + * @brief PDM TX line mode + * @note Mode DAC Mode 2 lines output + * ------------------------------------------- + * PDM codec 0 1 + * DAC 1-line 1 0 + * DAC 2-line 1 1 + * + * @param hw Peripheral I2S hardware instance address. + * @param line_mode PDM TX line mode + */ +static inline void i2s_ll_tx_pdm_line_mode(i2s_dev_t *hw, i2s_pdm_tx_line_mode_t line_mode) +{ + hw->tx_pcm2pdm_conf.tx_pdm_dac_mode_en = line_mode > I2S_PDM_TX_ONE_LINE_CODEC; + hw->tx_pcm2pdm_conf.tx_pdm_dac_2out_en = line_mode != I2S_PDM_TX_ONE_LINE_DAC; +} + +/** + * @brief Reset TX FIFO synchronization counter + * + * @param hw Peripheral I2S hardware instance address. + */ +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 + * count value + */ +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. + */ +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 + * count value + */ +static inline void 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/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index 4b419047e5..30d481d9c8 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -45,7 +45,7 @@ extern "C" { #define I2S_LL_RX_EVENT_MASK I2S_LL_EVENT_RX_EOF #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz -#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT /** * @brief Enable DMA descriptor owner check diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 1beb845b2d..4880c6850d 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -35,7 +35,7 @@ extern "C" { #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_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz -#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT /** * @brief I2S module general init, enable I2S clock. diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index ee3c94c29c..1803bd51f8 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -10,7 +10,7 @@ #include "soc/soc.h" #include "hal/i2s_hal.h" -#if SOC_I2S_HW_VERSION_2 && SOC_I2S_SUPPORTS_PDM_TX +#if SOC_I2S_HW_VERSION_2 && (SOC_I2S_SUPPORTS_PDM_TX || SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER) /* PDM tx high pass filter cut-off frequency and coefficients list * [0]: cut-off frequency; [1]: param0; [2]: param5 */ static const float cut_off_coef[21][3] = { @@ -22,6 +22,22 @@ static const float cut_off_coef[21][3] = { {63, 4, 7}, {58, 5, 6}, {49, 5, 7}, {46, 6, 6}, {35.5, 6, 7}, {23.3, 7, 7} }; + +static void s_i2s_hal_get_cut_off_coef(float freq, uint32_t *param0, uint32_t *param5) +{ + uint8_t cnt = 0; + float min = 1000; + /* Find the closest cut-off frequency and its coefficients */ + for (int i = 0; i < 21; i++) { + float tmp = cut_off_coef[i][0] < freq ? freq - cut_off_coef[i][0] : cut_off_coef[i][0] - freq; + if (tmp < min) { + min = tmp; + cnt = i; + } + } + *param0 = (uint32_t)cut_off_coef[cnt][1]; + *param5 = (uint32_t)cut_off_coef[cnt][2]; +} #endif /** @@ -183,20 +199,12 @@ void i2s_hal_pdm_set_tx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha i2s_ll_tx_set_ws_idle_pol(hal->dev, false); /* Slot mode seems not take effect according to the test, leave it default here */ i2s_ll_tx_pdm_slot_mode(hal->dev, is_mono, false, I2S_PDM_SLOT_BOTH); - uint8_t cnt = 0; - float min = 1000; - float expt_cut_off = slot_cfg->pdm_tx.hp_cut_off_freq_hz; - /* Find the closest cut-off frequency and its coefficients */ - for (int i = 0; i < 21; i++) { - float tmp = cut_off_coef[i][0] < expt_cut_off ? expt_cut_off - cut_off_coef[i][0] : cut_off_coef[i][0] - expt_cut_off; - if (tmp < min) { - min = tmp; - cnt = i; - } - } + uint32_t param0; + uint32_t param5; + s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_tx.hp_cut_off_freq_hz, ¶m0, ¶m5); i2s_ll_tx_enable_pdm_hp_filter(hal->dev, slot_cfg->pdm_tx.hp_en); - i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, cut_off_coef[cnt][1]); - i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, cut_off_coef[cnt][2]); + i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, param0); + i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, param5); i2s_ll_tx_set_pdm_sd_dither(hal->dev, slot_cfg->pdm_tx.sd_dither); i2s_ll_tx_set_pdm_sd_dither2(hal->dev, slot_cfg->pdm_tx.sd_dither2); #endif @@ -233,7 +241,18 @@ void i2s_hal_pdm_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha uint32_t slot_mask = slot_cfg->slot_mode == I2S_SLOT_MODE_STEREO ? I2S_PDM_SLOT_BOTH : slot_cfg->pdm_rx.slot_mask; #endif // SOC_I2S_SUPPORTS_PDM_RX > 1 i2s_ll_rx_set_active_chan_mask(hal->dev, slot_mask); -#endif // SOC_I2S_SUPPORTS_PDM_RX +#endif // SOC_I2S_HW_VERSION_1 + +#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER // TODO: add this macro to soc_caps + uint32_t param0; + uint32_t param5; + s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_rx.hp_cut_off_freq_hz, ¶m0, ¶m5); + i2s_ll_rx_enable_pdm_hp_filter(hal->dev, slot_cfg->pdm_rx.hp_en); + i2s_ll_rx_set_pdm_hp_filter_param0(hal->dev, param0); + i2s_ll_rx_set_pdm_hp_filter_param5(hal->dev, param5); + /* Set the amplification number, the default and the minimum value is 1. 0 will mute the channel */ + i2s_ll_rx_set_pdm_amplify_num(hal->dev, slot_cfg->pdm_rx.amplify_num ? slot_cfg->pdm_rx.amplify_num : 1); +#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER } void i2s_hal_pdm_enable_rx_channel(i2s_hal_context_t *hal) diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index e1286b876f..e2957e5cc4 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -91,7 +91,13 @@ typedef struct { /* PDM TX configurations */ struct { i2s_pdm_slot_mask_t slot_mask; /*!< Choose the slots to activate */ - } pdm_rx; /*!< Specific configurations for PDM TX mode */ +#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + bool hp_en; /*!< High pass filter enable */ + float hp_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */ + uint32_t amplify_num; /*!< The amplification number of the final conversion result */ +#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + + } pdm_rx; /*!< Specific configurations for PDM RX mode */ #endif }; diff --git a/components/soc/esp32c6/include/soc/i2s_struct.h b/components/soc/esp32c6/include/soc/i2s_struct.h index e2e4de298c..f7b7f069ad 100644 --- a/components/soc/esp32c6/include/soc/i2s_struct.h +++ b/components/soc/esp32c6/include/soc/i2s_struct.h @@ -240,34 +240,6 @@ typedef union { uint32_t val; } i2s_rx_conf1_reg_t; -/** Type of rx_clkm_conf register - * I2S RX clock configure register - */ -typedef union { - struct { - /** rx_clkm_div_num : R/W; bitpos: [7:0]; default: 2; - * Integral I2S clock divider value - */ - uint32_t rx_clkm_div_num:8; - uint32_t reserved_8:18; - /** rx_clk_active : R/W; bitpos: [26]; default: 0; - * I2S Rx module clock enable signal. - */ - uint32_t rx_clk_active:1; - /** rx_clk_sel : R/W; bitpos: [28:27]; default: 0; - * Select I2S Rx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: I2S_MCLK_in. - */ - uint32_t rx_clk_sel:2; - /** mclk_sel : R/W; bitpos: [29]; default: 0; - * 0: UseI2S Tx module clock as I2S_MCLK_OUT. 1: UseI2S Rx module clock as - * I2S_MCLK_OUT. - */ - uint32_t mclk_sel:1; - uint32_t reserved_30:2; - }; - uint32_t val; -} i2s_rx_clkm_conf_reg_t; - /** Type of tx_pcm2pdm_conf register * I2S TX PCM2PDM configuration register */ @@ -609,37 +581,6 @@ typedef union { uint32_t val; } i2s_tx_conf1_reg_t; -/** Type of tx_clkm_conf register - * I2S TX clock configure register - */ -typedef union { - struct { - /** tx_clkm_div_num : R/W; bitpos: [7:0]; default: 2; - * Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be - * (a-b) * n-div and b * (n+1)-div. So the average combination will be: for b <= - * a/2, z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2, z * [n-div + x * - * (n+1)-div] + y * (n+1)-div. - */ - uint32_t tx_clkm_div_num:8; - uint32_t reserved_8:18; - /** tx_clk_active : R/W; bitpos: [26]; default: 0; - * I2S Tx module clock enable signal. - */ - uint32_t tx_clk_active:1; - /** tx_clk_sel : R/W; bitpos: [28:27]; default: 0; - * Select I2S Tx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: - * I2S_MCLK_in. - */ - uint32_t tx_clk_sel:2; - /** clk_en : R/W; bitpos: [29]; default: 0; - * Set this bit to enable clk gate - */ - uint32_t clk_en:1; - uint32_t reserved_30:2; - }; - uint32_t val; -} i2s_tx_clkm_conf_reg_t; - /** Type of tx_tdm_ctrl register * I2S TX TDM mode control register */ @@ -742,36 +683,6 @@ typedef union { /** Group: RX clock and timing registers */ -/** Type of rx_clkm_div_conf register - * I2S RX module clock divider configure register - */ -typedef union { - struct { - /** rx_clkm_div_z : R/W; bitpos: [8:0]; default: 0; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_Z is b. For b > a/2, the value of - * I2S_RX_CLKM_DIV_Z is (a-b). - */ - uint32_t rx_clkm_div_z:9; - /** rx_clkm_div_y : R/W; bitpos: [17:9]; default: 1; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of - * I2S_RX_CLKM_DIV_Y is (a%(a-b)). - */ - uint32_t rx_clkm_div_y:9; - /** rx_clkm_div_x : R/W; bitpos: [26:18]; default: 0; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value - * of I2S_RX_CLKM_DIV_X is (a/(a-b)) - 1. - */ - uint32_t rx_clkm_div_x:9; - /** rx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of - * I2S_RX_CLKM_DIV_YN1 is 1. - */ - uint32_t rx_clkm_div_yn1:1; - uint32_t reserved_28:4; - }; - uint32_t val; -} i2s_rx_clkm_div_conf_reg_t; - /** Type of rx_timing register * I2S RX timing control register */ @@ -813,36 +724,6 @@ typedef union { /** Group: TX clock and timing registers */ -/** Type of tx_clkm_div_conf register - * I2S TX module clock divider configure register - */ -typedef union { - struct { - /** tx_clkm_div_z : R/W; bitpos: [8:0]; default: 0; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_Z is b. For b > a/2, the value of - * I2S_TX_CLKM_DIV_Z is (a-b). - */ - uint32_t tx_clkm_div_z:9; - /** tx_clkm_div_y : R/W; bitpos: [17:9]; default: 1; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of - * I2S_TX_CLKM_DIV_Y is (a%(a-b)). - */ - uint32_t tx_clkm_div_y:9; - /** tx_clkm_div_x : R/W; bitpos: [26:18]; default: 0; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value - * of I2S_TX_CLKM_DIV_X is (a/(a-b)) - 1. - */ - uint32_t tx_clkm_div_x:9; - /** tx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of - * I2S_TX_CLKM_DIV_YN1 is 1. - */ - uint32_t tx_clkm_div_yn1:1; - uint32_t reserved_28:4; - }; - uint32_t val; -} i2s_tx_clkm_div_conf_reg_t; - /** Type of tx_timing register * I2S TX timing control register */ @@ -993,10 +874,7 @@ typedef struct i2s_dev_t { volatile i2s_tx_conf_reg_t tx_conf; volatile i2s_rx_conf1_reg_t rx_conf1; volatile i2s_tx_conf1_reg_t tx_conf1; - volatile i2s_rx_clkm_conf_reg_t rx_clkm_conf; - volatile i2s_tx_clkm_conf_reg_t tx_clkm_conf; - volatile i2s_rx_clkm_div_conf_reg_t rx_clkm_div_conf; - volatile i2s_tx_clkm_div_conf_reg_t tx_clkm_div_conf; + uint32_t reserved_030[4]; volatile i2s_tx_pcm2pdm_conf_reg_t tx_pcm2pdm_conf; volatile i2s_tx_pcm2pdm_conf1_reg_t tx_pcm2pdm_conf1; uint32_t reserved_048[2]; diff --git a/components/soc/esp32h2/include/soc/i2s_struct.h b/components/soc/esp32h2/include/soc/i2s_struct.h index f4ac17a3b0..34f876838f 100644 --- a/components/soc/esp32h2/include/soc/i2s_struct.h +++ b/components/soc/esp32h2/include/soc/i2s_struct.h @@ -240,34 +240,6 @@ typedef union { uint32_t val; } i2s_rx_conf1_reg_t; -/** Type of rx_clkm_conf register - * I2S RX clock configure register - */ -typedef union { - struct { - /** rx_clkm_div_num : R/W; bitpos: [7:0]; default: 2; - * Integral I2S clock divider value - */ - uint32_t rx_clkm_div_num:8; - uint32_t reserved_8:18; - /** rx_clk_active : R/W; bitpos: [26]; default: 0; - * I2S Rx module clock enable signal. - */ - uint32_t rx_clk_active:1; - /** rx_clk_sel : R/W; bitpos: [28:27]; default: 0; - * Select I2S Rx module source clock. 0: no clock. 1: APLL. 2: CLK160. 3: I2S_MCLK_in. - */ - uint32_t rx_clk_sel:2; - /** mclk_sel : R/W; bitpos: [29]; default: 0; - * 0: UseI2S Tx module clock as I2S_MCLK_OUT. 1: UseI2S Rx module clock as - * I2S_MCLK_OUT. - */ - uint32_t mclk_sel:1; - uint32_t reserved_30:2; - }; - uint32_t val; -} i2s_rx_clkm_conf_reg_t; - /** Type of tx_pcm2pdm_conf register * I2S TX PCM2PDM configuration register */ @@ -607,37 +579,6 @@ typedef union { uint32_t val; } i2s_tx_conf1_reg_t; -/** Type of tx_clkm_conf register - * I2S TX clock configure register - */ -typedef union { - struct { - /** tx_clkm_div_num : R/W; bitpos: [7:0]; default: 2; - * Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be - * (a-b) * n-div and b * (n+1)-div. So the average combination will be: for b <= - * a/2, z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2, z * [n-div + x * - * (n+1)-div] + y * (n+1)-div. - */ - uint32_t tx_clkm_div_num:8; - uint32_t reserved_8:18; - /** tx_clk_active : R/W; bitpos: [26]; default: 0; - * I2S Tx module clock enable signal. - */ - uint32_t tx_clk_active:1; - /** tx_clk_sel : R/W; bitpos: [28:27]; default: 0; - * Select I2S Tx module source clock. 0: XTAL clock. 1: APLL. 2: CLK160. 3: - * I2S_MCLK_in. - */ - uint32_t tx_clk_sel:2; - /** clk_en : R/W; bitpos: [29]; default: 0; - * Set this bit to enable clk gate - */ - uint32_t clk_en:1; - uint32_t reserved_30:2; - }; - uint32_t val; -} i2s_tx_clkm_conf_reg_t; - /** Type of tx_tdm_ctrl register * I2S TX TDM mode control register */ @@ -740,36 +681,6 @@ typedef union { /** Group: RX clock and timing registers */ -/** Type of rx_clkm_div_conf register - * I2S RX module clock divider configure register - */ -typedef union { - struct { - /** rx_clkm_div_z : R/W; bitpos: [8:0]; default: 0; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_Z is b. For b > a/2, the value of - * I2S_RX_CLKM_DIV_Z is (a-b). - */ - uint32_t rx_clkm_div_z:9; - /** rx_clkm_div_y : R/W; bitpos: [17:9]; default: 1; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of - * I2S_RX_CLKM_DIV_Y is (a%(a-b)). - */ - uint32_t rx_clkm_div_y:9; - /** rx_clkm_div_x : R/W; bitpos: [26:18]; default: 0; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value - * of I2S_RX_CLKM_DIV_X is (a/(a-b)) - 1. - */ - uint32_t rx_clkm_div_x:9; - /** rx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of - * I2S_RX_CLKM_DIV_YN1 is 1. - */ - uint32_t rx_clkm_div_yn1:1; - uint32_t reserved_28:4; - }; - uint32_t val; -} i2s_rx_clkm_div_conf_reg_t; - /** Type of rx_timing register * I2S RX timing control register */ @@ -811,36 +722,6 @@ typedef union { /** Group: TX clock and timing registers */ -/** Type of tx_clkm_div_conf register - * I2S TX module clock divider configure register - */ -typedef union { - struct { - /** tx_clkm_div_z : R/W; bitpos: [8:0]; default: 0; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_Z is b. For b > a/2, the value of - * I2S_TX_CLKM_DIV_Z is (a-b). - */ - uint32_t tx_clkm_div_z:9; - /** tx_clkm_div_y : R/W; bitpos: [17:9]; default: 1; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of - * I2S_TX_CLKM_DIV_Y is (a%(a-b)). - */ - uint32_t tx_clkm_div_y:9; - /** tx_clkm_div_x : R/W; bitpos: [26:18]; default: 0; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value - * of I2S_TX_CLKM_DIV_X is (a/(a-b)) - 1. - */ - uint32_t tx_clkm_div_x:9; - /** tx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of - * I2S_TX_CLKM_DIV_YN1 is 1. - */ - uint32_t tx_clkm_div_yn1:1; - uint32_t reserved_28:4; - }; - uint32_t val; -} i2s_tx_clkm_div_conf_reg_t; - /** Type of tx_timing register * I2S TX timing control register */ @@ -991,10 +872,7 @@ typedef struct { volatile i2s_tx_conf_reg_t tx_conf; volatile i2s_rx_conf1_reg_t rx_conf1; volatile i2s_tx_conf1_reg_t tx_conf1; - volatile i2s_rx_clkm_conf_reg_t rx_clkm_conf; - volatile i2s_tx_clkm_conf_reg_t tx_clkm_conf; - volatile i2s_rx_clkm_div_conf_reg_t rx_clkm_div_conf; - volatile i2s_tx_clkm_div_conf_reg_t tx_clkm_div_conf; + uint32_t reserved_030[4]; volatile i2s_tx_pcm2pdm_conf_reg_t tx_pcm2pdm_conf; volatile i2s_tx_pcm2pdm_conf1_reg_t tx_pcm2pdm_conf1; uint32_t reserved_048[2]; diff --git a/components/soc/esp32p4/i2s_periph.c b/components/soc/esp32p4/i2s_periph.c index 1e466a3433..66225f77c1 100644 --- a/components/soc/esp32p4/i2s_periph.c +++ b/components/soc/esp32p4/i2s_periph.c @@ -11,4 +11,73 @@ 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] = { + [0] = { + .mck_out_sig = I2S0_MCLK_PAD_OUT_IDX, + + .m_tx_bck_sig = I2S0_O_BCK_PAD_OUT_IDX, + .m_rx_bck_sig = I2S0_I_BCK_PAD_OUT_IDX, + .m_tx_ws_sig = I2S0_O_WS_PAD_OUT_IDX, + .m_rx_ws_sig = I2S0_I_WS_PAD_OUT_IDX, + + .s_tx_bck_sig = I2S0_O_BCK_PAD_IN_IDX, + .s_rx_bck_sig = I2S0_I_BCK_PAD_IN_IDX, + .s_tx_ws_sig = I2S0_O_WS_PAD_IN_IDX, + .s_rx_ws_sig = I2S0_I_WS_PAD_IN_IDX, + + .data_out_sigs[0] = I2S0_O_SD_PAD_OUT_IDX, + .data_out_sigs[1] = I2S0_O_SD1_PAD_OUT_IDX, + .data_in_sigs[0] = I2S0_I_SD_PAD_IN_IDX, + .data_in_sigs[1] = I2S0_I_SD1_PAD_IN_IDX, + .data_in_sigs[2] = I2S0_I_SD2_PAD_IN_IDX, + .data_in_sigs[3] = I2S0_I_SD3_PAD_IN_IDX, + + .irq = -1, + .module = PERIPH_I2S0_MODULE, + }, + [1] = { + .mck_out_sig = I2S1_MCLK_PAD_OUT_IDX, + + .m_tx_bck_sig = I2S1_O_BCK_PAD_OUT_IDX, + .m_rx_bck_sig = I2S1_I_BCK_PAD_OUT_IDX, + .m_tx_ws_sig = I2S1_O_WS_PAD_OUT_IDX, + .m_rx_ws_sig = I2S1_I_WS_PAD_OUT_IDX, + + .s_tx_bck_sig = I2S1_O_BCK_PAD_IN_IDX, + .s_rx_bck_sig = I2S1_I_BCK_PAD_IN_IDX, + .s_tx_ws_sig = I2S1_O_WS_PAD_IN_IDX, + .s_rx_ws_sig = I2S1_I_WS_PAD_IN_IDX, + + .data_out_sigs[0] = I2S1_O_SD_PAD_OUT_IDX, + .data_out_sigs[1] = -1, + .data_in_sigs[0] = I2S1_I_SD_PAD_IN_IDX, + .data_in_sigs[1] = -1, + .data_in_sigs[2] = -1, + .data_in_sigs[3] = -1, + + .irq = -1, + .module = PERIPH_I2S1_MODULE, + }, + [2] = { + .mck_out_sig = I2S2_MCLK_PAD_OUT_IDX, + + .m_tx_bck_sig = I2S2_O_BCK_PAD_OUT_IDX, + .m_rx_bck_sig = I2S2_I_BCK_PAD_OUT_IDX, + .m_tx_ws_sig = I2S2_O_WS_PAD_OUT_IDX, + .m_rx_ws_sig = I2S2_I_WS_PAD_OUT_IDX, + + .s_tx_bck_sig = I2S2_O_BCK_PAD_IN_IDX, + .s_rx_bck_sig = I2S2_I_BCK_PAD_IN_IDX, + .s_tx_ws_sig = I2S2_O_WS_PAD_IN_IDX, + .s_rx_ws_sig = I2S2_I_WS_PAD_IN_IDX, + + .data_out_sigs[0] = I2S2_O_SD_PAD_OUT_IDX, + .data_out_sigs[1] = -1, + .data_in_sigs[0] = I2S2_I_SD_PAD_IN_IDX, + .data_in_sigs[1] = -1, + .data_in_sigs[2] = -1, + .data_in_sigs[3] = -1, + + .irq = -1, + .module = PERIPH_I2S2_MODULE, + }, }; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 6e71422bd9..28c867a876 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -71,6 +71,10 @@ config SOC_I2C_SUPPORTED bool default y +config SOC_I2S_SUPPORTED + bool + default y + config SOC_SYSTIMER_SUPPORTED bool default y @@ -433,7 +437,7 @@ config SOC_I2C_SUPPORT_RTC config SOC_I2S_NUM int - default 1 + default 3 config SOC_I2S_HW_VERSION_2 bool @@ -443,7 +447,7 @@ config SOC_I2S_SUPPORTS_XTAL bool default y -config SOC_I2S_SUPPORTS_PLL_F160M +config SOC_I2S_SUPPORTS_APLL bool default y @@ -451,10 +455,38 @@ config SOC_I2S_SUPPORTS_PCM bool default y +config SOC_I2S_SUPPORTS_PDM + bool + default y + +config SOC_I2S_SUPPORTS_PDM_TX + bool + default y + +config SOC_I2S_SUPPORTS_PDM_RX + bool + default y + +config SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + bool + default y + +config SOC_I2S_SUPPORTS_TDM + bool + default y + config SOC_I2S_PDM_MAX_TX_LINES int default 2 +config SOC_I2S_PDM_MAX_RX_LINES + int + default 4 + +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/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 32e27ca898..7137ba4a12 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -150,6 +150,7 @@ typedef enum { SOC_MOD_CLK_XTAL32K, /*!< XTAL32K_CLK comes from the external 32kHz crystal, passing a clock gating to the peripherals */ SOC_MOD_CLK_RC_FAST, /*!< RC_FAST_CLK comes from the internal 20MHz rc oscillator, passing a clock gating to the peripherals */ SOC_MOD_CLK_XTAL, /*!< XTAL_CLK comes from the external 40MHz crystal */ + SOC_MOD_CLK_APLL, /*!< Audio PLL is sourced from PLL, and its frequency is configurable through APLL configuration registers */ SOC_MOD_CLK_INVALID, /*!< Indication of the end of the available module clock sources */ } soc_module_clk_t; @@ -334,6 +335,20 @@ typedef enum { ///////////////////////////////////////////////// I2S ////////////////////////////////////////////////////////////// +/** + * @brief Array initializer for all supported clock sources of I2S + */ +#define SOC_I2S_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_APLL} + +/** + * @brief I2S clock source enum + */ +typedef enum { + I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default source clock */ + I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + I2S_CLK_SRC_APLL = SOC_MOD_CLK_APLL, /*!< Select APLL as the source clock */ +} soc_periph_i2s_clk_src_t; + /////////////////////////////////////////////////I2C//////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32p4/include/soc/i2s_struct.h b/components/soc/esp32p4/include/soc/i2s_struct.h index 87b35a0da7..6e05f6a2eb 100644 --- a/components/soc/esp32p4/include/soc/i2s_struct.h +++ b/components/soc/esp32p4/include/soc/i2s_struct.h @@ -277,6 +277,92 @@ typedef union { uint32_t val; } i2s_rx_pdm2pcm_conf_reg_t; +/** Type of tx_pcm2pdm_conf register + * I2S TX PCM2PDM configuration register + */ +typedef union { + struct { + /** tx_pdm_hp_bypass : R/W; bitpos: [0]; default: 0; + * I2S TX PDM bypass hp filter or not. The option has been removed. + */ + uint32_t tx_pdm_hp_bypass:1; + /** tx_pdm_sinc_osr2 : R/W; bitpos: [4:1]; default: 2; + * I2S TX PDM OSR2 value + */ + uint32_t tx_pdm_sinc_osr2:4; + /** tx_pdm_prescale : R/W; bitpos: [12:5]; default: 0; + * I2S TX PDM prescale for sigmadelta + */ + uint32_t tx_pdm_prescale:8; + /** tx_pdm_hp_in_shift : R/W; bitpos: [14:13]; default: 1; + * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 + */ + uint32_t tx_pdm_hp_in_shift:2; + /** tx_pdm_lp_in_shift : R/W; bitpos: [16:15]; default: 1; + * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 + */ + uint32_t tx_pdm_lp_in_shift:2; + /** tx_pdm_sinc_in_shift : R/W; bitpos: [18:17]; default: 1; + * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 + */ + uint32_t tx_pdm_sinc_in_shift:2; + /** tx_pdm_sigmadelta_in_shift : R/W; bitpos: [20:19]; default: 1; + * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 + */ + uint32_t tx_pdm_sigmadelta_in_shift:2; + /** tx_pdm_sigmadelta_dither2 : R/W; bitpos: [21]; default: 0; + * I2S TX PDM sigmadelta dither2 value + */ + uint32_t tx_pdm_sigmadelta_dither2:1; + /** tx_pdm_sigmadelta_dither : R/W; bitpos: [22]; default: 1; + * I2S TX PDM sigmadelta dither value + */ + uint32_t tx_pdm_sigmadelta_dither:1; + /** tx_pdm_dac_2out_en : R/W; bitpos: [23]; default: 0; + * I2S TX PDM dac mode enable + */ + uint32_t tx_pdm_dac_2out_en:1; + /** tx_pdm_dac_mode_en : R/W; bitpos: [24]; default: 0; + * I2S TX PDM dac 2channel enable + */ + uint32_t tx_pdm_dac_mode_en:1; + /** pcm2pdm_conv_en : R/W; bitpos: [25]; default: 0; + * I2S TX PDM Converter enable + */ + uint32_t pcm2pdm_conv_en:1; + uint32_t reserved_26:6; + }; + uint32_t val; +} i2s_tx_pcm2pdm_conf_reg_t; + +/** Type of tx_pcm2pdm_conf1 register + * I2S TX PCM2PDM configuration register + */ +typedef union { + struct { + /** tx_pdm_fp : R/W; bitpos: [9:0]; default: 960; + * I2S TX PDM Fp + */ + uint32_t tx_pdm_fp:10; + /** tx_pdm_fs : R/W; bitpos: [19:10]; default: 480; + * I2S TX PDM Fs + */ + uint32_t tx_pdm_fs:10; + /** tx_iir_hp_mult12_5 : R/W; bitpos: [22:20]; default: 7; + * The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 + + * I2S_TX_IIR_HP_MULT12_5[2:0]) + */ + uint32_t tx_iir_hp_mult12_5:3; + /** tx_iir_hp_mult12_0 : R/W; bitpos: [25:23]; default: 7; + * The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 + + * I2S_TX_IIR_HP_MULT12_0[2:0]) + */ + uint32_t tx_iir_hp_mult12_0:3; + uint32_t reserved_26:6; + }; + uint32_t val; +} i2s_tx_pcm2pdm_conf1_reg_t; + /** Type of rx_tdm_ctrl register * I2S TX TDM mode control register */ @@ -371,7 +457,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 { @@ -384,7 +470,7 @@ typedef union { uint32_t reserved_12:20; }; uint32_t val; -} i2s_rxeof_num_reg_t; +} i2s_rx_eof_num_reg_t; /** Group: TX Control and configuration registers */ @@ -530,89 +616,6 @@ typedef union { uint32_t val; } i2s_tx_conf1_reg_t; -/** Type of tx_pcm2pdm_conf register - * I2S TX PCM2PDM configuration register - */ -typedef union { - struct { - uint32_t reserved_0:1; - /** tx_pdm_sinc_osr2 : R/W; bitpos: [4:1]; default: 2; - * I2S TX PDM OSR2 value - */ - uint32_t tx_pdm_sinc_osr2:4; - /** tx_pdm_prescale : R/W; bitpos: [12:5]; default: 0; - * I2S TX PDM prescale for sigmadelta - */ - uint32_t tx_pdm_prescale:8; - /** tx_pdm_hp_in_shift : R/W; bitpos: [14:13]; default: 1; - * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 - */ - uint32_t tx_pdm_hp_in_shift:2; - /** tx_pdm_lp_in_shift : R/W; bitpos: [16:15]; default: 1; - * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 - */ - uint32_t tx_pdm_lp_in_shift:2; - /** tx_pdm_sinc_in_shift : R/W; bitpos: [18:17]; default: 1; - * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 - */ - uint32_t tx_pdm_sinc_in_shift:2; - /** tx_pdm_sigmadelta_in_shift : R/W; bitpos: [20:19]; default: 1; - * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 - */ - uint32_t tx_pdm_sigmadelta_in_shift:2; - /** tx_pdm_sigmadelta_dither2 : R/W; bitpos: [21]; default: 0; - * I2S TX PDM sigmadelta dither2 value - */ - uint32_t tx_pdm_sigmadelta_dither2:1; - /** tx_pdm_sigmadelta_dither : R/W; bitpos: [22]; default: 1; - * I2S TX PDM sigmadelta dither value - */ - uint32_t tx_pdm_sigmadelta_dither:1; - /** tx_pdm_dac_2out_en : R/W; bitpos: [23]; default: 0; - * I2S TX PDM dac mode enable - */ - uint32_t tx_pdm_dac_2out_en:1; - /** tx_pdm_dac_mode_en : R/W; bitpos: [24]; default: 0; - * I2S TX PDM dac 2channel enable - */ - uint32_t tx_pdm_dac_mode_en:1; - /** pcm2pdm_conv_en : R/W; bitpos: [25]; default: 0; - * I2S TX PDM Converter enable - */ - uint32_t pcm2pdm_conv_en:1; - uint32_t reserved_26:6; - }; - uint32_t val; -} i2s_tx_pcm2pdm_conf_reg_t; - -/** Type of tx_pcm2pdm_conf1 register - * I2S TX PCM2PDM configuration register - */ -typedef union { - struct { - /** tx_pdm_fp : R/W; bitpos: [9:0]; default: 960; - * I2S TX PDM Fp - */ - uint32_t tx_pdm_fp:10; - /** tx_pdm_fs : R/W; bitpos: [19:10]; default: 480; - * I2S TX PDM Fs - */ - uint32_t tx_pdm_fs:10; - /** tx_iir_hp_mult12_5 : R/W; bitpos: [22:20]; default: 7; - * The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 + - * I2S_TX_IIR_HP_MULT12_5[2:0]) - */ - uint32_t tx_iir_hp_mult12_5:3; - /** tx_iir_hp_mult12_0 : R/W; bitpos: [25:23]; default: 7; - * The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 + - * I2S_TX_IIR_HP_MULT12_0[2:0]) - */ - uint32_t tx_iir_hp_mult12_0:3; - uint32_t reserved_26:6; - }; - uint32_t val; -} i2s_tx_pcm2pdm_conf1_reg_t; - /** Type of tx_tdm_ctrl register * I2S TX TDM mode control register */ @@ -845,7 +848,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 { @@ -856,7 +859,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 */ @@ -986,8 +989,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; @@ -996,6 +999,9 @@ typedef struct { volatile i2s_date_reg_t date; } i2s_dev_t; +extern i2s_dev_t I2S0; +extern i2s_dev_t I2S1; +extern i2s_dev_t I2S2; #ifndef __cplusplus _Static_assert(sizeof(i2s_dev_t) == 0x84, "Invalid size of i2s_dev_t structure"); diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 2e97a113fc..a4343f13d9 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -50,6 +50,8 @@ #define SOC_RTC_MEM_SUPPORTED 1 // #define SOC_I2S_SUPPORTED 1 //TODO: IDF-6508 #define SOC_RMT_SUPPORTED 1 +#define SOC_I2S_SUPPORTED 1 +// #define SOC_RMT_SUPPORTED 1 //TODO: IDF-7476 // #define SOC_SDM_SUPPORTED 1 //TODO: IDF-7551 // #define SOC_GPSPI_SUPPORTED 1 //TODO: IDF-7502, TODO: IDF-7503 // #define SOC_LEDC_SUPPORTED 1 //TODO: IDF-6510 @@ -240,16 +242,19 @@ #define SOC_I2C_SUPPORT_RTC (1) /*-------------------------- I2S CAPS ----------------------------------------*/ -//TODO: IDF-6508 -#define SOC_I2S_NUM (1U) +#define SOC_I2S_NUM (3U) #define SOC_I2S_HW_VERSION_2 (1) #define SOC_I2S_SUPPORTS_XTAL (1) -#define SOC_I2S_SUPPORTS_PLL_F160M (1) +#define SOC_I2S_SUPPORTS_APLL (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_SUPPORTS_PDM (1) +#define SOC_I2S_SUPPORTS_PDM_TX (1) +#define SOC_I2S_SUPPORTS_PDM_RX (1) +#define SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER (1) +#define SOC_I2S_SUPPORTS_TDM (1) +#define SOC_I2S_PDM_MAX_TX_LINES (2) // On I2S0 +#define SOC_I2S_PDM_MAX_RX_LINES (4) // On I2S0 +#define SOC_I2S_TDM_FULL_DATA_WIDTH (1) /*!< No limitation to data bit width when using multiple slots */ /*-------------------------- LEDC CAPS ---------------------------------------*/ #define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1) diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index d0face2c1a..1622658bec 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -54,15 +54,15 @@ examples/peripherals/i2c/i2c_tools: examples/peripherals/i2s/i2s_basic/i2s_pdm: disable: - - if: SOC_I2S_SUPPORTS_PDM != 1 + - if: SOC_I2S_SUPPORTS_PDM != 1 or IDF_TARGET == "esp32p4" examples/peripherals/i2s/i2s_basic/i2s_std: disable: - - if: SOC_I2S_SUPPORTED != 1 + - if: SOC_I2S_SUPPORTED != 1 or IDF_TARGET == "esp32p4" examples/peripherals/i2s/i2s_basic/i2s_tdm: disable: - - if: SOC_I2S_SUPPORTS_TDM != 1 + - if: SOC_I2S_SUPPORTS_TDM != 1 or IDF_TARGET == "esp32p4" examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm: disable: @@ -71,10 +71,12 @@ examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm: examples/peripherals/i2s/i2s_codec/i2s_es8311: disable: - - if: SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1 + - if: (SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1) or IDF_TARGET == "esp32p4" reason: rely on I2S STD mode and I2C to config es7210 examples/peripherals/i2s/i2s_recorder: + disable: + - if: IDF_TARGET == "esp32p4" enable: - if: SOC_I2S_SUPPORTS_PDM_RX > 0 From 0b0f25c30d4309b01692b3fe2c935cc1c64a5793 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Wed, 2 Aug 2023 19:21:54 +0800 Subject: [PATCH 2/4] feat(i2s): supported getting the tx sync count and specify interrupt flags --- components/driver/dac/esp32/dac_dma.c | 1 + components/driver/deprecated/i2s_legacy.c | 69 +++-- components/driver/i2s/i2s_common.c | 123 ++++++-- components/driver/i2s/i2s_pdm.c | 20 +- components/driver/i2s/i2s_private.h | 16 +- components/driver/i2s/i2s_std.c | 13 +- components/driver/i2s/i2s_tdm.c | 17 +- .../driver/i2s/include/driver/i2s_common.h | 2 + .../driver/i2s/include/driver/i2s_pdm.h | 40 +-- .../driver/include/esp_private/i2s_sync.h | 71 +++++ .../driver/test_apps/.build-test-rules.yml | 16 + .../test_apps/i2s_test_apps/i2s/README.md | 4 +- .../i2s_test_apps/i2s/main/test_i2s.c | 9 +- .../i2s_test_apps/i2s/main/test_i2s_iram.c | 23 +- .../i2s_test_apps/i2s_multi_dev/README.md | 4 +- .../i2s_test_apps/legacy_i2s_driver/README.md | 4 +- .../i2s_test_apps/test_inc/test_i2s.h | 10 +- components/hal/esp32/include/hal/i2s_ll.h | 23 ++ components/hal/esp32c3/include/hal/i2s_ll.h | 23 ++ components/hal/esp32c6/include/hal/i2s_ll.h | 8 +- components/hal/esp32h2/include/hal/i2s_ll.h | 8 +- .../hal/esp32p4/include/hal/clk_gate_ll.h | 16 - .../hal/esp32p4/include/{ => hal}/i2s_ll.h | 290 ++++++++++++++---- components/hal/esp32s2/include/hal/i2s_ll.h | 24 ++ components/hal/esp32s3/include/hal/i2s_ll.h | 33 ++ components/hal/i2s_hal.c | 2 +- components/soc/esp32c3/i2s_periph.c | 2 +- components/soc/esp32c6/i2s_periph.c | 2 +- components/soc/esp32h2/i2s_periph.c | 2 +- components/soc/esp32p4/i2s_periph.c | 9 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 12 +- .../soc/esp32p4/include/soc/clk_tree_defs.h | 3 +- components/soc/esp32p4/include/soc/rtc.h | 38 +++ components/soc/esp32p4/include/soc/soc_caps.h | 2 + components/soc/esp32s3/i2s_periph.c | 4 +- examples/peripherals/.build-test-rules.yml | 24 +- .../i2s/i2s_codec/i2s_es8311/README.md | 4 +- 37 files changed, 749 insertions(+), 222 deletions(-) create mode 100644 components/driver/include/esp_private/i2s_sync.h rename components/hal/esp32p4/include/{ => hal}/i2s_ll.h (76%) diff --git a/components/driver/dac/esp32/dac_dma.c b/components/driver/dac/esp32/dac_dma.c index c5f8223a90..b5bd20e9b9 100644 --- a/components/driver/dac/esp32/dac_dma.c +++ b/components/driver/dac/esp32/dac_dma.c @@ -17,6 +17,7 @@ #include "hal/adc_ll.h" #include "hal/i2s_hal.h" #include "hal/i2s_types.h" +#include "hal/clk_tree_ll.h" #include "soc/i2s_periph.h" #include "../dac_priv_dma.h" #include "esp_private/i2s_platform.h" diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index f687cf9170..9397275979 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -58,6 +58,14 @@ static const char *TAG = "i2s(legacy)"; #define I2S_ENTER_CRITICAL(i2s_num) portENTER_CRITICAL(&i2s_spinlock[i2s_num]) #define I2S_EXIT_CRITICAL(i2s_num) portEXIT_CRITICAL(&i2s_spinlock[i2s_num]) +#if !SOC_RCC_IS_INDEPENDENT +#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#define I2S_RCC_ENV_DECLARE (void)__DECLARE_RCC_ATOMIC_ENV +#else +#define I2S_RCC_ATOMIC() +#define I2S_RCC_ENV_DECLARE +#endif + #define I2S_DMA_BUFFER_MAX_SIZE 4092 #if SOC_I2S_SUPPORTS_ADC_DAC @@ -1021,11 +1029,14 @@ static void i2s_set_clock_legacy(i2s_port_t i2s_num) i2s_clk_config_t *clk_cfg = &p_i2s[i2s_num]->clk_cfg; i2s_hal_clock_info_t clk_info; i2s_calculate_clock(i2s_num, &clk_info); - if (p_i2s[i2s_num]->dir & I2S_DIR_TX) { - i2s_hal_set_tx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src); - } - if (p_i2s[i2s_num]->dir & I2S_DIR_RX) { - i2s_hal_set_rx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src); + I2S_RCC_ATOMIC() { + I2S_RCC_ENV_DECLARE; + if (p_i2s[i2s_num]->dir & I2S_DIR_TX) { + i2s_hal_set_tx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src); + } + if (p_i2s[i2s_num]->dir & I2S_DIR_RX) { + i2s_hal_set_rx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src); + } } } @@ -1479,17 +1490,6 @@ static esp_err_t i2s_init_legacy(i2s_port_t i2s_num, int intr_alloc_flag) ESP_RETURN_ON_ERROR(i2s_realloc_dma_buffer(i2s_num, p_i2s[i2s_num]->rx), TAG, "Allocate I2S dma rx buffer failed"); } - /* Initialize I2S DMA object */ -#if SOC_I2S_HW_VERSION_2 - /* Enable tx/rx submodule clock */ - if (p_i2s[i2s_num]->dir & I2S_DIR_TX) { - i2s_ll_tx_enable_clock(p_i2s[i2s_num]->hal.dev); - } - if (p_i2s[i2s_num]->dir & I2S_DIR_RX) { - i2s_ll_rx_enable_clock(p_i2s[i2s_num]->hal.dev); - } -#endif - return ESP_OK; } @@ -1538,12 +1538,15 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) #if SOC_I2S_SUPPORTS_APLL if (obj->use_apll) { - // switch back to PLL clock source - if (obj->dir & I2S_DIR_TX) { - i2s_ll_tx_clk_set_src(obj->hal.dev, I2S_CLK_SRC_DEFAULT); - } - if (obj->dir & I2S_DIR_RX) { - i2s_ll_rx_clk_set_src(obj->hal.dev, I2S_CLK_SRC_DEFAULT); + I2S_RCC_ATOMIC() { + I2S_RCC_ENV_DECLARE; + // switch back to PLL clock source + if (obj->dir & I2S_DIR_TX) { + i2s_ll_tx_clk_set_src(obj->hal.dev, I2S_CLK_SRC_DEFAULT); + } + if (obj->dir & I2S_DIR_RX) { + i2s_ll_rx_clk_set_src(obj->hal.dev, I2S_CLK_SRC_DEFAULT); + } } periph_rtc_apll_release(); } @@ -1556,11 +1559,13 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) } #endif #if SOC_I2S_HW_VERSION_2 - if (obj->dir & I2S_DIR_TX) { - i2s_ll_tx_disable_clock(obj->hal.dev); - } - if (obj->dir & I2S_DIR_RX) { - i2s_ll_rx_disable_clock(obj->hal.dev); + I2S_RCC_ATOMIC() { + if (obj->dir & I2S_DIR_TX) { + i2s_ll_tx_disable_clock(obj->hal.dev); + } + if (obj->dir & I2S_DIR_RX) { + i2s_ll_rx_disable_clock(obj->hal.dev); + } } #endif /* Disable module clock */ @@ -1904,8 +1909,9 @@ esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name) if (!comp_using_i2s[id]) { ret = ESP_OK; comp_using_i2s[id] = comp_name; - periph_module_enable(i2s_periph_signal[id].module); - i2s_ll_enable_clock(I2S_LL_GET_HW(id)); + I2S_RCC_ATOMIC() { + i2s_ll_enable_clock(I2S_LL_GET_HW(id)); + } } portEXIT_CRITICAL(&i2s_spinlock[id]); return ret; @@ -1920,8 +1926,9 @@ esp_err_t i2s_platform_release_occupation(int id) ret = ESP_OK; comp_using_i2s[id] = NULL; /* Disable module clock */ - periph_module_disable(i2s_periph_signal[id].module); - i2s_ll_disable_clock(I2S_LL_GET_HW(id)); + I2S_RCC_ATOMIC() { + i2s_ll_disable_clock(I2S_LL_GET_HW(id)); + } } portEXIT_CRITICAL(&i2s_spinlock[id]); return ret; diff --git a/components/driver/i2s/i2s_common.c b/components/driver/i2s/i2s_common.c index d1e7f2dbde..41dde28b77 100644 --- a/components/driver/i2s/i2s_common.c +++ b/components/driver/i2s/i2s_common.c @@ -25,6 +25,11 @@ #include "soc/soc_caps.h" #include "hal/gpio_hal.h" #include "hal/i2s_hal.h" +#if CONFIG_IDF_TARGET_ESP32P4 +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" +#include "rom/cache.h" +#endif #if SOC_I2S_SUPPORTS_ADC_DAC #include "hal/adc_ll.h" @@ -35,7 +40,6 @@ #endif #include "esp_private/i2s_platform.h" -#include "esp_private/periph_ctrl.h" #include "esp_private/esp_clk.h" #include "driver/gpio.h" @@ -261,6 +265,7 @@ static esp_err_t i2s_register_channel(i2s_controller_t *i2s_obj, i2s_dir_t dir, new_chan->callbacks.on_send_q_ovf = NULL; new_chan->dma.rw_pos = 0; new_chan->dma.curr_ptr = NULL; + new_chan->dma.curr_desc = NULL; new_chan->start = NULL; new_chan->stop = NULL; @@ -330,6 +335,26 @@ uint32_t i2s_get_buf_size(i2s_chan_handle_t handle, uint32_t data_bit_width, uin uint32_t bytes_per_sample = ((data_bit_width + 15) / 16) * 2; uint32_t bytes_per_frame = bytes_per_sample * active_chan; uint32_t bufsize = dma_frame_num * bytes_per_frame; +#if CONFIG_IDF_TARGET_ESP32P4 + /* bufsize need to align with cache line size */ + uint32_t alignment = cache_hal_get_cache_line_size(CACHE_TYPE_DATA); + uint32_t aligned_frame_num = dma_frame_num; + /* To make the buffer aligned with the cache line size, search for the ceil aligned size first, + If the buffer size exceed the max DMA buffer size, toggle the sign to search for the floor aligned size */ + for (int sign = 1; bufsize % alignment != 0; aligned_frame_num += sign) { + bufsize = aligned_frame_num * bytes_per_frame; + /* If the buffer size exceed the max dma size */ + if (bufsize > I2S_DMA_BUFFER_MAX_SIZE) { + sign = -1; // toggle the search sign + aligned_frame_num = dma_frame_num; // Reset the frame num + bufsize = aligned_frame_num * bytes_per_frame; // Reset the bufsize + } + } + if (bufsize / bytes_per_frame != dma_frame_num) { + ESP_LOGW(TAG, "dma frame num is adjusted to %"PRIu32" to algin the dma buffer with %"PRIu32 + ", bufsize = %"PRIu32, bufsize / bytes_per_frame, alignment, bufsize); + } +#endif /* Limit DMA buffer size if it is out of range (DMA buffer limitation is 4092 bytes) */ if (bufsize > I2S_DMA_BUFFER_MAX_SIZE) { uint32_t frame_num = I2S_DMA_BUFFER_MAX_SIZE / bytes_per_frame; @@ -348,18 +373,21 @@ esp_err_t i2s_free_dma_desc(i2s_chan_handle_t handle) for (int i = 0; i < handle->dma.desc_num; i++) { if (handle->dma.bufs[i]) { free(handle->dma.bufs[i]); + handle->dma.bufs[i] = NULL; } if (handle->dma.desc[i]) { free(handle->dma.desc[i]); + handle->dma.desc[i] = NULL; } } if (handle->dma.bufs) { free(handle->dma.bufs); + handle->dma.bufs = NULL; } if (handle->dma.desc) { free(handle->dma.desc); + handle->dma.desc = NULL; } - handle->dma.desc = NULL; return ESP_OK; } @@ -372,13 +400,20 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu handle->dma.desc_num = num; handle->dma.buf_size = bufsize; +#if SOC_GDMA_TRIG_PERIPH_I2S0_BUS == SOC_GDMA_BUS_AHB + uint32_t alignment = 32; + uint32_t desc_size = alignment; +#else + uint32_t alignment = 4; + uint32_t desc_size = sizeof(lldesc_t); +#endif /* Descriptors must be in the internal RAM */ handle->dma.desc = (lldesc_t **)heap_caps_calloc(num, sizeof(lldesc_t *), I2S_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(handle->dma.desc, ESP_ERR_NO_MEM, err, TAG, "create I2S DMA decriptor array failed"); handle->dma.bufs = (uint8_t **)heap_caps_calloc(num, sizeof(uint8_t *), I2S_MEM_ALLOC_CAPS); for (int i = 0; i < num; i++) { /* Allocate DMA descriptor */ - handle->dma.desc[i] = (lldesc_t *) heap_caps_calloc(1, sizeof(lldesc_t), I2S_DMA_ALLOC_CAPS); + handle->dma.desc[i] = (lldesc_t *) heap_caps_aligned_calloc(alignment, 1, desc_size, I2S_DMA_ALLOC_CAPS); ESP_GOTO_ON_FALSE(handle->dma.desc[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA description failed"); handle->dma.desc[i]->owner = 1; handle->dma.desc[i]->eof = 1; @@ -386,15 +421,18 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu handle->dma.desc[i]->length = bufsize; handle->dma.desc[i]->size = bufsize; handle->dma.desc[i]->offset = 0; - handle->dma.bufs[i] = (uint8_t *) heap_caps_calloc(1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS); + handle->dma.bufs[i] = (uint8_t *) heap_caps_aligned_calloc(alignment, 1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(handle->dma.bufs[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed"); handle->dma.desc[i]->buf = handle->dma.bufs[i]; - ESP_GOTO_ON_FALSE(handle->dma.desc[i]->buf, ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed"); ESP_LOGV(TAG, "desc addr: %8p\tbuffer addr:%8p", handle->dma.desc[i], handle->dma.bufs[i]); } /* Connect DMA descriptor as a circle */ for (int i = 0; i < num; i++) { /* Link to the next descriptor */ STAILQ_NEXT(handle->dma.desc[i], qe) = (i < (num - 1)) ? (handle->dma.desc[i + 1]) : handle->dma.desc[0]; +#if CONFIG_IDF_TARGET_ESP32P4 + Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)(handle->dma.desc[i]), desc_size); +#endif } if (handle->dir == I2S_DIR_RX) { i2s_ll_rx_set_eof_num(handle->controller->hal.dev, bufsize); @@ -459,6 +497,9 @@ static bool IRAM_ATTR i2s_dma_rx_callback(gdma_channel_handle_t dma_chan, gdma_e uint32_t dummy; finish_desc = (lldesc_t *)event_data->rx_eof_desc_addr; +#if CONFIG_IDF_TARGET_ESP32P4 + Cache_Invalidate_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)finish_desc->buf, handle->dma.buf_size); +#endif i2s_event_data_t evt = { .data = &(finish_desc->buf), .size = handle->dma.buf_size, @@ -487,7 +528,7 @@ static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_e lldesc_t *finish_desc; uint32_t dummy; - finish_desc = (lldesc_t *)(event_data->tx_eof_desc_addr); + finish_desc = (lldesc_t *)event_data->tx_eof_desc_addr; i2s_event_data_t evt = { .data = &(finish_desc->buf), .size = handle->dma.buf_size, @@ -505,6 +546,9 @@ static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_e if (handle->dma.auto_clear) { uint8_t *sent_buf = (uint8_t *)finish_desc->buf; memset(sent_buf, 0, handle->dma.buf_size); +#if CONFIG_IDF_TARGET_ESP32P4 + Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)sent_buf, handle->dma.buf_size); +#endif } xQueueSendFromISR(handle->msg_queue, &(finish_desc->buf), &need_yield2); @@ -646,7 +690,7 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag) gdma_register_rx_event_callbacks(handle->dma.dma_chan, &cb, handle); } #else - intr_flag |= ESP_INTR_FLAG_SHARED; + intr_flag |= handle->intr_flags ? handle->intr_flags : ESP_INTR_FLAG_LOWMED; /* Initialize I2S module interrupt */ if (handle->dir == I2S_DIR_TX) { esp_intr_alloc_intrstatus(i2s_periph_signal[port_id].irq, intr_flag, @@ -771,6 +815,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t * ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_TX, chan_cfg->dma_desc_num), err, TAG, "register I2S tx channel failed"); i2s_obj->tx_chan->role = chan_cfg->role; + i2s_obj->tx_chan->intr_flags = chan_cfg->intr_flags; i2s_obj->tx_chan->dma.auto_clear = chan_cfg->auto_clear; i2s_obj->tx_chan->dma.desc_num = chan_cfg->dma_desc_num; i2s_obj->tx_chan->dma.frame_num = chan_cfg->dma_frame_num; @@ -784,6 +829,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t * ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_RX, chan_cfg->dma_desc_num), err, TAG, "register I2S rx channel failed"); i2s_obj->rx_chan->role = chan_cfg->role; + i2s_obj->rx_chan->intr_flags = chan_cfg->intr_flags; i2s_obj->rx_chan->dma.desc_num = chan_cfg->dma_desc_num; i2s_obj->rx_chan->dma.frame_num = chan_cfg->dma_frame_num; i2s_obj->rx_chan->start = i2s_rx_channel_start; @@ -821,10 +867,12 @@ esp_err_t i2s_del_channel(i2s_chan_handle_t handle) bool is_bound = true; #if SOC_I2S_HW_VERSION_2 - if (dir == I2S_DIR_TX) { - i2s_ll_tx_disable_clock(handle->controller->hal.dev); - } else { - i2s_ll_rx_disable_clock(handle->controller->hal.dev); + I2S_RCC_ATOMIC() { + if (dir == I2S_DIR_TX) { + i2s_ll_tx_disable_clock(handle->controller->hal.dev); + } else { + i2s_ll_rx_disable_clock(handle->controller->hal.dev); + } } #endif #if SOC_I2S_SUPPORTS_APLL @@ -978,6 +1026,7 @@ esp_err_t i2s_channel_disable(i2s_chan_handle_t handle) xSemaphoreTake(handle->binary, portMAX_DELAY); /* Reset the descriptor pointer */ handle->dma.curr_ptr = NULL; + handle->dma.curr_desc = NULL; handle->dma.rw_pos = 0; handle->stop(handle); #if CONFIG_PM_ENABLE @@ -1005,11 +1054,11 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src, xSemaphoreTake(tx_handle->mutex, portMAX_DELAY); /* The pre-load data will be loaded from the first descriptor */ - if (tx_handle->dma.curr_ptr == NULL) { - tx_handle->dma.curr_ptr = tx_handle->dma.desc[0]; + if (tx_handle->dma.curr_desc == NULL) { + tx_handle->dma.curr_desc = tx_handle->dma.desc[0]; + tx_handle->dma.curr_ptr = (void *)tx_handle->dma.desc[0]->buf; tx_handle->dma.rw_pos = 0; } - lldesc_t *desc_ptr = (lldesc_t *)tx_handle->dma.curr_ptr; /* Loop until no bytes in source buff remain or the descriptors are full */ while (remain_bytes) { @@ -1020,7 +1069,10 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src, break; } /* Load the data from the last loaded position */ - memcpy((uint8_t *)(desc_ptr->buf + tx_handle->dma.rw_pos), data_ptr, bytes_can_load); + memcpy((uint8_t *)(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos), data_ptr, bytes_can_load); +#if CONFIG_IDF_TARGET_ESP32P4 + Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos), (uint32_t)bytes_can_load); +#endif data_ptr += bytes_can_load; // Move forward the data pointer total_loaded_bytes += bytes_can_load; // Add to the total loaded bytes remain_bytes -= bytes_can_load; // Update the remaining bytes to be loaded @@ -1030,9 +1082,9 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src, /* If the next descriptor is not the first descriptor, keep load to the first descriptor * otherwise all descriptor has been loaded, break directly, the dma buffer position * will remain at the end of the last dma buffer */ - if (STAILQ_NEXT(desc_ptr, qe) != tx_handle->dma.desc[0]) { - desc_ptr = STAILQ_NEXT(desc_ptr, qe); - tx_handle->dma.curr_ptr = (void *)desc_ptr; + if (STAILQ_NEXT((lldesc_t *)tx_handle->dma.curr_desc, qe) != tx_handle->dma.desc[0]) { + tx_handle->dma.curr_desc = STAILQ_NEXT((lldesc_t *)tx_handle->dma.curr_desc, qe); + tx_handle->dma.curr_ptr = (void *)(((lldesc_t *)tx_handle->dma.curr_desc)->buf); tx_handle->dma.rw_pos = 0; } else { break; @@ -1077,6 +1129,9 @@ esp_err_t i2s_channel_write(i2s_chan_handle_t handle, const void *src, size_t si bytes_can_write = size; } memcpy(data_ptr, src_byte, bytes_can_write); +#if CONFIG_IDF_TARGET_ESP32P4 + Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)data_ptr, (uint32_t)bytes_can_write); +#endif size -= bytes_can_write; src_byte += bytes_can_write; handle->dma.rw_pos += bytes_can_write; @@ -1146,8 +1201,9 @@ esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name) if ((!g_i2s.controller[id]) && (g_i2s.comp_name[id] == NULL)) { g_i2s.comp_name[id] = comp_name; /* Enable module clock */ - periph_module_enable(i2s_periph_signal[id].module); - i2s_ll_enable_clock(I2S_LL_GET_HW(id)); + I2S_RCC_ATOMIC() { + i2s_ll_enable_clock(I2S_LL_GET_HW(id)); + } } else { occupied_comp = g_i2s.comp_name[id]; ret = ESP_ERR_NOT_FOUND; @@ -1167,8 +1223,9 @@ esp_err_t i2s_platform_release_occupation(int id) if (!g_i2s.controller[id]) { g_i2s.comp_name[id] = NULL; /* Disable module clock */ - periph_module_disable(i2s_periph_signal[id].module); - i2s_ll_disable_clock(I2S_LL_GET_HW(id)); + I2S_RCC_ATOMIC() { + i2s_ll_disable_clock(I2S_LL_GET_HW(id)); + } } else { ret = ESP_ERR_INVALID_STATE; } @@ -1183,3 +1240,25 @@ size_t inline i2s_platform_get_dma_buffer_offset(void) * then find the corresponding field , the address of this field is the offset of this type */ return (size_t)&(((i2s_chan_handle_t)0)->dma.bufs); } + +#if SOC_I2S_SUPPORTS_TX_SYNC_CNT +uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle) +{ + return i2s_ll_tx_get_bclk_sync_count(tx_handle->controller->hal.dev); +} + +uint32_t i2s_sync_get_fifo_count(i2s_chan_handle_t tx_handle) +{ + return i2s_ll_tx_get_fifo_sync_count(tx_handle->controller->hal.dev); +} + +void i2s_sync_reset_bclk_count(i2s_chan_handle_t tx_handle) +{ + i2s_ll_tx_reset_bclk_sync_counter(tx_handle->controller->hal.dev); +} + +void i2s_sync_reset_fifo_count(i2s_chan_handle_t tx_handle) +{ + i2s_ll_tx_reset_fifo_sync_counter(tx_handle->controller->hal.dev); +} +#endif // SOC_I2S_SUPPORTS_TX_SYNC_CNT diff --git a/components/driver/i2s/i2s_pdm.c b/components/driver/i2s/i2s_pdm.c index 7991f6e969..2426e896fe 100644 --- a/components/driver/i2s/i2s_pdm.c +++ b/components/driver/i2s/i2s_pdm.c @@ -70,7 +70,10 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx portENTER_CRITICAL(&g_i2s.spinlock); /* Set clock configurations in HAL*/ - i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + I2S_RCC_ATOMIC() { + I2S_RCC_ENV_DECLARE; + i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + } #if SOC_I2S_HW_VERSION_2 /* Work around for PDM TX clock, overwrite the raw division directly to reduce the noise * This set of coefficients is a special division to reduce the background noise in PDM TX mode */ @@ -187,10 +190,7 @@ esp_err_t i2s_channel_init_pdm_tx_mode(i2s_chan_handle_t handle, const i2s_pdm_t ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed"); i2s_ll_tx_enable_pdm(handle->controller->hal.dev); -#if SOC_I2S_HW_VERSION_2 - /* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */ - i2s_ll_tx_enable_clock(handle->controller->hal.dev); -#endif + #ifdef CONFIG_PM_ENABLE esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX; #if SOC_I2S_SUPPORTS_APLL @@ -357,7 +357,10 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx portENTER_CRITICAL(&g_i2s.spinlock); /* Set clock configurations in HAL*/ - i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + I2S_RCC_ATOMIC() { + I2S_RCC_ENV_DECLARE; + i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + } portEXIT_CRITICAL(&g_i2s.spinlock); /* Update the mode info: clock configuration */ @@ -467,10 +470,7 @@ esp_err_t i2s_channel_init_pdm_rx_mode(i2s_chan_handle_t handle, const i2s_pdm_r ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed"); i2s_ll_rx_enable_pdm(handle->controller->hal.dev); -#if SOC_I2S_HW_VERSION_2 - /* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */ - i2s_ll_rx_enable_clock(handle->controller->hal.dev); -#endif + #ifdef CONFIG_PM_ENABLE esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX; #if SOC_I2S_SUPPORTS_APLL diff --git a/components/driver/i2s/i2s_private.h b/components/driver/i2s/i2s_private.h index 23dfe79f5f..802eb32fbb 100644 --- a/components/driver/i2s/i2s_private.h +++ b/components/driver/i2s/i2s_private.h @@ -16,8 +16,10 @@ #if SOC_GDMA_SUPPORTED #include "esp_private/gdma.h" #endif +#include "esp_private/periph_ctrl.h" #include "esp_pm.h" #include "esp_err.h" +#include "sdkconfig.h" #ifdef __cplusplus extern "C" { @@ -26,14 +28,22 @@ extern "C" { // If ISR handler is allowed to run whilst cache is disabled, // Make sure all the code and related variables used by the handler are in the SRAM #if CONFIG_I2S_ISR_IRAM_SAFE -#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED) +#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED) #define I2S_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #else -#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED) +#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED) #define I2S_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #endif //CONFIG_I2S_ISR_IRAM_SAFE #define I2S_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA) +#if !SOC_RCC_IS_INDEPENDENT +#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#define I2S_RCC_ENV_DECLARE (void)__DECLARE_RCC_ATOMIC_ENV +#else +#define I2S_RCC_ATOMIC() +#define I2S_RCC_ENV_DECLARE +#endif + #define I2S_NULL_POINTER_CHECK(tag, p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, tag, "input parameter '"#p"' is NULL") /** @@ -61,6 +71,7 @@ typedef struct { bool auto_clear; /*!< Set to auto clear DMA TX descriptor, i2s will always send zero automatically if no data to send */ uint32_t rw_pos; /*!< reading/writing pointer position */ void *curr_ptr; /*!< Pointer to current dma buffer */ + void *curr_desc; /*!< Pointer to current dma descriptor used for pre-load */ lldesc_t **desc; /*!< dma descriptor array */ uint8_t **bufs; /*!< dma buffer array */ } i2s_dma_t; @@ -88,6 +99,7 @@ struct i2s_channel_obj_t { i2s_dma_t dma; /*!< i2s dma object */ i2s_state_t state; /*!< i2s driver state. Ensuring the driver working in a correct sequence */ /* Stored configurations */ + int intr_flags; void *mode_info; /*!< Slot, clock and gpio information of each mode */ #if SOC_I2S_SUPPORTS_APLL bool apll_en; /*!< Flag of wether APLL enabled */ diff --git a/components/driver/i2s/i2s_std.c b/components/driver/i2s/i2s_std.c index 2570e3b4b2..0b32139c21 100644 --- a/components/driver/i2s/i2s_std.c +++ b/components/driver/i2s/i2s_std.c @@ -77,10 +77,13 @@ static esp_err_t i2s_std_set_clock(i2s_chan_handle_t handle, const i2s_std_clk_c portENTER_CRITICAL(&g_i2s.spinlock); /* Set clock configurations in HAL*/ - if (handle->dir == I2S_DIR_TX) { - i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); - } else { - i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + I2S_RCC_ATOMIC() { + I2S_RCC_ENV_DECLARE; + if (handle->dir == I2S_DIR_TX) { + i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + } else { + i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + } } portEXIT_CRITICAL(&g_i2s.spinlock); @@ -226,10 +229,8 @@ esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_conf /* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */ if (handle->dir == I2S_DIR_TX) { i2s_ll_tx_enable_std(handle->controller->hal.dev); - i2s_ll_tx_enable_clock(handle->controller->hal.dev); } else { i2s_ll_rx_enable_std(handle->controller->hal.dev); - i2s_ll_rx_enable_clock(handle->controller->hal.dev); } #endif diff --git a/components/driver/i2s/i2s_tdm.c b/components/driver/i2s/i2s_tdm.c index 5484881dd9..b4353f8c83 100644 --- a/components/driver/i2s/i2s_tdm.c +++ b/components/driver/i2s/i2s_tdm.c @@ -79,10 +79,13 @@ static esp_err_t i2s_tdm_set_clock(i2s_chan_handle_t handle, const i2s_tdm_clk_c portENTER_CRITICAL(&g_i2s.spinlock); /* Set clock configurations in HAL*/ - if (handle->dir == I2S_DIR_TX) { - i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); - } else { - i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + I2S_RCC_ATOMIC() { + I2S_RCC_ENV_DECLARE; + if (handle->dir == I2S_DIR_TX) { + i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + } else { + i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + } } portEXIT_CRITICAL(&g_i2s.spinlock); @@ -232,10 +235,8 @@ esp_err_t i2s_channel_init_tdm_mode(i2s_chan_handle_t handle, const i2s_tdm_conf /* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */ if (handle->dir == I2S_DIR_TX) { i2s_ll_tx_enable_tdm(handle->controller->hal.dev); - i2s_ll_tx_enable_clock(handle->controller->hal.dev); } else { i2s_ll_rx_enable_tdm(handle->controller->hal.dev); - i2s_ll_rx_enable_clock(handle->controller->hal.dev); } #endif #ifdef CONFIG_PM_ENABLE @@ -275,12 +276,12 @@ esp_err_t i2s_channel_reconfig_tdm_clock(i2s_chan_handle_t handle, const i2s_tdm #if SOC_I2S_SUPPORTS_APLL /* Enable APLL and acquire its lock when the clock source is changed to APLL */ - if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && clk_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) { + if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && tdm_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) { periph_rtc_apll_acquire(); handle->apll_en = true; } /* Disable APLL and release its lock when clock source is changed to 160M_PLL */ - if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && clk_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) { + if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && tdm_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) { periph_rtc_apll_release(); handle->apll_en = false; } diff --git a/components/driver/i2s/include/driver/i2s_common.h b/components/driver/i2s/include/driver/i2s_common.h index 819ab0d23f..fb2c99a4f1 100644 --- a/components/driver/i2s/include/driver/i2s_common.h +++ b/components/driver/i2s/include/driver/i2s_common.h @@ -25,6 +25,7 @@ extern "C" { .dma_desc_num = 6, \ .dma_frame_num = 240, \ .auto_clear = false, \ + .intr_flags = 0, \ } #define I2S_GPIO_UNUSED GPIO_NUM_NC /*!< Used in i2s_gpio_config_t for signals which are not used */ @@ -63,6 +64,7 @@ typedef struct { * it should be the multiple of '3' when the data bit width is 24. */ bool auto_clear; /*!< Set to auto clear DMA TX buffer, i2s will always send zero automatically if no data to send */ + int intr_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */ } i2s_chan_config_t; /** diff --git a/components/driver/i2s/include/driver/i2s_pdm.h b/components/driver/i2s/include/driver/i2s_pdm.h index d8bd632c99..11601166aa 100644 --- a/components/driver/i2s/include/driver/i2s_pdm.h +++ b/components/driver/i2s/include/driver/i2s_pdm.h @@ -23,6 +23,23 @@ extern "C" { #if SOC_I2S_SUPPORTS_PDM_RX +#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER +/** + * @brief PDM format in 2 slots(RX) + * @param bits_per_sample i2s data bit width, only support 16 bits for PDM mode + * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO + */ +#define I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \ + .data_bit_width = bits_per_sample, \ + .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \ + .slot_mode = mono_or_stereo, \ + .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \ + I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \ + .hpf_en = true, \ + .hpf_cut_off_freq_hz = 35.5, \ + .amplify_num = 1, \ +} +#else /** * @brief PDM format in 2 slots(RX) * @param bits_per_sample i2s data bit width, only support 16 bits for PDM mode @@ -35,6 +52,7 @@ extern "C" { .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \ I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \ } +#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER /** * @brief i2s default pdm rx clock configuration @@ -48,23 +66,7 @@ extern "C" { .bclk_div = 8, \ } -#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER -/** - * @brief PDM format in 2 slots(RX) - * @param bits_per_sample i2s data bit width, only support 16 bits for PDM mode - * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO - */ -#define I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \ - .data_bit_width = bits_per_sample, \ - .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \ - .slot_mode = mono_or_stereo, \ - .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \ - I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \ - .hp_en = true, \ - .hp_cut_off_freq_hz = 35.5, \ - .amplify_num = 1, \ /* TODO: maybe need an enum */ -} -#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + /** * @brief I2S slot configuration for pdm rx mode @@ -329,8 +331,8 @@ typedef struct { i2s_pdm_sig_scale_t sinc_scale; /*!< Sinc filter scaling value */ #if SOC_I2S_HW_VERSION_2 i2s_pdm_tx_line_mode_t line_mode; /*!< PDM TX line mode, one-line codec, one-line dac, two-line dac mode can be selected */ - bool hp_en; /*!< High pass filter enable */ - float hp_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */ + bool hpf_en; /*!< High pass filter enable */ + float hpf_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */ uint32_t sd_dither; /*!< Sigma-delta filter dither */ uint32_t sd_dither2; /*!< Sigma-delta filter dither2 */ #endif // SOC_I2S_HW_VERSION_2 diff --git a/components/driver/include/esp_private/i2s_sync.h b/components/driver/include/esp_private/i2s_sync.h new file mode 100644 index 0000000000..83c4190397 --- /dev/null +++ b/components/driver/include/esp_private/i2s_sync.h @@ -0,0 +1,71 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// DO NOT USE THESE APIS IN YOUR APPLICATIONS +// The following APIs are for internal use, public to other IDF components, but not for users' applications. + +/** + * This file is used for getting the bclk and fifo sending count + * for the synchronization among different I2S ports. + * + * The APIs in this file might be called frequently, so they are made light-weight and flexible to be called + * + * NOTE: These APIs are private for ESP internal usages. + * Please be aware of the risk that APIs might be changed regarding the use case. + */ + +#pragma once + +#include +#include "driver/i2s_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_I2S_SUPPORTS_TX_SYNC_CNT + +/** + * @brief Get the counter number of BCLK ticks + * @note The BCLK tick count reflects the real data that have sent on line + * + * @param[in] tx_handle The I2S tx channel handle + * @return + * - BCLK tick count + */ +uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle); + +/** + * @brief Get the counter number of fifo + * @note The FIFO count reflects how many slots have processed + * Normally, fifo_cnt = slot_bit_width * bclk_cnt + * If fifo_cnt < slot_bit_width * bclk_cnt, that means some data are still stuck in the I2S controller + * + * @param[in] tx_handle The I2S tx channel handle + * @return + * - FIFO slot count + */ +uint32_t i2s_sync_get_fifo_count(i2s_chan_handle_t tx_handle); + +/** + * @brief Reset the bclk counter + * + * @param[in] tx_handle The I2S tx channel handle + */ +void i2s_sync_reset_bclk_count(i2s_chan_handle_t tx_handle); + +/** + * @brief Reset the fifo counter + * + * @param[in] tx_handle The I2S tx channel handle + */ +void i2s_sync_reset_fifo_count(i2s_chan_handle_t tx_handle); + +#endif // SOC_I2S_SUPPORTS_TX_SYNC_CNT + +#ifdef __cplusplus +} +#endif diff --git a/components/driver/test_apps/.build-test-rules.yml b/components/driver/test_apps/.build-test-rules.yml index f69afb0d59..b1fd554b0c 100644 --- a/components/driver/test_apps/.build-test-rules.yml +++ b/components/driver/test_apps/.build-test-rules.yml @@ -33,15 +33,27 @@ components/driver/test_apps/i2c_test_apps: components/driver/test_apps/i2s_test_apps: disable: - if: SOC_I2S_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners components/driver/test_apps/i2s_test_apps/i2s: disable: - if: SOC_I2S_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners components/driver/test_apps/i2s_test_apps/i2s_multi_dev: disable: - if: SOC_I2S_SUPPORTED != 1 - if: SOC_I2S_HW_VERSION_2 != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac: disable: @@ -50,6 +62,10 @@ components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac: components/driver/test_apps/i2s_test_apps/legacy_i2s_driver: disable: - if: SOC_I2S_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners components/driver/test_apps/ledc: disable: diff --git a/components/driver/test_apps/i2s_test_apps/i2s/README.md b/components/driver/test_apps/i2s_test_apps/i2s/README.md index 19f1d19a54..a79fcf4c5e 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s/README.md +++ b/components/driver/test_apps/i2s_test_apps/i2s/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c index a419ea6c2e..0cbe69b6ff 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c +++ b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c @@ -11,6 +11,7 @@ #include "freertos/task.h" #include "freertos/queue.h" #include "freertos/semphr.h" +#include "sdkconfig.h" #include "driver/gpio.h" #include "hal/gpio_hal.h" #include "esp_err.h" @@ -775,7 +776,7 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_c // pcnt will count the pulse number on WS signal in 100ms TEST_ESP_OK(pcnt_unit_clear_count(pcnt_unit)); TEST_ESP_OK(pcnt_unit_start(pcnt_unit)); - vTaskDelay(pdMS_TO_TICKS(TEST_I2S_PERIOD_MS)); + esp_rom_delay_us(100 * 1000); TEST_ESP_OK(pcnt_unit_stop(pcnt_unit)); TEST_ESP_OK(pcnt_unit_get_count(pcnt_unit, &real_pulse)); printf("[%"PRIu32" Hz] %d pulses, expected %d, err %d\n", test_freq[i], real_pulse, expt_pulse, real_pulse - expt_pulse); @@ -803,9 +804,10 @@ TEST_CASE("I2S_default_PLL_clock_test", "[i2s]") TEST_ESP_OK(i2s_new_channel(&chan_cfg, NULL, &rx_handle)); TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); -#if SOC_I2S_SUPPORTS_PLL_F160M || SOC_I2S_SUPPORTS_PLL_F96M +// ESP32-P4 has no PLL except XTAL +#if !CONFIG_IDF_TARGET_ESP32P4 i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg); -#endif // SOC_I2S_SUPPORTS_PLL_F160M || SOC_I2S_SUPPORTS_PLL_F96M +#endif // CONFIG_IDF_TARGET_ESP32P4 #if SOC_I2S_SUPPORTS_XTAL std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_XTAL; i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg); @@ -882,7 +884,6 @@ TEST_CASE("I2S_package_lost_test", "[i2s]") for (i = 0; i < test_num; i++) { printf("Testing %"PRIu32" Hz sample rate\n", test_freq[i]); std_cfg.clk_cfg.sample_rate_hz = test_freq[i]; - std_cfg.clk_cfg.sample_rate_hz = test_freq[i]; TEST_ESP_OK(i2s_channel_reconfig_std_clock(rx_handle, &std_cfg.clk_cfg)); TEST_ESP_OK(i2s_channel_enable(rx_handle)); for (int j = 0; j < 10; j++) { diff --git a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s_iram.c b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s_iram.c index 518dcf4b87..021f4f30eb 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s_iram.c +++ b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s_iram.c @@ -13,6 +13,9 @@ #include "driver/i2s_std.h" #include "esp_attr.h" #include "soc/soc_caps.h" +#if CONFIG_IDF_TARGET_ESP32P4 +#include "rom/cache.h" +#endif #include "esp_private/i2s_platform.h" #include "esp_private/spi_flash_os.h" #include "../../test_inc/test_i2s.h" @@ -39,9 +42,13 @@ static void IRAM_ATTR test_i2s_iram_write(i2s_chan_handle_t tx_handle) // disable cache and non-iram ISR handlers spi_flash_guard_get()->start(); // write data into dma buffer directly, the data in dma buffer will be sent automatically - for (int i=0; i < 100; i++) { - dma_bufs[0][i] = i + 1; + for (int i = 0; i < 400; i++) { + dma_bufs[0][i] = i % 100 + 1; } +#if CONFIG_IDF_TARGET_ESP32P4 + // TODO: need to consider PSRAM if I2S driver supports EDMA + Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)dma_bufs[0], 400); +#endif // enable cache and non-iram ISR handlers spi_flash_guard_get()->end(); } @@ -52,8 +59,8 @@ TEST_CASE("i2s_iram_interrupt_safe", "[i2s]") i2s_chan_handle_t rx_chan = NULL; i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); - chan_cfg.dma_desc_num = 6; - chan_cfg.dma_frame_num = 200; + chan_cfg.dma_desc_num = 2; + chan_cfg.dma_frame_num = 100; TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_chan, &rx_chan)); i2s_std_config_t std_cfg = { .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(16000), @@ -73,14 +80,14 @@ TEST_CASE("i2s_iram_interrupt_safe", "[i2s]") }; TEST_ESP_OK(i2s_channel_init_std_mode(tx_chan, &std_cfg)); TEST_ESP_OK(i2s_channel_init_std_mode(rx_chan, &std_cfg)); - int is_triggerred = 0; + int is_triggered = 0; i2s_event_callbacks_t cbs = { .on_recv = NULL, .on_recv_q_ovf = NULL, .on_sent = test_i2s_tx_done_callback, .on_send_q_ovf = NULL, }; - TEST_ESP_OK(i2s_channel_register_event_callback(tx_chan, &cbs, &is_triggerred)); + TEST_ESP_OK(i2s_channel_register_event_callback(tx_chan, &cbs, &is_triggered)); TEST_ESP_OK(i2s_channel_enable(tx_chan)); TEST_ESP_OK(i2s_channel_enable(rx_chan)); @@ -92,7 +99,7 @@ TEST_CASE("i2s_iram_interrupt_safe", "[i2s]") for (int retry = 0; retry < 3; retry++) { i2s_channel_read(rx_chan, recv_buf, 2000, &r_bytes, pdMS_TO_TICKS(1000)); for (i = 0; i < 2000 - 100; i++) { - if (recv_buf[i] != 0) { + if (recv_buf[i] == 1 && recv_buf[i + 1] == 2) { goto finish; } } @@ -107,7 +114,7 @@ finish: for (int j = 1; j <= 100; j++) { TEST_ASSERT_EQUAL_UINT8(recv_buf[i++], j); } - TEST_ASSERT(is_triggerred); + TEST_ASSERT(is_triggered); free(recv_buf); } diff --git a/components/driver/test_apps/i2s_test_apps/i2s_multi_dev/README.md b/components/driver/test_apps/i2s_test_apps/i2s_multi_dev/README.md index 541c8b1e9a..bb5058d387 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s_multi_dev/README.md +++ b/components/driver/test_apps/i2s_test_apps/i2s_multi_dev/README.md @@ -1,3 +1,3 @@ -| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md index 19f1d19a54..a79fcf4c5e 100644 --- a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md +++ b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/i2s_test_apps/test_inc/test_i2s.h b/components/driver/test_apps/i2s_test_apps/test_inc/test_i2s.h index 4c1a3763b5..1adaf4e1fc 100644 --- a/components/driver/test_apps/i2s_test_apps/test_inc/test_i2s.h +++ b/components/driver/test_apps/i2s_test_apps/test_inc/test_i2s.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -44,6 +44,14 @@ extern "C" { #define SLAVE_WS_IO 15 #define DATA_IN_IO 19 #define DATA_OUT_IO 18 +#elif CONFIG_IDF_TARGET_ESP32P4 +#define MASTER_MCK_IO 34 +#define MASTER_BCK_IO 35 +#define MASTER_WS_IO 48 +#define SLAVE_BCK_IO 10 +#define SLAVE_WS_IO 11 +#define DATA_IN_IO 12 +#define DATA_OUT_IO 49 #else #define MASTER_MCK_IO 0 #define MASTER_BCK_IO 4 diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index c03f56ce02..d718d17a34 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -18,6 +18,7 @@ #include "hal/misc.h" #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" +#include "soc/dport_reg.h" #include "hal/i2s_types.h" #include "hal/hal_utils.h" @@ -90,12 +91,23 @@ static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en) */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { + if (hw == &I2S0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + } else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + } if (hw->clkm_conf.clk_en == 0) { hw->clkm_conf.clk_en = 1; hw->conf2.val = 0; } } +/// 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_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) + /** * @brief I2S module disable clock. * @@ -106,8 +118,19 @@ static inline void i2s_ll_disable_clock(i2s_dev_t *hw) if (hw->clkm_conf.clk_en == 1) { hw->clkm_conf.clk_en = 0; } + if (hw == &I2S0) { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + } } +/// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) + /** * @brief I2S tx msb right enable * diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index 1bf9d1ecc4..e79f5ec9c5 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -17,6 +17,7 @@ #include "hal/assert.h" #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" +#include "soc/system_struct.h" #include "hal/i2s_types.h" #include "hal/hal_utils.h" @@ -43,9 +44,15 @@ extern "C" { */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { + SYSTEM.perip_clk_en0.reg_i2s1_clk_en = 1; + SYSTEM.perip_rst_en0.reg_i2s1_rst = 0; hw->tx_clkm_conf.clk_en = 1; } +/// 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_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) + /** * @brief I2S module disable I2S clock. * @@ -54,8 +61,14 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) static inline void i2s_ll_disable_clock(i2s_dev_t *hw) { hw->tx_clkm_conf.clk_en = 0; + SYSTEM.perip_clk_en0.reg_i2s1_clk_en = 0; + SYSTEM.perip_rst_en0.reg_i2s1_rst = 1; } +/// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) + /** * @brief Enable I2S tx module clock * @@ -86,6 +99,11 @@ static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) hw->tx_clkm_conf.tx_clk_active = 0; } +/// 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 +// i2s_ll_tx_disable_clock don't need RCC ENV actually, but still defined here for compatiblity +#define i2s_ll_tx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_tx_disable_clock(__VA_ARGS__) + /** * @brief Disable I2S rx module clock * @@ -96,6 +114,11 @@ static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) hw->rx_clkm_conf.rx_clk_active = 0; } +/// 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 +// i2s_ll_rx_disable_clock don't need RCC ENV actually, but still defined here for compatiblity +#define i2s_ll_rx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_rx_disable_clock(__VA_ARGS__) + /** * @brief I2S mclk use tx module clock * diff --git a/components/hal/esp32c6/include/hal/i2s_ll.h b/components/hal/esp32c6/include/hal/i2s_ll.h index 33da02f677..86c5788fbf 100644 --- a/components/hal/esp32c6/include/hal/i2s_ll.h +++ b/components/hal/esp32c6/include/hal/i2s_ll.h @@ -44,8 +44,8 @@ extern "C" { */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { - // The clock gate enabling is moved to `periph_module_enable` - (void)hw; + PCR.i2s_conf.i2s_clk_en = 1; + PCR.i2s_conf.i2s_rst_en = 0; } /** @@ -55,8 +55,8 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_disable_clock(i2s_dev_t *hw) { - // The clock gate disabling is moved to `periph_module_disable` - (void)hw; + PCR.i2s_conf.i2s_clk_en = 0; + PCR.i2s_conf.i2s_rst_en = 1; } /** diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index c7cd73dd4f..9f9e648ce8 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -45,8 +45,8 @@ extern "C" { */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { - // The clock gate enabling is moved to `periph_module_enable` - (void)hw; + PCR.i2s_conf.i2s_clk_en = 1; + PCR.i2s_conf.i2s_rst_en = 0; } /** @@ -56,8 +56,8 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_disable_clock(i2s_dev_t *hw) { - // The clock gate disabling is moved to `periph_module_disable` - (void)hw; + PCR.i2s_conf.i2s_clk_en = 0; + PCR.i2s_conf.i2s_rst_en = 1; } /** diff --git a/components/hal/esp32p4/include/hal/clk_gate_ll.h b/components/hal/esp32p4/include/hal/clk_gate_ll.h index 48e7a09509..8b21f7dfbb 100644 --- a/components/hal/esp32p4/include/hal/clk_gate_ll.h +++ b/components/hal/esp32p4/include/hal/clk_gate_ll.h @@ -36,12 +36,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph) return HP_SYS_CLKRST_REG_I2C0_APB_CLK_EN; case PERIPH_I2C1_MODULE: return HP_SYS_CLKRST_REG_I2C1_APB_CLK_EN; - case PERIPH_I2S0_MODULE: - return HP_SYS_CLKRST_REG_I2S0_TX_CLK_EN | HP_SYS_CLKRST_REG_I2S0_RX_CLK_EN; - case PERIPH_I2S1_MODULE: - return HP_SYS_CLKRST_REG_I2S1_RX_CLK_EN | HP_SYS_CLKRST_REG_I2S1_TX_CLK_EN; - case PERIPH_I2S2_MODULE: - return HP_SYS_CLKRST_REG_I2S2_RX_CLK_EN | HP_SYS_CLKRST_REG_I2S2_TX_CLK_EN; case PERIPH_LCD_MODULE: return HP_SYS_CLKRST_REG_LCD_CLK_EN; case PERIPH_UART0_MODULE: @@ -151,12 +145,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en return HP_SYS_CLKRST_REG_RST_EN_CAN2; case PERIPH_LEDC_MODULE: return HP_SYS_CLKRST_REG_RST_EN_LEDC; - case PERIPH_I2S0_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_I2S0_APB; - case PERIPH_I2S1_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_I2S1_APB; - case PERIPH_I2S2_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_I2S2_APB; case PERIPH_GPSPI2_MODULE: return HP_SYS_CLKRST_REG_RST_EN_SPI2; case PERIPH_GPSPI3_MODULE: @@ -294,10 +282,6 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph) case PERIPH_TWAI1_MODULE: case PERIPH_TWAI2_MODULE: case PERIPH_LEDC_MODULE: - case PERIPH_I2S0_MODULE: - return HP_SYS_CLKRST_HP_RST_EN1_REG; - case PERIPH_I2S1_MODULE: - case PERIPH_I2S2_MODULE: case PERIPH_GPSPI2_MODULE: case PERIPH_GPSPI3_MODULE: case PERIPH_CAM_MODULE: diff --git a/components/hal/esp32p4/include/i2s_ll.h b/components/hal/esp32p4/include/hal/i2s_ll.h similarity index 76% rename from components/hal/esp32p4/include/i2s_ll.h rename to components/hal/esp32p4/include/hal/i2s_ll.h index c2ce486e04..3d7027ede3 100644 --- a/components/hal/esp32p4/include/i2s_ll.h +++ b/components/hal/esp32p4/include/hal/i2s_ll.h @@ -17,7 +17,7 @@ #include "hal/assert.h" #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" -#include "soc/pcr_struct.h" +#include "soc/hp_sys_clkrst_struct.h" #include "hal/i2s_types.h" @@ -26,6 +26,7 @@ extern "C" { #endif #define I2S_LL_GET_HW(num) (((num) == 0)? (&I2S0) : ((num) == 1) ? (&I2S1) : (&I2S2)) +#define I2S_LL_GET_ID(hw) (((hw) == &I2S0)? 0 : ((hw) == &I2S1) ? 1 : 2) #define I2S_LL_TDM_CH_MASK (0xffff) #define I2S_LL_PDM_BCK_FACTOR (64) @@ -53,10 +54,30 @@ typedef struct { */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { - // The clock gate enabling is moved to `periph_module_enable` - (void)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.soc_clk_ctrl2.reg_i2s0_apb_clk_en = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s0_apb = 0; + break; + case 1: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s1_apb_clk_en = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s1_apb = 0; + break; + case 2: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s2_apb_clk_en = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s2_apb = 0; + break; + default: + // Never reach + HAL_ASSERT(false); + } } +/// 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_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) + /** * @brief I2S module disable I2S clock. * @@ -64,10 +85,30 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_disable_clock(i2s_dev_t *hw) { - // The clock gate disabling is moved to `periph_module_disable` - (void)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.soc_clk_ctrl2.reg_i2s0_apb_clk_en = 0; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s0_apb = 1; + break; + case 1: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s1_apb_clk_en = 0; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s1_apb = 1; + break; + case 2: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s2_apb_clk_en = 0; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s2_apb = 1; + break; + default: + // Never reach + HAL_ASSERT(false); + } } +/// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) + /** * @brief Enable I2S tx module clock * @@ -75,8 +116,18 @@ static inline void i2s_ll_disable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw) { - (void)hw; - PCR.i2s_tx_clkm_conf.i2s_tx_clkm_en = 1; + // 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_ctrl13.reg_i2s0_tx_clk_en = 1; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_tx_clk_en = 1; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_tx_clk_en = 1; + return; + } } /** @@ -86,8 +137,18 @@ static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw) { - (void)hw; - PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 1; + // 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_ctrl11.reg_i2s0_rx_clk_en = 1; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s1_rx_clk_en = 1; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s2_rx_clk_en = 1; + return; + } } /** @@ -97,10 +158,24 @@ static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) { - (void)hw; - PCR.i2s_tx_clkm_conf.i2s_tx_clkm_en = 0; + // 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_ctrl13.reg_i2s0_tx_clk_en = 0; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_tx_clk_en = 0; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_tx_clk_en = 0; + 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_tx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_tx_disable_clock(__VA_ARGS__) + /** * @brief Disable I2S rx module clock * @@ -108,10 +183,24 @@ static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) { - (void)hw; - PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 0; + // 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_ctrl11.reg_i2s0_rx_clk_en = 0; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s1_rx_clk_en = 0; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s2_rx_clk_en = 0; + 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_rx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_rx_disable_clock(__VA_ARGS__) + /** * @brief I2S mclk use tx module clock * @@ -119,8 +208,18 @@ static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) */ 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; + // 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 = 0; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_mst_clk_sel = 0; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_mst_clk_sel = 0; + return; + } } /** @@ -130,8 +229,18 @@ static inline void i2s_ll_mclk_bind_to_tx_clk(i2s_dev_t *hw) */ 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; + // 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; + } } /** @@ -200,6 +309,22 @@ static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) hw->rx_conf.rx_fifo_reset = 0; } +static inline uint32_t i2s_ll_get_clk_src(i2s_clock_src_t src) +{ + switch (src) + { + case I2S_CLK_SRC_XTAL: + return 0; + case I2S_CLK_SRC_APLL: + return 1; + case I2S_CLK_SRC_EXTERNAL: + return 2; + default: + HAL_ASSERT(false && "unsupported clock source"); + break; + } +} + /** * @brief Set TX source clock * @@ -208,18 +333,18 @@ static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) */ 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_APLL: - PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 1; - break; - default: - HAL_ASSERT(false && "unsupported clock source"); - break; + // 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); + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_tx_clk_src_sel = clk_src; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_tx_clk_src_sel = clk_src; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_tx_clk_src_sel = clk_src; + return; } } @@ -231,18 +356,18 @@ static inline void i2s_ll_tx_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) { - (void)hw; - switch (src) - { - case I2S_CLK_SRC_XTAL: - PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 0; - break; - case I2S_CLK_SRC_APLL: - PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 1; - break; - default: - HAL_ASSERT(false && "unsupported clock source"); - break; + // 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); + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.peri_clk_ctrl11.reg_i2s0_rx_clk_src_sel = clk_src; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s1_rx_clk_src_sel = clk_src; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s2_rx_clk_src_sel = clk_src; + return; } } @@ -269,14 +394,30 @@ 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; - 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; + // 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; + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_tx_div_yn1 = yn1; + 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; + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_tx_div_yn1 = yn1; + 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; + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_yn1 = yn1; + return; + } } /** @@ -291,14 +432,30 @@ 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; - 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; + // 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; + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_rx_div_yn1 = yn1; + 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; + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_yn1 = yn1; + 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; + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_rx_div_yn1 = yn1; + return; + } } /** @@ -890,13 +1047,12 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) * @brief Enable RX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param pdm_enable Set true to RX enable PDM mode */ -static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) +static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw) { - hw->rx_conf.rx_pdm_en = pdm_enable; - hw->rx_conf.rx_tdm_en = !pdm_enable; - hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = pdm_enable; + hw->rx_conf.rx_pdm_en = 1; + hw->rx_conf.rx_tdm_en = 0; + hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = 1; } /** @@ -1198,6 +1354,7 @@ static inline void i2s_ll_tx_pdm_line_mode(i2s_dev_t *hw, i2s_pdm_tx_line_mode_t * * @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; @@ -1209,8 +1366,9 @@ static inline void i2s_ll_tx_reset_fifo_sync_counter(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. * @return - * count value + * 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; @@ -1221,6 +1379,7 @@ static inline uint32_t i2s_ll_tx_get_fifo_sync_count(i2s_dev_t *hw) * * @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; @@ -1232,9 +1391,10 @@ static inline void i2s_ll_tx_reset_bclk_sync_counter(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. * @return - * count value + * fifo count value */ -static inline void i2s_ll_tx_get_bclk_sync_count(i2s_dev_t *hw) +__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; } diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index 30d481d9c8..f8791f1d19 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -18,6 +18,8 @@ #include "hal/misc.h" #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" +#include "soc/system_reg.h" +#include "soc/dport_access.h" #include "hal/i2s_types.h" #include "hal/hal_utils.h" @@ -87,6 +89,13 @@ static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en) */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { + if (hw == &I2S0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + } else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + } if (hw->clkm_conf.clk_en == 0) { hw->clkm_conf.clk_sel = 2; hw->clkm_conf.clk_en = 1; @@ -94,6 +103,10 @@ static inline void i2s_ll_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_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) + /** * @brief I2S module disable clock. * @@ -104,8 +117,19 @@ static inline void i2s_ll_disable_clock(i2s_dev_t *hw) if (hw->clkm_conf.clk_en == 1) { hw->clkm_conf.clk_en = 0; } + if (hw == &I2S0) { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + } } +/// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) + /** * @brief I2S tx msb right enable * diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 4880c6850d..ac4d99f859 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -17,6 +17,7 @@ #include "hal/assert.h" #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" +#include "soc/system_struct.h" #include "hal/i2s_types.h" #include "hal/hal_utils.h" @@ -44,9 +45,20 @@ extern "C" { */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { + if (hw == &I2S0) { + SYSTEM.perip_clk_en0.i2s0_clk_en = 1; + SYSTEM.perip_rst_en0.i2s0_rst = 0; + } else { + SYSTEM.perip_clk_en0.i2s1_clk_en = 1; + SYSTEM.perip_rst_en0.i2s1_rst = 0; + } hw->tx_clkm_conf.clk_en = 1; } +/// 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_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) + /** * @brief I2S module disable I2S clock. * @@ -55,8 +67,19 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) static inline void i2s_ll_disable_clock(i2s_dev_t *hw) { hw->tx_clkm_conf.clk_en = 0; + if (hw == &I2S0) { + SYSTEM.perip_clk_en0.i2s0_clk_en = 0; + SYSTEM.perip_rst_en0.i2s0_rst = 1; + } else { + SYSTEM.perip_clk_en0.i2s1_clk_en = 0; + SYSTEM.perip_rst_en0.i2s1_rst = 1; + } } +/// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) + /** * @brief Enable I2S tx module clock * @@ -87,6 +110,11 @@ static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) hw->tx_clkm_conf.tx_clk_active = 0; } +/// 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 +// i2s_ll_tx_disable_clock don't need RCC ENV actually, but still defined here for compatiblity +#define i2s_ll_tx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_tx_disable_clock(__VA_ARGS__) + /** * @brief Disable I2S rx module clock * @@ -97,6 +125,11 @@ static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) hw->rx_clkm_conf.rx_clk_active = 0; } +/// 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 +// i2s_ll_rx_disable_clock don't need RCC ENV actually, but still defined here for compatiblity +#define i2s_ll_rx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_rx_disable_clock(__VA_ARGS__) + /** * @brief I2S mclk use tx module clock * diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index 1803bd51f8..15653cce84 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -243,7 +243,7 @@ void i2s_hal_pdm_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha i2s_ll_rx_set_active_chan_mask(hal->dev, slot_mask); #endif // SOC_I2S_HW_VERSION_1 -#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER // TODO: add this macro to soc_caps +#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER uint32_t param0; uint32_t param5; s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_rx.hp_cut_off_freq_hz, ¶m0, ¶m5); diff --git a/components/soc/esp32c3/i2s_periph.c b/components/soc/esp32c3/i2s_periph.c index 0aad6d6cad..ec14aa72a2 100644 --- a/components/soc/esp32c3/i2s_periph.c +++ b/components/soc/esp32c3/i2s_periph.c @@ -29,7 +29,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_out_sigs[1] = I2SO_SD1_OUT_IDX, .data_in_sig = I2SI_SD_IN_IDX, - .irq = -1, + .irq = ETS_I2S1_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32c6/i2s_periph.c b/components/soc/esp32c6/i2s_periph.c index 3965e936ee..cb0a6a14ff 100644 --- a/components/soc/esp32c6/i2s_periph.c +++ b/components/soc/esp32c6/i2s_periph.c @@ -29,7 +29,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_out_sigs[1] = I2SO_SD1_OUT_IDX, .data_in_sig = I2SI_SD_IN_IDX, - .irq = -1, + .irq = ETS_I2S1_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32h2/i2s_periph.c b/components/soc/esp32h2/i2s_periph.c index 4183de00a6..cf70f2cb94 100644 --- a/components/soc/esp32h2/i2s_periph.c +++ b/components/soc/esp32h2/i2s_periph.c @@ -28,7 +28,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_out_sig = I2SO_SD_OUT_IDX, .data_in_sig = I2SI_SD_IN_IDX, - .irq = -1, + .irq = ETS_I2S1_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32p4/i2s_periph.c b/components/soc/esp32p4/i2s_periph.c index 66225f77c1..39078caab4 100644 --- a/components/soc/esp32p4/i2s_periph.c +++ b/components/soc/esp32p4/i2s_periph.c @@ -13,6 +13,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { [0] = { .mck_out_sig = I2S0_MCLK_PAD_OUT_IDX, + .mck_in_sig = I2S0_MCLK_PAD_IN_IDX, .m_tx_bck_sig = I2S0_O_BCK_PAD_OUT_IDX, .m_rx_bck_sig = I2S0_I_BCK_PAD_OUT_IDX, @@ -31,11 +32,12 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[2] = I2S0_I_SD2_PAD_IN_IDX, .data_in_sigs[3] = I2S0_I_SD3_PAD_IN_IDX, - .irq = -1, + .irq = ETS_I2S0_INTR_SOURCE, .module = PERIPH_I2S0_MODULE, }, [1] = { .mck_out_sig = I2S1_MCLK_PAD_OUT_IDX, + .mck_in_sig = I2S1_MCLK_PAD_IN_IDX, .m_tx_bck_sig = I2S1_O_BCK_PAD_OUT_IDX, .m_rx_bck_sig = I2S1_I_BCK_PAD_OUT_IDX, @@ -54,11 +56,12 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[2] = -1, .data_in_sigs[3] = -1, - .irq = -1, + .irq = ETS_I2S1_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, }, [2] = { .mck_out_sig = I2S2_MCLK_PAD_OUT_IDX, + .mck_in_sig = I2S2_MCLK_PAD_IN_IDX, .m_tx_bck_sig = I2S2_O_BCK_PAD_OUT_IDX, .m_rx_bck_sig = I2S2_I_BCK_PAD_OUT_IDX, @@ -77,7 +80,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[2] = -1, .data_in_sigs[3] = -1, - .irq = -1, + .irq = ETS_I2S2_INTR_SOURCE, .module = PERIPH_I2S2_MODULE, }, }; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 28c867a876..fbc3963a49 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -67,11 +67,11 @@ config SOC_RMT_SUPPORTED bool default y -config SOC_I2C_SUPPORTED +config SOC_I2S_SUPPORTED bool default y -config SOC_I2S_SUPPORTED +config SOC_I2C_SUPPORTED bool default y @@ -471,6 +471,10 @@ config SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER bool default y +config SOC_I2S_SUPPORTS_TX_SYNC_CNT + bool + default y + config SOC_I2S_SUPPORTS_TDM bool default y @@ -1127,6 +1131,10 @@ config SOC_MODEM_CLOCK_IS_INDEPENDENT bool default n +config SOC_CLK_APLL_SUPPORTED + bool + default y + config SOC_CLK_XTAL32K_SUPPORTED bool default y diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 7137ba4a12..664e5d4b7b 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -338,7 +338,7 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of I2S */ -#define SOC_I2S_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_APLL} +#define SOC_I2S_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_APLL, I2S_CLK_SRC_EXTERNAL} /** * @brief I2S clock source enum @@ -347,6 +347,7 @@ typedef enum { I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default source clock */ I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ I2S_CLK_SRC_APLL = SOC_MOD_CLK_APLL, /*!< Select APLL as the source clock */ + I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */ } soc_periph_i2s_clk_src_t; /////////////////////////////////////////////////I2C//////////////////////////////////////////////////////////////////// diff --git a/components/soc/esp32p4/include/soc/rtc.h b/components/soc/esp32p4/include/soc/rtc.h index a27bacea55..f81d22c205 100644 --- a/components/soc/esp32p4/include/soc/rtc.h +++ b/components/soc/esp32p4/include/soc/rtc.h @@ -486,6 +486,44 @@ bool rtc_dig_8m_enabled(void); */ uint32_t rtc_clk_freq_cal(uint32_t cal_val); +/** + * @brief Enable or disable APLL + * + * Output frequency is given by the formula: + * apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) + * + * The dividend in this expression should be in the range of 240 - 600 MHz. + * + * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. + * + * @param enable true to enable, false to disable + */ +void rtc_clk_apll_enable(bool enable); + +/** + * @brief Calculate APLL clock coeffifcients + * + * @param freq expected APLL frequency + * @param o_div frequency divider, 0..31 + * @param sdm0 frequency adjustment parameter, 0..255 + * @param sdm1 frequency adjustment parameter, 0..255 + * @param sdm2 frequency adjustment parameter, 0..63 + * + * @return + * - 0 Failed + * - else Sucess + */ +uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2); + +/** + * @brief Set APLL clock coeffifcients + * + * @param o_div frequency divider, 0..31 + * @param sdm0 frequency adjustment parameter, 0..255 + * @param sdm1 frequency adjustment parameter, 0..255 + * @param sdm2 frequency adjustment parameter, 0..63 + */ +void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2); // -------------------------- CLOCK TREE DEFS ALIAS ---------------------------- // **WARNING**: The following are only for backwards compatibility. diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index a4343f13d9..984d1526f9 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -251,6 +251,7 @@ #define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_RX (1) #define SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER (1) +#define SOC_I2S_SUPPORTS_TX_SYNC_CNT (1) #define SOC_I2S_SUPPORTS_TDM (1) #define SOC_I2S_PDM_MAX_TX_LINES (2) // On I2S0 #define SOC_I2S_PDM_MAX_RX_LINES (4) // On I2S0 @@ -515,6 +516,7 @@ #define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (0) #define SOC_MODEM_CLOCK_IS_INDEPENDENT (0) +#define SOC_CLK_APLL_SUPPORTED (1) /*!< Support Audio PLL */ #define SOC_CLK_XTAL32K_SUPPORTED (1) /*!< Support to connect an external low frequency crystal */ #define SOC_CLK_OSC_SLOW_SUPPORTED (1) /*!< Support to connect an external oscillator, not a crystal */ #define SOC_CLK_RC32K_SUPPORTED (1) /*!< Support an internal 32kHz RC oscillator */ diff --git a/components/soc/esp32s3/i2s_periph.c b/components/soc/esp32s3/i2s_periph.c index 4966264483..853541bd9e 100644 --- a/components/soc/esp32s3/i2s_periph.c +++ b/components/soc/esp32s3/i2s_periph.c @@ -32,7 +32,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[2] = I2S0I_SD2_IN_IDX, .data_in_sigs[3] = I2S0I_SD3_IN_IDX, - .irq = -1, + .irq = ETS_I2S0_INTR_SOURCE, .module = PERIPH_I2S0_MODULE, }, { @@ -56,7 +56,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[2] = -1, .data_in_sigs[3] = -1, - .irq = -1, + .irq = ETS_I2S1_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, } }; diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 1622658bec..d5bc6686d6 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -55,28 +55,48 @@ examples/peripherals/i2c/i2c_tools: examples/peripherals/i2s/i2s_basic/i2s_pdm: disable: - if: SOC_I2S_SUPPORTS_PDM != 1 or IDF_TARGET == "esp32p4" + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners examples/peripherals/i2s/i2s_basic/i2s_std: disable: - if: SOC_I2S_SUPPORTED != 1 or IDF_TARGET == "esp32p4" + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners examples/peripherals/i2s/i2s_basic/i2s_tdm: disable: - if: SOC_I2S_SUPPORTS_TDM != 1 or IDF_TARGET == "esp32p4" + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm: disable: - if: SOC_I2S_SUPPORTS_TDM != 1 or (SOC_I2C_SUPPORTED != 1 or SOC_GPSPI_SUPPORTED != 1) reason: rely on I2S TDM mode to receive audio, I2C to config es7210 and SPI to save audio to SD card + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners examples/peripherals/i2s/i2s_codec/i2s_es8311: disable: - - if: (SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1) or IDF_TARGET == "esp32p4" + - if: (SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1) reason: rely on I2S STD mode and I2C to config es7210 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners examples/peripherals/i2s/i2s_recorder: disable: - - if: IDF_TARGET == "esp32p4" + - if: SOC_SDMMC_HOST_SUPPORTED != 1 or IDF_TARGET == "esp32p4" enable: - if: SOC_I2S_SUPPORTS_PDM_RX > 0 diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md b/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md index bbfcf8f9f4..7bd46beba2 100644 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md +++ b/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | # I2S ES8311 Example From 72a0746e626c8f690cfa2f1ccca2f87beb42f286 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Wed, 6 Sep 2023 10:55:47 +0800 Subject: [PATCH 3/4] refactor(apll): move the apll soc caps to clk_tree_ll --- components/driver/dac/esp32/dac_dma.c | 2 +- components/driver/dac/esp32s2/dac_dma.c | 7 +- components/driver/deprecated/i2s_legacy.c | 35 +++--- components/driver/i2s/i2s_common.c | 16 ++- components/driver/i2s/i2s_pdm.c | 6 +- components/driver/i2s/i2s_private.h | 10 +- components/driver/i2s/i2s_std.c | 3 +- components/driver/i2s/i2s_tdm.c | 3 +- .../driver/i2s/include/driver/i2s_pdm.h | 13 ++- .../esp_hw_support/include/clk_ctrl_os.h | 2 +- .../esp_hw_support/port/esp32/rtc_clk.c | 4 +- .../esp_hw_support/port/esp32s2/rtc_clk.c | 4 +- .../hal/esp32/include/hal/clk_tree_ll.h | 11 +- components/hal/esp32/include/hal/i2s_ll.h | 85 +++++++++----- components/hal/esp32c3/include/hal/i2s_ll.h | 69 ++++++----- components/hal/esp32c6/include/hal/i2s_ll.h | 30 +++-- components/hal/esp32h2/include/hal/i2s_ll.h | 30 +++-- .../hal/esp32p4/include/hal/clk_tree_ll.h | 10 ++ components/hal/esp32p4/include/hal/i2s_ll.h | 109 ++++++++++-------- .../hal/esp32s2/include/hal/clk_tree_ll.h | 11 +- components/hal/esp32s2/include/hal/i2s_ll.h | 84 +++++++++----- components/hal/esp32s3/include/hal/i2s_ll.h | 85 +++++++------- components/hal/i2s_hal.c | 40 ++++--- components/hal/include/hal/i2s_hal.h | 23 +++- .../soc/esp32/include/soc/Kconfig.soc_caps.in | 16 --- components/soc/esp32/include/soc/soc_caps.h | 7 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32p4/include/soc/soc_caps.h | 2 + .../esp32s2/include/soc/Kconfig.soc_caps.in | 16 --- components/soc/esp32s2/include/soc/soc_caps.h | 5 - 30 files changed, 430 insertions(+), 312 deletions(-) diff --git a/components/driver/dac/esp32/dac_dma.c b/components/driver/dac/esp32/dac_dma.c index b5bd20e9b9..f1e648f16d 100644 --- a/components/driver/dac/esp32/dac_dma.c +++ b/components/driver/dac/esp32/dac_dma.c @@ -47,7 +47,7 @@ static const char *TAG = "DAC_DMA"; static uint32_t s_dac_set_apll_freq(uint32_t mclk) { /* Calculate the expected APLL */ - int div = (int)((SOC_APLL_MIN_HZ / mclk) + 1); + int div = (int)((CLK_LL_APLL_MIN_HZ / mclk) + 1); /* apll_freq = mclk * div * when div = 1, hardware will still divide 2 * when div = 0, hardware will divide 255 diff --git a/components/driver/dac/esp32s2/dac_dma.c b/components/driver/dac/esp32s2/dac_dma.c index af9dfb11c6..d13c63f39b 100644 --- a/components/driver/dac/esp32s2/dac_dma.c +++ b/components/driver/dac/esp32s2/dac_dma.c @@ -19,6 +19,7 @@ #include "hal/dac_ll.h" #include "hal/adc_ll.h" #include "hal/hal_utils.h" +#include "hal/clk_tree_ll.h" #include "soc/lldesc.h" #include "soc/soc.h" #include "soc/soc_caps.h" @@ -75,9 +76,9 @@ static esp_err_t s_dac_dma_periph_set_clock(uint32_t freq_hz, bool is_apll){ uint32_t digi_ctrl_freq; // Digital controller clock if (is_apll) { /* Theoretical frequency range (due to the limitation of DAC, the maximum frequency may not reach): - * SOC_APLL_MAX_HZ: 119.24 Hz ~ 67.5 MHz - * SOC_APLL_MIN_HZ: 5.06 Hz ~ 2.65 MHz */ - digi_ctrl_freq = s_dac_set_apll_freq(freq_hz < 120 ? SOC_APLL_MIN_HZ :SOC_APLL_MAX_HZ); + * CLK_LL_APLL_MAX_HZ: 119.24 Hz ~ 67.5 MHz + * CLK_LL_APLL_MIN_HZ: 5.06 Hz ~ 2.65 MHz */ + digi_ctrl_freq = s_dac_set_apll_freq(freq_hz < 120 ? CLK_LL_APLL_MIN_HZ :CLK_LL_APLL_MAX_HZ); ESP_RETURN_ON_FALSE(digi_ctrl_freq, ESP_ERR_INVALID_ARG, TAG, "set APLL coefficients failed"); } else { digi_ctrl_freq = APB_CLK_FREQ; diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index 9397275979..9b2ec2a349 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -25,6 +25,10 @@ #include "hal/gpio_hal.h" #include "driver/i2s_types_legacy.h" #include "hal/i2s_hal.h" +#if SOC_I2S_SUPPORTS_APLL +#include "hal/clk_tree_ll.h" +#endif + #if SOC_I2S_SUPPORTS_DAC #include "hal/dac_ll.h" #include "hal/dac_types.h" @@ -58,12 +62,16 @@ static const char *TAG = "i2s(legacy)"; #define I2S_ENTER_CRITICAL(i2s_num) portENTER_CRITICAL(&i2s_spinlock[i2s_num]) #define I2S_EXIT_CRITICAL(i2s_num) portEXIT_CRITICAL(&i2s_spinlock[i2s_num]) +#if SOC_SYS_DIGI_CLKRST_REG_SHARED +#define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define I2S_CLOCK_SRC_ATOMIC() +#endif + #if !SOC_RCC_IS_INDEPENDENT -#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC() -#define I2S_RCC_ENV_DECLARE (void)__DECLARE_RCC_ATOMIC_ENV +#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC() #else #define I2S_RCC_ATOMIC() -#define I2S_RCC_ENV_DECLARE #endif #define I2S_DMA_BUFFER_MAX_SIZE 4092 @@ -641,7 +649,7 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3 #if SOC_I2S_SUPPORTS_APLL if (use_apll) { /* Calculate the expected APLL */ - int div = (int)((SOC_APLL_MIN_HZ / mclk) + 1); + int div = (int)((CLK_LL_APLL_MIN_HZ / mclk) + 1); /* apll_freq = mclk * div * when div = 1, hardware will still divide 2 * when div = 0, the final mclk will be unpredictable @@ -1029,8 +1037,7 @@ static void i2s_set_clock_legacy(i2s_port_t i2s_num) i2s_clk_config_t *clk_cfg = &p_i2s[i2s_num]->clk_cfg; i2s_hal_clock_info_t clk_info; i2s_calculate_clock(i2s_num, &clk_info); - I2S_RCC_ATOMIC() { - I2S_RCC_ENV_DECLARE; + I2S_CLOCK_SRC_ATOMIC() { if (p_i2s[i2s_num]->dir & I2S_DIR_TX) { i2s_hal_set_tx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src); } @@ -1538,14 +1545,13 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) #if SOC_I2S_SUPPORTS_APLL if (obj->use_apll) { - I2S_RCC_ATOMIC() { - I2S_RCC_ENV_DECLARE; + I2S_CLOCK_SRC_ATOMIC() { // switch back to PLL clock source if (obj->dir & I2S_DIR_TX) { - i2s_ll_tx_clk_set_src(obj->hal.dev, I2S_CLK_SRC_DEFAULT); + i2s_hal_set_tx_clock(&obj->hal, NULL, I2S_CLK_SRC_DEFAULT); } if (obj->dir & I2S_DIR_RX) { - i2s_ll_rx_clk_set_src(obj->hal.dev, I2S_CLK_SRC_DEFAULT); + i2s_hal_set_rx_clock(&obj->hal, NULL, I2S_CLK_SRC_DEFAULT); } } periph_rtc_apll_release(); @@ -1559,7 +1565,7 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) } #endif #if SOC_I2S_HW_VERSION_2 - I2S_RCC_ATOMIC() { + I2S_CLOCK_SRC_ATOMIC() { if (obj->dir & I2S_DIR_TX) { i2s_ll_tx_disable_clock(obj->hal.dev); } @@ -1910,7 +1916,9 @@ esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name) ret = ESP_OK; comp_using_i2s[id] = comp_name; I2S_RCC_ATOMIC() { - i2s_ll_enable_clock(I2S_LL_GET_HW(id)); + i2s_ll_enable_bus_clock(id, true); + i2s_ll_reset_register(id); + i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), true); } } portEXIT_CRITICAL(&i2s_spinlock[id]); @@ -1927,7 +1935,8 @@ esp_err_t i2s_platform_release_occupation(int id) comp_using_i2s[id] = NULL; /* Disable module clock */ I2S_RCC_ATOMIC() { - i2s_ll_disable_clock(I2S_LL_GET_HW(id)); + i2s_ll_enable_bus_clock(id, false); + i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), false); } } portEXIT_CRITICAL(&i2s_spinlock[id]); diff --git a/components/driver/i2s/i2s_common.c b/components/driver/i2s/i2s_common.c index 41dde28b77..269fe52b5d 100644 --- a/components/driver/i2s/i2s_common.c +++ b/components/driver/i2s/i2s_common.c @@ -36,6 +36,7 @@ #include "driver/adc_i2s_legacy.h" #endif #if SOC_I2S_SUPPORTS_APLL +#include "hal/clk_tree_ll.h" #include "clk_ctrl_os.h" #endif @@ -401,7 +402,7 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu handle->dma.buf_size = bufsize; #if SOC_GDMA_TRIG_PERIPH_I2S0_BUS == SOC_GDMA_BUS_AHB - uint32_t alignment = 32; + uint32_t alignment = 64; uint32_t desc_size = alignment; #else uint32_t alignment = 4; @@ -448,14 +449,14 @@ err: static uint32_t i2s_set_get_apll_freq(uint32_t mclk_freq_hz) { /* Calculate the expected APLL */ - int mclk_div = (int)((SOC_APLL_MIN_HZ / mclk_freq_hz) + 1); + int mclk_div = (int)((CLK_LL_APLL_MIN_HZ / mclk_freq_hz) + 1); /* apll_freq = mclk * div * when div = 1, hardware will still divide 2 * when div = 0, the final mclk will be unpredictable * So the div here should be at least 2 */ mclk_div = mclk_div < 2 ? 2 : mclk_div; uint32_t expt_freq = mclk_freq_hz * mclk_div; - if (expt_freq > SOC_APLL_MAX_HZ) { + if (expt_freq > CLK_LL_APLL_MAX_HZ) { ESP_LOGE(TAG, "The required APLL frequency exceed its maximum value"); return 0; } @@ -867,7 +868,7 @@ esp_err_t i2s_del_channel(i2s_chan_handle_t handle) bool is_bound = true; #if SOC_I2S_HW_VERSION_2 - I2S_RCC_ATOMIC() { + I2S_CLOCK_SRC_ATOMIC() { if (dir == I2S_DIR_TX) { i2s_ll_tx_disable_clock(handle->controller->hal.dev); } else { @@ -1202,7 +1203,9 @@ esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name) g_i2s.comp_name[id] = comp_name; /* Enable module clock */ I2S_RCC_ATOMIC() { - i2s_ll_enable_clock(I2S_LL_GET_HW(id)); + i2s_ll_enable_bus_clock(id, true); + i2s_ll_reset_register(id); + i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), true); } } else { occupied_comp = g_i2s.comp_name[id]; @@ -1224,7 +1227,8 @@ esp_err_t i2s_platform_release_occupation(int id) g_i2s.comp_name[id] = NULL; /* Disable module clock */ I2S_RCC_ATOMIC() { - i2s_ll_disable_clock(I2S_LL_GET_HW(id)); + i2s_ll_enable_bus_clock(id, false); + i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), false); } } else { ret = ESP_ERR_INVALID_STATE; diff --git a/components/driver/i2s/i2s_pdm.c b/components/driver/i2s/i2s_pdm.c index 2426e896fe..574247c0c8 100644 --- a/components/driver/i2s/i2s_pdm.c +++ b/components/driver/i2s/i2s_pdm.c @@ -70,8 +70,7 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx portENTER_CRITICAL(&g_i2s.spinlock); /* Set clock configurations in HAL*/ - I2S_RCC_ATOMIC() { - I2S_RCC_ENV_DECLARE; + I2S_CLOCK_SRC_ATOMIC() { i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); } #if SOC_I2S_HW_VERSION_2 @@ -357,8 +356,7 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx portENTER_CRITICAL(&g_i2s.spinlock); /* Set clock configurations in HAL*/ - I2S_RCC_ATOMIC() { - I2S_RCC_ENV_DECLARE; + I2S_CLOCK_SRC_ATOMIC() { i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); } portEXIT_CRITICAL(&g_i2s.spinlock); diff --git a/components/driver/i2s/i2s_private.h b/components/driver/i2s/i2s_private.h index 802eb32fbb..90858a04b4 100644 --- a/components/driver/i2s/i2s_private.h +++ b/components/driver/i2s/i2s_private.h @@ -36,12 +36,16 @@ extern "C" { #endif //CONFIG_I2S_ISR_IRAM_SAFE #define I2S_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA) +#if SOC_SYS_DIGI_CLKRST_REG_SHARED +#define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define I2S_CLOCK_SRC_ATOMIC() +#endif + #if !SOC_RCC_IS_INDEPENDENT -#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC() -#define I2S_RCC_ENV_DECLARE (void)__DECLARE_RCC_ATOMIC_ENV +#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC() #else #define I2S_RCC_ATOMIC() -#define I2S_RCC_ENV_DECLARE #endif #define I2S_NULL_POINTER_CHECK(tag, p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, tag, "input parameter '"#p"' is NULL") diff --git a/components/driver/i2s/i2s_std.c b/components/driver/i2s/i2s_std.c index 0b32139c21..715ca04399 100644 --- a/components/driver/i2s/i2s_std.c +++ b/components/driver/i2s/i2s_std.c @@ -77,8 +77,7 @@ static esp_err_t i2s_std_set_clock(i2s_chan_handle_t handle, const i2s_std_clk_c portENTER_CRITICAL(&g_i2s.spinlock); /* Set clock configurations in HAL*/ - I2S_RCC_ATOMIC() { - I2S_RCC_ENV_DECLARE; + I2S_CLOCK_SRC_ATOMIC() { if (handle->dir == I2S_DIR_TX) { i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); } else { diff --git a/components/driver/i2s/i2s_tdm.c b/components/driver/i2s/i2s_tdm.c index b4353f8c83..caed5c51a4 100644 --- a/components/driver/i2s/i2s_tdm.c +++ b/components/driver/i2s/i2s_tdm.c @@ -79,8 +79,7 @@ static esp_err_t i2s_tdm_set_clock(i2s_chan_handle_t handle, const i2s_tdm_clk_c portENTER_CRITICAL(&g_i2s.spinlock); /* Set clock configurations in HAL*/ - I2S_RCC_ATOMIC() { - I2S_RCC_ENV_DECLARE; + I2S_CLOCK_SRC_ATOMIC() { if (handle->dir == I2S_DIR_TX) { i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); } else { diff --git a/components/driver/i2s/include/driver/i2s_pdm.h b/components/driver/i2s/include/driver/i2s_pdm.h index 11601166aa..f697c2371b 100644 --- a/components/driver/i2s/include/driver/i2s_pdm.h +++ b/components/driver/i2s/include/driver/i2s_pdm.h @@ -35,8 +35,8 @@ extern "C" { .slot_mode = mono_or_stereo, \ .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \ I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \ - .hpf_en = true, \ - .hpf_cut_off_freq_hz = 35.5, \ + .hp_en = true, \ + .hp_cut_off_freq_hz = 35.5, \ .amplify_num = 1, \ } #else @@ -81,7 +81,10 @@ typedef struct { #if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER bool hp_en; /*!< High pass filter enable */ float hp_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */ - uint32_t amplify_num; /*!< The amplification number of the final conversion result, range 1~15, default 1 */ + uint32_t amplify_num; /*!< The amplification number of the final conversion result. + * The data that have converted from PDM to PCM module, will time 'amplify_num' additionally to amplify the final result. + * Note that it's only a multiplier of the digital PCM data, not the gain of the analog signal + * range 1~15, default 1 */ #endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER } i2s_pdm_rx_slot_config_t; @@ -331,8 +334,8 @@ typedef struct { i2s_pdm_sig_scale_t sinc_scale; /*!< Sinc filter scaling value */ #if SOC_I2S_HW_VERSION_2 i2s_pdm_tx_line_mode_t line_mode; /*!< PDM TX line mode, one-line codec, one-line dac, two-line dac mode can be selected */ - bool hpf_en; /*!< High pass filter enable */ - float hpf_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */ + bool hp_en; /*!< High pass filter enable */ + float hp_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */ uint32_t sd_dither; /*!< Sigma-delta filter dither */ uint32_t sd_dither2; /*!< Sigma-delta filter dither2 */ #endif // SOC_I2S_HW_VERSION_2 diff --git a/components/esp_hw_support/include/clk_ctrl_os.h b/components/esp_hw_support/include/clk_ctrl_os.h index 519fddee40..99366497fe 100644 --- a/components/esp_hw_support/include/clk_ctrl_os.h +++ b/components/esp_hw_support/include/clk_ctrl_os.h @@ -54,7 +54,7 @@ void periph_rtc_apll_release(void); * @brief Calculate and set APLL coefficients by given frequency * @note Have to call 'periph_rtc_apll_acquire' to enable APLL power before setting frequency * @note This calculation is based on the inequality: - * xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= SOC_APLL_MULTIPLIER_OUT_MIN_HZ(350 MHz) + * xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= CLK_LL_APLL_MULTIPLIER_MIN_HZ(350 MHz) * It will always calculate the minimum coefficients that can satisfy the inequality above, instead of loop them one by one. * which means more appropriate coefficients are likely to exist. * But this algorithm can meet almost all the cases and the accuracy can be guaranteed as well. diff --git a/components/esp_hw_support/port/esp32/rtc_clk.c b/components/esp_hw_support/port/esp32/rtc_clk.c index 384964e3d3..1856425f2e 100644 --- a/components/esp_hw_support/port/esp32/rtc_clk.c +++ b/components/esp_hw_support/port/esp32/rtc_clk.c @@ -217,7 +217,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value. * With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is * 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */ - o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2; + o_div = (int)(CLK_LL_APLL_MULTIPLIER_MIN_HZ / (float)(freq * 2) + 1) - 2; if (o_div > 31) { ESP_HW_LOGE(TAG, "Expected frequency is too small"); return 0; @@ -227,7 +227,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code. * With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is * 500 MHz / ((0 + 2) * 2) = 125000000 Hz */ - o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2; + o_div = (int)(CLK_LL_APLL_MULTIPLIER_MAX_HZ / (float)(freq * 2)) - 2; if (o_div < 0) { ESP_HW_LOGE(TAG, "Expected frequency is too big"); return 0; diff --git a/components/esp_hw_support/port/esp32s2/rtc_clk.c b/components/esp_hw_support/port/esp32s2/rtc_clk.c index 8c77c4cd88..75558b8f50 100644 --- a/components/esp_hw_support/port/esp32s2/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s2/rtc_clk.c @@ -119,7 +119,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value. * With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is * 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */ - o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2; + o_div = (int)(CLK_LL_APLL_MULTIPLIER_MIN_HZ / (float)(freq * 2) + 1) - 2; if (o_div > 31) { ESP_HW_LOGE(TAG, "Expected frequency is too small"); return 0; @@ -129,7 +129,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code. * With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is * 500 MHz / ((0 + 2) * 2) = 125000000 Hz */ - o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2; + o_div = (int)(CLK_LL_APLL_MULTIPLIER_MAX_HZ / (float)(freq * 2)) - 2; if (o_div < 0) { ESP_HW_LOGE(TAG, "Expected frequency is too big"); return 0; diff --git a/components/hal/esp32/include/hal/clk_tree_ll.h b/components/hal/esp32/include/hal/clk_tree_ll.h index 79ea9fc003..67ae94a51a 100644 --- a/components/hal/esp32/include/hal/clk_tree_ll.h +++ b/components/hal/esp32/include/hal/clk_tree_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -73,6 +73,15 @@ extern "C" { #define CLK_LL_XTAL_32K_BOOTSTRAP_DRES_VAL 3 #define CLK_LL_XTAL_32K_BOOTSTRAP_DBIAS_VAL 0 +/* APLL multiplier output frequency range */ +// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) +#define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz +#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz + +/* APLL output frequency range */ +#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation +#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation + /** * @brief XTAL32K_CLK enable modes */ diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index d718d17a34..a6a7a1b15f 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -84,52 +84,73 @@ static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en) hw->lc_conf.out_eof_mode = en; } +/** + * @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) +{ + if (enable) { + if (i2s_id == 0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + } else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + } + } else if (i2s_id == 1) { + if (i2s_id == 0) { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + } + } +} + +/// 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_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__) + + +/** + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + if (i2s_id == 0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + } else if (i2s_id == 1) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + } +} + +/// 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_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__) + /** * @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_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - if (hw == &I2S0) { - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); - } else { - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); - } - if (hw->clkm_conf.clk_en == 0) { + if (enable && !hw->clkm_conf.clk_en) { hw->clkm_conf.clk_en = 1; hw->conf2.val = 0; - } -} - -/// 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_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) - -/** - * @brief I2S module disable clock. - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_disable_clock(i2s_dev_t *hw) -{ - if (hw->clkm_conf.clk_en == 1) { + } else if (!enable && hw->clkm_conf.clk_en) { hw->clkm_conf.clk_en = 0; } - if (hw == &I2S0) { - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); - } else { - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); - } } /// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) +#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__) /** * @brief I2S tx msb right enable diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index e79f5ec9c5..1b7e9de0da 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -37,37 +37,54 @@ extern "C" { #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz #define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_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; + SYSTEM.perip_clk_en0.reg_i2s1_clk_en = enable; +} + +/// 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_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__) + + +/** + * @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; + SYSTEM.perip_rst_en0.reg_i2s1_rst = 1; + SYSTEM.perip_rst_en0.reg_i2s1_rst = 0; +} + +/// 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_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__) + /** * @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_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - SYSTEM.perip_clk_en0.reg_i2s1_clk_en = 1; - SYSTEM.perip_rst_en0.reg_i2s1_rst = 0; - hw->tx_clkm_conf.clk_en = 1; + hw->tx_clkm_conf.clk_en = enable; } /// 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_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) - -/** - * @brief I2S module disable I2S clock. - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_disable_clock(i2s_dev_t *hw) -{ - hw->tx_clkm_conf.clk_en = 0; - SYSTEM.perip_clk_en0.reg_i2s1_clk_en = 0; - SYSTEM.perip_rst_en0.reg_i2s1_rst = 1; -} - -/// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) +#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__) /** * @brief Enable I2S tx module clock @@ -99,11 +116,6 @@ static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) hw->tx_clkm_conf.tx_clk_active = 0; } -/// 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 -// i2s_ll_tx_disable_clock don't need RCC ENV actually, but still defined here for compatiblity -#define i2s_ll_tx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_tx_disable_clock(__VA_ARGS__) - /** * @brief Disable I2S rx module clock * @@ -114,11 +126,6 @@ static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) hw->rx_clkm_conf.rx_clk_active = 0; } -/// 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 -// i2s_ll_rx_disable_clock don't need RCC ENV actually, but still defined here for compatiblity -#define i2s_ll_rx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_rx_disable_clock(__VA_ARGS__) - /** * @brief I2S mclk use tx module clock * diff --git a/components/hal/esp32c6/include/hal/i2s_ll.h b/components/hal/esp32c6/include/hal/i2s_ll.h index 86c5788fbf..52c15d43f0 100644 --- a/components/hal/esp32c6/include/hal/i2s_ll.h +++ b/components/hal/esp32c6/include/hal/i2s_ll.h @@ -38,25 +38,39 @@ extern "C" { #define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT /** - * @brief I2S module general init, enable I2S clock. * - * @param hw Peripheral I2S hardware instance address. + * @param i2s_id The port id of I2S + * @param enable Set true to enable the buf clock */ -static inline void i2s_ll_enable_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable) { - PCR.i2s_conf.i2s_clk_en = 1; + (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 disable I2S clock. + * @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_disable_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - PCR.i2s_conf.i2s_clk_en = 0; - PCR.i2s_conf.i2s_rst_en = 1; + (void)hw; + (void)enable; + // No need to do anything } /** diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index 9f9e648ce8..0baf7101e5 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -39,25 +39,39 @@ extern "C" { #define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT /** - * @brief I2S module general init, enable I2S clock. * - * @param hw Peripheral I2S hardware instance address. + * @param i2s_id The port id of I2S + * @param enable Set true to enable the buf clock */ -static inline void i2s_ll_enable_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable) { - PCR.i2s_conf.i2s_clk_en = 1; + (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 disable I2S clock. + * @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_disable_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - PCR.i2s_conf.i2s_clk_en = 0; - PCR.i2s_conf.i2s_rst_en = 1; + (void)hw; + (void)enable; + // No need to do anything } /** diff --git a/components/hal/esp32p4/include/hal/clk_tree_ll.h b/components/hal/esp32p4/include/hal/clk_tree_ll.h index c3fee0041a..29a38bdfc5 100644 --- a/components/hal/esp32p4/include/hal/clk_tree_ll.h +++ b/components/hal/esp32p4/include/hal/clk_tree_ll.h @@ -30,6 +30,16 @@ extern "C" { #define CLK_LL_PLL_480M_FREQ_MHZ (480) +/* APLL multiplier output frequency range */ +// TODO: IDF-7526 check if the APLL frequency range is same as before +// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) +#define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz +#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz + +/* APLL output frequency range */ +#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation +#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation + #define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \ .dac = 3, \ .dres = 3, \ diff --git a/components/hal/esp32p4/include/hal/i2s_ll.h b/components/hal/esp32p4/include/hal/i2s_ll.h index 3d7027ede3..0fd64cad6f 100644 --- a/components/hal/esp32p4/include/hal/i2s_ll.h +++ b/components/hal/esp32p4/include/hal/i2s_ll.h @@ -47,67 +47,74 @@ typedef struct { uint16_t numer; // Numerator part of I2S module clock divider } i2s_ll_mclk_div_t; +/** + * @brief Enable the bus clock for I2S module + * + * @param i2s_id The port id of I2S + * @param enable Set true to enable the buf clock + */ +static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable) +{ + switch (i2s_id) { + case 0: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s0_apb_clk_en = enable; + return; + case 1: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s1_apb_clk_en = enable; + return; + case 2: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s2_apb_clk_en = enable; + 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_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + switch (i2s_id) { + case 0: + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s0_apb = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s0_apb = 0; + return; + case 1: + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s1_apb = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s1_apb = 0; + return; + case 2: + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s2_apb = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s2_apb = 0; + 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_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__) + /** * @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_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - // 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.soc_clk_ctrl2.reg_i2s0_apb_clk_en = 1; - HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s0_apb = 0; - break; - case 1: - HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s1_apb_clk_en = 1; - HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s1_apb = 0; - break; - case 2: - HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s2_apb_clk_en = 1; - HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s2_apb = 0; - break; - default: - // Never reach - HAL_ASSERT(false); - } + (void)hw; + (void)enable; + // No need to do anything } /// 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_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) - -/** - * @brief I2S module disable I2S clock. - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_disable_clock(i2s_dev_t *hw) -{ - // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer - switch (I2S_LL_GET_ID(hw)) { - case 0: - HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s0_apb_clk_en = 0; - HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s0_apb = 1; - break; - case 1: - HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s1_apb_clk_en = 0; - HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s1_apb = 1; - break; - case 2: - HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s2_apb_clk_en = 0; - HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s2_apb = 1; - break; - default: - // Never reach - HAL_ASSERT(false); - } -} - -/// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) +#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__) /** * @brief Enable I2S tx module clock diff --git a/components/hal/esp32s2/include/hal/clk_tree_ll.h b/components/hal/esp32s2/include/hal/clk_tree_ll.h index f7d67937ee..b0505b1ce2 100644 --- a/components/hal/esp32s2/include/hal/clk_tree_ll.h +++ b/components/hal/esp32s2/include/hal/clk_tree_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -47,6 +47,15 @@ extern "C" { #define CLK_LL_APLL_CAL_DELAY_2 0x3f #define CLK_LL_APLL_CAL_DELAY_3 0x1f +/* APLL multiplier output frequency range */ +// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) +#define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz +#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz + +/* APLL output frequency range */ +#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation +#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation + #define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \ .dac = 3, \ .dres = 3, \ diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index f8791f1d19..2c97bf157a 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -82,53 +82,73 @@ static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en) hw->lc_conf.out_eof_mode = en; } +/** + * @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) +{ + if (enable) { + if (i2s_id == 0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + } else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + } + } else { + if (i2s_id == 0) { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + } + } +} + +/// 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_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + if (i2s_id == 0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + } else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + } +} + +/// 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_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__) + /** * @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_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - if (hw == &I2S0) { - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); - } else { - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); - } - if (hw->clkm_conf.clk_en == 0) { + if (enable && !hw->clkm_conf.clk_en) { hw->clkm_conf.clk_sel = 2; hw->clkm_conf.clk_en = 1; hw->conf2.val = 0; - } -} - -/// 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_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) - -/** - * @brief I2S module disable clock. - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_disable_clock(i2s_dev_t *hw) -{ - if (hw->clkm_conf.clk_en == 1) { + } else if (!enable && hw->clkm_conf.clk_en) { hw->clkm_conf.clk_en = 0; } - if (hw == &I2S0) { - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); - } else { - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); - } } /// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) +#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__) /** * @brief I2S tx msb right enable diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index ac4d99f859..89b53f8c24 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -38,47 +38,60 @@ extern "C" { #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz #define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_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) +{ + if (i2s_id == 0) { + SYSTEM.perip_clk_en0.i2s0_clk_en = enable; + } else if (i2s_id == 1) { + SYSTEM.perip_clk_en0.i2s1_clk_en = enable; + } +} + +/// 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_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + if (i2s_id == 0) { + SYSTEM.perip_rst_en0.i2s0_rst = 1; + SYSTEM.perip_rst_en0.i2s0_rst = 0; + } else if (i2s_id == 1) { + SYSTEM.perip_rst_en0.i2s1_rst = 1; + SYSTEM.perip_rst_en0.i2s1_rst = 0; + } +} + +/// 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_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__) + /** * @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_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - if (hw == &I2S0) { - SYSTEM.perip_clk_en0.i2s0_clk_en = 1; - SYSTEM.perip_rst_en0.i2s0_rst = 0; - } else { - SYSTEM.perip_clk_en0.i2s1_clk_en = 1; - SYSTEM.perip_rst_en0.i2s1_rst = 0; - } - hw->tx_clkm_conf.clk_en = 1; + hw->tx_clkm_conf.clk_en = enable; } /// 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_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) - -/** - * @brief I2S module disable I2S clock. - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_disable_clock(i2s_dev_t *hw) -{ - hw->tx_clkm_conf.clk_en = 0; - if (hw == &I2S0) { - SYSTEM.perip_clk_en0.i2s0_clk_en = 0; - SYSTEM.perip_rst_en0.i2s0_rst = 1; - } else { - SYSTEM.perip_clk_en0.i2s1_clk_en = 0; - SYSTEM.perip_rst_en0.i2s1_rst = 1; - } -} - -/// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) +#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__) /** * @brief Enable I2S tx module clock @@ -110,11 +123,6 @@ static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) hw->tx_clkm_conf.tx_clk_active = 0; } -/// 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 -// i2s_ll_tx_disable_clock don't need RCC ENV actually, but still defined here for compatiblity -#define i2s_ll_tx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_tx_disable_clock(__VA_ARGS__) - /** * @brief Disable I2S rx module clock * @@ -125,11 +133,6 @@ static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) hw->rx_clkm_conf.rx_clk_active = 0; } -/// 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 -// i2s_ll_rx_disable_clock don't need RCC ENV actually, but still defined here for compatiblity -#define i2s_ll_rx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_rx_disable_clock(__VA_ARGS__) - /** * @brief I2S mclk use tx module clock * diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index 15653cce84..5ea3de62d6 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -65,30 +65,38 @@ void i2s_hal_init(i2s_hal_context_t *hal, int port_id) hal->dev = I2S_LL_GET_HW(port_id); } -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) +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) { - hal_utils_clk_div_t mclk_div = {}; + 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); + 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); + 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) +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) { - hal_utils_clk_div_t mclk_div = {}; + 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); + 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); + 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); + } } /*------------------------------------------------------------------------- diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index e2957e5cc4..6e8af9bf84 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -142,20 +142,35 @@ void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, hal_utils_ * @brief Set tx channel clock * * @param hal Context of the HAL layer - * @param clk_info clock information + * @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); +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_SYS_DIGI_CLKRST_REG_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 rx channel clock * * @param hal Context of the HAL layer - * @param clk_info clock information + * @param clk_info clock information, if it is NULL, only set the clock source * @param clk_src clock source */ -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 SOC_SYS_DIGI_CLKRST_REG_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_rx_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_hal_set_rx_clock(__VA_ARGS__) +#else +#define i2s_hal_set_rx_clock(...) _i2s_hal_set_rx_clock(__VA_ARGS__) +#endif /*------------------------------------------------------------------------- | STD configuration | diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index a3348e6022..0945f539af 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -811,22 +811,6 @@ config SOC_CLK_APLL_SUPPORTED bool default y -config SOC_APLL_MULTIPLIER_OUT_MIN_HZ - int - default 350000000 - -config SOC_APLL_MULTIPLIER_OUT_MAX_HZ - int - default 500000000 - -config SOC_APLL_MIN_HZ - int - default 5303031 - -config SOC_APLL_MAX_HZ - int - default 125000000 - config SOC_CLK_RC_FAST_D256_SUPPORTED bool default y diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index ab27817b34..a3ebb1c9b5 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -1,6 +1,6 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -399,11 +399,6 @@ /*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/ #define SOC_CLK_APLL_SUPPORTED (1) -// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) -#define SOC_APLL_MULTIPLIER_OUT_MIN_HZ (350000000) // 350 MHz -#define SOC_APLL_MULTIPLIER_OUT_MAX_HZ (500000000) // 500 MHz -#define SOC_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation -#define SOC_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation #define SOC_CLK_RC_FAST_D256_SUPPORTED (1) #define SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 (1) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index fbc3963a49..76a4587ddd 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1123,6 +1123,10 @@ config SOC_PM_PAU_LINK_NUM int default 4 +config SOC_SYS_DIGI_CLKRST_REG_SHARED + bool + default y + config SOC_CLK_RC_FAST_SUPPORT_CALIBRATION bool default n diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 984d1526f9..d3a1b23870 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -154,6 +154,7 @@ #define SOC_CPU_HAS_PMA 1 #define SOC_CPU_IDRAM_SPLIT_USING_PMP 1 +// TODO: IDF-5360 (Copy from esp32c3, need check) /*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/ /** The maximum length of a Digital Signature in bits. */ #define SOC_DS_SIGNATURE_MAX_BIT_LEN (4096) @@ -513,6 +514,7 @@ #define SOC_PM_PAU_LINK_NUM (4) /*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/ +#define SOC_SYS_DIGI_CLKRST_REG_SHARED (1) #define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (0) #define SOC_MODEM_CLOCK_IS_INDEPENDENT (0) diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index 8643908f4f..f548a06b79 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -1035,22 +1035,6 @@ config SOC_CLK_APLL_SUPPORTED bool default y -config SOC_APLL_MULTIPLIER_OUT_MIN_HZ - int - default 350000000 - -config SOC_APLL_MULTIPLIER_OUT_MAX_HZ - int - default 500000000 - -config SOC_APLL_MIN_HZ - int - default 5303031 - -config SOC_APLL_MAX_HZ - int - default 125000000 - config SOC_CLK_RC_FAST_D256_SUPPORTED bool default y diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 6a3dff526e..809fb5ffc5 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -446,11 +446,6 @@ /*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/ #define SOC_CLK_APLL_SUPPORTED (1) -// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) -#define SOC_APLL_MULTIPLIER_OUT_MIN_HZ (350000000) // 350 MHz -#define SOC_APLL_MULTIPLIER_OUT_MAX_HZ (500000000) // 500 MHz -#define SOC_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation -#define SOC_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation #define SOC_CLK_RC_FAST_D256_SUPPORTED (1) #define SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 (1) From e1039f9ce28245f8b9ba814bc85e4ac773a0b239 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Thu, 7 Sep 2023 16:47:26 +0800 Subject: [PATCH 4/4] fix(i2s_platform): merge the i2s platform acquire API --- components/driver/CMakeLists.txt | 3 +- components/driver/deprecated/i2s_legacy.c | 47 +----- components/driver/i2s/i2s_common.c | 142 ++++++------------ components/driver/i2s/i2s_platform.c | 78 ++++++++++ components/driver/i2s/i2s_private.h | 38 ++++- .../driver/i2s/include/driver/i2s_common.h | 4 +- components/hal/esp32p4/include/hal/i2s_ll.h | 45 +++--- components/hal/include/hal/i2s_hal.h | 4 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 - components/soc/esp32p4/include/soc/soc_caps.h | 3 - docs/docs_not_updated/esp32h2.txt | 1 - docs/docs_not_updated/esp32p4.txt | 1 - docs/en/api-reference/peripherals/i2s.rst | 1 + 13 files changed, 177 insertions(+), 194 deletions(-) create mode 100644 components/driver/i2s/i2s_platform.c diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 0a168abb5a..6af58de63d 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -111,6 +111,7 @@ endif() # I2S related source files if(CONFIG_SOC_I2S_SUPPORTED) list(APPEND srcs "i2s/i2s_common.c" + "i2s/i2s_platform.c" "i2s/i2s_std.c" "deprecated/i2s_legacy.c") if(CONFIG_SOC_I2S_SUPPORTS_PDM) @@ -236,7 +237,7 @@ else() # Can be removed together with legacy drivers) idf_component_register(SRCS "${srcs}" INCLUDE_DIRS ${includes} - PRIV_REQUIRES efuse esp_timer + PRIV_REQUIRES efuse esp_timer esp_mm REQUIRES esp_pm esp_ringbuf freertos soc hal esp_hw_support LDFRAGMENTS ${ldfragments} ) diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index 9b2ec2a349..494aba2e25 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -52,6 +52,7 @@ #include "esp_pm.h" #include "esp_efuse.h" #include "esp_rom_gpio.h" +#include "esp_private/i2s_platform.h" #include "esp_private/periph_ctrl.h" #include "esp_private/esp_clk.h" @@ -62,7 +63,7 @@ static const char *TAG = "i2s(legacy)"; #define I2S_ENTER_CRITICAL(i2s_num) portENTER_CRITICAL(&i2s_spinlock[i2s_num]) #define I2S_EXIT_CRITICAL(i2s_num) portEXIT_CRITICAL(&i2s_spinlock[i2s_num]) -#if SOC_SYS_DIGI_CLKRST_REG_SHARED +#if SOC_PERIPH_CLK_CTRL_SHARED #define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() #else #define I2S_CLOCK_SRC_ATOMIC() @@ -150,9 +151,6 @@ typedef struct { uint32_t total_slot; /*!< Total slot number */ } i2s_obj_t; -// Record the component name that using I2S peripheral -static const char *comp_using_i2s[SOC_I2S_NUM] = {[0 ... SOC_I2S_NUM - 1] = NULL}; - // Global I2S object pointer static i2s_obj_t *p_i2s[SOC_I2S_NUM] = { [0 ... SOC_I2S_NUM - 1] = NULL, @@ -163,11 +161,6 @@ static portMUX_TYPE i2s_spinlock[SOC_I2S_NUM] = { [0 ... SOC_I2S_NUM - 1] = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED, }; - -__attribute__((weak)) esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name); - -__attribute__((weak)) esp_err_t i2s_platform_release_occupation(int id); - /*------------------------------------------------------------- I2S DMA operation -------------------------------------------------------------*/ @@ -1907,42 +1900,6 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) return ESP_OK; } -esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name) -{ - esp_err_t ret = ESP_ERR_NOT_FOUND; - ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id"); - portENTER_CRITICAL(&i2s_spinlock[id]); - if (!comp_using_i2s[id]) { - ret = ESP_OK; - comp_using_i2s[id] = comp_name; - I2S_RCC_ATOMIC() { - i2s_ll_enable_bus_clock(id, true); - i2s_ll_reset_register(id); - i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), true); - } - } - portEXIT_CRITICAL(&i2s_spinlock[id]); - return ret; -} - -esp_err_t i2s_platform_release_occupation(int id) -{ - esp_err_t ret = ESP_ERR_INVALID_STATE; - ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id"); - portENTER_CRITICAL(&i2s_spinlock[id]); - if (comp_using_i2s[id]) { - ret = ESP_OK; - comp_using_i2s[id] = NULL; - /* Disable module clock */ - I2S_RCC_ATOMIC() { - i2s_ll_enable_bus_clock(id, false); - i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), false); - } - } - portEXIT_CRITICAL(&i2s_spinlock[id]); - return ret; -} - /** * @brief This function will be called during start up, to check that the new i2s driver is not running along with the legacy i2s driver */ diff --git a/components/driver/i2s/i2s_common.c b/components/driver/i2s/i2s_common.c index 269fe52b5d..3a80b15805 100644 --- a/components/driver/i2s/i2s_common.c +++ b/components/driver/i2s/i2s_common.c @@ -25,10 +25,9 @@ #include "soc/soc_caps.h" #include "hal/gpio_hal.h" #include "hal/i2s_hal.h" -#if CONFIG_IDF_TARGET_ESP32P4 +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #include "hal/cache_hal.h" #include "hal/cache_ll.h" -#include "rom/cache.h" #endif #if SOC_I2S_SUPPORTS_ADC_DAC @@ -52,6 +51,10 @@ #include "esp_intr_alloc.h" #include "esp_check.h" #include "esp_attr.h" +#include "esp_dma_utils.h" +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#include "esp_cache.h" +#endif #include "esp_rom_gpio.h" #include "esp_memory_utils.h" @@ -60,18 +63,15 @@ * Set 4092 here to align with 4-byte, so that the position of the slot data in the buffer will be relatively fixed */ #define I2S_DMA_BUFFER_MAX_SIZE (4092) -/** - * @brief Global i2s platform object - * @note For saving all the I2S related information - */ -i2s_platform_t g_i2s = { - .spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED, - .controller[0 ... (SOC_I2S_NUM - 1)] = NULL, // groups will be lazy installed - .comp_name[0 ... (SOC_I2S_NUM - 1)] = NULL, -}; - static const char *TAG = "i2s_common"; +__attribute__((always_inline)) +inline void *i2s_dma_calloc(size_t num, size_t size, uint32_t caps, size_t *actual_size) { + void *ptr = NULL; + esp_dma_calloc(num, size, caps, &ptr, actual_size); + return ptr; +} + /*--------------------------------------------------------------------------- I2S Static APIs ---------------------------------------------------------------------------- @@ -298,6 +298,11 @@ err: return ret; } +#ifndef __cplusplus +/* To make sure the i2s_event_callbacks_t is same size as i2s_event_callbacks_internal_t */ +_Static_assert(sizeof(i2s_event_callbacks_t) == sizeof(i2s_event_callbacks_internal_t), "Invalid size of i2s_event_callbacks_t structure"); +#endif + esp_err_t i2s_channel_register_event_callback(i2s_chan_handle_t handle, const i2s_event_callbacks_t *callbacks, void *user_data) { I2S_NULL_POINTER_CHECK(TAG, handle); @@ -336,9 +341,9 @@ uint32_t i2s_get_buf_size(i2s_chan_handle_t handle, uint32_t data_bit_width, uin uint32_t bytes_per_sample = ((data_bit_width + 15) / 16) * 2; uint32_t bytes_per_frame = bytes_per_sample * active_chan; uint32_t bufsize = dma_frame_num * bytes_per_frame; -#if CONFIG_IDF_TARGET_ESP32P4 +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE /* bufsize need to align with cache line size */ - uint32_t alignment = cache_hal_get_cache_line_size(CACHE_TYPE_DATA); + uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); uint32_t aligned_frame_num = dma_frame_num; /* To make the buffer aligned with the cache line size, search for the ceil aligned size first, If the buffer size exceed the max DMA buffer size, toggle the sign to search for the floor aligned size */ @@ -401,20 +406,14 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu handle->dma.desc_num = num; handle->dma.buf_size = bufsize; -#if SOC_GDMA_TRIG_PERIPH_I2S0_BUS == SOC_GDMA_BUS_AHB - uint32_t alignment = 64; - uint32_t desc_size = alignment; -#else - uint32_t alignment = 4; - uint32_t desc_size = sizeof(lldesc_t); -#endif /* Descriptors must be in the internal RAM */ handle->dma.desc = (lldesc_t **)heap_caps_calloc(num, sizeof(lldesc_t *), I2S_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(handle->dma.desc, ESP_ERR_NO_MEM, err, TAG, "create I2S DMA decriptor array failed"); handle->dma.bufs = (uint8_t **)heap_caps_calloc(num, sizeof(uint8_t *), I2S_MEM_ALLOC_CAPS); + size_t desc_size = 0; for (int i = 0; i < num; i++) { /* Allocate DMA descriptor */ - handle->dma.desc[i] = (lldesc_t *) heap_caps_aligned_calloc(alignment, 1, desc_size, I2S_DMA_ALLOC_CAPS); + handle->dma.desc[i] = (lldesc_t *) i2s_dma_calloc(1, sizeof(lldesc_t), I2S_DMA_ALLOC_CAPS, &desc_size); ESP_GOTO_ON_FALSE(handle->dma.desc[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA description failed"); handle->dma.desc[i]->owner = 1; handle->dma.desc[i]->eof = 1; @@ -422,7 +421,7 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu handle->dma.desc[i]->length = bufsize; handle->dma.desc[i]->size = bufsize; handle->dma.desc[i]->offset = 0; - handle->dma.bufs[i] = (uint8_t *) heap_caps_aligned_calloc(alignment, 1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS); + handle->dma.bufs[i] = (uint8_t *) i2s_dma_calloc(1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS, NULL); ESP_GOTO_ON_FALSE(handle->dma.bufs[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed"); handle->dma.desc[i]->buf = handle->dma.bufs[i]; ESP_LOGV(TAG, "desc addr: %8p\tbuffer addr:%8p", handle->dma.desc[i], handle->dma.bufs[i]); @@ -431,8 +430,8 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu for (int i = 0; i < num; i++) { /* Link to the next descriptor */ STAILQ_NEXT(handle->dma.desc[i], qe) = (i < (num - 1)) ? (handle->dma.desc[i + 1]) : handle->dma.desc[0]; -#if CONFIG_IDF_TARGET_ESP32P4 - Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)(handle->dma.desc[i]), desc_size); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(handle->dma.desc[i], desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); #endif } if (handle->dir == I2S_DIR_RX) { @@ -498,8 +497,8 @@ static bool IRAM_ATTR i2s_dma_rx_callback(gdma_channel_handle_t dma_chan, gdma_e uint32_t dummy; finish_desc = (lldesc_t *)event_data->rx_eof_desc_addr; -#if CONFIG_IDF_TARGET_ESP32P4 - Cache_Invalidate_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)finish_desc->buf, handle->dma.buf_size); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync((void *)finish_desc->buf, handle->dma.buf_size, ESP_CACHE_MSYNC_FLAG_INVALIDATE); #endif i2s_event_data_t evt = { .data = &(finish_desc->buf), @@ -547,8 +546,8 @@ static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_e if (handle->dma.auto_clear) { uint8_t *sent_buf = (uint8_t *)finish_desc->buf; memset(sent_buf, 0, handle->dma.buf_size); -#if CONFIG_IDF_TARGET_ESP32P4 - Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)sent_buf, handle->dma.buf_size); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(sent_buf, handle->dma.buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); #endif } xQueueSendFromISR(handle->msg_queue, &(finish_desc->buf), &need_yield2); @@ -691,7 +690,7 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag) gdma_register_rx_event_callbacks(handle->dma.dma_chan, &cb, handle); } #else - intr_flag |= handle->intr_flags ? handle->intr_flags : ESP_INTR_FLAG_LOWMED; + intr_flag |= handle->intr_prio_flags; /* Initialize I2S module interrupt */ if (handle->dir == I2S_DIR_TX) { esp_intr_alloc_intrstatus(i2s_periph_signal[port_id].irq, intr_flag, @@ -708,10 +707,10 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag) return ESP_OK; } -void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input, bool is_invert) +void i2s_gpio_check_and_set(int gpio, uint32_t signal_idx, bool is_input, bool is_invert) { /* Ignore the pin if pin = I2S_GPIO_UNUSED */ - if (gpio != I2S_GPIO_UNUSED) { + if (gpio != (int)I2S_GPIO_UNUSED) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); if (is_input) { /* Set direction, for some GPIOs, the input function are not enabled as default */ @@ -724,9 +723,9 @@ void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input, } } -void i2s_gpio_loopback_set(gpio_num_t gpio, uint32_t out_sig_idx, uint32_t in_sig_idx) +void i2s_gpio_loopback_set(int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx) { - if (gpio != I2S_GPIO_UNUSED) { + if (gpio != (int)I2S_GPIO_UNUSED) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); gpio_set_direction(gpio, GPIO_MODE_INPUT_OUTPUT); esp_rom_gpio_connect_out_signal(gpio, out_sig_idx, 0, 0); @@ -734,9 +733,9 @@ void i2s_gpio_loopback_set(gpio_num_t gpio, uint32_t out_sig_idx, uint32_t in_si } } -esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, i2s_clock_src_t clk_src, bool is_invert) +esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_src, bool is_invert) { - if (gpio_num == I2S_GPIO_UNUSED) { + if (gpio_num == (int)I2S_GPIO_UNUSED) { return ESP_OK; } #if CONFIG_IDF_TARGET_ESP32 @@ -785,6 +784,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t * I2S_NULL_POINTER_CHECK(TAG, tx_handle || rx_handle); ESP_RETURN_ON_FALSE(chan_cfg->id < SOC_I2S_NUM || chan_cfg->id == I2S_NUM_AUTO, ESP_ERR_INVALID_ARG, TAG, "invalid I2S port id"); ESP_RETURN_ON_FALSE(chan_cfg->dma_desc_num >= 2, ESP_ERR_INVALID_ARG, TAG, "there should be at least 2 DMA buffers"); + ESP_RETURN_ON_FALSE(chan_cfg->intr_priority >= 0 && chan_cfg->intr_priority <= 7, ESP_ERR_INVALID_ARG, TAG, "intr_priority should be within 0~7"); esp_err_t ret = ESP_OK; i2s_controller_t *i2s_obj = NULL; @@ -816,7 +816,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t * ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_TX, chan_cfg->dma_desc_num), err, TAG, "register I2S tx channel failed"); i2s_obj->tx_chan->role = chan_cfg->role; - i2s_obj->tx_chan->intr_flags = chan_cfg->intr_flags; + i2s_obj->tx_chan->intr_prio_flags = chan_cfg->intr_priority ? BIT(chan_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED; i2s_obj->tx_chan->dma.auto_clear = chan_cfg->auto_clear; i2s_obj->tx_chan->dma.desc_num = chan_cfg->dma_desc_num; i2s_obj->tx_chan->dma.frame_num = chan_cfg->dma_frame_num; @@ -830,7 +830,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t * ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_RX, chan_cfg->dma_desc_num), err, TAG, "register I2S rx channel failed"); i2s_obj->rx_chan->role = chan_cfg->role; - i2s_obj->rx_chan->intr_flags = chan_cfg->intr_flags; + i2s_obj->rx_chan->intr_prio_flags = chan_cfg->intr_priority ? BIT(chan_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED; i2s_obj->rx_chan->dma.desc_num = chan_cfg->dma_desc_num; i2s_obj->rx_chan->dma.frame_num = chan_cfg->dma_frame_num; i2s_obj->rx_chan->start = i2s_rx_channel_start; @@ -1071,8 +1071,8 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src, } /* Load the data from the last loaded position */ memcpy((uint8_t *)(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos), data_ptr, bytes_can_load); -#if CONFIG_IDF_TARGET_ESP32P4 - Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos), (uint32_t)bytes_can_load); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos, bytes_can_load, ESP_CACHE_MSYNC_FLAG_DIR_C2M); #endif data_ptr += bytes_can_load; // Move forward the data pointer total_loaded_bytes += bytes_can_load; // Add to the total loaded bytes @@ -1130,8 +1130,8 @@ esp_err_t i2s_channel_write(i2s_chan_handle_t handle, const void *src, size_t si bytes_can_write = size; } memcpy(data_ptr, src_byte, bytes_can_write); -#if CONFIG_IDF_TARGET_ESP32P4 - Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)data_ptr, (uint32_t)bytes_can_write); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(data_ptr, bytes_can_write, ESP_CACHE_MSYNC_FLAG_DIR_C2M); #endif size -= bytes_can_write; src_byte += bytes_can_write; @@ -1187,64 +1187,6 @@ esp_err_t i2s_channel_read(i2s_chan_handle_t handle, void *dest, size_t size, si return ret; } -/*--------------------------------------------------------------------------- - I2S Platform APIs - ---------------------------------------------------------------------------- - Scope: This file and ADC/DAC/LCD driver - ----------------------------------------------------------------------------*/ - -esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name) -{ - esp_err_t ret = ESP_OK; - const char *occupied_comp = NULL; - ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id"); - portENTER_CRITICAL(&g_i2s.spinlock); - if ((!g_i2s.controller[id]) && (g_i2s.comp_name[id] == NULL)) { - g_i2s.comp_name[id] = comp_name; - /* Enable module clock */ - I2S_RCC_ATOMIC() { - i2s_ll_enable_bus_clock(id, true); - i2s_ll_reset_register(id); - i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), true); - } - } else { - occupied_comp = g_i2s.comp_name[id]; - ret = ESP_ERR_NOT_FOUND; - } - portEXIT_CRITICAL(&g_i2s.spinlock); - if (occupied_comp != NULL) { - ESP_LOGW(TAG, "i2s controller %d has been occupied by %s", id, occupied_comp); - } - return ret; -} - -esp_err_t i2s_platform_release_occupation(int id) -{ - esp_err_t ret = ESP_OK; - ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id"); - portENTER_CRITICAL(&g_i2s.spinlock); - if (!g_i2s.controller[id]) { - g_i2s.comp_name[id] = NULL; - /* Disable module clock */ - I2S_RCC_ATOMIC() { - i2s_ll_enable_bus_clock(id, false); - i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), false); - } - } else { - ret = ESP_ERR_INVALID_STATE; - } - portEXIT_CRITICAL(&g_i2s.spinlock); - return ret; -} - -// Only used in `test_i2s_iram.c` to write DMA buffer directly -size_t inline i2s_platform_get_dma_buffer_offset(void) -{ - /* Force to transfer address '0' into 'i2s_chan_handle_t' type, - * then find the corresponding field , the address of this field is the offset of this type */ - return (size_t)&(((i2s_chan_handle_t)0)->dma.bufs); -} - #if SOC_I2S_SUPPORTS_TX_SYNC_CNT uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle) { diff --git a/components/driver/i2s/i2s_platform.c b/components/driver/i2s/i2s_platform.c new file mode 100644 index 0000000000..39d9e87cc2 --- /dev/null +++ b/components/driver/i2s/i2s_platform.c @@ -0,0 +1,78 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_check.h" +#include "i2s_private.h" + +static const char *TAG = "i2s_platform"; + +/** + * @brief Global i2s platform object + * @note For saving all the I2S related information + */ +i2s_platform_t g_i2s = { + .spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED, + .controller[0 ... (SOC_I2S_NUM - 1)] = NULL, // groups will be lazy installed + .comp_name[0 ... (SOC_I2S_NUM - 1)] = NULL, +}; + +/*--------------------------------------------------------------------------- + I2S Platform APIs + ---------------------------------------------------------------------------- + Scope: This file and ADC/DAC/LCD driver + ----------------------------------------------------------------------------*/ + +esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name) +{ + esp_err_t ret = ESP_OK; + const char *occupied_comp = NULL; + ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id"); + portENTER_CRITICAL(&g_i2s.spinlock); + if ((!g_i2s.controller[id]) && (g_i2s.comp_name[id] == NULL)) { + g_i2s.comp_name[id] = comp_name; + /* Enable module clock */ + I2S_RCC_ATOMIC() { + i2s_ll_enable_bus_clock(id, true); + i2s_ll_reset_register(id); + i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), true); + } + } else { + occupied_comp = g_i2s.comp_name[id]; + ret = ESP_ERR_NOT_FOUND; + } + portEXIT_CRITICAL(&g_i2s.spinlock); + if (occupied_comp != NULL) { + ESP_LOGW(TAG, "i2s controller %d has been occupied by %s", id, occupied_comp); + } + return ret; +} + +esp_err_t i2s_platform_release_occupation(int id) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id"); + portENTER_CRITICAL(&g_i2s.spinlock); + if (!g_i2s.controller[id]) { + g_i2s.comp_name[id] = NULL; + /* Disable module clock */ + I2S_RCC_ATOMIC() { + i2s_ll_enable_bus_clock(id, false); + i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), false); + } + } else { + ret = ESP_ERR_INVALID_STATE; + } + portEXIT_CRITICAL(&g_i2s.spinlock); + return ret; +} + +// Only used in `test_i2s_iram.c` to write DMA buffer directly +size_t i2s_platform_get_dma_buffer_offset(void) +{ + /* Force to transfer address '0' into 'i2s_chan_handle_t' type, + * then find the corresponding field , the address of this field is the offset of this type */ + return (size_t)&(((i2s_chan_handle_t)0)->dma.bufs); +} diff --git a/components/driver/i2s/i2s_private.h b/components/driver/i2s/i2s_private.h index 90858a04b4..9405062ca5 100644 --- a/components/driver/i2s/i2s_private.h +++ b/components/driver/i2s/i2s_private.h @@ -9,7 +9,7 @@ #include "freertos/FreeRTOS.h" #include "soc/lldesc.h" #include "soc/soc_caps.h" -#include "hal/i2s_types.h" +#include "hal/i2s_hal.h" #include "driver/i2s_types.h" #include "freertos/semphr.h" #include "freertos/queue.h" @@ -36,7 +36,7 @@ extern "C" { #endif //CONFIG_I2S_ISR_IRAM_SAFE #define I2S_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA) -#if SOC_SYS_DIGI_CLKRST_REG_SHARED +#if SOC_PERIPH_CLK_CTRL_SHARED #define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() #else #define I2S_CLOCK_SRC_ATOMIC() @@ -59,6 +59,28 @@ typedef enum { I2S_CHAN_STATE_RUNNING, /*!< i2s channel is idling (initialized and enabled) */ } i2s_state_t; +/** + * @brief Group of I2S callbacks + * @note The callbacks are all running under ISR environment + * @note When CONFIG_I2S_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. + * The variables used in the function should be in the SRAM as well. + * @note Declare the internal type to remove the dependency of `i2s_common.h` + */ +typedef struct { + i2s_isr_callback_t on_recv; /**< Callback of data received event, only for rx channel + * The event data includes DMA buffer address and size that just finished receiving data + */ + i2s_isr_callback_t on_recv_q_ovf; /**< Callback of receiving queue overflowed event, only for rx channel + * The event data includes buffer size that has been overwritten + */ + i2s_isr_callback_t on_sent; /**< Callback of data sent event, only for tx channel + * The event data includes DMA buffer address and size that just finished sending data + */ + i2s_isr_callback_t on_send_q_ovf; /**< Callback of sending queue overflowed event, only for tx channel + * The event data includes buffer size that has been overwritten + */ +} i2s_event_callbacks_internal_t; + /** * @brief i2s channel level configurations * @note It performs as channel handle @@ -103,7 +125,7 @@ struct i2s_channel_obj_t { i2s_dma_t dma; /*!< i2s dma object */ i2s_state_t state; /*!< i2s driver state. Ensuring the driver working in a correct sequence */ /* Stored configurations */ - int intr_flags; + int intr_prio_flags;/*!< i2s interrupt priority flags */ void *mode_info; /*!< Slot, clock and gpio information of each mode */ #if SOC_I2S_SUPPORTS_APLL bool apll_en; /*!< Flag of wether APLL enabled */ @@ -117,7 +139,7 @@ struct i2s_channel_obj_t { esp_pm_lock_handle_t pm_lock; /*!< Power management lock, to avoid apb clock frequency changes while i2s is working */ #endif QueueHandle_t msg_queue; /*!< Message queue handler, used for transporting data between interrupt and read/write task */ - i2s_event_callbacks_t callbacks; /*!< Callback functions */ + i2s_event_callbacks_internal_t callbacks; /*!< Callback functions */ void *user_data; /*!< User data for callback functions */ void (*start)(i2s_chan_handle_t); /*!< start tx/rx channel */ void (*stop)(i2s_chan_handle_t); /*!< stop tx/rx channel */ @@ -133,7 +155,7 @@ typedef struct { const char *comp_name[SOC_I2S_NUM]; /*!< The component name that occupied i2s controller */ } i2s_platform_t; -extern i2s_platform_t g_i2s; +extern i2s_platform_t g_i2s; /*!< Global i2s instance for driver internal use */ /** * @brief Initialize I2S DMA interrupt @@ -200,7 +222,7 @@ uint32_t i2s_get_source_clk_freq(i2s_clock_src_t clk_src, uint32_t mclk_freq_hz) * @param is_input Is input gpio * @param is_invert Is invert gpio */ -void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input, bool is_invert); +void i2s_gpio_check_and_set(int gpio, uint32_t signal_idx, bool is_input, bool is_invert); /** * @brief Check gpio validity and output mclk signal @@ -213,7 +235,7 @@ void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input, * - ESP_OK Set mclk output gpio success * - ESP_ERR_INVALID_ARG Invalid GPIO number */ -esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, i2s_clock_src_t clk_src, bool is_invert); +esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_src, bool is_invert); /** * @brief Attach data out signal and data in signal to a same gpio @@ -222,7 +244,7 @@ esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, i2s_clock_src_t * @param out_sig_idx Data out signal index * @param in_sig_idx Data in signal index */ -void i2s_gpio_loopback_set(gpio_num_t gpio, uint32_t out_sig_idx, uint32_t in_sig_idx); +void i2s_gpio_loopback_set(int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx); #ifdef __cplusplus } diff --git a/components/driver/i2s/include/driver/i2s_common.h b/components/driver/i2s/include/driver/i2s_common.h index fb2c99a4f1..0b6dc30331 100644 --- a/components/driver/i2s/include/driver/i2s_common.h +++ b/components/driver/i2s/include/driver/i2s_common.h @@ -25,7 +25,7 @@ extern "C" { .dma_desc_num = 6, \ .dma_frame_num = 240, \ .auto_clear = false, \ - .intr_flags = 0, \ + .intr_priority = 0, \ } #define I2S_GPIO_UNUSED GPIO_NUM_NC /*!< Used in i2s_gpio_config_t for signals which are not used */ @@ -64,7 +64,7 @@ typedef struct { * it should be the multiple of '3' when the data bit width is 24. */ bool auto_clear; /*!< Set to auto clear DMA TX buffer, i2s will always send zero automatically if no data to send */ - int intr_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */ + int intr_priority; /*!< I2S interrupt priority, range [0, 7], if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */ } i2s_chan_config_t; /** diff --git a/components/hal/esp32p4/include/hal/i2s_ll.h b/components/hal/esp32p4/include/hal/i2s_ll.h index 0fd64cad6f..c3b69cf98d 100644 --- a/components/hal/esp32p4/include/hal/i2s_ll.h +++ b/components/hal/esp32p4/include/hal/i2s_ll.h @@ -19,6 +19,7 @@ #include "soc/i2s_struct.h" #include "soc/hp_sys_clkrst_struct.h" #include "hal/i2s_types.h" +#include "hal/hal_utils.h" #ifdef __cplusplus @@ -31,22 +32,12 @@ extern "C" { #define I2S_LL_TDM_CH_MASK (0xffff) #define I2S_LL_PDM_BCK_FACTOR (64) -#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9) -#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) +#define I2S_LL_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 (40 * 1000000) // XTAL_CLK: 40MHz #define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_XTAL_CLK_FREQ // No PLL clock source on P4, use XTAL as default -/** - * @brief I2S clock configuration structure - * @note Fmclk = Fsclk /(integ+numer/denom) - */ -typedef struct { - uint16_t integ; // Integer part of I2S module clock divider - uint16_t denom; // Denominator part of I2S module clock divider - uint16_t numer; // Numerator part of I2S module clock divider -} i2s_ll_mclk_div_t; - /** * @brief Enable the bus clock for I2S module * @@ -328,7 +319,7 @@ static inline uint32_t i2s_ll_get_clk_src(i2s_clock_src_t src) return 2; default: HAL_ASSERT(false && "unsupported clock source"); - break; + return -1; } } @@ -471,7 +462,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 i2s_ll_mclk_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,13 +475,13 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mc 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->denom && mclk_div->numer) { - div_yn1 = mclk_div->numer * 2 > mclk_div->denom; - div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer; - div_x = mclk_div->denom / div_z - 1; - div_y = mclk_div->denom % div_z; + 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->integ, div_x, div_y, div_z, div_yn1); + i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1); } /** @@ -511,7 +502,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 i2s_ll_mclk_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,13 +515,13 @@ static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mc 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->denom && mclk_div->numer) { - div_yn1 = mclk_div->numer * 2 > mclk_div->denom; - div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer; - div_x = mclk_div->denom / div_z - 1; - div_y = mclk_div->denom % div_z; + 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->integ, div_x, div_y, div_z, div_yn1); + i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1); } /** diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index 6e8af9bf84..bfa5dfe1c2 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -147,7 +147,7 @@ void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, hal_utils_ */ 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_SYS_DIGI_CLKRST_REG_SHARED +#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__) @@ -164,7 +164,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); -#if SOC_SYS_DIGI_CLKRST_REG_SHARED +#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_rx_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_hal_set_rx_clock(__VA_ARGS__) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 76a4587ddd..fbc3963a49 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1123,10 +1123,6 @@ config SOC_PM_PAU_LINK_NUM int default 4 -config SOC_SYS_DIGI_CLKRST_REG_SHARED - bool - default y - config SOC_CLK_RC_FAST_SUPPORT_CALIBRATION bool default n diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index d3a1b23870..abc8d3f8b9 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -48,7 +48,6 @@ // #define SOC_EFUSE_SUPPORTED 1 //TODO: IDF-7512 #define SOC_RTC_FAST_MEM_SUPPORTED 1 #define SOC_RTC_MEM_SUPPORTED 1 -// #define SOC_I2S_SUPPORTED 1 //TODO: IDF-6508 #define SOC_RMT_SUPPORTED 1 #define SOC_I2S_SUPPORTED 1 // #define SOC_RMT_SUPPORTED 1 //TODO: IDF-7476 @@ -154,7 +153,6 @@ #define SOC_CPU_HAS_PMA 1 #define SOC_CPU_IDRAM_SPLIT_USING_PMP 1 -// TODO: IDF-5360 (Copy from esp32c3, need check) /*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/ /** The maximum length of a Digital Signature in bits. */ #define SOC_DS_SIGNATURE_MAX_BIT_LEN (4096) @@ -514,7 +512,6 @@ #define SOC_PM_PAU_LINK_NUM (4) /*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/ -#define SOC_SYS_DIGI_CLKRST_REG_SHARED (1) #define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (0) #define SOC_MODEM_CLOCK_IS_INDEPENDENT (0) diff --git a/docs/docs_not_updated/esp32h2.txt b/docs/docs_not_updated/esp32h2.txt index a0fd1f872f..fb3d48388c 100644 --- a/docs/docs_not_updated/esp32h2.txt +++ b/docs/docs_not_updated/esp32h2.txt @@ -3,7 +3,6 @@ api-guides/coexist api-guides/cplusplus api-guides/dfu api-guides/index -api-reference/peripherals/i2s api-reference/peripherals/spi_features api-reference/peripherals/sdio_slave api-reference/peripherals/adc_calibration diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index 839e965ed4..c4061400c6 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -111,7 +111,6 @@ api-reference/peripherals/gpio.rst api-reference/peripherals/sdspi_host.rst api-reference/peripherals/dac.rst api-reference/peripherals/spi_slave.rst -api-reference/peripherals/i2s.rst api-reference/peripherals/touch_element.rst api-reference/peripherals/lcd.rst api-reference/peripherals/ana_cmpr.rst diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index c379114a3a..071352c3f6 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -116,6 +116,7 @@ ESP32-C3 I2S 0 I2S 0 none I2S 0 none none 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 ========= ======== ======== ======== ======== ======== ========== Standard Mode