Skip to content

Commit

Permalink
Merge branch 'bugfix/i2s_pdm_dac_wrong_clock_freq' into 'master'
Browse files Browse the repository at this point in the history
i2s_pdm: fix tx frequency limitation

Closes IDFGH-9010

See merge request espressif/esp-idf!21764
  • Loading branch information
L-KAYA committed Dec 30, 2022
2 parents c681c92 + 943dcd2 commit 42509fa
Show file tree
Hide file tree
Showing 23 changed files with 120 additions and 65 deletions.
2 changes: 1 addition & 1 deletion components/driver/deprecated/dac_common_legacy.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ esp_err_t dac_cw_generator_config(dac_cw_config_t *cw)
{
ESP_RETURN_ON_FALSE(cw, ESP_ERR_INVALID_ARG, TAG, "invalid clock configuration");
portENTER_CRITICAL(&rtc_spinlock);
/* Enable the rtc8m clock temporary to get the correct frequecy */
/* Enable the rtc8m clock temporary to get the correct frequency */
periph_rtc_dig_clk8m_enable();
uint32_t rtc_freq = periph_rtc_dig_clk8m_get_freq();
periph_rtc_dig_clk8m_disable();
Expand Down
1 change: 1 addition & 0 deletions components/driver/deprecated/i2s_legacy.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion components/driver/i2s/i2s_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ static uint32_t i2s_set_get_apll_freq(uint32_t mclk_freq_hz)
mclk_div = mclk_div < 2 ? 2 : mclk_div;
uint32_t expt_freq = mclk_freq_hz * mclk_div;
if (expt_freq > SOC_APLL_MAX_HZ) {
ESP_LOGE(TAG, "The required APLL frequecy exceed its maximum value");
ESP_LOGE(TAG, "The required APLL frequency exceed its maximum value");
return 0;
}
uint32_t real_freq = 0;
Expand Down
22 changes: 13 additions & 9 deletions components/driver/i2s/i2s_pdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,19 @@ 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);
clk_info->mclk_div = clk_info->sclk / clk_info->mclk;

/* 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;
}
Expand All @@ -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 */
Expand All @@ -64,7 +68,7 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
/* Set clock configurations in HAL*/
i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
#if SOC_I2S_HW_VERSION_2
/* Work aroud for PDM TX clock, overwrite the raw division directly to reduce the noise
/* Work around for PDM TX clock, overwrite the raw division directly to reduce the noise
* This set of coefficients is a special division to reduce the background noise in PDM TX mode */
i2s_ll_tx_set_raw_clk_div(handle->controller->hal.dev, 1, 1, 0, 0);
#endif
Expand Down Expand Up @@ -213,7 +217,7 @@ esp_err_t i2s_channel_reconfig_pdm_tx_clock(i2s_chan_handle_t handle, const i2s_
esp_err_t ret = ESP_OK;

xSemaphoreTake(handle->mutex, portMAX_DELAY);
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard moded");
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be disabled before reconfiguring the clock");
i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)handle->mode_info;
ESP_GOTO_ON_FALSE(pdm_tx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
Expand Down Expand Up @@ -263,7 +267,7 @@ esp_err_t i2s_channel_reconfig_pdm_tx_slot(i2s_chan_handle_t handle, const i2s_p
esp_err_t ret = ESP_OK;

xSemaphoreTake(handle->mutex, portMAX_DELAY);
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard moded");
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be disabled before reconfiguring the slot");

i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)handle->mode_info;
Expand Down Expand Up @@ -294,7 +298,7 @@ esp_err_t i2s_channel_reconfig_pdm_tx_gpio(i2s_chan_handle_t handle, const i2s_p
esp_err_t ret = ESP_OK;

xSemaphoreTake(handle->mutex, portMAX_DELAY);
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard moded");
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio");

ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
Expand Down Expand Up @@ -489,7 +493,7 @@ esp_err_t i2s_channel_reconfig_pdm_rx_clock(i2s_chan_handle_t handle, const i2s_
esp_err_t ret = ESP_OK;

xSemaphoreTake(handle->mutex, portMAX_DELAY);
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard moded");
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be disabled before reconfiguring the clock");
i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)handle->mode_info;
ESP_GOTO_ON_FALSE(pdm_rx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
Expand Down Expand Up @@ -539,7 +543,7 @@ esp_err_t i2s_channel_reconfig_pdm_rx_slot(i2s_chan_handle_t handle, const i2s_p
esp_err_t ret = ESP_OK;

xSemaphoreTake(handle->mutex, portMAX_DELAY);
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard moded");
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be disabled before reconfiguring the slot");

i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)handle->mode_info;
Expand Down Expand Up @@ -569,7 +573,7 @@ esp_err_t i2s_channel_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_p
esp_err_t ret = ESP_OK;

xSemaphoreTake(handle->mutex, portMAX_DELAY);
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard moded");
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio");

ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
Expand Down
4 changes: 2 additions & 2 deletions components/driver/i2s/i2s_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ esp_err_t i2s_free_dma_desc(i2s_chan_handle_t handle);
* @return
* - ESP_OK Allocate memory success
* - ESP_ERR_INVALID_ARG NULL pointer or bufsize is too big
* - ESP_ERR_NO_MEM No memmory for DMA descriptor and DMA buffer
* - ESP_ERR_NO_MEM No memory for DMA descriptor and DMA buffer
*/
esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bufsize);

Expand All @@ -165,7 +165,7 @@ uint32_t i2s_get_buf_size(i2s_chan_handle_t handle, uint32_t data_bit_width, uin
* @brief Get the frequency of the source clock
*
* @param clk_src clock source
* @param mclk_freq_hz Expected mclk frequenct in Hz
* @param mclk_freq_hz Expected mclk frequency in Hz
* @return
* - Actual source clock frequency
*/
Expand Down
6 changes: 3 additions & 3 deletions components/driver/i2s/i2s_std.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ esp_err_t i2s_channel_reconfig_std_clock(i2s_chan_handle_t handle, const i2s_std
esp_err_t ret = ESP_OK;

xSemaphoreTake(handle->mutex, portMAX_DELAY);
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_STD, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard moded");
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_STD, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be disabled before reconfiguring the clock");

i2s_std_config_t *std_cfg = (i2s_std_config_t *)handle->mode_info;
Expand Down Expand Up @@ -309,7 +309,7 @@ esp_err_t i2s_channel_reconfig_std_slot(i2s_chan_handle_t handle, const i2s_std_
esp_err_t ret = ESP_OK;

xSemaphoreTake(handle->mutex, portMAX_DELAY);
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_STD, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard moded");
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_STD, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be disabled before reconfiguring the slot");

i2s_std_config_t *std_cfg = (i2s_std_config_t *)handle->mode_info;
Expand Down Expand Up @@ -339,7 +339,7 @@ esp_err_t i2s_channel_reconfig_std_gpio(i2s_chan_handle_t handle, const i2s_std_
esp_err_t ret = ESP_OK;

xSemaphoreTake(handle->mutex, portMAX_DELAY);
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_STD, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard moded");
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_STD, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio");

ESP_GOTO_ON_ERROR(i2s_std_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
Expand Down
6 changes: 3 additions & 3 deletions components/driver/i2s/i2s_tdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ esp_err_t i2s_channel_reconfig_tdm_clock(i2s_chan_handle_t handle, const i2s_tdm
esp_err_t ret = ESP_OK;

xSemaphoreTake(handle->mutex, portMAX_DELAY);
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_TDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard moded");
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_TDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be disabled before reconfiguring the clock");
i2s_tdm_config_t *tdm_cfg = (i2s_tdm_config_t *)handle->mode_info;
ESP_GOTO_ON_FALSE(tdm_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
Expand Down Expand Up @@ -314,7 +314,7 @@ esp_err_t i2s_channel_reconfig_tdm_slot(i2s_chan_handle_t handle, const i2s_tdm_
esp_err_t ret = ESP_OK;

xSemaphoreTake(handle->mutex, portMAX_DELAY);
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_TDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard moded");
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_TDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be disabled before reconfiguring the slot");

i2s_tdm_config_t *tdm_cfg = (i2s_tdm_config_t *)handle->mode_info;
Expand Down Expand Up @@ -347,7 +347,7 @@ esp_err_t i2s_channel_reconfig_tdm_gpio(i2s_chan_handle_t handle, const i2s_tdm_
esp_err_t ret = ESP_OK;

xSemaphoreTake(handle->mutex, portMAX_DELAY);
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_TDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard moded");
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_TDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio");

ESP_GOTO_ON_ERROR(i2s_tdm_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
Expand Down
4 changes: 2 additions & 2 deletions components/driver/include/driver/i2s_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ typedef struct {
i2s_isr_callback_t on_sent; /**< Callback of data sent event, only for tx channel
* The event data includes DMA buffer address and size that just finished sending data
*/
i2s_isr_callback_t on_send_q_ovf; /**< Callback of sending queue overflowed evnet, only for tx channel
i2s_isr_callback_t on_send_q_ovf; /**< Callback of sending queue overflowed event, only for tx channel
* The event data includes buffer size that has been overwritten
*/
} i2s_event_callbacks_t;
Expand Down Expand Up @@ -130,7 +130,7 @@ esp_err_t i2s_channel_get_info(i2s_chan_handle_t handle, i2s_chan_info_t *chan_i
* @brief Enable the i2s channel
* @note Only allowed to be called when the channel state is READY, (i.e., channel has been initialized, but not started)
* the channel will enter RUNNING state once it is enabled successfully.
* @note Enbale the channel can start the I2S communication on hardware. It will start outputting bclk and ws signal.
* @note Enable the channel can start the I2S communication on hardware. It will start outputting bclk and ws signal.
* For mclk signal, it will start to output when initialization is finished
*
* @param[in] handle I2S channel handler
Expand Down
Loading

0 comments on commit 42509fa

Please sign in to comment.