mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
i2s: extract std/pdm/tdm modes
Type structures of these modes are defined. Driver and HAL layer are modified to fit these concepts.
This commit is contained in:
@@ -29,19 +29,24 @@ extern "C" {
|
||||
|
||||
#define I2S_LL_BASE_CLK (2 * APB_CLK_FREQ)
|
||||
|
||||
#define I2S_LL_BCK_MAX_PRESCALE (64)
|
||||
|
||||
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (6)
|
||||
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
|
||||
|
||||
#define I2S_LL_EVENT_RX_EOF BIT(9)
|
||||
#define I2S_LL_EVENT_TX_EOF BIT(12)
|
||||
#define I2S_LL_EVENT_RX_DSCR_ERR BIT(13)
|
||||
#define I2S_LL_EVENT_TX_DSCR_ERR BIT(14)
|
||||
#define I2S_INTR_MAX (UINT32_MAX)
|
||||
|
||||
/* I2S clock configuration structure */
|
||||
typedef struct {
|
||||
uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a)
|
||||
uint16_t mclk_div; // I2S module clock divider, Fmclk = Fsclk /(mclk_div+b/a)
|
||||
uint16_t a;
|
||||
uint16_t b; // The decimal part of module clock devider, the decimal is: b/a
|
||||
uint16_t b; // The decimal part of module clock divider, the decimal is: b/a
|
||||
} i2s_ll_mclk_div_t;
|
||||
|
||||
#define I2S_LL_EVENT_TX_EOF (1 << 12)
|
||||
#define I2S_LL_BCK_MAX_PRESCALE (64)
|
||||
|
||||
/**
|
||||
* @brief Enable DMA descriptor owner check
|
||||
*
|
||||
@@ -267,16 +272,68 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2S TX clock devider
|
||||
* @brief Configure I2S TX module clock divider
|
||||
* @note mclk on ESP32S2 is shared by both TX and RX channel
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param set Pointer to I2S clock devider configuration paramater
|
||||
* @param sclk system clock, 0 means use apll
|
||||
* @param mclk module clock
|
||||
* @param mclk_div integer part of the division from sclk to mclk
|
||||
*/
|
||||
static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set)
|
||||
static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mclk, uint32_t mclk_div)
|
||||
{
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, set->mclk_div);
|
||||
hw->clkm_conf.clkm_div_b = set->b;
|
||||
hw->clkm_conf.clkm_div_a = set->a;
|
||||
int ma = 0;
|
||||
int mb = 0;
|
||||
int denominator = 1;
|
||||
int numerator = 0;
|
||||
|
||||
uint32_t freq_diff = abs(sclk - mclk * mclk_div);
|
||||
if (!freq_diff) {
|
||||
goto finish;
|
||||
}
|
||||
float decimal = freq_diff / (float)mclk;
|
||||
// Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 / 126.0
|
||||
if (decimal > 125.0 / 126.0) {
|
||||
mclk_div++;
|
||||
goto finish;
|
||||
}
|
||||
uint32_t min = ~0;
|
||||
for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) {
|
||||
int b = (int)(a * (freq_diff / (double)mclk) + 0.5);
|
||||
ma = freq_diff * a;
|
||||
mb = mclk * b;
|
||||
if (ma == mb) {
|
||||
denominator = a;
|
||||
numerator = b;
|
||||
goto finish;
|
||||
}
|
||||
if (abs((mb - ma)) < min) {
|
||||
denominator = a;
|
||||
numerator = b;
|
||||
min = abs(mb - ma);
|
||||
}
|
||||
}
|
||||
finish:
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, mclk_div);
|
||||
hw->clkm_conf.clkm_div_b = numerator;
|
||||
hw->clkm_conf.clkm_div_a = denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2S module clock divider
|
||||
* @note mclk on ESP32 is shared by both TX and RX channel
|
||||
* mclk = sclk / (mclk_div + b/a)
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param mclk_div integer part of the division from sclk to mclk
|
||||
* @param a Denominator of decimal part
|
||||
* @param b Numerator of decimal part
|
||||
*/
|
||||
static inline void i2s_ll_set_raw_mclk_div(i2s_dev_t *hw, uint32_t mclk_div, uint32_t a, uint32_t b)
|
||||
{
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, mclk_div);
|
||||
hw->clkm_conf.clkm_div_b = b;
|
||||
hw->clkm_conf.clkm_div_a = a;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -291,16 +348,17 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2S RX clock devider
|
||||
* @brief Configure I2S RX module clock divider
|
||||
* @note mclk on ESP32S2 is shared by both TX and RX channel
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param set Pointer to I2S clock devider configuration paramater
|
||||
* @param sclk system clock, 0 means use apll
|
||||
* @param mclk module clock
|
||||
* @param mclk_div integer part of the division from sclk to mclk
|
||||
*/
|
||||
static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set)
|
||||
static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mclk, uint32_t mclk_div)
|
||||
{
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, set->mclk_div);
|
||||
hw->clkm_conf.clkm_div_b = set->b;
|
||||
hw->clkm_conf.clkm_div_a = set->a;
|
||||
i2s_ll_tx_set_mclk(hw, sclk, mclk, mclk_div);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -327,7 +385,6 @@ static inline void i2s_ll_enable_intr(i2s_dev_t *hw, uint32_t mask, bool en)
|
||||
static inline void i2s_ll_tx_enable_intr(i2s_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.out_eof = 1;
|
||||
hw->int_ena.out_dscr_err = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,7 +395,6 @@ static inline void i2s_ll_tx_enable_intr(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_tx_disable_intr(i2s_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.out_eof = 0;
|
||||
hw->int_ena.out_dscr_err = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,7 +405,6 @@ static inline void i2s_ll_tx_disable_intr(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_rx_enable_intr(i2s_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.in_suc_eof = 1;
|
||||
hw->int_ena.in_dscr_err = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -360,7 +415,6 @@ static inline void i2s_ll_rx_enable_intr(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_rx_disable_intr(i2s_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.in_suc_eof = 0;
|
||||
hw->int_ena.in_dscr_err = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -419,15 +473,34 @@ static inline void i2s_ll_rx_reset_dma(i2s_dev_t *hw)
|
||||
hw->lc_conf.in_rst = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf2.val = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf2.val = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable TX PDM mode.
|
||||
* @note ESP32-S2 doesn't support pdm
|
||||
* This function is used to be compatible with those support pdm
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address (ignored)
|
||||
* @param pdm_enable Set true to TX enable PDM mode (ignored)
|
||||
*/
|
||||
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pdm_enable)
|
||||
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw)
|
||||
{
|
||||
// Remain empty
|
||||
}
|
||||
@@ -438,9 +511,8 @@ static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pdm_enable)
|
||||
* This function is used to be compatible with those support pdm
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address (ignored)
|
||||
* @param pdm_enable Set true to RX enable PDM mode (ignored)
|
||||
*/
|
||||
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable)
|
||||
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw)
|
||||
{
|
||||
// Remain empty
|
||||
}
|
||||
@@ -592,7 +664,7 @@ static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, uint32_t eof_num)
|
||||
*/
|
||||
static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit)
|
||||
{
|
||||
hw->fifo_conf.tx_fifo_mod = (chan_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2);
|
||||
hw->fifo_conf.tx_fifo_mod = (chan_bit <= I2S_DATA_BIT_WIDTH_16BIT ? 0 : 2);
|
||||
hw->sample_rate_conf.tx_bits_mod = data_bit;
|
||||
}
|
||||
|
||||
@@ -605,7 +677,7 @@ static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int
|
||||
*/
|
||||
static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit)
|
||||
{
|
||||
hw->fifo_conf.rx_fifo_mod = (chan_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2);
|
||||
hw->fifo_conf.rx_fifo_mod = (chan_bit <= I2S_DATA_BIT_WIDTH_16BIT ? 0 : 2);
|
||||
hw->sample_rate_conf.rx_bits_mod = data_bit;
|
||||
}
|
||||
|
||||
@@ -794,7 +866,7 @@ static inline void i2s_ll_tx_enable_dma_equal(i2s_dev_t *hw, bool en)
|
||||
static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
|
||||
{
|
||||
int data_bit = hw->sample_rate_conf.tx_bits_mod;
|
||||
hw->fifo_conf.tx_fifo_mod = data_bit <= I2S_BITS_PER_SAMPLE_16BIT ? mono_ena : 2 + mono_ena;
|
||||
hw->fifo_conf.tx_fifo_mod = data_bit <= I2S_DATA_BIT_WIDTH_16BIT ? mono_ena : 2 + mono_ena;
|
||||
hw->conf.tx_dma_equal = mono_ena;
|
||||
hw->conf_chan.tx_chan_mod = mono_ena;
|
||||
}
|
||||
@@ -808,7 +880,7 @@ static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
|
||||
static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
|
||||
{
|
||||
int data_bit = hw->sample_rate_conf.rx_bits_mod;
|
||||
hw->fifo_conf.rx_fifo_mod = data_bit <= I2S_BITS_PER_SAMPLE_16BIT ? mono_ena : 2 + mono_ena;
|
||||
hw->fifo_conf.rx_fifo_mod = data_bit <= I2S_DATA_BIT_WIDTH_16BIT ? mono_ena : 2 + mono_ena;
|
||||
hw->conf.rx_dma_equal = mono_ena;
|
||||
hw->conf_chan.rx_chan_mod = mono_ena;
|
||||
}
|
||||
|
Reference in New Issue
Block a user