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:
laokaiyao
2022-03-14 11:34:46 +08:00
parent c1bcb8756b
commit f17edba20b
25 changed files with 2793 additions and 2126 deletions

View File

@@ -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;
}