i2s: workaround for inacurate PLL frequency after switching

This commit is contained in:
laokaiyao 2023-03-29 17:18:14 +08:00 committed by Kevin (Lao Kaiyao)
parent bc216802c6
commit a143a85822
8 changed files with 242 additions and 208 deletions

View File

@ -746,10 +746,8 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_c
esp_rom_gpio_connect_out_signal(MASTER_WS_IO, i2s_periph_signal[0].m_rx_ws_sig, 0, 0); esp_rom_gpio_connect_out_signal(MASTER_WS_IO, i2s_periph_signal[0].m_rx_ws_sig, 0, 0);
esp_rom_gpio_connect_in_signal(MASTER_WS_IO, pcnt_periph_signals.groups[0].units[0].channels[0].pulse_sig, 0); esp_rom_gpio_connect_in_signal(MASTER_WS_IO, pcnt_periph_signals.groups[0].units[0].channels[0].pulse_sig, 0);
/* Test common sample rate
* Workaround: set 12000 as 12001 to bypass the unknown failure, TODO: IDF-6705 */
const uint32_t test_freq[] = { const uint32_t test_freq[] = {
8000, 10001, 11025, 12001, 16000, 22050, 8000, 10000, 11025, 12000, 16000, 22050,
24000, 32000, 44100, 48000, 64000, 88200, 24000, 32000, 44100, 48000, 64000, 88200,
96000, 128000,144000,196000}; 96000, 128000,144000,196000};
int real_pulse = 0; int real_pulse = 0;

View File

@ -874,10 +874,8 @@ static void i2s_test_common_sample_rate(i2s_port_t id)
esp_rom_gpio_connect_out_signal(MASTER_WS_IO, i2s_periph_signal[0].m_tx_ws_sig, 0, 0); esp_rom_gpio_connect_out_signal(MASTER_WS_IO, i2s_periph_signal[0].m_tx_ws_sig, 0, 0);
esp_rom_gpio_connect_in_signal(MASTER_WS_IO, pcnt_periph_signals.groups[0].units[0].channels[0].pulse_sig, 0); esp_rom_gpio_connect_in_signal(MASTER_WS_IO, pcnt_periph_signals.groups[0].units[0].channels[0].pulse_sig, 0);
/* Test common sample rate
* Workaround: set 12000 as 12001 to bypass the unknown failure, TODO: IDF-6705 */
const uint32_t test_freq[] = { const uint32_t test_freq[] = {
8000, 10000, 11025, 12001, 16000, 22050, 8000, 10000, 11025, 12000, 16000, 22050,
24000, 32000, 44100, 48000, 64000, 88200, 24000, 32000, 44100, 48000, 64000, 88200,
96000, 128000, 144000,196000}; 96000, 128000, 144000,196000};
int real_pulse = 0; int real_pulse = 0;

View File

@ -285,6 +285,23 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
hw->sample_rate_conf.tx_bck_div_num = val; hw->sample_rate_conf.tx_bck_div_num = val;
} }
/**
* @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;
}
/** /**
* @brief Configure I2S TX module clock divider * @brief Configure I2S TX module clock divider
* @note mclk on ESP32 is shared by both TX and RX channel * @note mclk on ESP32 is shared by both TX and RX channel
@ -328,26 +345,12 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mcl
} }
} }
finish: finish:
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, mclk_div); /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
hw->clkm_conf.clkm_div_b = numerator; * Set to particular coefficients first then update to the target coefficients,
hw->clkm_conf.clkm_div_a = denominator; * otherwise the clock division might be inaccurate.
} * The particular coefficients here is calculated from 44100 Hz with 2 slots & 16-bit width @ 160MHz sclk */
i2s_ll_set_raw_mclk_div(hw, 13, 48, 1);
/** i2s_ll_set_raw_mclk_div(hw, mclk_div, denominator, numerator);
* @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;
} }
/** /**

View File

@ -254,10 +254,12 @@ 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 x, uint32_t y, uint32_t z, uint32_t yn1) static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1)
{ {
hw->tx_clkm_div_conf.tx_clkm_div_x = x; typeof(hw->tx_clkm_div_conf) div = {};
hw->tx_clkm_div_conf.tx_clkm_div_y = y; div.tx_clkm_div_x = x;
hw->tx_clkm_div_conf.tx_clkm_div_z = z; div.tx_clkm_div_y = y;
hw->tx_clkm_div_conf.tx_clkm_div_yn1 = yn1; div.tx_clkm_div_z = z;
div.tx_clkm_div_yn1 = yn1;
hw->tx_clkm_div_conf.val = div.val;
} }
/** /**
@ -271,10 +273,12 @@ static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t
*/ */
static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1) static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1)
{ {
hw->rx_clkm_div_conf.rx_clkm_div_x = x; typeof(hw->rx_clkm_div_conf) div = {};
hw->rx_clkm_div_conf.rx_clkm_div_y = y; div.rx_clkm_div_x = x;
hw->rx_clkm_div_conf.rx_clkm_div_z = z; div.rx_clkm_div_y = y;
hw->rx_clkm_div_conf.rx_clkm_div_yn1 = yn1; div.rx_clkm_div_z = z;
div.rx_clkm_div_yn1 = yn1;
hw->rx_clkm_div_conf.val = div.val;
} }
/** /**
@ -319,23 +323,25 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mcl
} }
} }
finish: finish:
if (denominator == 0 || numerator == 0) { /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
hw->tx_clkm_div_conf.tx_clkm_div_x = 0; * Set to particular coefficients first then update to the target coefficients,
hw->tx_clkm_div_conf.tx_clkm_div_y = 0; * otherwise the clock division might be inaccurate.
hw->tx_clkm_div_conf.tx_clkm_div_z = 0; * The particular coefficients here is calculated from 44100 Hz with 2 slots & 16-bit width @ 160MHz sclk */
} else { i2s_ll_tx_set_raw_clk_div(hw, 47, 0, 1, 0);
if (numerator > denominator / 2) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_clkm_conf, tx_clkm_div_num, 13);
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); uint32_t div_x = 0;
hw->tx_clkm_div_conf.tx_clkm_div_z = denominator - numerator; uint32_t div_y = 0;
hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 1; uint32_t div_z = 0;
} else { uint32_t div_yn1 = 0;
hw->tx_clkm_div_conf.tx_clkm_div_x = denominator / numerator - 1; /* If any of denominator and numerator is 0, set all the coefficients to 0 */
hw->tx_clkm_div_conf.tx_clkm_div_y = denominator % numerator; if (denominator && numerator) {
hw->tx_clkm_div_conf.tx_clkm_div_z = numerator; div_yn1 = numerator * 2 > denominator;
hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0; div_z = div_yn1 ? denominator - numerator : numerator;
} div_x = denominator / div_z - 1;
div_y = denominator % div_z;
} }
i2s_ll_tx_set_raw_clk_div(hw, div_x, div_y, div_z, div_yn1);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_clkm_conf, tx_clkm_div_num, mclk_div); HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_clkm_conf, tx_clkm_div_num, mclk_div);
} }
@ -393,23 +399,25 @@ static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mcl
} }
} }
finish: finish:
if (denominator == 0 || numerator == 0) { /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
hw->rx_clkm_div_conf.rx_clkm_div_x = 0; * Set to particular coefficients first then update to the target coefficients,
hw->rx_clkm_div_conf.rx_clkm_div_y = 0; * otherwise the clock division might be inaccurate.
hw->rx_clkm_div_conf.rx_clkm_div_z = 0; * The particular coefficients here is calculated from 44100 Hz with 2 slots & 16-bit width @ 160MHz sclk */
} else { i2s_ll_rx_set_raw_clk_div(hw, 47, 0, 1, 0);
if (numerator > denominator / 2) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_clkm_conf, rx_clkm_div_num, 13);
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); uint32_t div_x = 0;
hw->rx_clkm_div_conf.rx_clkm_div_z = denominator - numerator; uint32_t div_y = 0;
hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 1; uint32_t div_z = 0;
} else { uint32_t div_yn1 = 0;
hw->rx_clkm_div_conf.rx_clkm_div_x = denominator / numerator - 1; /* If any of denominator and numerator is 0, set all the coefficients to 0 */
hw->rx_clkm_div_conf.rx_clkm_div_y = denominator % numerator; if (denominator && numerator) {
hw->rx_clkm_div_conf.rx_clkm_div_z = numerator; div_yn1 = numerator * 2 > denominator;
hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0; div_z = div_yn1 ? denominator - numerator : numerator;
} div_x = denominator / div_z - 1;
div_y = denominator % div_z;
} }
i2s_ll_rx_set_raw_clk_div(hw, div_x, div_y, div_z, div_yn1);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_clkm_conf, rx_clkm_div_num, mclk_div); HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_clkm_conf, rx_clkm_div_num, mclk_div);
} }

View File

@ -266,10 +266,12 @@ 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 x, uint32_t y, uint32_t z, uint32_t yn1) static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1)
{ {
(void)hw; (void)hw;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = x; typeof(PCR.i2s_tx_clkm_div_conf) div = {};
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = y; div.i2s_tx_clkm_div_x = x;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = z; div.i2s_tx_clkm_div_y = y;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = yn1; div.i2s_tx_clkm_div_z = z;
div.i2s_tx_clkm_div_yn1 = yn1;
PCR.i2s_tx_clkm_div_conf.val = div.val;
} }
/** /**
@ -284,10 +286,12 @@ static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t
static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1) static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1)
{ {
(void)hw; (void)hw;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = x; typeof(PCR.i2s_rx_clkm_div_conf) div = {};
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = y; div.i2s_rx_clkm_div_x = x;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = z; div.i2s_rx_clkm_div_y = y;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = yn1; div.i2s_rx_clkm_div_z = z;
div.i2s_rx_clkm_div_yn1 = yn1;
PCR.i2s_rx_clkm_div_conf.val = div.val;
} }
/** /**
@ -333,23 +337,25 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mcl
} }
} }
finish: finish:
if (denominator == 0 || numerator == 0) { /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = 0; * Set to particular coefficients first then update to the target coefficients,
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = 0; * otherwise the clock division might be inaccurate.
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = 0; * The particular coefficients here is calculated from 44100 Hz with 2 slots & 16-bit width @ 160MHz sclk */
} else { i2s_ll_tx_set_raw_clk_div(hw, 47, 0, 1, 0);
if (numerator > denominator / 2) { HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_tx_clkm_conf, i2s_tx_clkm_div_num, 13);
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = denominator / (denominator - numerator) - 1;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = denominator % (denominator - numerator); uint32_t div_x = 0;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = denominator - numerator; uint32_t div_y = 0;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = 1; uint32_t div_z = 0;
} else { uint32_t div_yn1 = 0;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = denominator / numerator - 1; /* If any of denominator and numerator is 0, set all the coefficients to 0 */
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = denominator % numerator; if (denominator && numerator) {
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = numerator; div_yn1 = numerator * 2 > denominator;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = 0; div_z = div_yn1 ? denominator - numerator : numerator;
} div_x = denominator / div_z - 1;
div_y = denominator % div_z;
} }
i2s_ll_tx_set_raw_clk_div(hw, div_x, div_y, div_z, div_yn1);
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_tx_clkm_conf, i2s_tx_clkm_div_num, mclk_div); HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_tx_clkm_conf, i2s_tx_clkm_div_num, mclk_div);
} }
@ -408,23 +414,25 @@ static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mcl
} }
} }
finish: finish:
if (denominator == 0 || numerator == 0) { /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = 0; * Set to particular coefficients first then update to the target coefficients,
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = 0; * otherwise the clock division might be inaccurate.
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = 0; * The particular coefficients here is calculated from 44100 Hz with 2 slots & 16-bit width @ 160MHz sclk */
} else { i2s_ll_rx_set_raw_clk_div(hw, 47, 0, 1, 0);
if (numerator > denominator / 2) { HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_rx_clkm_conf, i2s_rx_clkm_div_num, 13);
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = denominator / (denominator - numerator) - 1;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = denominator % (denominator - numerator); uint32_t div_x = 0;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = denominator - numerator; uint32_t div_y = 0;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = 1; uint32_t div_z = 0;
} else { uint32_t div_yn1 = 0;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = denominator / numerator - 1; /* If any of denominator and numerator is 0, set all the coefficients to 0 */
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = denominator % numerator; if (denominator && numerator) {
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = numerator; div_yn1 = numerator * 2 > denominator;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = 0; div_z = div_yn1 ? denominator - numerator : numerator;
} div_x = denominator / div_z - 1;
div_y = denominator % div_z;
} }
i2s_ll_rx_set_raw_clk_div(hw, div_x, div_y, div_z, div_yn1);
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_rx_clkm_conf, i2s_rx_clkm_div_num, mclk_div); HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_rx_clkm_conf, i2s_rx_clkm_div_num, mclk_div);
} }

View File

@ -273,10 +273,12 @@ 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 x, uint32_t y, uint32_t z, uint32_t yn1) static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1)
{ {
(void)hw; (void)hw;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = x; typeof(PCR.i2s_tx_clkm_div_conf) div = {};
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = y; div.i2s_tx_clkm_div_x = x;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = z; div.i2s_tx_clkm_div_y = y;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = yn1; div.i2s_tx_clkm_div_z = z;
div.i2s_tx_clkm_div_yn1 = yn1;
PCR.i2s_tx_clkm_div_conf.val = div.val;
} }
/** /**
@ -291,10 +293,12 @@ static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t
static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1) static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1)
{ {
(void)hw; (void)hw;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = x; typeof(PCR.i2s_rx_clkm_div_conf) div = {};
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = y; div.i2s_rx_clkm_div_x = x;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = z; div.i2s_rx_clkm_div_y = y;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = yn1; div.i2s_rx_clkm_div_z = z;
div.i2s_rx_clkm_div_yn1 = yn1;
PCR.i2s_rx_clkm_div_conf.val = div.val;
} }
/** /**
@ -340,23 +344,25 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mcl
} }
} }
finish: finish:
if (denominator == 0 || numerator == 0) { /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = 0; * Set to particular coefficients first then update to the target coefficients,
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = 0; * otherwise the clock division might be inaccurate.
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = 0; * The particular coefficients here is calculated from 44100 Hz with 2 slots & 16-bit width @96MHz sclk */
} else { i2s_ll_tx_set_raw_clk_div(hw, 1, 1, 73, 1);
if (numerator > denominator / 2) { HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_tx_clkm_conf, i2s_tx_clkm_div_num, 8);
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = denominator / (denominator - numerator) - 1;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = denominator % (denominator - numerator); uint32_t div_x = 0;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = denominator - numerator; uint32_t div_y = 0;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = 1; uint32_t div_z = 0;
} else { uint32_t div_yn1 = 0;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_x = denominator / numerator - 1; /* If any of denominator and numerator is 0, set all the coefficients to 0 */
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_y = denominator % numerator; if (denominator && numerator) {
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_z = numerator; div_yn1 = numerator * 2 > denominator;
PCR.i2s_tx_clkm_div_conf.i2s_tx_clkm_div_yn1 = 0; div_z = div_yn1 ? denominator - numerator : numerator;
} div_x = denominator / div_z - 1;
div_y = denominator % div_z;
} }
i2s_ll_tx_set_raw_clk_div(hw, div_x, div_y, div_z, div_yn1);
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_tx_clkm_conf, i2s_tx_clkm_div_num, mclk_div); HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_tx_clkm_conf, i2s_tx_clkm_div_num, mclk_div);
} }
@ -415,23 +421,25 @@ static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mcl
} }
} }
finish: finish:
if (denominator == 0 || numerator == 0) { /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = 0; * Set to particular coefficients first then update to the target coefficients,
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = 0; * otherwise the clock division might be inaccurate.
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = 0; * The particular coefficients here is calculated from 44100 Hz with 2 slots & 16-bit width @96MHz sclk */
} else { i2s_ll_rx_set_raw_clk_div(hw, 1, 1, 73, 1);
if (numerator > denominator / 2) { HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_rx_clkm_conf, i2s_rx_clkm_div_num, 8);
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = denominator / (denominator - numerator) - 1;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = denominator % (denominator - numerator); uint32_t div_x = 0;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = denominator - numerator; uint32_t div_y = 0;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = 1; uint32_t div_z = 0;
} else { uint32_t div_yn1 = 0;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_x = denominator / numerator - 1; /* If any of denominator and numerator is 0, set all the coefficients to 0 */
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_y = denominator % numerator; if (denominator && numerator) {
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_z = numerator; div_yn1 = numerator * 2 > denominator;
PCR.i2s_rx_clkm_div_conf.i2s_rx_clkm_div_yn1 = 0; div_z = div_yn1 ? denominator - numerator : numerator;
} div_x = denominator / div_z - 1;
div_y = denominator % div_z;
} }
i2s_ll_rx_set_raw_clk_div(hw, div_x, div_y, div_z, div_yn1);
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_rx_clkm_conf, i2s_rx_clkm_div_num, mclk_div); HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_rx_clkm_conf, i2s_rx_clkm_div_num, mclk_div);
} }

View File

@ -276,6 +276,23 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
hw->sample_rate_conf.tx_bck_div_num = val; hw->sample_rate_conf.tx_bck_div_num = val;
} }
/**
* @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;
}
/** /**
* @brief Configure I2S TX module clock divider * @brief Configure I2S TX module clock divider
* @note mclk on ESP32S2 is shared by both TX and RX channel * @note mclk on ESP32S2 is shared by both TX and RX channel
@ -319,26 +336,12 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mcl
} }
} }
finish: finish:
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, mclk_div); /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
hw->clkm_conf.clkm_div_b = numerator; * Set to particular coefficients first then update to the target coefficients,
hw->clkm_conf.clkm_div_a = denominator; * otherwise the clock division might be inaccurate.
} * The particular coefficients here is calculated from 44100 Hz with 2 slots & 16-bit width @ 160MHz sclk */
i2s_ll_set_raw_mclk_div(hw, 13, 48, 1);
/** i2s_ll_set_raw_mclk_div(hw, mclk_div, denominator, numerator);
* @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;
} }
/** /**

View File

@ -254,10 +254,12 @@ 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 x, uint32_t y, uint32_t z, uint32_t yn1) static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1)
{ {
hw->tx_clkm_div_conf.tx_clkm_div_x = x; typeof(hw->tx_clkm_div_conf) div = {};
hw->tx_clkm_div_conf.tx_clkm_div_y = y; div.tx_clkm_div_x = x;
hw->tx_clkm_div_conf.tx_clkm_div_z = z; div.tx_clkm_div_y = y;
hw->tx_clkm_div_conf.tx_clkm_div_yn1 = yn1; div.tx_clkm_div_z = z;
div.tx_clkm_div_yn1 = yn1;
hw->tx_clkm_div_conf.val = div.val;
} }
/** /**
@ -271,10 +273,12 @@ static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t
*/ */
static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1) static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1)
{ {
hw->rx_clkm_div_conf.rx_clkm_div_x = x; typeof(hw->rx_clkm_div_conf) div = {};
hw->rx_clkm_div_conf.rx_clkm_div_y = y; div.rx_clkm_div_x = x;
hw->rx_clkm_div_conf.rx_clkm_div_z = z; div.rx_clkm_div_y = y;
hw->rx_clkm_div_conf.rx_clkm_div_yn1 = yn1; div.rx_clkm_div_z = z;
div.rx_clkm_div_yn1 = yn1;
hw->rx_clkm_div_conf.val = div.val;
} }
/** /**
@ -319,24 +323,26 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mcl
} }
} }
finish: finish:
/* 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 particular coefficients here is calculated from 44100 Hz with 2 slots & 16-bit width @ 160MHz sclk */
i2s_ll_tx_set_raw_clk_div(hw, 47, 0, 1, 0);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_clkm_conf, tx_clkm_div_num, 13);
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 (denominator && numerator) {
div_yn1 = numerator * 2 > denominator;
div_z = div_yn1 ? denominator - numerator : numerator;
div_x = denominator / div_z - 1;
div_y = denominator % div_z;
}
i2s_ll_tx_set_raw_clk_div(hw, div_x, div_y, div_z, div_yn1);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_clkm_conf, tx_clkm_div_num, mclk_div); HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_clkm_conf, tx_clkm_div_num, mclk_div);
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 (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 = denominator / numerator - 1;
hw->tx_clkm_div_conf.tx_clkm_div_y = denominator % numerator;
hw->tx_clkm_div_conf.tx_clkm_div_z = numerator;
hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0;
}
}
} }
/** /**
@ -393,24 +399,26 @@ static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, uint32_t sclk, uint32_t mcl
} }
} }
finish: finish:
/* 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 particular coefficients here is calculated from 44100 Hz with 2 slots & 16-bit width @ 160MHz sclk */
i2s_ll_rx_set_raw_clk_div(hw, 47, 0, 1, 0);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_clkm_conf, rx_clkm_div_num, 13);
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 (denominator && numerator) {
div_yn1 = numerator * 2 > denominator;
div_z = div_yn1 ? denominator - numerator : numerator;
div_x = denominator / div_z - 1;
div_y = denominator % div_z;
}
i2s_ll_rx_set_raw_clk_div(hw, div_x, div_y, div_z, div_yn1);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_clkm_conf, rx_clkm_div_num, mclk_div); HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_clkm_conf, rx_clkm_div_num, mclk_div);
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 (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 = denominator / numerator - 1;
hw->rx_clkm_div_conf.rx_clkm_div_y = denominator % numerator;
hw->rx_clkm_div_conf.rx_clkm_div_z = numerator;
hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0;
}
}
} }
/** /**