mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-22 09:06:27 +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:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -33,9 +33,9 @@ extern "C" {
|
||||
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
@@ -103,7 +103,7 @@ static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw)
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_mclk_use_tx_clk(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_mclk_bind_to_tx_clk(i2s_dev_t *hw)
|
||||
{
|
||||
hw->rx_clkm_conf.mclk_sel = 0;
|
||||
}
|
||||
@@ -113,7 +113,7 @@ static inline void i2s_ll_mclk_use_tx_clk(i2s_dev_t *hw)
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_mclk_use_rx_clk(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_mclk_bind_to_rx_clk(i2s_dev_t *hw)
|
||||
{
|
||||
hw->rx_clkm_conf.mclk_sel = 1;
|
||||
}
|
||||
@@ -218,31 +218,65 @@ 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
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
if (set->a == 0 || set->b == 0) {
|
||||
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:
|
||||
if (denominator == 0 || numerator == 0) {
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_x = 0;
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_y = 0;
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_z = 0;
|
||||
} else {
|
||||
if (set->b > set->a / 2) {
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / (set->a - set->b) - 1;
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % (set->a - set->b);
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_z = set->a - set->b;
|
||||
if (numerator > denominator / 2) {
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_x = denominator / (denominator - numerator) - 1;
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_y = denominator % (denominator - numerator);
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_z = denominator - numerator;
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 1;
|
||||
} else {
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / set->b - 1;
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % set->b + 1;
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_z = set->b;
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_x = denominator / numerator - 1;
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_y = denominator % numerator + 1;
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_z = numerator;
|
||||
hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0;
|
||||
}
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_clkm_conf, tx_clkm_div_num, set->mclk_div);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_clkm_conf, tx_clkm_div_num, mclk_div);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -257,31 +291,66 @@ 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 ESP32 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)
|
||||
{
|
||||
if (set->a == 0 || set->b == 0) {
|
||||
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:
|
||||
if (denominator == 0 || numerator == 0) {
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_x = 0;
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_y = 0;
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_z = 0;
|
||||
} else {
|
||||
if (set->b > set->a / 2) {
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / (set->a - set->b) - 1;
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % (set->a - set->b);
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_z = set->a - set->b;
|
||||
if (numerator > denominator / 2) {
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_x = denominator / (denominator - numerator) - 1;
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_y = denominator % (denominator - numerator);
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_z = denominator - numerator;
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 1;
|
||||
} else {
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / set->b - 1;
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % set->b + 1;
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_z = set->b;
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_x = denominator / numerator - 1;
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_y = denominator % numerator + 1;
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_z = numerator;
|
||||
hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0;
|
||||
}
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_clkm_conf, rx_clkm_div_num, set->mclk_div);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_clkm_conf, rx_clkm_div_num, mclk_div);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -503,17 +572,59 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @param pdm_enable Set true to TX enable PDM mode
|
||||
*/
|
||||
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)
|
||||
{
|
||||
hw->tx_conf.tx_pdm_en = pdm_enable;
|
||||
hw->tx_conf.tx_tdm_en = !pdm_enable;
|
||||
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pdm_enable;
|
||||
hw->tx_conf.tx_pdm_en = true;
|
||||
hw->tx_conf.tx_tdm_en = false;
|
||||
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user