Prechádzať zdrojové kódy

i2s_pdm: fix tx frequency limitation

Closes: https://github.com/espressif/esp-idf/issues/10420
laokaiyao 3 rokov pred
rodič
commit
943dcd2cd1

+ 1 - 0
components/driver/deprecated/i2s_legacy.c

@@ -1201,6 +1201,7 @@ esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, const i2s_pdm_tx_upsample
     p_i2s[i2s_num]->clk_cfg.up_sample_fp = upsample_cfg->fp;
     p_i2s[i2s_num]->clk_cfg.up_sample_fs = upsample_cfg->fs;
     i2s_ll_tx_set_pdm_fpfs(p_i2s[i2s_num]->hal.dev, upsample_cfg->fp, upsample_cfg->fs);
+    i2s_ll_tx_set_pdm_over_sample_ratio(p_i2s[i2s_num]->hal.dev, upsample_cfg->fp / upsample_cfg->fs);
     i2s_start(i2s_num);
     xSemaphoreGive(p_i2s[i2s_num]->tx->mux);
     return i2s_set_clk(i2s_num, p_i2s[i2s_num]->clk_cfg.sample_rate_hz, p_i2s[i2s_num]->slot_cfg.data_bit_width, p_i2s[i2s_num]->slot_cfg.slot_mode);

+ 6 - 2
components/driver/i2s/i2s_pdm.c

@@ -35,7 +35,9 @@ static esp_err_t i2s_pdm_tx_calculate_clock(i2s_chan_handle_t handle, const i2s_
     uint32_t rate = clk_cfg->sample_rate_hz;
     i2s_pdm_tx_clk_config_t *pdm_tx_clk = (i2s_pdm_tx_clk_config_t *)clk_cfg;
 
-    clk_info->bclk = rate * I2S_LL_PDM_BCK_FACTOR * pdm_tx_clk->up_sample_fp / pdm_tx_clk->up_sample_fs;
+    // Over sampling ratio (integer, mostly should be 1 or 2)
+    uint32_t over_sample_ratio = pdm_tx_clk->up_sample_fp / pdm_tx_clk->up_sample_fs;
+    clk_info->bclk = rate * I2S_LL_PDM_BCK_FACTOR * over_sample_ratio;
     clk_info->bclk_div = 8;
     clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
     clk_info->sclk = i2s_get_source_clk_freq(clk_cfg->clk_src, clk_info->mclk);
@@ -43,8 +45,9 @@ static esp_err_t i2s_pdm_tx_calculate_clock(i2s_chan_handle_t handle, const i2s_
 
     /* Check if the configuration is correct */
     ESP_RETURN_ON_FALSE(clk_info->mclk_div, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
-    /* Set upsampling configuration */
+    /* Set up sampling configuration */
     i2s_ll_tx_set_pdm_fpfs(handle->controller->hal.dev, pdm_tx_clk->up_sample_fp, pdm_tx_clk->up_sample_fs);
+    i2s_ll_tx_set_pdm_over_sample_ratio(handle->controller->hal.dev, over_sample_ratio);
 
     return ESP_OK;
 }
@@ -53,6 +56,7 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
 {
     esp_err_t ret = ESP_OK;
     i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)(handle->mode_info);
+    ESP_RETURN_ON_FALSE(clk_cfg->up_sample_fs <= 480, ESP_ERR_INVALID_ARG, TAG, "up_sample_fs should be within 480");
 
     i2s_hal_clock_info_t clk_info;
     /* Calculate clock parameters */

+ 4 - 4
components/driver/include/driver/i2s_pdm.h

@@ -210,7 +210,7 @@ esp_err_t i2s_channel_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_p
  *       2: fp = 960, fs = 480, in this case, Fpdm = 128*Fpcm = 128*sample_rate_hz
  *       If the pdm receiver do not care the pdm serial clock, it's recommended set Fpdm = 128*48000.
  *       Otherwise, the second configuration should be adopted.
- * @param rate sample rate
+ * @param rate sample rate (not suggest to exceed 48000 Hz, otherwise more glitches and noise may appear)
  */
 #define I2S_PDM_TX_CLK_DEFAULT_CONFIG(rate) { \
     .sample_rate_hz = rate, \
@@ -256,7 +256,7 @@ typedef struct {
     i2s_pdm_sig_scale_t     lp_scale;           /*!< Low pass filter scaling value */
     i2s_pdm_sig_scale_t     sinc_scale;         /*!< Sinc filter scaling value */
 #if SOC_I2S_HW_VERSION_2
-    i2s_pdm_tx_line_mode_t  line_mode;          /*!< PDM TX line mode, on-line codec, one-line dac, two-line dac mode can be selected */
+    i2s_pdm_tx_line_mode_t  line_mode;          /*!< PDM TX line mode, one-line codec, one-line dac, two-line dac mode can be selected */
     bool                    hp_en;              /*!< High pass filter enable */
     float                   hp_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */
     uint32_t                sd_dither;          /*!< Sigma-delta filter dither */
@@ -269,12 +269,12 @@ typedef struct {
  */
 typedef struct {
     /* General fields */
-    uint32_t                sample_rate_hz;     /*!< I2S sample rate */
+    uint32_t                sample_rate_hz;     /*!< I2S sample rate, not suggest to exceed 48000 Hz, otherwise more glitches and noise may appear */
     i2s_clock_src_t         clk_src;            /*!< Choose clock source */
     i2s_mclk_multiple_t     mclk_multiple;      /*!< The multiple of mclk to the sample rate */
     /* Particular fields */
     uint32_t                up_sample_fp;       /*!< Up-sampling param fp */
-    uint32_t                up_sample_fs;       /*!< Up-sampling param fs */
+    uint32_t                up_sample_fs;       /*!< Up-sampling param fs, not allowed to be greater than 480 */
 } i2s_pdm_tx_clk_config_t;
 
 /**

+ 11 - 1
components/hal/esp32/include/hal/i2s_ll.h

@@ -1044,6 +1044,17 @@ static inline void i2s_ll_tx_set_pdm_sd_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t
     hw->pdm_conf.tx_sigmadelta_in_shift = sig_scale;
 }
 
+/**
+ * @brief Set the PDM TX over sampling ratio
+ *
+ * @param hw  Peripheral I2S hardware instance address.
+ * @param ovr Over sampling ratio
+ */
+static inline void i2s_ll_tx_set_pdm_over_sample_ratio(i2s_dev_t *hw, uint32_t ovr)
+{
+    hw->pdm_conf.tx_sinc_osr2 = ovr;
+}
+
 /**
  * @brief Configure I2S TX PDM sample rate
  *        Fpdm = 64*Fpcm*fp/fs
@@ -1056,7 +1067,6 @@ static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f
 {
     hw->pdm_freq_conf.tx_pdm_fp = fp;
     hw->pdm_freq_conf.tx_pdm_fs = fs;
-    hw->pdm_conf.tx_sinc_osr2 = fp / fs;
 }
 
 /**

+ 11 - 1
components/hal/esp32c3/include/hal/i2s_ll.h

@@ -877,6 +877,17 @@ static inline void i2s_ll_tx_set_pdm_sd_dither2(i2s_dev_t *hw, uint32_t dither2)
     hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither2 = dither2;
 }
 
+/**
+ * @brief Set the PDM TX over sampling ratio
+ *
+ * @param hw  Peripheral I2S hardware instance address.
+ * @param ovr Over sampling ratio
+ */
+static inline void i2s_ll_tx_set_pdm_over_sample_ratio(i2s_dev_t *hw, uint32_t ovr)
+{
+    hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = ovr;
+}
+
 /**
  * @brief Configure I2S TX PDM sample rate
  *        Fpdm = 64*Fpcm*fp/fs
@@ -889,7 +900,6 @@ static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f
 {
     hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp;
     hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs;
-    hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = fp / fs;
 }
 
 /**

+ 11 - 1
components/hal/esp32c6/include/hal/i2s_ll.h

@@ -892,6 +892,17 @@ static inline void i2s_ll_tx_set_pdm_sd_dither2(i2s_dev_t *hw, uint32_t dither2)
     hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither2 = dither2;
 }
 
+/**
+ * @brief Set the PDM TX over sampling ratio
+ *
+ * @param hw  Peripheral I2S hardware instance address.
+ * @param ovr Over sampling ratio
+ */
+static inline void i2s_ll_tx_set_pdm_over_sample_ratio(i2s_dev_t *hw, uint32_t ovr)
+{
+    hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = ovr;
+}
+
 /**
  * @brief Configure I2S TX PDM sample rate
  *        Fpdm = 64*Fpcm*fp/fs
@@ -904,7 +915,6 @@ static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f
 {
     hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp;
     hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs;
-    hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = fp / fs;
 }
 
 /**

+ 11 - 1
components/hal/esp32h4/include/hal/i2s_ll.h

@@ -878,6 +878,17 @@ static inline void i2s_ll_tx_set_pdm_sd_dither2(i2s_dev_t *hw, uint32_t dither2)
     hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither2 = dither2;
 }
 
+/**
+ * @brief Set the PDM TX over sampling ratio
+ *
+ * @param hw  Peripheral I2S hardware instance address.
+ * @param ovr Over sampling ratio
+ */
+static inline void i2s_ll_tx_set_pdm_over_sample_ratio(i2s_dev_t *hw, uint32_t ovr)
+{
+    hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = ovr;
+}
+
 /**
  * @brief Configure I2S TX PDM sample rate
  *        Fpdm = 64*Fpcm*fp/fs
@@ -890,7 +901,6 @@ static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f
 {
     hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp;
     hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs;
-    hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = fp / fs;
 }
 
 /**

+ 11 - 1
components/hal/esp32s3/include/hal/i2s_ll.h

@@ -780,6 +780,17 @@ static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw)
     hw->rx_conf.rx_pdm2pcm_en = true;
 }
 
+/**
+ * @brief Set the PDM TX over sampling ratio
+ *
+ * @param hw  Peripheral I2S hardware instance address.
+ * @param ovr Over sampling ratio
+ */
+static inline void i2s_ll_tx_set_pdm_over_sample_ratio(i2s_dev_t *hw, uint32_t ovr)
+{
+    hw->tx_pcm2pdm_conf.tx_sinc_osr2 = ovr;
+}
+
 /**
  * @brief Configure I2S TX PDM sample rate
  *        Fpdm = 64*Fpcm*fp/fs
@@ -792,7 +803,6 @@ static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f
 {
     hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp;
     hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs;
-    hw->tx_pcm2pdm_conf.tx_sinc_osr2 = fp / fs;
 }
 
 /**