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..53a4213621 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 * @@ -608,11 +625,11 @@ static inline void i2s_ll_tx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) * @brief Enable I2S TX PDM sigma-delta codec * * @param hw Peripheral I2S hardware instance address. - * @param dither I2S TX PDM sigmadelta dither value + * @param enable whether enable sd dac one line mode */ static inline void i2s_ll_tx_enable_pdm_sd_codec(i2s_dev_t *hw, bool enable) { - hw->tx_pcm2pdm_conf.tx_pdm_dac_2out_en = enable; + hw->tx_pcm2pdm_conf.tx_pdm_dac_2out_en = !enable; hw->tx_pcm2pdm_conf.tx_pdm_dac_mode_en = enable; } diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index 38a700c5f6..60519fbf06 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 * @@ -609,11 +626,11 @@ static inline void i2s_ll_tx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) * @brief Enable I2S TX PDM sigma-delta codec * * @param hw Peripheral I2S hardware instance address. - * @param dither I2S TX PDM sigmadelta dither value + * @param enable whether enable sd dac one line mode */ static inline void i2s_ll_tx_enable_pdm_sd_codec(i2s_dev_t *hw, bool enable) { - hw->tx_pcm2pdm_conf.tx_pdm_dac_2out_en = enable; + hw->tx_pcm2pdm_conf.tx_pdm_dac_2out_en = !enable; hw->tx_pcm2pdm_conf.tx_pdm_dac_mode_en = enable; } diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index c1b3ae7f50..f8a63ed16c 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 * @@ -663,11 +680,11 @@ static inline void i2s_ll_tx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) * @brief Enable I2S TX PDM sigma-delta codec * * @param hw Peripheral I2S hardware instance address. - * @param dither I2S TX PDM sigmadelta dither value + * @param enable whether enable sd dac one line mode */ static inline void i2s_ll_tx_enable_pdm_sd_codec(i2s_dev_t *hw, bool enable) { - hw->tx_pcm2pdm_conf.tx_dac_2out_en = enable; + hw->tx_pcm2pdm_conf.tx_dac_2out_en = !enable; hw->tx_pcm2pdm_conf.tx_dac_mode_en = enable; } diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index 2faf735690..a95aa8cc78 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -10,6 +10,7 @@ #include "soc/soc.h" #include "soc/soc_caps.h" #include "hal/i2s_hal.h" +#include "sdkconfig.h" /** * @brief Calculate the closest sample rate clock configuration. @@ -97,7 +98,7 @@ void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num) } #if SOC_I2S_SUPPORTS_PDM_TX -void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rate) +void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rate, bool is_mono) { /* enable pdm tx mode */ i2s_ll_tx_enable_pdm(hal->dev, true); @@ -129,11 +130,11 @@ void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rat /* set pdm tx high pass filter parameters */ i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, 6); i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, 7); - /* enable pdm sigma-delta codec */ - i2s_ll_tx_enable_pdm_sd_codec(hal->dev, true); + /* enable pdm sigma-delta dac */ + i2s_ll_tx_enable_pdm_sd_codec(hal->dev, is_mono); /* 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 } @@ -180,8 +181,12 @@ void i2s_hal_tx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t * i2s_ll_tx_enable_big_endian(hal->dev, hal_cfg->big_edin); i2s_ll_tx_set_bit_order(hal->dev, hal_cfg->bit_order_msb); i2s_ll_tx_set_skip_mask(hal->dev, hal_cfg->skip_msk); +#else +#if CONFIG_IDF_TARGET_ESP32 + i2s_ll_tx_enable_msb_right(hal->dev, hal_cfg->sample_bits <= I2S_BITS_PER_SAMPLE_16BIT); #else i2s_ll_tx_enable_msb_right(hal->dev, false); +#endif i2s_ll_tx_enable_right_first(hal->dev, false); i2s_ll_tx_force_enable_fifo_mod(hal->dev, true); #endif @@ -204,8 +209,12 @@ void i2s_hal_rx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t * i2s_ll_rx_enable_left_align(hal->dev, hal_cfg->left_align); i2s_ll_rx_enable_big_endian(hal->dev, hal_cfg->big_edin); i2s_ll_rx_set_bit_order(hal->dev, hal_cfg->bit_order_msb); +#else +#if CONFIG_IDF_TARGET_ESP32 + i2s_ll_rx_enable_msb_right(hal->dev, hal_cfg->sample_bits <= I2S_BITS_PER_SAMPLE_16BIT); #else i2s_ll_rx_enable_msb_right(hal->dev, false); +#endif i2s_ll_rx_enable_right_first(hal->dev, false); i2s_ll_rx_force_enable_fifo_mod(hal->dev, true); #endif @@ -240,6 +249,13 @@ void i2s_hal_tx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t i2s_ll_tx_set_chan_num(hal->dev, chan_num); #else i2s_ll_tx_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 +#if SOC_I2S_SUPPORTS_PDM_CODEC + if (hal_cfg->mode & I2S_MODE_PDM) { + // Fixed to 16 while using mono mode and 32 while using stereo mode + data_bits = hal_cfg->chan_fmt == I2S_CHANNEL_FMT_RIGHT_LEFT ? 32 : 16; + chan_bits = data_bits; + } #endif i2s_ll_tx_set_sample_bit(hal->dev, chan_bits, data_bits); i2s_ll_tx_enable_mono_mode(hal->dev, is_mono); @@ -250,7 +266,13 @@ void i2s_hal_tx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t i2s_ll_tx_enable_msb_shift(hal->dev, shift_en); i2s_ll_tx_set_ws_width(hal->dev, ws_width); #if SOC_I2S_SUPPORTS_TDM - i2s_ll_tx_set_half_sample_bit(hal->dev, chan_num * chan_bits / 2); + uint32_t half_sample_bits = chan_num * chan_bits / 2; +#if SOC_I2S_SUPPORTS_PDM_CODEC + if (hal_cfg->mode & I2S_MODE_PDM) { + half_sample_bits = 16; // Fixed to 16 in PDM mode + } +#endif + i2s_ll_tx_set_half_sample_bit(hal->dev, half_sample_bits); #endif } @@ -266,6 +288,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 @@ -310,7 +335,7 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf #if SOC_I2S_SUPPORTS_PDM_TX if (hal_cfg->mode & I2S_MODE_PDM) { /* Set tx pdm mode */ - i2s_hal_tx_set_pdm_mode_default(hal, hal_cfg->sample_rate); + i2s_hal_tx_set_pdm_mode_default(hal, hal_cfg->sample_rate, hal_cfg->chan_fmt != I2S_CHANNEL_FMT_RIGHT_LEFT); } else #endif { diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index 0e75b80143..2be94f66d1 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -352,8 +352,9 @@ void i2s_hal_rx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t * * * @param hal Context of the HAL layer * @param sample_rate PDM sample rate + * @param is_mono whether is mono */ -void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rate); +void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rate, bool is_mono); #endif #if SOC_I2S_SUPPORTS_PDM_RX