feat(i2s): support to select PDM data format

This commit is contained in:
laokaiyao
2024-08-15 19:02:42 +08:00
parent 390745c999
commit 9b779d8b3c
37 changed files with 863 additions and 254 deletions

View File

@@ -1259,7 +1259,9 @@ esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t downsampl
xSemaphoreTake(p_i2s[i2s_num]->rx->mux, portMAX_DELAY);
i2s_stop(i2s_num);
p_i2s[i2s_num]->clk_cfg.dn_sample_mode = downsample;
#if SOC_I2S_SUPPORTS_PDM2PCM
i2s_ll_rx_set_pdm_dsr(p_i2s[i2s_num]->hal.dev, downsample);
#endif
i2s_start(i2s_num);
xSemaphoreGive(p_i2s[i2s_num]->rx->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);
@@ -1276,8 +1278,10 @@ esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, const i2s_pdm_tx_upsample
i2s_stop(i2s_num);
p_i2s[i2s_num]->clk_cfg.up_sample_fp = upsample_cfg->fp;
p_i2s[i2s_num]->clk_cfg.up_sample_fs = upsample_cfg->fs;
#if SOC_I2S_SUPPORTS_PCM2PDM
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);
#endif
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);
@@ -1393,6 +1397,11 @@ static esp_err_t i2s_config_transfer(i2s_port_t i2s_num, const i2s_config_t *i2s
#if SOC_I2S_SUPPORTS_PDM_TX
if (p_i2s[i2s_num]->mode == I2S_COMM_MODE_PDM) {
/* Generate PDM TX slot configuration */
#if SOC_I2S_SUPPORTS_PCM2PDM
SLOT_CFG(pdm_tx).data_fmt = I2S_PDM_DATA_FMT_PCM;
#else
SLOT_CFG(pdm_tx).data_fmt = I2S_PDM_DATA_FMT_RAW;
#endif
SLOT_CFG(pdm_tx).sd_prescale = 0;
SLOT_CFG(pdm_tx).sd_scale = I2S_PDM_SIG_SCALING_MUL_1;
SLOT_CFG(pdm_tx).hp_scale = I2S_PDM_SIG_SCALING_MUL_1;
@@ -1417,6 +1426,11 @@ static esp_err_t i2s_config_transfer(i2s_port_t i2s_num, const i2s_config_t *i2s
#if SOC_I2S_SUPPORTS_PDM_RX
if (p_i2s[i2s_num]->mode == I2S_COMM_MODE_PDM) {
#if SOC_I2S_SUPPORTS_PDM2PCM
SLOT_CFG(pdm_rx).data_fmt = I2S_PDM_DATA_FMT_PCM;
#else
SLOT_CFG(pdm_rx).data_fmt = I2S_PDM_DATA_FMT_RAW;
#endif
/* Generate PDM RX clock configuration */
CLK_CFG().dn_sample_mode = I2S_PDM_DSR_8S;
p_i2s[i2s_num]->active_slot = (int)p_i2s[i2s_num]->slot_cfg.slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
@@ -1501,12 +1515,22 @@ static esp_err_t i2s_init_legacy(i2s_port_t i2s_num, int intr_alloc_flag)
else if (p_i2s[i2s_num]->mode == I2S_COMM_MODE_PDM) {
#if SOC_I2S_SUPPORTS_PDM_TX
if (p_i2s[i2s_num]->dir & I2S_DIR_TX) {
i2s_hal_pdm_enable_tx_channel(&(p_i2s[i2s_num]->hal));
#if SOC_I2S_SUPPORTS_PCM2PDM
i2s_hal_pdm_enable_tx_channel(&(p_i2s[i2s_num]->hal), true);
#else
ESP_LOGW(TAG, "CAUTION! This target has no PCM2PDM filter, please write raw PDM data");
i2s_hal_pdm_enable_tx_channel(&(p_i2s[i2s_num]->hal), false);
#endif // SOC_I2S_SUPPORTS_PCM2PDM
}
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
if (p_i2s[i2s_num]->dir & I2S_DIR_RX) {
i2s_hal_pdm_enable_rx_channel(&(p_i2s[i2s_num]->hal));
#if SOC_I2S_SUPPORTS_PDM2PCM
i2s_hal_pdm_enable_rx_channel(&(p_i2s[i2s_num]->hal), true);
#else
ESP_LOGW(TAG, "CAUTION! This target has no PDM2PCM filter, the data read are in raw PDM format");
i2s_hal_pdm_enable_rx_channel(&(p_i2s[i2s_num]->hal), false);
#endif // SOC_I2S_SUPPORTS_PDM2PCM
}
#endif
}

View File

@@ -37,18 +37,34 @@ static esp_err_t i2s_pdm_tx_calculate_clock(i2s_chan_handle_t handle, const i2s_
i2s_pdm_tx_clk_config_t *pdm_tx_clk = (i2s_pdm_tx_clk_config_t *)clk_cfg;
// 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;
uint32_t over_sample_ratio = 0;
clk_info->bclk_div = clk_cfg->bclk_div < I2S_PDM_TX_BCLK_DIV_MIN ? I2S_PDM_TX_BCLK_DIV_MIN : clk_cfg->bclk_div;
if (!handle->is_raw_pdm) {
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;
} else {
/* Mainly warns the case when the user uses the raw PDM mode but set a PCM sample rate
* The typical PDM over sample rate is several MHz (above 1 MHz),
* but the typical PCM sample rate is less than 100 KHz */
if (rate < 512000) {
ESP_LOGW(TAG, "the over sample rate might be too small for the raw PDM mode");
}
clk_info->bclk = rate * 2;
}
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 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);
ESP_RETURN_ON_FALSE(clk_info->mclk_div < 256, ESP_ERR_INVALID_ARG, TAG, "sample rate is too small");
#if SOC_I2S_SUPPORTS_PCM2PDM
if (!handle->is_raw_pdm) {
/* 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);
}
#endif
return ESP_OK;
}
@@ -88,7 +104,11 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
static esp_err_t i2s_pdm_tx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_tx_slot_config_t *slot_cfg)
{
#if !SOC_I2S_SUPPORTS_PCM2PDM
ESP_RETURN_ON_FALSE(slot_cfg->data_fmt == I2S_PDM_DATA_FMT_RAW, ESP_ERR_NOT_SUPPORTED, TAG, "not support PCM2PDM converter on this target");
#endif
/* Update the total slot num and active slot num */
handle->is_raw_pdm = slot_cfg->data_fmt == I2S_PDM_DATA_FMT_RAW;
handle->total_slot = 2;
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
@@ -195,7 +215,7 @@ esp_err_t i2s_channel_init_pdm_tx_mode(i2s_chan_handle_t handle, const i2s_pdm_t
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_clock(handle, &pdm_tx_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed");
i2s_ll_tx_enable_pdm(handle->controller->hal.dev);
i2s_ll_tx_enable_pdm(handle->controller->hal.dev, pdm_tx_cfg->slot_cfg.data_fmt == I2S_PDM_DATA_FMT_PCM);
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
@@ -331,7 +351,17 @@ static esp_err_t i2s_pdm_rx_calculate_clock(i2s_chan_handle_t handle, const i2s_
uint32_t rate = clk_cfg->sample_rate_hz;
i2s_pdm_rx_clk_config_t *pdm_rx_clk = (i2s_pdm_rx_clk_config_t *)clk_cfg;
clk_info->bclk = rate * I2S_LL_PDM_BCK_FACTOR * (pdm_rx_clk->dn_sample_mode == I2S_PDM_DSR_16S ? 2 : 1);
if (!handle->is_raw_pdm) {
clk_info->bclk = rate * I2S_LL_PDM_BCK_FACTOR * (pdm_rx_clk->dn_sample_mode == I2S_PDM_DSR_16S ? 2 : 1);
} else {
/* Mainly warns the case when the user uses the raw PDM mode but set a PCM sample rate
* The typical PDM over sample rate is several MHz (above 1 MHz),
* but the typical PCM sample rate is less than 100 KHz */
if (rate < 512000) {
ESP_LOGW(TAG, "the over sample rate might be too small for the raw PDM mode");
}
clk_info->bclk = rate * 2;
}
clk_info->bclk_div = clk_cfg->bclk_div < I2S_PDM_RX_BCLK_DIV_MIN ? I2S_PDM_RX_BCLK_DIV_MIN : clk_cfg->bclk_div;
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);
@@ -339,8 +369,12 @@ static esp_err_t i2s_pdm_rx_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 down-sampling configuration */
i2s_ll_rx_set_pdm_dsr(handle->controller->hal.dev, pdm_rx_clk->dn_sample_mode);
#if SOC_I2S_SUPPORTS_PDM2PCM
if (!handle->is_raw_pdm) {
/* Set down-sampling configuration */
i2s_ll_rx_set_pdm_dsr(handle->controller->hal.dev, pdm_rx_clk->dn_sample_mode);
}
#endif
return ESP_OK;
}
@@ -373,7 +407,11 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx
static esp_err_t i2s_pdm_rx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_rx_slot_config_t *slot_cfg)
{
#if !SOC_I2S_SUPPORTS_PDM2PCM
ESP_RETURN_ON_FALSE(slot_cfg->data_fmt == I2S_PDM_DATA_FMT_RAW, ESP_ERR_NOT_SUPPORTED, TAG, "not support PDM2PCM converter on this target");
#endif
/* Update the total slot num and active slot num */
handle->is_raw_pdm = slot_cfg->data_fmt == I2S_PDM_DATA_FMT_RAW;
handle->total_slot = 2;
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
@@ -450,6 +488,9 @@ static esp_err_t i2s_pdm_rx_set_gpio(i2s_chan_handle_t handle, const i2s_pdm_rx_
esp_err_t i2s_channel_init_pdm_rx_mode(i2s_chan_handle_t handle, const i2s_pdm_rx_config_t *pdm_rx_cfg)
{
#if CONFIG_I2S_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
#endif
I2S_NULL_POINTER_CHECK(TAG, handle);
ESP_RETURN_ON_FALSE(handle->dir == I2S_DIR_RX, ESP_ERR_INVALID_ARG, TAG, "This channel handle is not a RX handle");
ESP_RETURN_ON_FALSE(handle->controller->id == I2S_NUM_0, ESP_ERR_INVALID_ARG, TAG, "This channel handle is registered on I2S1, but PDM is only supported on I2S0");
@@ -478,7 +519,7 @@ esp_err_t i2s_channel_init_pdm_rx_mode(i2s_chan_handle_t handle, const i2s_pdm_r
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_clock(handle, &pdm_rx_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed");
i2s_ll_rx_enable_pdm(handle->controller->hal.dev);
i2s_ll_rx_enable_pdm(handle->controller->hal.dev, pdm_rx_cfg->slot_cfg.data_fmt == I2S_PDM_DATA_FMT_PCM);
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;

View File

@@ -163,6 +163,7 @@ struct i2s_channel_obj_t {
#if SOC_I2S_SUPPORTS_APLL
bool apll_en; /*!< Flag of whether APLL enabled */
#endif
bool is_raw_pdm; /*!< Flag of whether send/receive PDM in raw data, i.e., no PCM2PDM/PDM2PCM filter enabled */
uint32_t active_slot; /*!< Active slot number */
uint32_t total_slot; /*!< Total slot number */
/* Locks and queues */

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -25,35 +25,71 @@ extern "C" {
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
/**
* @brief PDM format in 2 slots(RX)
* @brief PDM mode in 2 slots(RX). Read data in PCM format
* @param bits_per_sample I2S data bit width, only support 16 bits for PDM mode
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
#define I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \
.data_fmt = I2S_PDM_DATA_FMT_PCM, \
.hp_en = true, \
.hp_cut_off_freq_hz = 35.5, \
.amplify_num = 1, \
}
#else
/**
* @brief PDM format in 2 slots(RX)
* @brief PDM mode in 2 slots(RX). Read data in raw PDM format
* @param bits_per_sample I2S data bit width, only support 16 bits for PDM mode
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
#define I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \
.data_fmt = I2S_PDM_DATA_FMT_RAW, \
}
#else
/**
* @brief PDM format in 2 slots(RX). Read data in PCM format
* @param bits_per_sample I2S data bit width, only support 16 bits for PDM mode
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \
.data_fmt = I2S_PDM_DATA_FMT_PCM, \
}
/**
* @brief PDM mode in 2 slots(RX). Read data in raw PDM format
* @param bits_per_sample I2S data bit width, only support 16 bits for PDM mode
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \
.data_fmt = I2S_PDM_DATA_FMT_RAW, \
}
#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
/** @cond */
#if SOC_I2S_SUPPORTS_PDM2PCM
# define I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)
#else
# define I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)
#endif
/** @endcond */
/**
* @brief I2S default PDM RX clock configuration
* @param rate sample rate
@@ -74,8 +110,15 @@ typedef struct {
i2s_data_bit_width_t data_bit_width; /*!< I2S sample data bit width (valid data bits per sample), only support 16 bits for PDM mode */
i2s_slot_bit_width_t slot_bit_width; /*!< I2S slot bit width (total bits per slot) , only support 16 bits for PDM mode */
i2s_slot_mode_t slot_mode; /*!< Set mono or stereo mode with I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO */
/* Particular fields */
i2s_pdm_slot_mask_t slot_mask; /*!< Choose the slots to activate */
i2s_pdm_data_fmt_t data_fmt; /*!< The data format of PDM RX mode. It determines what kind of data format is read in software.
* Typically, set this field to I2S_PDM_DATA_FMT_PCM when PCM2PDM filter is supported in the hardware,
* so that the hardware PDM2PCM filter will help to convert the raw PDM data on the line into PCM format,
* And then you can read PCM format data in software. Otherwise if this field is set to I2S_PDM_DATA_FMT_RAW,
* The data read in software are still in raw PDM format, you may need to convert the raw PDM data into PCM format manually by a software filter.
*/
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
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 */
@@ -92,7 +135,10 @@ typedef struct {
*/
typedef struct {
/* General fields */
uint32_t sample_rate_hz; /*!< I2S sample rate */
uint32_t sample_rate_hz; /*!< I2S sample rate.
* - For raw PDM mode, it typically ranges 1.024MHz ~ 6.144MHz.
* - For PCM mode (PDM2PCM filter enabled), it usually ranges 16KHz ~ 48KHz
*/
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 */
@@ -102,7 +148,7 @@ typedef struct {
} i2s_pdm_rx_clk_config_t;
/**
* @brief I2S PDM TX mode GPIO pins configuration
* @brief I2S PDM RX mode GPIO pins configuration
*/
typedef struct {
gpio_num_t clk; /*!< PDM clk pin, output */
@@ -120,7 +166,7 @@ typedef struct {
*/
typedef struct {
i2s_pdm_rx_clk_config_t clk_cfg; /*!< PDM RX clock configurations, can be generated by macro I2S_PDM_RX_CLK_DEFAULT_CONFIG */
i2s_pdm_rx_slot_config_t slot_cfg; /*!< PDM RX slot configurations, can be generated by macro I2S_PDM_RX_SLOT_DEFAULT_CONFIG */
i2s_pdm_rx_slot_config_t slot_cfg; /*!< PDM RX slot configurations, can be generated by macro I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG or I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG */
i2s_pdm_rx_gpio_config_t gpio_cfg; /*!< PDM RX slot configurations, specified by user */
} i2s_pdm_rx_config_t;
@@ -132,7 +178,7 @@ typedef struct {
* @param[in] handle I2S RX channel handler
* @param[in] pdm_rx_cfg Configurations for PDM RX mode, including clock, slot and GPIO
* The clock configuration can be generated by the helper macro `I2S_PDM_RX_CLK_DEFAULT_CONFIG`
* The slot configuration can be generated by the helper macro `I2S_PDM_RX_SLOT_DEFAULT_CONFIG`
* The slot configuration can be generated by the helper macro `I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG` or `I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG`
*
* @return
* - ESP_OK Initialize successfully
@@ -164,7 +210,7 @@ esp_err_t i2s_channel_reconfig_pdm_rx_clock(i2s_chan_handle_t handle, const i2s_
* @note The input channel handle has to be initialized to PDM RX mode, i.e., `i2s_channel_init_pdm_rx_mode` has been called before reconfiguring
*
* @param[in] handle I2S RX channel handler
* @param[in] slot_cfg PDM RX mode slot configuration, can be generated by `I2S_PDM_RX_SLOT_DEFAULT_CONFIG`
* @param[in] slot_cfg PDM RX mode slot configuration, can be generated by `I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG` or `I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG`
* @return
* - ESP_OK Set clock successfully
* - ESP_ERR_NO_MEM No memory for DMA buffer
@@ -193,14 +239,15 @@ esp_err_t i2s_channel_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_p
#if SOC_I2S_SUPPORTS_PDM_TX
#if SOC_I2S_HW_VERSION_2
/**
* @brief PDM style in 2 slots(TX) for codec line mode
* @brief PDM style in 2 slots(TX) for codec line mode. Write PCM data.
* @param bits_per_sample I2S data bit width, only support 16 bits for PDM mode
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_PDM_TX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
#define I2S_PDM_TX_SLOT_PCM_FMT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.data_fmt = I2S_PDM_DATA_FMT_PCM, \
.sd_prescale = 0, \
.sd_scale = I2S_PDM_SIG_SCALING_MUL_1, \
.hp_scale = I2S_PDM_SIG_SCALING_DIV_2, \
@@ -213,6 +260,19 @@ esp_err_t i2s_channel_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_p
.sd_dither2 = 1, \
}
/**
* @brief PDM style in 2 slots(TX) for codec line mode. Write raw PDM data.
* @param bits_per_sample I2S data bit width, only support 16 bits for PDM mode
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_PDM_TX_SLOT_RAW_FMT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.data_fmt = I2S_PDM_DATA_FMT_RAW, \
.line_mode = I2S_PDM_TX_ONE_LINE_CODEC, \
}
/**
* @brief PDM style in 1 slots(TX) for DAC line mode
* @note The noise might be different with different configurations, this macro provides a set of configurations
@@ -220,10 +280,11 @@ esp_err_t i2s_channel_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_p
* @param bits_per_sample I2S data bit width, only support 16 bits for PDM mode
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_PDM_TX_SLOT_DAC_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
#define I2S_PDM_TX_SLOT_PCM_FMT_DAC_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.data_fmt = I2S_PDM_DATA_FMT_PCM, \
.sd_prescale = 0, \
.sd_scale = I2S_PDM_SIG_SCALING_MUL_1, \
.hp_scale = I2S_PDM_SIG_SCALING_MUL_1, \
@@ -236,25 +297,69 @@ esp_err_t i2s_channel_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_p
.sd_dither = 0, \
.sd_dither2 = 1, \
}
#else // SOC_I2S_HW_VERSION_2
/**
* @brief PDM style in 2 slots(TX) for codec line mode
* @brief PDM style in 1 slots(TX) for DAC line mode. Write raw PDM data.
* @note The noise might be different with different configurations, this macro provides a set of configurations
* that have relatively high SNR (Signal Noise Ratio), you can also adjust them to fit your case.
* @param bits_per_sample I2S data bit width, only support 16 bits for PDM mode
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_PDM_TX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
#define I2S_PDM_TX_SLOT_RAW_FMT_DAC_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.data_fmt = I2S_PDM_DATA_FMT_RAW, \
.line_mode = ((mono_or_stereo) == I2S_SLOT_MODE_MONO ? \
I2S_PDM_TX_ONE_LINE_DAC : I2S_PDM_TX_TWO_LINE_DAC), \
}
#else // SOC_I2S_HW_VERSION_2
/**
* @brief PDM style in 2 slots(TX) for codec line mode. Write PCM data.
* @param bits_per_sample I2S data bit width, only support 16 bits for PDM mode
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_PDM_TX_SLOT_PCM_FMT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = I2S_PDM_SLOT_BOTH, \
.data_fmt = I2S_PDM_DATA_FMT_PCM, \
.sd_prescale = 0, \
.sd_scale = I2S_PDM_SIG_SCALING_MUL_1, \
.hp_scale = I2S_PDM_SIG_SCALING_MUL_1, \
.lp_scale = I2S_PDM_SIG_SCALING_MUL_1, \
.sinc_scale = I2S_PDM_SIG_SCALING_MUL_1, \
}
/**
* @brief PDM style in 2 slots(TX) for codec line mode. Write PDM data.
* @param bits_per_sample I2S data bit width, only support 16 bits for PDM mode
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_PDM_TX_SLOT_RAW_FMT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = I2S_PDM_SLOT_BOTH, \
.data_fmt = I2S_PDM_DATA_FMT_RAW, \
}
#endif // SOC_I2S_HW_VERSION_2
/** @cond */
#if SOC_I2S_SUPPORTS_PCM2PDM
# define I2S_PDM_TX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) I2S_PDM_TX_SLOT_PCM_FMT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)
# if SOC_I2S_HW_VERSION_2
# define I2S_PDM_TX_SLOT_DAC_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) I2S_PDM_TX_SLOT_PCM_FMT_DAC_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)
# endif // SOC_I2S_HW_VERSION_2
#else
# define I2S_PDM_TX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) I2S_PDM_TX_SLOT_RAW_FMT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)
# if SOC_I2S_HW_VERSION_2
# define I2S_PDM_TX_SLOT_DAC_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) I2S_PDM_TX_SLOT_RAW_FMT_DAC_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo)
# endif // SOC_I2S_HW_VERSION_2
#endif // SOC_I2S_SUPPORTS_PCM2PDM
/** @endcond */
/**
* @brief I2S default PDM TX clock configuration for codec line mode
* @note TX PDM can only be set to the following two up-sampling rate configurations:
@@ -323,6 +428,12 @@ typedef struct {
#if SOC_I2S_HW_VERSION_1
i2s_pdm_slot_mask_t slot_mask; /*!< Slot mask to choose left or right slot */
#endif
i2s_pdm_data_fmt_t data_fmt; /*!< The data format of PDM TX mode. It determines what kind of data format is written in software.
* Typically, set this field to I2S_PDM_DATA_FMT_PCM when PCM2PDM filter is supported in the hardware,
* so that you can write PCM format data in software, and then the hardware PCM2PDM filter will help to
* convert it into PDM format on the line. Otherwise if this field is set to I2S_PDM_DATA_FMT_RAW,
* The data written in software are supposed to be the raw PDM format.
*/
uint32_t sd_prescale; /*!< Sigma-delta filter prescale */
i2s_pdm_sig_scale_t sd_scale; /*!< Sigma-delta filter scaling value */
i2s_pdm_sig_scale_t hp_scale; /*!< High pass filter scaling value */
@@ -342,7 +453,10 @@ typedef struct {
*/
typedef struct {
/* General fields */
uint32_t sample_rate_hz; /*!< I2S sample rate, not suggest to exceed 48000 Hz, otherwise more glitches and noise may appear */
uint32_t sample_rate_hz; /*!< I2S sample rate.
* - For raw PDM mode, it typically ranges 1.024MHz ~ 6.144MHz.
* - For PCM mode (PCM2PDM filter enabled), it usually ranges 16KHz ~ 48KHz
*/
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 */

View File

@@ -962,25 +962,26 @@ static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw)
* @brief Enable I2S TX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm_ena Set true to enable TX PDM mode
* @param pcm2pdm_en Set true to enable TX PCM to PDM filter
*/
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw)
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en)
{
hw->conf2.val = 0;
hw->pdm_conf.tx_pdm_en = true;
hw->pdm_conf.pcm2pdm_conv_en = true;
hw->pdm_conf.pcm2pdm_conv_en = pcm2pdm_en;
}
/**
* @brief Enable I2S RX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm2pcm_en Set true to enable RX PDM to PCM filter
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw)
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm_en)
{
hw->conf2.val = 0;
hw->pdm_conf.rx_pdm_en = true;
hw->pdm_conf.pdm2pcm_conv_en = true;
hw->pdm_conf.pdm2pcm_conv_en = pdm2pcm_en;
}
/**

View File

@@ -733,15 +733,29 @@ static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw)
}
/**
* @brief Enable TX PDM mode.
* @brief Enable I2S TX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pcm2pdm_en Set true to enable TX PCM to PDM filter
*/
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw)
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en)
{
hw->tx_conf.tx_pdm_en = true;
hw->tx_conf.tx_tdm_en = false;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = true;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pcm2pdm_en;
}
/**
* @brief Enable I2S RX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm2pcm_en Set true to enable RX PDM to PCM filter
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm_en)
{
HAL_ASSERT(!pdm2pcm_en); // C3 does not have PDM2PCM filter
hw->rx_conf.rx_pdm_en = true;
hw->rx_conf.rx_tdm_en = false;
}
/**
@@ -903,21 +917,6 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw)
return hw->tx_pcm2pdm_conf1.tx_pdm_fs;
}
/**
* @brief Enable RX PDM mode.
* @note ESP32-C3 doesn't support pdm in rx mode, disable anyway
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm_enable Set true to RX enable PDM mode (ignored)
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable)
{
// Due to the lack of `PDM to PCM` module on ESP32-C3, PDM RX is not available
HAL_ASSERT(!pdm_enable);
hw->rx_conf.rx_pdm_en = 0;
hw->rx_conf.rx_tdm_en = 1;
}
/**
* @brief Configura TX a/u-law decompress or compress
*

View File

@@ -765,15 +765,16 @@ static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw)
}
/**
* @brief Enable TX PDM mode.
* @brief Enable I2S TX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pcm2pdm_en Set true to enable TX PCM to PDM filter
*/
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw)
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en)
{
hw->tx_conf.tx_pdm_en = true;
hw->tx_conf.tx_tdm_en = false;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = true;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pcm2pdm_en;
}
/**
@@ -937,17 +938,86 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw)
/**
* @brief Enable RX PDM mode.
* @note ESP32-C5 doesn't support pdm in rx mode, disable anyway
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm_enable Set true to RX enable PDM mode (ignored)
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable)
{
// Due to the lack of `PDM to PCM` module on ESP32-C5, PDM RX is not available
HAL_ASSERT(!pdm_enable);
hw->rx_conf.rx_pdm_en = 0;
hw->rx_conf.rx_tdm_en = 1;
hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = pdm_enable;
}
/**
* @brief Configure RX PDM downsample
*
* @param hw Peripheral I2S hardware instance address.
* @param dsr PDM downsample configuration parameter
*/
static inline void i2s_ll_rx_set_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr)
{
hw->rx_pdm2pcm_conf.rx_pdm_sinc_dsr_16_en = dsr;
}
/**
* @brief Get RX PDM downsample configuration
*
* @param hw Peripheral I2S hardware instance address.
* @param dsr Pointer to accept PDM downsample configuration
*/
static inline void i2s_ll_rx_get_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr)
{
*dsr = (i2s_pdm_dsr_t)hw->rx_pdm2pcm_conf.rx_pdm_sinc_dsr_16_en;
}
/**
* @brief Configure RX PDM amplify number
* @note This is the amplification number of the digital amplifier,
* which is added after the PDM to PCM conversion result and mainly used for
* amplify the small PDM signal under the VAD scenario
* pcm_result = pdm_input * amplify_num
* pcm_result = 0 if amplify_num = 0
*
* @param hw Peripheral I2S hardware instance address.
* @param amp_num PDM RX amplify number
*/
static inline void i2s_ll_rx_set_pdm_amplify_num(i2s_dev_t *hw, uint32_t amp_num)
{
hw->rx_pdm2pcm_conf.rx_pdm2pcm_amplify_num = amp_num;
}
/**
* @brief Set I2S RX PDM high pass filter param0
*
* @param hw Peripheral I2S hardware instance address.
* @param param The fourth parameter of PDM RX IIR_HP filter stage 1 is (504 + I2S_RX_IIR_HP_MULT12_0[2:0])
*/
static inline void i2s_ll_rx_set_pdm_hp_filter_param0(i2s_dev_t *hw, uint32_t param)
{
hw->rx_pdm2pcm_conf.rx_iir_hp_mult12_0 = param;
}
/**
* @brief Set I2S RX PDM high pass filter param5
*
* @param hw Peripheral I2S hardware instance address.
* @param param The fourth parameter of PDM RX IIR_HP filter stage 2 is (504 + I2S_RX_IIR_HP_MULT12_5[2:0])
*/
static inline void i2s_ll_rx_set_pdm_hp_filter_param5(i2s_dev_t *hw, uint32_t param)
{
hw->rx_pdm2pcm_conf.rx_iir_hp_mult12_5 = param;
}
/**
* @brief Enable I2S RX PDM high pass filter
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable I2S RX PDM high pass filter, set false to bypass it
*/
static inline void i2s_ll_rx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable)
{
hw->rx_pdm2pcm_conf.rx_pdm_hp_bypass = !enable;
}
/**

View File

@@ -755,15 +755,29 @@ static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw)
}
/**
* @brief Enable TX PDM mode.
* @brief Enable I2S TX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pcm2pdm_en Set true to enable TX PCM to PDM filter
*/
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw)
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en)
{
hw->tx_conf.tx_pdm_en = true;
hw->tx_conf.tx_tdm_en = false;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = true;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pcm2pdm_en;
}
/**
* @brief Enable I2S RX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm2pcm_en Set true to enable RX PDM to PCM filter
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm_en)
{
HAL_ASSERT(!pdm2pcm_en); // C6 does not have PDM2PCM filter
hw->rx_conf.rx_pdm_en = true;
hw->rx_conf.rx_tdm_en = false;
}
/**
@@ -925,21 +939,6 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw)
return hw->tx_pcm2pdm_conf1.tx_pdm_fs;
}
/**
* @brief Enable RX PDM mode.
* @note ESP32-C6 doesn't support pdm in rx mode, disable anyway
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm_enable Set true to RX enable PDM mode (ignored)
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable)
{
// Due to the lack of `PDM to PCM` module on ESP32-C6, PDM RX is not available
HAL_ASSERT(!pdm_enable);
hw->rx_conf.rx_pdm_en = 0;
hw->rx_conf.rx_tdm_en = 1;
}
/**
* @brief Configura TX a/u-law decompress or compress
*

View File

@@ -764,15 +764,16 @@ static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw)
}
/**
* @brief Enable TX PDM mode.
* @brief Enable I2S TX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pcm2pdm_en Set true to enable TX PCM to PDM filter
*/
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw)
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en)
{
hw->tx_conf.tx_pdm_en = true;
hw->tx_conf.tx_tdm_en = false;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = true;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pcm2pdm_en;
}
/**
@@ -936,17 +937,53 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw)
/**
* @brief Enable RX PDM mode.
* @note ESP32-C61 doesn't support pdm in rx mode, disable anyway
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm_enable Set true to RX enable PDM mode (ignored)
* @param pdm2pcm Set true to RX enable PDM mode
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable)
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm)
{
// Due to the lack of `PDM to PCM` module on ESP32-C61, PDM RX is not available
HAL_ASSERT(!pdm_enable);
hw->rx_conf.rx_pdm_en = 0;
hw->rx_conf.rx_tdm_en = 1;
hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = pdm2pcm;
}
/**
* @brief Configure RX PDM downsample
*
* @param hw Peripheral I2S hardware instance address.
* @param dsr PDM downsample configuration parameter
*/
static inline void i2s_ll_rx_set_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr)
{
hw->rx_pdm2pcm_conf.rx_pdm_sinc_dsr_16_en = dsr;
}
/**
* @brief Get RX PDM downsample configuration
*
* @param hw Peripheral I2S hardware instance address.
* @param dsr Pointer to accept PDM downsample configuration
*/
static inline void i2s_ll_rx_get_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr)
{
*dsr = (i2s_pdm_dsr_t)hw->rx_pdm2pcm_conf.rx_pdm_sinc_dsr_16_en;
}
/**
* @brief Configure RX PDM amplify number
* @note This is the amplification number of the digital amplifier,
* which is added after the PDM to PCM conversion result and mainly used for
* amplify the small PDM signal under the VAD scenario
* pcm_result = pdm_input * amplify_num
* pcm_result = 0 if amplify_num = 0
*
* @param hw Peripheral I2S hardware instance address.
* @param amp_num PDM RX amplify number
*/
static inline void i2s_ll_rx_set_pdm_amplify_num(i2s_dev_t *hw, uint32_t amp_num)
{
hw->rx_pdm2pcm_conf.rx_pdm2pcm_amplify_num = amp_num;
}
/**

View File

@@ -762,15 +762,29 @@ static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw)
}
/**
* @brief Enable TX PDM mode.
* @brief Enable I2S TX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pcm2pdm_en Set true to enable TX PCM to PDM filter
*/
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw)
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en)
{
hw->tx_conf.tx_pdm_en = true;
hw->tx_conf.tx_tdm_en = false;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = true;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pcm2pdm_en;
}
/**
* @brief Enable I2S RX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm2pcm_en Set true to enable RX PDM to PCM filter
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm_en)
{
HAL_ASSERT(!pdm2pcm_en); // H2 does not have PDM2PCM filter
hw->rx_conf.rx_pdm_en = true;
hw->rx_conf.rx_tdm_en = false;
}
/**
@@ -932,21 +946,6 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw)
return hw->tx_pcm2pdm_conf1.tx_pdm_fs;
}
/**
* @brief Enable RX PDM mode.
* @note ESP32-H2 doesn't support pdm in rx mode, disable anyway
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm_enable Set true to RX enable PDM mode (ignored)
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable)
{
// Due to the lack of `PDM to PCM` module on ESP32-H2, PDM RX is not available
HAL_ASSERT(!pdm_enable);
hw->rx_conf.rx_pdm_en = 0;
hw->rx_conf.rx_tdm_en = 1;
}
/**
* @brief Configura TX a/u-law decompress or compress
*

View File

@@ -1024,15 +1024,29 @@ static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw)
}
/**
* @brief Enable TX PDM mode.
* @brief Enable I2S TX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pcm2pdm_en Set true to enable TX PCM to PDM filter
*/
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw)
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en)
{
hw->tx_conf.tx_pdm_en = true;
hw->tx_conf.tx_tdm_en = false;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = true;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pcm2pdm_en;
}
/**
* @brief Enable I2S RX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm2pcm_en Set true to enable RX PDM to PCM filter
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm_en)
{
hw->rx_conf.rx_pdm_en = true;
hw->rx_conf.rx_tdm_en = false;
hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = pdm2pcm_en;
}
/**
@@ -1194,18 +1208,6 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw)
return hw->tx_pcm2pdm_conf1.tx_pdm_fs;
}
/**
* @brief Enable RX PDM mode.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw)
{
hw->rx_conf.rx_pdm_en = 1;
hw->rx_conf.rx_tdm_en = 0;
hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = 1;
}
/**
* @brief Configure RX PDM downsample
*

View File

@@ -22,6 +22,7 @@
#include "soc/dport_access.h"
#include "hal/i2s_types.h"
#include "hal/hal_utils.h"
#include "hal/assert.h"
#ifdef __cplusplus
@@ -502,27 +503,31 @@ static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw)
}
/**
* @brief Enable TX PDM mode.
* @brief Enable I2S TX PDM mode
* @note ESP32-S2 doesn't support pdm
* This function is used to be compatible with those support pdm
*
* @param hw Peripheral I2S hardware instance address (ignored)
* @param hw Peripheral I2S hardware instance address.
* @param pcm2pdm_en Set true to enable TX PCM to PDM filter
*/
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw)
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en)
{
// Remain empty
// remain empty
(void)hw;
(void)pcm2pdm_en;
}
/**
* @brief Enable RX PDM mode.
* @brief Enable I2S RX PDM mode
* @note ESP32-S2 doesn't support pdm
* This function is used to be compatible with those support pdm
*
* @param hw Peripheral I2S hardware instance address (ignored)
* @param hw Peripheral I2S hardware instance address.
* @param pdm2pcm_en Set true to enable RX PDM to PCM filter
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw)
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm_en)
{
// Remain empty
// remain empty
(void)hw;
(void)pdm2pcm_en;
}
/**

View File

@@ -741,27 +741,29 @@ static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw)
}
/**
* @brief Enable TX PDM mode.
* @brief Enable I2S TX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pcm2pdm_en Set true to enable TX PCM to PDM filter
*/
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw)
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en)
{
hw->tx_conf.tx_pdm_en = true;
hw->tx_conf.tx_tdm_en = false;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = true;
hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pcm2pdm_en;
}
/**
* @brief Enable RX PDM mode.
* @brief Enable I2S RX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm2pcm_en Set true to enable RX PDM to PCM filter
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw)
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm_en)
{
hw->rx_conf.rx_pdm_en = true;
hw->rx_conf.rx_tdm_en = false;
hw->rx_conf.rx_pdm2pcm_en = true;
hw->rx_conf.rx_pdm2pcm_en = pdm2pcm_en;
}
/**

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,6 +8,7 @@
// The HAL layer for I2S (common part)
#include "soc/soc.h"
#include "hal/assert.h"
#include "hal/i2s_hal.h"
#if SOC_I2S_HW_VERSION_2 && (SOC_I2S_SUPPORTS_PDM_TX || SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER)
@@ -217,11 +218,13 @@ void i2s_hal_pdm_set_tx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
i2s_ll_tx_set_slave_mod(hal->dev, is_slave); //TX Slave
i2s_ll_tx_enable_msb_shift(hal->dev, false);
i2s_ll_tx_set_pdm_prescale(hal->dev, slot_cfg->pdm_tx.sd_prescale);
i2s_ll_tx_set_pdm_hp_scale(hal->dev, slot_cfg->pdm_tx.hp_scale);
i2s_ll_tx_set_pdm_lp_scale(hal->dev, slot_cfg->pdm_tx.lp_scale);
i2s_ll_tx_set_pdm_sinc_scale(hal->dev, slot_cfg->pdm_tx.sinc_scale);
i2s_ll_tx_set_pdm_sd_scale(hal->dev, slot_cfg->pdm_tx.sd_scale);
if (slot_cfg->pdm_tx.data_fmt == I2S_PDM_DATA_FMT_PCM) {
i2s_ll_tx_set_pdm_prescale(hal->dev, slot_cfg->pdm_tx.sd_prescale);
i2s_ll_tx_set_pdm_hp_scale(hal->dev, slot_cfg->pdm_tx.hp_scale);
i2s_ll_tx_set_pdm_lp_scale(hal->dev, slot_cfg->pdm_tx.lp_scale);
i2s_ll_tx_set_pdm_sinc_scale(hal->dev, slot_cfg->pdm_tx.sinc_scale);
i2s_ll_tx_set_pdm_sd_scale(hal->dev, slot_cfg->pdm_tx.sd_scale);
}
#if SOC_I2S_HW_VERSION_1
uint32_t slot_bit_width = (int)slot_cfg->slot_bit_width < (int)slot_cfg->data_bit_width ?
@@ -244,20 +247,25 @@ void i2s_hal_pdm_set_tx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
i2s_ll_tx_set_ws_idle_pol(hal->dev, false);
/* Slot mode seems not take effect according to the test, leave it default here */
i2s_ll_tx_pdm_slot_mode(hal->dev, is_mono, false, I2S_PDM_SLOT_BOTH);
uint32_t param0;
uint32_t param5;
s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_tx.hp_cut_off_freq_hzx10, &param0, &param5);
i2s_ll_tx_enable_pdm_hp_filter(hal->dev, slot_cfg->pdm_tx.hp_en);
i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, param0);
i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, param5);
i2s_ll_tx_set_pdm_sd_dither(hal->dev, slot_cfg->pdm_tx.sd_dither);
i2s_ll_tx_set_pdm_sd_dither2(hal->dev, slot_cfg->pdm_tx.sd_dither2);
if (slot_cfg->pdm_tx.data_fmt == I2S_PDM_DATA_FMT_PCM) {
uint32_t param0;
uint32_t param5;
s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_tx.hp_cut_off_freq_hzx10, &param0, &param5);
i2s_ll_tx_enable_pdm_hp_filter(hal->dev, slot_cfg->pdm_tx.hp_en);
i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, param0);
i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, param5);
i2s_ll_tx_set_pdm_sd_dither(hal->dev, slot_cfg->pdm_tx.sd_dither);
i2s_ll_tx_set_pdm_sd_dither2(hal->dev, slot_cfg->pdm_tx.sd_dither2);
}
#endif
}
void i2s_hal_pdm_enable_tx_channel(i2s_hal_context_t *hal)
void i2s_hal_pdm_enable_tx_channel(i2s_hal_context_t *hal, bool pcm2pdm_en)
{
i2s_ll_tx_enable_pdm(hal->dev);
#if !SOC_I2S_SUPPORTS_PCM2PDM
HAL_ASSERT(!pcm2pdm_en);
#endif
i2s_ll_tx_enable_pdm(hal->dev, pcm2pdm_en);
}
#endif
@@ -289,20 +297,25 @@ void i2s_hal_pdm_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
#endif // SOC_I2S_HW_VERSION_1
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
uint32_t param0;
uint32_t param5;
s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_rx.hp_cut_off_freq_hzx10, &param0, &param5);
i2s_ll_rx_enable_pdm_hp_filter(hal->dev, slot_cfg->pdm_rx.hp_en);
i2s_ll_rx_set_pdm_hp_filter_param0(hal->dev, param0);
i2s_ll_rx_set_pdm_hp_filter_param5(hal->dev, param5);
/* Set the amplification number, the default and the minimum value is 1. 0 will mute the channel */
i2s_ll_rx_set_pdm_amplify_num(hal->dev, slot_cfg->pdm_rx.amplify_num ? slot_cfg->pdm_rx.amplify_num : 1);
if (slot_cfg->pdm_rx.data_fmt != I2S_PDM_DATA_FMT_RAW) {
uint32_t param0;
uint32_t param5;
s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_rx.hp_cut_off_freq_hzx10, &param0, &param5);
i2s_ll_rx_enable_pdm_hp_filter(hal->dev, slot_cfg->pdm_rx.hp_en);
i2s_ll_rx_set_pdm_hp_filter_param0(hal->dev, param0);
i2s_ll_rx_set_pdm_hp_filter_param5(hal->dev, param5);
/* Set the amplification number, the default and the minimum value is 1. 0 will mute the channel */
i2s_ll_rx_set_pdm_amplify_num(hal->dev, slot_cfg->pdm_rx.amplify_num ? slot_cfg->pdm_rx.amplify_num : 1);
}
#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
}
void i2s_hal_pdm_enable_rx_channel(i2s_hal_context_t *hal)
void i2s_hal_pdm_enable_rx_channel(i2s_hal_context_t *hal, bool pdm2pcm_en)
{
i2s_ll_rx_enable_pdm(hal->dev);
#if !SOC_I2S_SUPPORTS_PDM2CDM
HAL_ASSERT(!pdm2pcm_en);
#endif
i2s_ll_rx_enable_pdm(hal->dev, pdm2pcm_en);
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -73,6 +73,12 @@ typedef struct {
#if SOC_I2S_HW_VERSION_1
i2s_pdm_slot_mask_t slot_mask; /*!< Slot mask to choose left or right slot */
#endif
i2s_pdm_data_fmt_t data_fmt; /*!< The data format of PDM TX mode. It determines what kind of data format is written in software.
* Typically, set this field to I2S_PDM_DATA_FMT_PCM when PCM2PDM filter is supported in the hardware,
* so that you can write PCM format data in software, and then the hardware PCM2PDM filter will help to
* convert it into PDM format on the line. Otherwise if this field is set to I2S_PDM_DATA_FMT_RAW,
* The data written in software are supposed to be the raw PDM format.
*/
uint32_t sd_prescale; /*!< Sigma-delta filter prescale */
i2s_pdm_sig_scale_t sd_scale; /*!< Sigma-delta filter scaling value */
i2s_pdm_sig_scale_t hp_scale; /*!< High pass filter scaling value */
@@ -92,6 +98,12 @@ typedef struct {
/* PDM TX configurations */
struct {
i2s_pdm_slot_mask_t slot_mask; /*!< Choose the slots to activate */
i2s_pdm_data_fmt_t data_fmt; /*!< The data format of PDM RX mode. It determines what kind of data format is read in software.
* Typically, set this field to I2S_PDM_DATA_FMT_PCM when PCM2PDM filter is supported in the hardware,
* so that the hardware PDM2PCM filter will help to convert the raw PDM data on the line into PCM format,
* And then you can read PCM format data in software. Otherwise if this field is set to I2S_PDM_DATA_FMT_RAW,
* The data read in software are still in raw PDM format, you may need to convert the raw PDM data into PCM format manually by a software filter.
*/
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
bool hp_en; /*!< High pass filter enable */
uint32_t hp_cut_off_freq_hzx10; /*!< High pass filter cut-off frequency times 10, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */
@@ -233,8 +245,9 @@ void i2s_hal_pdm_set_tx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
* @brief Enable tx channel as pdm mode
*
* @param hal Context of the HAL layer
* @param pcm2pdm_en Enable pcm to pdm conversion
*/
void i2s_hal_pdm_enable_tx_channel(i2s_hal_context_t *hal);
void i2s_hal_pdm_enable_tx_channel(i2s_hal_context_t *hal, bool pcm2pdm_en);
#endif // SOC_I2S_SUPPORTS_PDM_TX
#if SOC_I2S_SUPPORTS_PDM_RX
@@ -251,8 +264,9 @@ void i2s_hal_pdm_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
* @brief Enable rx channel as pdm mode
*
* @param hal Context of the HAL layer
* @param pdm2pcm_en Enable pdm to pcm conversion
*/
void i2s_hal_pdm_enable_rx_channel(i2s_hal_context_t *hal);
void i2s_hal_pdm_enable_rx_channel(i2s_hal_context_t *hal, bool pdm2pcm_en);
#endif // SOC_I2S_SUPPORTS_PDM_RX
#endif // SOC_I2S_SUPPORTS_PDM

View File

@@ -85,6 +85,29 @@ typedef enum {
} i2s_pcm_compress_t;
#endif // SOC_I2S_SUPPORTS_PCM
/**
* @brief I2S PDM data format
*
*/
typedef enum {
I2S_PDM_DATA_FMT_PCM = 0, /*!< PDM RX:
* Enable the hardware PDM to PCM filter to convert the inputted PDM data on the line into PCM format in software,
* so that the read data in software is PCM format data already, no need additional software filter.
* PCM data format is only available when PCM2PDM filter is supported in hardware.
* PDM TX:
* Enable the hardware PCM to PDM filter to convert the written PCM data in software into PDM format on the line,
* so that we only need to write the PCM data in software, no need to prepare raw PDM data in software.
* PCM data format is only available when PDM2PCM filter is supported in hardware.
*/
I2S_PDM_DATA_FMT_RAW = 1, /*!< PDM RX:
* Read the raw PDM data directly in software, without the hardware PDM to PCM filter.
* You may need a software PDM to PCM filter to convert the raw PDM data that read into PCM format.
* PDM TX:
* Write the raw PDM data directly in software, without the hardware PCM to PDM filter.
* You may need to prepare the raw PDM data in software to output the PDM format data on the line.
*/
} i2s_pdm_data_fmt_t;
#if SOC_I2S_SUPPORTS_PDM_RX
/**
* @brief I2S PDM RX down-sampling mode

View File

@@ -415,14 +415,22 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 1
config SOC_I2S_SUPPORTS_PCM2PDM
bool
default y
config SOC_I2S_SUPPORTS_PDM_RX
bool
default y
config SOC_I2S_SUPPORTS_PDM2PCM
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 1
config SOC_I2S_PDM_MAX_RX_LINES
int
default 1

View File

@@ -1,6 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -217,9 +217,11 @@
#define SOC_I2S_SUPPORTS_APLL (1)
#define SOC_I2S_SUPPORTS_PLL_F160M (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1) // Support to output raw PDM format data
#define SOC_I2S_SUPPORTS_PCM2PDM (1) // Support to write PCM format but output PDM format data with the help of PCM to PDM filter
#define SOC_I2S_SUPPORTS_PDM_RX (1) // Support to input raw PDM format data
#define SOC_I2S_SUPPORTS_PDM2PCM (1) // Support to input PDM format but read PCM format data with the help of PDM to PCM filter
#define SOC_I2S_PDM_MAX_TX_LINES (1U)
#define SOC_I2S_SUPPORTS_PDM_RX (1)
#define SOC_I2S_PDM_MAX_RX_LINES (1U)
#define SOC_I2S_SUPPORTS_ADC_DAC (1)
#define SOC_I2S_SUPPORTS_ADC (1)

View File

@@ -511,10 +511,22 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_SUPPORTS_PCM2PDM
bool
default y
config SOC_I2S_SUPPORTS_PDM_RX
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 2
config SOC_I2S_PDM_MAX_RX_LINES
int
default 1
config SOC_I2S_SUPPORTS_TDM
bool
default y

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -216,8 +216,11 @@
#define SOC_I2S_SUPPORTS_PLL_F160M (1)
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1) // Support to output raw PDM format data
#define SOC_I2S_SUPPORTS_PCM2PDM (1) // Support to write PCM format but output PDM format data with the help of PCM to PDM filter
#define SOC_I2S_SUPPORTS_PDM_RX (1) // Support to input raw PDM format data
#define SOC_I2S_PDM_MAX_TX_LINES (2)
#define SOC_I2S_PDM_MAX_RX_LINES (1U)
#define SOC_I2S_SUPPORTS_TDM (1)
/*-------------------------- LEDC CAPS ---------------------------------------*/

View File

@@ -643,10 +643,6 @@ config SOC_I2S_SUPPORTS_ETM
bool
default y
config SOC_I2S_SUPPORTS_TX_SYNC_CNT
bool
default y
config SOC_I2S_SUPPORTS_XTAL
bool
default y
@@ -671,10 +667,34 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_SUPPORTS_PCM2PDM
bool
default y
config SOC_I2S_SUPPORTS_PDM_RX
bool
default y
config SOC_I2S_SUPPORTS_PDM2PCM
bool
default y
config SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
bool
default y
config SOC_I2S_SUPPORTS_TX_SYNC_CNT
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 2
config SOC_I2S_PDM_MAX_RX_LINES
int
default 1
config SOC_I2S_SUPPORTS_TDM
bool
default y

View File

@@ -278,14 +278,19 @@
#define SOC_I2S_NUM (1U)
#define SOC_I2S_HW_VERSION_2 (1)
#define SOC_I2S_SUPPORTS_ETM (1)
#define SOC_I2S_SUPPORTS_TX_SYNC_CNT (1)
#define SOC_I2S_SUPPORTS_XTAL (1)
#define SOC_I2S_SUPPORTS_PLL_F160M (1)
#define SOC_I2S_SUPPORTS_PLL_F240M (1)
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1) // Support to output raw PDM format data
#define SOC_I2S_SUPPORTS_PCM2PDM (1) // Support to write PCM format but output PDM format data with the help of PCM to PDM filter
#define SOC_I2S_SUPPORTS_PDM_RX (1) // Support to input raw PDM format data
#define SOC_I2S_SUPPORTS_PDM2PCM (1) // Support to input PDM format but read PCM format data with the help of PDM to PCM filter
#define SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER (1)
#define SOC_I2S_SUPPORTS_TX_SYNC_CNT (1)
#define SOC_I2S_PDM_MAX_TX_LINES (2)
#define SOC_I2S_PDM_MAX_RX_LINES (1U)
#define SOC_I2S_SUPPORTS_TDM (1)
#define SOC_I2S_TDM_FULL_DATA_WIDTH (1) /*!< No limitation to data bit width when using multiple slots */
#define SOC_I2S_SUPPORT_SLEEP_RETENTION 1 /*!< The sleep retention feature can help back up I2S registers before sleep */

View File

@@ -667,10 +667,22 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_SUPPORTS_PCM2PDM
bool
default y
config SOC_I2S_SUPPORTS_PDM_RX
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 2
config SOC_I2S_PDM_MAX_RX_LINES
int
default 1
config SOC_I2S_SUPPORTS_TDM
bool
default y

View File

@@ -271,8 +271,11 @@
#define SOC_I2S_SUPPORTS_PLL_F160M (1)
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1) // Support to output raw PDM format data
#define SOC_I2S_SUPPORTS_PCM2PDM (1) // Support to write PCM format but output PDM format data with the help of PCM to PDM filter
#define SOC_I2S_SUPPORTS_PDM_RX (1) // Support to input raw PDM format data
#define SOC_I2S_PDM_MAX_TX_LINES (2)
#define SOC_I2S_PDM_MAX_RX_LINES (1U)
#define SOC_I2S_SUPPORTS_TDM (1)
#define SOC_I2S_SUPPORT_SLEEP_RETENTION 1 /*!< The sleep retention feature can help back up I2S registers before sleep */

View File

@@ -539,10 +539,6 @@ config SOC_I2S_SUPPORTS_ETM
bool
default y
config SOC_I2S_SUPPORTS_TX_SYNC_CNT
bool
default y
config SOC_I2S_SUPPORTS_XTAL
bool
default y
@@ -567,10 +563,30 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_SUPPORTS_PCM2PDM
bool
default y
config SOC_I2S_SUPPORTS_PDM_RX
bool
default y
config SOC_I2S_SUPPORTS_PDM2PCM
bool
default y
config SOC_I2S_SUPPORTS_TX_SYNC_CNT
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 2
config SOC_I2S_PDM_MAX_RX_LINES
int
default 1
config SOC_I2S_SUPPORTS_TDM
bool
default y

View File

@@ -234,14 +234,18 @@
#define SOC_I2S_NUM (1U)
#define SOC_I2S_HW_VERSION_2 (1)
#define SOC_I2S_SUPPORTS_ETM (1)
#define SOC_I2S_SUPPORTS_TX_SYNC_CNT (1)
#define SOC_I2S_SUPPORTS_XTAL (1)
#define SOC_I2S_SUPPORTS_PLL_F160M (1)
#define SOC_I2S_SUPPORTS_PLL_F120M (1)
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1) // Support to output raw PDM format data
#define SOC_I2S_SUPPORTS_PCM2PDM (1) // Support to write PCM format but output PDM format data with the help of PCM to PDM filter
#define SOC_I2S_SUPPORTS_PDM_RX (1) // Support to input raw PDM format data
#define SOC_I2S_SUPPORTS_PDM2PCM (1) // Support to input PDM format but read PCM format data with the help of PDM to PCM filter
#define SOC_I2S_SUPPORTS_TX_SYNC_CNT (1)
#define SOC_I2S_PDM_MAX_TX_LINES (2)
#define SOC_I2S_PDM_MAX_RX_LINES (1U)
#define SOC_I2S_SUPPORTS_TDM (1)
#define SOC_I2S_SUPPORT_SLEEP_RETENTION (1)

View File

@@ -667,10 +667,22 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_SUPPORTS_PCM2PDM
bool
default y
config SOC_I2S_SUPPORTS_PDM_RX
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 2
config SOC_I2S_PDM_MAX_RX_LINES
int
default 1
config SOC_I2S_SUPPORTS_TDM
bool
default y

View File

@@ -271,8 +271,11 @@
#define SOC_I2S_SUPPORTS_PLL_F64M (1)
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1) // Support to output raw PDM format data
#define SOC_I2S_SUPPORTS_PCM2PDM (1) // Support to write PCM format but output PDM format data with the help of PCM to PDM filter
#define SOC_I2S_SUPPORTS_PDM_RX (1) // Support to input raw PDM format data
#define SOC_I2S_PDM_MAX_TX_LINES (2)
#define SOC_I2S_PDM_MAX_RX_LINES (1U)
#define SOC_I2S_SUPPORTS_TDM (1)
#define SOC_I2S_TDM_FULL_DATA_WIDTH (1) /*!< No limitation to data bit width when using multiple slots */
#define SOC_I2S_SUPPORT_SLEEP_RETENTION 1 /*!< The sleep retention feature can help back up I2S registers before sleep */

View File

@@ -835,10 +835,18 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_SUPPORTS_PCM2PDM
bool
default y
config SOC_I2S_SUPPORTS_PDM_RX
bool
default y
config SOC_I2S_SUPPORTS_PDM2PCM
bool
default y
config SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
bool
default y

View File

@@ -323,8 +323,10 @@
#define SOC_I2S_SUPPORTS_APLL (1)
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_RX (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1) // Support to output raw PDM format data
#define SOC_I2S_SUPPORTS_PCM2PDM (1) // Support to write PCM format but output PDM format data with the help of PCM to PDM filter
#define SOC_I2S_SUPPORTS_PDM_RX (1) // Support to input raw PDM format data
#define SOC_I2S_SUPPORTS_PDM2PCM (1) // Support to input PDM format but read PCM format data with the help of PDM to PCM filter
#define SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER (1)
#define SOC_I2S_SUPPORTS_TX_SYNC_CNT (1)
#define SOC_I2S_SUPPORTS_TDM (1)

View File

@@ -583,14 +583,22 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 2
config SOC_I2S_SUPPORTS_PCM2PDM
bool
default y
config SOC_I2S_SUPPORTS_PDM_RX
bool
default y
config SOC_I2S_SUPPORTS_PDM2PCM
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 2
config SOC_I2S_PDM_MAX_RX_LINES
int
default 4

View File

@@ -228,9 +228,11 @@
#define SOC_I2S_SUPPORTS_PLL_F160M (1)
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1) // Support to output raw PDM format data
#define SOC_I2S_SUPPORTS_PCM2PDM (1) // Support to write PCM format but output PDM format data with the help of PCM to PDM filter
#define SOC_I2S_SUPPORTS_PDM_RX (1) // Support to input raw PDM format data
#define SOC_I2S_SUPPORTS_PDM2PCM (1) // Support to input PDM format but read PCM format data with the help of PDM to PCM filter
#define SOC_I2S_PDM_MAX_TX_LINES (2)
#define SOC_I2S_SUPPORTS_PDM_RX (1)
#define SOC_I2S_PDM_MAX_RX_LINES (4)
#define SOC_I2S_SUPPORTS_TDM (1)

View File

@@ -115,19 +115,23 @@ I2S Communication Mode
Overview of All Modes
^^^^^^^^^^^^^^^^^^^^^
========= ======== ======== ======== ======== ======== ==========
Target Standard PDM TX PDM RX TDM ADC/DAC LCD/Camera
========= ======== ======== ======== ======== ======== ==========
ESP32 I2S 0/1 I2S 0 I2S 0 none I2S 0 I2S 0
ESP32-S2 I2S 0 none none none none I2S 0
ESP32-C3 I2S 0 I2S 0 none I2S 0 none none
ESP32-C6 I2S 0 I2S 0 none I2S 0 none none
ESP32-S3 I2S 0/1 I2S 0 I2S 0 I2S 0/1 none none
ESP32-H2 I2S 0 I2S 0 none I2S 0 none none
ESP32-P4 I2S 0~2 I2S 0 I2S 0 I2S 0~2 none none
ESP32-C5 I2S 0 I2S 0 I2S 0 I2S 0 none none
ESP32-C61 I2S 0 I2S 0 I2S 0 I2S 0 none none
========= ======== ======== ======== ======== ======== ==========
========= ======== ============ ============ ========= ======== ======== ==========
Target Standard PCM-to-PDM PDM-to-PCM PDM TDM ADC/DAC LCD/Camera
========= ======== ============ ============ ========= ======== ======== ==========
ESP32 I2S 0/1 I2S 0 I2S 0 I2S 0/1 none I2S 0 I2S 0
ESP32-S2 I2S 0 none none none none none I2S 0
ESP32-C3 I2S 0 I2S 0 none I2S 0 I2S 0 none none
ESP32-C6 I2S 0 I2S 0 none I2S 0 I2S 0 none none
ESP32-S3 I2S 0/1 I2S 0 I2S 0 I2S 0/1 I2S 0/1 none none
ESP32-H2 I2S 0 I2S 0 none I2S 0 I2S 0 none none
ESP32-P4 I2S 0~2 I2S 0 I2S 0 I2S 0~2 I2S 0~2 none none
ESP32-C5 I2S 0 I2S 0 I2S 0 I2S 0 I2S 0 none none
ESP32-C61 I2S 0 I2S 0 I2S 0 I2S 0 I2S 0 none none
========= ======== ============ ============ ========= ======== ======== ==========
.. note::
If you are using PDM mode, note that not all I2S ports support conversion between raw PDM and PCM formats, because these ports do not have PCM-to-PDM data format converter in TX direction, or PDM-to-PCM data format converter in RX direction. Ports without the converter can only read/write raw PDM data. To read/write PCM format data on these ports, you may need an extra software filter for PDM-to-PCM conversion.
Standard Mode
^^^^^^^^^^^^^
@@ -147,28 +151,76 @@ In standard mode, there are always two sound channels, i.e., the left and right
.. wavedrom:: /../_static/diagrams/i2s/std_pcm.json
.. only:: SOC_I2S_SUPPORTS_PDM_TX
.. only:: SOC_I2S_SUPPORTS_PDM
PDM Mode (TX)
^^^^^^^^^^^^^
PDM Mode
^^^^^^^^
PDM (Pulse-density Modulation) mode for the TX channel can convert PCM data into PDM format which always has left and right slots. PDM TX is only supported on I2S0 and it only supports 16-bit width sample data. It needs at least a CLK pin for clock signal and a DOUT pin for data signal (i.e., the WS and SD signal in the following figure; the BCK signal is an internal bit sampling clock, which is not needed between PDM devices). This mode allows users to configure the up-sampling parameters :cpp:member:`i2s_pdm_tx_clk_config_t::up_sample_fp` and :cpp:member:`i2s_pdm_tx_clk_config_t::up_sample_fs`. The up-sampling rate can be calculated by ``up_sample_rate = i2s_pdm_tx_clk_config_t::up_sample_fp / i2s_pdm_tx_clk_config_t::up_sample_fs``. There are two up-sampling modes in PDM TX:
- **Fixed Clock Frequency**: In this mode, the up-sampling rate changes according to the sample rate. Setting ``fp = 960`` and ``fs = sample_rate / 100``, then the clock frequency (Fpdm) on CLK pin will be fixed to ``128 * 48 KHz = 6.144 MHz``. Note that this frequency is not equal to the sample rate (Fpcm).
- **Fixed Up-sampling Rate**: In this mode, the up-sampling rate is fixed to 2. Setting ``fp = 960`` and ``fs = 480``, then the clock frequency (Fpdm) on CLK pin will be ``128 * sample_rate``.
PDM (Pulse-density Modulation) digitalizes the analog signal by oversampling with 1-bit resolution. It represents the analog signal by the pulse density, the higher the pulse density, the larger the corresponding analog quantity. The PDM timing diagram is shown as follow:
.. wavedrom:: /../_static/diagrams/i2s/pdm.json
The PDM format data can be transferred into PCM format by the following steps:
.. only:: SOC_I2S_SUPPORTS_PDM_RX
1. Low-pass filtering: To restore the analog wave. It is usually a FIR filter;
2. Down-sampling: To reduce the PDM sample rate to the expected PCM sample rate. Normally we decimate one sample every specific number of samples;
3. High-pass filtering: To remove the DC offset of the analog wave;
4. Amplifying: To adjust the final gain of the converted PCM format data. It can be done by simply amplifying a coefficient.
PDM Mode (RX)
^^^^^^^^^^^^^
For I2S ports with a ``PCM-to-PDM`` converter, the hardware can convert PCM format data to PDM format when sending the data.
For I2S ports with a ``PDM-to-PCM`` converter, the hardware can convert PDM format data to PCM format when receiving the data.
If the hardware does not have the converters above, then the PDM mode can only read/write raw PDM format data. You need to realize a software filter to convert the raw PDM data into PCM format.
PDM (Pulse-density Modulation) mode for RX channel can receive PDM-format data and convert the data into PCM format. PDM RX is only supported on I2S0, and it only supports 16-bit width sample data. PDM RX needs at least a CLK pin for clock signal and a DIN pin for data signal. This mode allows users to configure the down-sampling parameter :cpp:member:`i2s_pdm_rx_clk_config_t::dn_sample_mode`. There are two down-sampling modes in PDM RX:
.. note::
- :cpp:enumerator:`i2s_pdm_dsr_t::I2S_PDM_DSR_8S`: In this mode, the clock frequency (Fpdm) on the WS pin is ``sample_rate (Fpcm) * 64``.
- :cpp:enumerator:`i2s_pdm_dsr_t::I2S_PDM_DSR_16S`: In this mode, the clock frequency (Fpdm) on the WS pin is ``sample_rate (Fpcm) * 128``.
In PDM mode, regardless of whether you are using raw PDM or PCM format, the data unit width is always 16 bits. For example, if you are sending data in raw PDM format, the data in the buffer is supposed to be arranged as follows: CH0 0x1234, CH1 0x5678, CH0 0x9abc, CH1 0xdef0. Same in the RX direction.
.. only:: SOC_I2S_SUPPORTS_PDM_TX
PDM TX Mode in Raw PDM Format
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To use the PDM TX mode in raw PDM format, set :cpp:member:`i2s_pdm_tx_slot_config_t::data_fmt` to :cpp:enumerator:`i2s_pdm_data_fmt_t::I2S_PDM_DATA_FMT_RAW`. Be cautious when setting :cpp:member:`i2s_pdm_tx_clk_config_t::sample_rate_hz`, as the PDM sample rate is normally in the MHz range, typically between 1.024 MHz and 6.144 MHz. Adjust it according to your needs.
As for the slot configuration of raw PDM format, you can use the helper macros like :c:macro:`I2S_PDM_TX_SLOT_RAW_FMT_DEFAULT_CONFIG` or :c:macro:`I2S_PDM_TX_SLOT_RAW_FMT_DAC_DEFAULT_CONFIG`.
.. only:: SOC_I2S_SUPPORTS_PCM2PDM
PDM TX Mode in PCM Format (with PCM-to-PDM Converter)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{IDF_TARGET_NAME} supports PCM-to-PDM converter on ``I2S0``. To send PCM format data in the PDM TX mode, you need to set :cpp:member:`i2s_pdm_tx_slot_config_t::data_fmt` to :cpp:enumerator:`i2s_pdm_data_fmt_t::I2S_PDM_DATA_FMT_PCM`. And then please take care when setting the :cpp:member:`i2s_pdm_tx_clk_config_t::sample_rate_hz`, the PCM sample rate is normally below 100KHz, typically, it ranges from 16KHz to 48KHz, you can set it according to your needs.
And the up-sampling parameters can be set for the PCM-to-PDM converter, i.e., :cpp:member:`i2s_pdm_tx_clk_config_t::up_sample_fp` and :cpp:member:`i2s_pdm_tx_clk_config_t::up_sample_fs`. The up-sampling rate can be calculated by ``up_sample_rate = i2s_pdm_tx_clk_config_t::up_sample_fp / i2s_pdm_tx_clk_config_t::up_sample_fs``. There are two up-sampling modes for PCM-to-PDM converter. The relation of the PDM clock on CLK pin and the PCM sample rate that set in the driver are shown as follow:
- **Fixed Clock Frequency**: In this mode, the up-sampling rate changes according to the sample rate. Setting ``fp = 960`` and ``fs = (PCM)sample_rate / 100``, then the PDM clock frequency on the CLK pin will be fixed to ``128 * 48 KHz = 6.144 MHz``.
- **Fixed Up-sampling Rate**: In this mode, the up-sampling rate is fixed to 2. Setting ``fp = 960`` and ``fs = 480``, then the PDM clock frequency on CLK pin will be ``128 * (PCM)sample_rate``.
As for the slot configuration of PCM format, you can use the helper macros like :c:macro:`I2S_PDM_TX_SLOT_PCM_FMT_DEFAULT_CONFIG` or :c:macro:`I2S_PDM_TX_SLOT_PCM_FMT_DAC_DEFAULT_CONFIG`.
.. only:: SOC_I2S_SUPPORTS_PDM_RX
PDM RX Mode in Raw PDM Format
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To use the PDM RX mode in raw PDM format, you need to set :cpp:member:`i2s_pdm_rx_slot_config_t::data_fmt` to :cpp:enumerator:`i2s_pdm_data_fmt_t::I2S_PDM_DATA_FMT_RAW`. And then please take care when setting the :cpp:member:`i2s_pdm_rx_clk_config_t::sample_rate_hz`, the PDM sample rate is normally several MHz, typically, it ranges from 1.024MHz to 6.144MHz, you can set it according to your needs.
As for the slot configuration of raw PDM format, you can use the helper macro :c:macro:`I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG`.
.. only:: SOC_I2S_SUPPORTS_PDM2PCM
PDM RX Mode in PCM Format (with PDM-to-PCM Converter)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{IDF_TARGET_NAME} supports PDM-to-PCM converter on ``I2S0``. To receive PCM format data in the PDM RX mode, you need to set :cpp:member:`i2s_pdm_rx_slot_config_t::data_fmt` to :cpp:enumerator:`i2s_pdm_data_fmt_t::I2S_PDM_DATA_FMT_PCM`. And then please take care when setting the :cpp:member:`i2s_pdm_rx_clk_config_t::sample_rate_hz`, the PCM sample rate is normally below 100KHz, typically, it ranges from 16KHz to 48KHz, you can set it according to your needs.
The down-sampling parameter can be set to the PDM-to-PCM converter, which is :cpp:member:`i2s_pdm_rx_clk_config_t::dn_sample_mode`. There are two down-sampling modes for PDM-to-PCM converter, the relation of the PDM clock on CLK pin and the PCM sample rate that set in the driver are shown as follow:
- :cpp:enumerator:`i2s_pdm_dsr_t::I2S_PDM_DSR_8S`: In this mode, the PDM clock frequency on the CLK pin is ``(PCM) sample_rate * 64``.
- :cpp:enumerator:`i2s_pdm_dsr_t::I2S_PDM_DSR_16S`: In this mode, the PDM clock frequency on the CLK pin is ``(PCM) sample_rate * 128``.
As for the slot configuration of PCM format, you can use the helper macro like :c:macro:`I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG`
.. only:: SOC_I2S_SUPPORTS_TDM
@@ -666,9 +718,13 @@ Here is the table of the data received in the buffer with different :cpp:member:
- :example:`peripherals/i2s/i2s_recorder` demonstrates how to record audio from a digital MEMS microphone using the I2S peripheral in PDM data format and save it to an SD card in ``.wav`` file format on {IDF_TARGET_NAME} development boards.
- :example:`peripherals/i2s/i2s_basic/i2s_pdm` demonstrates how to use the PDM RX mode on {IDF_TARGET_NAME}, including the necessary hardware setup and configuration.
For PDM mode in RX channel, the slot configuration helper macro is:
For PDM mode in RX channel, the slot configuration helper macro are:
- :c:macro:`I2S_PDM_RX_SLOT_DEFAULT_CONFIG`
- :c:macro:`I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG` It provides some default configurations for receiving the raw PDM format data.
.. only:: SOC_I2S_SUPPORTS_PDM2PCM
- :c:macro:`I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG` It provides some default configurations for receiving the converted PCM format data.
The clock configuration helper macro is:
@@ -730,7 +786,9 @@ Here is the table of the data received in the buffer with different :cpp:member:
/* Init the channel into PDM RX mode */
i2s_pdm_rx_config_t pdm_rx_cfg = {
.clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(36000),
.slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
// If PDM-to-PCM converter is not supported, please use raw PDM format
// .slot_cfg = I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
.slot_cfg = I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.clk = GPIO_NUM_5,
.din = GPIO_NUM_19,

View File

@@ -115,19 +115,23 @@ I2S 通信模式
模式概览
^^^^^^^^
========= ======== ======== ======== ======== ======== ==========
芯片 I2S 标准 PDM TX PDM RX TDM ADC/DAC LCD/摄像头
========= ======== ======== ======== ======== ======== ==========
ESP32 I2S 0/1 I2S 0 I2S 0 I2S 0 I2S 0
ESP32-S2 I2S 0 无 I2S 0
ESP32-C3 I2S 0 I2S 0 I2S 0 无 无
ESP32-C6 I2S 0 I2S 0 I2S 0 无 无
ESP32-S3 I2S 0/1 I2S 0 I2S 0 I2S 0/1 无 无
ESP32-H2 I2S 0 I2S 0 I2S 0 无 无
ESP32-P4 I2S 0~2 I2S 0 I2S 0 I2S 0~2 无 无
ESP32-C5 I2S 0 I2S 0 I2S 0 I2S 0 无 无
ESP32-C61 I2S 0 I2S 0 I2S 0 I2S 0 无 无
========= ======== ======== ======== ======== ======== ==========
========= ======== ========== ========== =========== ========== ======== ===========
芯片 I2S 标准 PCM-to-PDM PDM-to-PCM PDM TDM ADC/DAC LCD/摄像头
========= ======== ========== ========== =========== ========== ======== ===========
ESP32 I2S 0/1 I2S 0 I2S 0 I2S 0/1 无 I2S 0 I2S 0
ESP32-S2 I2S 0 I2S 0
ESP32-C3 I2S 0 I2S 0 I2S 0 I2S 0 无 无
ESP32-C6 I2S 0 I2S 0 I2S 0 I2S 0 无 无
ESP32-S3 I2S 0/1 I2S 0 I2S 0 I2S 0/1 I2S 0/1 无 无
ESP32-H2 I2S 0 I2S 0 I2S 0 I2S 0 无 无
ESP32-P4 I2S 0~2 I2S 0 I2S 0 I2S 0~2 I2S 0~2 无 无
ESP32-C5 I2S 0 I2S 0 I2S 0 I2S 0 I2S 0 无 无
ESP32-C61 I2S 0 I2S 0 I2S 0 I2S 0 I2S 0 无 无
========= ======== ========== ========== =========== ========== ======== ===========
.. note::
如需使用 PDM 模式,请注意不是所有 I2S 端口都支持原始 PDM 格式与 PCM 格式之间的转换,因为有些端口在 TX 方向上没有 PCM-to-PDM 数据格式转换器,或在 RX 方向上没有 PDM-to-PCM 数据格式转换器。因此,这些没有硬件格式转换器的端口只能读写原始 PDM 格式的数据。如果需要在这些端口上处理 PCM 格式的数据,则需额外采用一个软件滤波器来实现 PDM 格式和 PCM 格式之间的转换。
标准模式
^^^^^^^^
@@ -147,28 +151,76 @@ ESP32-C61 I2S 0 I2S 0 I2S 0 I2S 0 无 无
.. wavedrom:: /../_static/diagrams/i2s/std_pcm.json
.. only:: SOC_I2S_SUPPORTS_PDM_TX
PDM 模式 (TX)
^^^^^^^^^^^^^
.. only:: SOC_I2S_SUPPORTS_PDM
在 PDMPulse-density Modulation脉冲密度调制模式下TX 通道可以将 PCM 数据转换为 PDM 格式该格式始终有左右两个声道。PDM TX 只在 I2S0 中受支持,且只支持 16 位宽的采样数据。PDM TX 至少需要一个 CLK 管脚用于时钟信号,一个 DOUT 管脚用于数据信号(即下图中的 WS 和 SD 信号。BCK 信号为内部位采样时钟,在 PDM 设备之间不需要。PDM 模式允许用户配置上采样参数 :cpp:member:`i2s_pdm_tx_clk_config_t::up_sample_fp` 和 :cpp:member:`i2s_pdm_tx_clk_config_t::up_sample_fs`,上采样率可以通过公式 ``up_sample_rate = i2s_pdm_tx_clk_config_t::up_sample_fp / i2s_pdm_tx_clk_config_t::up_sample_fs`` 来计算。在 PDM TX 中有以下两种上采样模式:
PDM 模式
^^^^^^^^
- **固定时钟频率模式**:在这种模式下,上采样率将根据采样率的变化而变化。设置 ``fp = 960````fs = sample_rate / 100``,则 CLK 管脚上的时钟频率 (Fpdm) 将固定为 ``128 * 48 KHz = 6.144 MHz``。注意此频率不等于采样率 (Fpcm)。
- **固定上采样率模式**:在这种模式下,上采样率固定为 2。设置 ``fp = 960````fs = 480``,则 CLK 管脚上的时钟频率 (Fpdm) 将为 ``128 * sample_rate``
PDMPulse-density Modulation脉冲密度调制通过采样的方式将模拟信号数字化为 1 位精度的数字信号。它以脉冲密度的方式呈现模拟信号的大小即密度越高对应的模拟信号值越大。PDM 时序图如下所示:
.. wavedrom:: /../_static/diagrams/i2s/pdm.json
PDM 格式的数据通常可以经过以下几个步骤转换为 PCM 格式:
.. only:: SOC_I2S_SUPPORTS_PDM_RX
1. 低通滤波:用于还原模拟信号波形。一般采用 FIR 滤波器;
2. 下采样:用于将 PDM 的过采样率降低到期望的 PCM 采样率。下采样可以用简单的抽值法实现;
3. 高通滤波:用于去除信号的直流部分;
4. 放大:用于调整转换后的 PCM 数据的増益。一般由转换后的 PCM 信号乘以一个系数得到最终 PCM 信号。
PDM 模式 (RX)
^^^^^^^^^^^^^
对于具有 ``PCM-to-PDM`` 格式转换器的 I2S 端口,可以在发送数据的时候,将 PCM 数据转换为 PDM 格式发送。
对于具有 ``PDM-to-PCM`` 格式转换器的 I2S 端口,可以再接收数据的时候,将收到的 PDM 格式的数据转换为 PCM 格式。
若硬件不具备上述的格式转换器,则 PDM 模式只能收发原始的 PDM 格式数据。需要在软件上实现 PDM-to-PCM 的转换逻辑以此得到常用的 PCM 格式数据。
在 PDMPulse-density Modulation脉冲密度调制模式下RX 通道可以接收 PDM 格式的数据并将数据转换成 PCM 格式。PDM RX 只在 I2S0 中受支持,且只支持 16 位宽的采样数据。PDM RX 至少需要一个 CLK 管脚用于时钟信号,一个 DIN 管脚用于数据信号。此模式允许用户配置下采样参数 :cpp:member:`i2s_pdm_rx_clk_config_t::dn_sample_mode`。在 PDM RX 中有以下两种下采样模式:
.. note::
- :cpp:enumerator:`i2s_pdm_dsr_t::I2S_PDM_DSR_8S`在这种模式下WS 管脚的时钟频率 (Fpdm) 将为 ``sample_rate (Fpcm) * 64``
- :cpp:enumerator:`i2s_pdm_dsr_t::I2S_PDM_DSR_16S` 在这种模式下WS 管脚的时钟频率 (Fpdm) 将为 ``sample_rate (Fpcm) * 128``
无论原始 PDM 格式还是 PCM 格式PDM 模式下的一个数据单元总是 16 比特的位宽。例如,用原始 PDM 格式发送数据那么您数组中的数据应该像这样排列CH0 0x1234CH1 0x5678CH0 0x9abcCH1 0xdef0。RX 方向同理。
.. only:: SOC_I2S_SUPPORTS_PDM_TX
PDM TX 模式原始 PDM 数据格式
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
要发送原始 PDM 格式的数据,您需要将 :cpp:member:`i2s_pdm_tx_slot_config_t::data_fmt` 设为 :cpp:enumerator:`i2s_pdm_data_fmt_t::I2S_PDM_DATA_FMT_RAW`。另外在设置 :cpp:member:`i2s_pdm_tx_clk_config_t::sample_rate_hz` 时请注意PDM 的采样率通常在若干 MHz典型值范围一般是 1.024MHz 到 6.144MHz 之间,您可以根据需求来设置。
而原始 PDM 数据格式下的声道配置,可以通过帮助宏 :c:macro:`I2S_PDM_TX_SLOT_RAW_FMT_DEFAULT_CONFIG`::c:macro:`I2S_PDM_TX_SLOT_RAW_FMT_DAC_DEFAULT_CONFIG` 来配置。
.. only:: SOC_I2S_SUPPORTS_PCM2PDM
PDM TX 模式 PCM 数据格式(采用 PCM-to-PDM 格式转换器)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{IDF_TARGET_NAME} 在 ``I2S0`` 上支持 PCM-to-PDM 格式转换器,您可以通过 :cpp:member:`i2s_pdm_tx_slot_config_t::data_fmt` 设为 :cpp:enumerator:`i2s_pdm_data_fmt_t::I2S_PDM_DATA_FMT_PCM` 来启用 PCM-to-PDM 格式转换器。启用后会将发送的 PCM 格式的数据转换为 PDM 格式发送。另外在设置 :cpp:member:`i2s_pdm_tx_clk_config_t::sample_rate_hz` 时请注意PCM 的采样率通常低于 100 KHz典型值的范围一般是 16KHz 到 48KHz 之间,您可以根据需求来设置。
另外 PCM-to-PDM 转换器可配置上采样参数 :cpp:member:`i2s_pdm_tx_clk_config_t::up_sample_fp`:cpp:member:`i2s_pdm_tx_clk_config_t::up_sample_fs`。上采样率可以通过公式 ``up_sample_rate = i2s_pdm_tx_clk_config_t::up_sample_fp / i2s_pdm_tx_clk_config_t::up_sample_fs`` 来计算。在 PDM TX 中有以下两种上采样模式,输出的 PDM 采样频率和配置的 PCM 采样频率关系如下:
- **固定时钟频率模式**:在这种模式下,上采样率将根据采样率的变化而变化。设置 ``fp = 960````fs = (PCM)sample_rate / 100``,则 CLK 管脚上的输出的 PDM 时钟频率将固定为 ``128 * 48 KHz = 6.144 MHz``
- **固定上采样率模式**:在这种模式下,上采样率固定为 2。即设置 ``fp = 960````fs = 480``,则 CLK 管脚上的 PDM 的时钟频率将为 ``128 * sample_rate``
而 PCM 数据格式下的声道配置,您可以通过帮助宏 :c:macro:`I2S_PDM_TX_SLOT_PCM_FMT_DEFAULT_CONFIG`:c:macro:`I2S_PDM_TX_SLOT_PCM_FMT_DAC_DEFAULT_CONFIG` 来配置。
.. only:: SOC_I2S_SUPPORTS_PDM_RX
PDM RX 模式原始 PDM 数据格式
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
要接收原始 PDM 格式的数据,您需要将 :cpp:member:`i2s_pdm_rx_slot_config_t::data_fmt` 设为 :cpp:enumerator:`i2s_pdm_data_fmt_t::I2S_PDM_DATA_FMT_RAW`。另外在设置 :cpp:member:`i2s_pdm_rx_clk_config_t::sample_rate_hz` 时请注意PDM 的采样率通常在若干 MHz典型值范围一般是 1.024MHz 到 6.144MHz 之间,您可以根据需求来设置。
而原始 PDM 数据格式下的声道配置,可以通过帮助宏 :c:macro:`I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG` 来配置。
.. only:: SOC_I2S_SUPPORTS_PDM2PCM
PDM RX 模式 PCM 数据格式(采用 PDM-to-PCM 格式转换器)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{IDF_TARGET_NAME} 在 ``I2S0`` 上支持 PDM-to-PCM 格式转换器,您可以通过 :cpp:member:`i2s_pdm_rx_slot_config_t::data_fmt` 设为 :cpp:enumerator:`i2s_pdm_data_fmt_t::I2S_PDM_DATA_FMT_PCM` 来启用 PDM-to-PCM 格式转换器。启用后会将接收到的 PDM 格式的数据转换为 PCM 格式。另外在设置 :cpp:member:`i2s_pdm_rx_clk_config_t::sample_rate_hz` 时请注意PCM 的采样率通常低于 100 KHz典型值的范围一般是 16KHz 到 48KHz 之间,您可以根据需求来设置。
另外 PDM-to-PCM 转换器可配置下采样参数 :cpp:member:`i2s_pdm_rx_clk_config_t::dn_sample_mode`。在 PDM RX 中有以下两种下采样模式,输出的 PDM 采样频率和配置的 PCM 采样频率关系如下:
- :cpp:enumerator:`i2s_pdm_dsr_t::I2S_PDM_DSR_8S`在这种模式下CLK 管脚的 PDM 时钟频率将为 ``(PCM) sample_rate * 64``
- :cpp:enumerator:`i2s_pdm_dsr_t::I2S_PDM_DSR_16S` 在这种模式下CLK 管脚的 PDM 时钟频率将为 ``(PCM) sample_rate * 128``
而 PCM 数据格式下的声道配置,可以通过帮助宏 :c:macro:`I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG` 来配置。
.. only:: SOC_I2S_SUPPORTS_TDM
@@ -668,7 +720,11 @@ STD RX 模式
针对 RX 通道的 PDM 模式,声道配置的辅助宏为:
- :c:macro:`I2S_PDM_RX_SLOT_DEFAULT_CONFIG`
- :c:macro:`I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG` 该辅助宏为接收原始 PDM 数据格式提供了一些默认配置。
.. only:: SOC_I2S_SUPPORTS_PDM2PCM
- :c:macro:`I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG` 该辅助宏为接收转换后的 PCM 数据格式提供了一些默认配置。
时钟配置的辅助宏为:
@@ -730,7 +786,9 @@ STD RX 模式
/* 初始化通道为 PDM RX 模式 */
i2s_pdm_rx_config_t pdm_rx_cfg = {
.clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(36000),
.slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
// 若不支持 PDM 转 PCM 格式转换器,请使用原始 PDM 格式
// .slot_cfg = I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
.slot_cfg = I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.clk = GPIO_NUM_5,
.din = GPIO_NUM_19,

View File

@@ -15,6 +15,7 @@
#include "sdkconfig.h"
#include "i2s_pdm_example.h"
#include "i2s_example_pins.h"
#include "esp_log.h"
#define EXAMPLE_PDM_RX_CLK_IO EXAMPLE_I2S_BCLK_IO1 // I2S PDM RX clock io number
#define EXAMPLE_PDM_RX_DIN_IO EXAMPLE_I2S_DIN_IO1 // I2S PDM RX data in io number
@@ -24,10 +25,21 @@
#define EXAMPLE_PDM_RX_DIN3_IO EXAMPLE_I2S_DIN3_IO1 // I2S PDM RX data line3 in io number
#endif
#define EXAMPLE_PDM_RX_FREQ_HZ 16000 // I2S PDM RX frequency
#if SOC_I2S_SUPPORTS_PDM2PCM
#define EXAMPLE_PDM_RX_FREQ_HZ 16000 // I2S PDM RX frequency in PCM format
#else
#define EXAMPLE_PDM_RX_FREQ_HZ 2048000 // I2S PDM RX over sample frequency in raw PDM format
#endif
static const char *TAG = "i2s_pdm_rx";
static i2s_chan_handle_t i2s_example_init_pdm_rx(void)
{
#if SOC_I2S_SUPPORTS_PDM2PCM
ESP_LOGI(TAG, "I2S PDM RX example (receiving data in PCM format)");
#else
ESP_LOGI(TAG, "I2S PDM RX example (receiving data in raw PDM format)");
#endif // SOC_I2S_SUPPORTS_PDM2PCM
i2s_chan_handle_t rx_chan; // I2S rx channel handler
/* Setp 1: Determine the I2S channel configuration and allocate RX channel only
* The default configuration can be generated by the helper macro,
@@ -42,7 +54,12 @@ static i2s_chan_handle_t i2s_example_init_pdm_rx(void)
i2s_pdm_rx_config_t pdm_rx_cfg = {
.clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(EXAMPLE_PDM_RX_FREQ_HZ),
/* The data bit-width of PDM mode is fixed to 16 */
.slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
#if SOC_I2S_SUPPORTS_PDM2PCM
.slot_cfg = I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
#else
// For the target that not support PDM-to-PCM format, we can only receive RAW PDM data format
.slot_cfg = I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
#endif // SOC_I2S_SUPPORTS_PDM2PCM
.gpio_cfg = {
.clk = EXAMPLE_PDM_RX_CLK_IO,
#if SOC_I2S_PDM_MAX_RX_LINES == 4

View File

@@ -32,9 +32,11 @@ menu "Example Configuration"
config EXAMPLE_SAMPLE_RATE
int "Audio Sample Rate"
default 44100
default 44100 if SOC_I2S_SUPPORTS_PDM2PCM
default 5644800
help
Set the audio sample rate frequency. Usually 16000 or 44100 Hz.
Set the audio sample rate frequency. Usually 16000 or 44100 Hz if PCM data format supported.
Oversample rate usually can be 2048000 or 5644800 Hz if only raw PDM data format supported.
config EXAMPLE_BIT_SAMPLE
int "Audio Bit Sample"

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -22,6 +22,7 @@
#include "driver/spi_common.h"
#include "sdmmc_cmd.h"
#include "format_wav.h"
#include "esp_log.h"
static const char *TAG = "pdm_rec_example";
@@ -144,13 +145,22 @@ void record_wav(uint32_t rec_time)
void init_microphone(void)
{
#if SOC_I2S_SUPPORTS_PDM2PCM
ESP_LOGI(TAG, "Receive PDM microphone data in PCM format");
#else
ESP_LOGI(TAG, "Receive PDM microphone data in raw PDM format");
#endif // SOC_I2S_SUPPORTS_PDM2PCM
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, NULL, &rx_handle));
i2s_pdm_rx_config_t pdm_rx_cfg = {
.clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(CONFIG_EXAMPLE_SAMPLE_RATE),
/* The default mono slot is the left slot (whose 'select pin' of the PDM microphone is pulled down) */
.slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
#if SOC_I2S_SUPPORTS_PDM2PCM
.slot_cfg = I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
#else
.slot_cfg = I2S_PDM_RX_SLOT_RAW_FMT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
#endif
.gpio_cfg = {
.clk = CONFIG_EXAMPLE_I2S_CLK_GPIO,
.din = CONFIG_EXAMPLE_I2S_DATA_GPIO,