From 76cdab5f4281b44cc7d69d6a93b5a19f16bff46c Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Fri, 5 Aug 2022 18:31:37 +0800 Subject: [PATCH] i2s: fixed pdm rx sample rate doubled issue Closes: https://github.com/espressif/esp-idf/issues/8660 --- components/driver/i2s.c | 13 +++++++++++++ components/hal/esp32c3/include/hal/i2s_ll.h | 17 +++++++++++++++++ components/hal/esp32h2/include/hal/i2s_ll.h | 17 +++++++++++++++++ components/hal/esp32s3/include/hal/i2s_ll.h | 17 +++++++++++++++++ components/hal/i2s_hal.c | 5 ++++- 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index ead76ed916..4af9488602 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -1092,6 +1092,8 @@ static esp_err_t i2s_calculate_pdm_rx_clock(int i2s_num, i2s_hal_clock_cfg_t *cl /* Check if the configuration is correct */ ESP_RETURN_ON_FALSE(clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large"); + ESP_LOGD(TAG, "[sclk] %d [mclk] %d [mclk_div] %d [bclk] %d [bclk_div] %d", + clk_cfg->sclk, clk_cfg->mclk, clk_cfg->mclk_div, clk_cfg->bclk, clk_cfg->bclk_div); return ESP_OK; } @@ -1620,7 +1622,11 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ cfg->chan_mask = I2S_TDM_ACTIVE_CH0; // right slot mono cfg->chan_fmt = I2S_CHANNEL_FMT_ONLY_RIGHT; } +#if SOC_I2S_SUPPORTS_PDM_RX + cfg->total_chan = (p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_PDM) ? 1 : 2; +#else cfg->total_chan = 2; +#endif } } else { if (ch >> 16) { @@ -1673,6 +1679,13 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ ESP_RETURN_ON_FALSE(p_i2s[i2s_num]->tx, ESP_ERR_INVALID_ARG, TAG, "I2S TX DMA object has not initialized yet"); /* Waiting for transmit finish */ i2s_tx_set_clk_and_channel(i2s_num, &clk_cfg); + /* Workaround for ESP32-S3/C3, overwrite with speicial coefficients to lower down the noise */ +#if SOC_I2S_SUPPORTS_PDM_CODEC + if (p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_PDM) { + i2s_ll_tx_set_raw_clk_div(p_i2s[i2s_num]->hal.dev, 1, 1, 0, 0); + } +#endif // SOC_I2S_SUPPORTS_PDM_TX + /* If buffer size changed, the DMA buffer need realloc */ if (need_realloc) { p_i2s[i2s_num]->tx->buf_size = buf_size; diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index f7cb496b4b..50d4e2060a 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -217,6 +217,23 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) hw->tx_conf1.tx_bck_div_num = val - 1; } +/** + * @brief Set I2S tx raw clock division + * + * @param hw Peripheral I2S hardware instance address. + * @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 x, uint32_t y, uint32_t z, uint32_t yn1) +{ + hw->tx_clkm_div_conf.tx_clkm_div_x = x; + hw->tx_clkm_div_conf.tx_clkm_div_y = y; + hw->tx_clkm_div_conf.tx_clkm_div_z = z; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = yn1; +} + /** * @brief Configure I2S TX clock devider * diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index 38a700c5f6..a74a70b2c0 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -218,6 +218,23 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) hw->tx_conf1.tx_bck_div_num = val - 1; } +/** + * @brief Set I2S tx raw clock division + * + * @param hw Peripheral I2S hardware instance address. + * @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 x, uint32_t y, uint32_t z, uint32_t yn1) +{ + hw->tx_clkm_div_conf.tx_clkm_div_x = x; + hw->tx_clkm_div_conf.tx_clkm_div_y = y; + hw->tx_clkm_div_conf.tx_clkm_div_z = z; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = yn1; +} + /** * @brief Configure I2S TX clock devider * diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index c1b3ae7f50..11ed3ebb15 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -220,6 +220,23 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) hw->tx_conf1.tx_bck_div_num = val - 1; } +/** + * @brief Set I2S tx raw clock division + * + * @param hw Peripheral I2S hardware instance address. + * @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 x, uint32_t y, uint32_t z, uint32_t yn1) +{ + hw->tx_clkm_div_conf.tx_clkm_div_x = x; + hw->tx_clkm_div_conf.tx_clkm_div_y = y; + hw->tx_clkm_div_conf.tx_clkm_div_z = z; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = yn1; +} + /** * @brief Configure I2S TX clock devider * diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index a1ea4c7b68..0fdc56c550 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -134,7 +134,7 @@ void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rat i2s_ll_tx_enable_pdm_sd_codec(hal->dev, true); /* set pdm tx sigma-delta codec dither */ i2s_ll_tx_set_pdm_sd_dither(hal->dev, 0); - i2s_ll_tx_set_pdm_sd_dither2(hal->dev, 0); + i2s_ll_tx_set_pdm_sd_dither2(hal->dev, 1); #endif // SOC_I2S_SUPPORTS_PDM_CODEC } @@ -275,6 +275,9 @@ void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t chan_num = hal_cfg->total_chan; i2s_ll_rx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask >> 16); i2s_ll_rx_set_chan_num(hal->dev, chan_num); +#if SOC_I2S_SUPPORTS_PDM_RX + is_mono = (hal_cfg->mode & I2S_MODE_PDM) ? false : true; +#endif #else i2s_ll_rx_set_chan_mod(hal->dev, hal_cfg->chan_fmt < I2S_CHANNEL_FMT_ONLY_RIGHT ? hal_cfg->chan_fmt : (hal_cfg->chan_fmt >> 1)); // 0-two channel;1-right;2-left;3-righ;4-left #endif