mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/add_default_config_for_i2s_pdm_dac_mode' into 'master'
i2s: public bclk_div and add a default config for PDM TX DAC Closes IDF-7289 See merge request espressif/esp-idf!23466
This commit is contained in:
commit
e9e5f1b90f
@ -30,6 +30,7 @@ static const char *TAG = "i2s_pdm";
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM_TX
|
||||
#define I2S_PDM_TX_BCLK_DIV_MIN 8 /*!< The minimum bclk_div for PDM TX mode */
|
||||
static esp_err_t i2s_pdm_tx_calculate_clock(i2s_chan_handle_t handle, const i2s_pdm_tx_clk_config_t *clk_cfg, i2s_hal_clock_info_t *clk_info)
|
||||
{
|
||||
uint32_t rate = clk_cfg->sample_rate_hz;
|
||||
@ -38,7 +39,7 @@ static esp_err_t i2s_pdm_tx_calculate_clock(i2s_chan_handle_t handle, const i2s_
|
||||
// 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->bclk_div = clk_cfg->bclk_div < I2S_PDM_TX_BCLK_DIV_MIN ? I2S_PDM_TX_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);
|
||||
clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
|
||||
@ -318,13 +319,14 @@ err:
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM_RX
|
||||
#define I2S_PDM_RX_BCLK_DIV_MIN 8 /*!< The minimum bclk_div for PDM RX mode */
|
||||
static esp_err_t i2s_pdm_rx_calculate_clock(i2s_chan_handle_t handle, const i2s_pdm_rx_clk_config_t *clk_cfg, i2s_hal_clock_info_t *clk_info)
|
||||
{
|
||||
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);
|
||||
clk_info->bclk_div = 8;
|
||||
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);
|
||||
clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
|
||||
|
@ -44,7 +44,8 @@ extern "C" {
|
||||
.sample_rate_hz = rate, \
|
||||
.clk_src = I2S_CLK_SRC_DEFAULT, \
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE_256, \
|
||||
.dn_sample_mode = I2S_PDM_DSR_8S \
|
||||
.dn_sample_mode = I2S_PDM_DSR_8S, \
|
||||
.bclk_div = 8, \
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,6 +70,8 @@ typedef struct {
|
||||
i2s_mclk_multiple_t mclk_multiple; /*!< The multiple of mclk to the sample rate */
|
||||
/* Particular fields */
|
||||
i2s_pdm_dsr_t dn_sample_mode; /*!< Down-sampling rate mode */
|
||||
uint32_t bclk_div; /*!< The division from mclk to bclk. The typical and minimum value is I2S_PDM_RX_BCLK_DIV_MIN.
|
||||
* It will be set to I2S_PDM_RX_BCLK_DIV_MIN by default if it is smaller than I2S_PDM_RX_BCLK_DIV_MIN */
|
||||
} i2s_pdm_rx_clk_config_t;
|
||||
|
||||
/**
|
||||
@ -165,7 +168,7 @@ 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)
|
||||
* @brief PDM style in 2 slots(TX) for codec line mode
|
||||
* @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
|
||||
*/
|
||||
@ -184,9 +187,33 @@ esp_err_t i2s_channel_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_p
|
||||
.sd_dither = 0, \
|
||||
.sd_dither2 = 1, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
* 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_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, \
|
||||
.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, \
|
||||
.line_mode = ((mono_or_stereo) == I2S_SLOT_MODE_MONO ? \
|
||||
I2S_PDM_TX_ONE_LINE_DAC : I2S_PDM_TX_TWO_LINE_DAC), \
|
||||
.hp_en = true, \
|
||||
.hp_cut_off_freq_hz = 35.5, \
|
||||
.sd_dither = 0, \
|
||||
.sd_dither2 = 1, \
|
||||
}
|
||||
#else // SOC_I2S_HW_VERSION_2
|
||||
/**
|
||||
* @brief PDM style in 2 slots(TX)
|
||||
* @brief PDM style in 2 slots(TX) for codec line mode
|
||||
* @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
|
||||
*/
|
||||
@ -204,7 +231,7 @@ esp_err_t i2s_channel_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_p
|
||||
#endif // SOC_I2S_HW_VERSION_2
|
||||
|
||||
/**
|
||||
* @brief i2s default pdm tx clock configuration
|
||||
* @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:
|
||||
* 1: fp = 960, fs = sample_rate_hz / 100, in this case, Fpdm = 128*48000
|
||||
* 2: fp = 960, fs = 480, in this case, Fpdm = 128*Fpcm = 128*sample_rate_hz
|
||||
@ -218,6 +245,27 @@ esp_err_t i2s_channel_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_p
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE_256, \
|
||||
.up_sample_fp = 960, \
|
||||
.up_sample_fs = 480, \
|
||||
.bclk_div = 8, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief i2s default pdm tx clock configuration for DAC line mode
|
||||
* @note TX PDM can only be set to the following two up-sampling rate configurations:
|
||||
* 1: fp = 960, fs = sample_rate_hz / 100, in this case, Fpdm = 128*48000
|
||||
* 2: fp = 960, fs = 480, in this case, Fpdm = 128*Fpcm = 128*sample_rate_hz
|
||||
* If the pdm receiver do not care the pdm serial clock, it's recommended set Fpdm = 128*48000.
|
||||
* Otherwise, the second configuration should be adopted.
|
||||
* @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 rate sample rate (not suggest to exceed 48000 Hz, otherwise more glitches and noise may appear)
|
||||
*/
|
||||
#define I2S_PDM_TX_CLK_DAC_DEFAULT_CONFIG(rate) { \
|
||||
.sample_rate_hz = rate, \
|
||||
.clk_src = I2S_CLK_SRC_DEFAULT, \
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE_256, \
|
||||
.up_sample_fp = 960, \
|
||||
.up_sample_fs = (rate) / 100, \
|
||||
.bclk_div = 13, \
|
||||
}
|
||||
|
||||
/*
|
||||
@ -275,6 +323,8 @@ typedef struct {
|
||||
/* Particular fields */
|
||||
uint32_t up_sample_fp; /*!< Up-sampling param fp */
|
||||
uint32_t up_sample_fs; /*!< Up-sampling param fs, not allowed to be greater than 480 */
|
||||
uint32_t bclk_div; /*!< The division from mclk to bclk. The minimum value is I2S_PDM_TX_BCLK_DIV_MIN.
|
||||
* It will be set to I2S_PDM_TX_BCLK_DIV_MIN by default if it is smaller than I2S_PDM_TX_BCLK_DIV_MIN */
|
||||
} i2s_pdm_tx_clk_config_t;
|
||||
|
||||
/**
|
||||
|
@ -45,9 +45,6 @@ examples/peripherals/i2s/i2s_adc_dac:
|
||||
examples/peripherals/i2s/i2s_basic/i2s_pdm:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTS_PDM != 1
|
||||
- if: IDF_TARGET == "esp32h2"
|
||||
temporary: true
|
||||
reason: rtc timer is not supported
|
||||
|
||||
examples/peripherals/i2s/i2s_basic/i2s_std:
|
||||
disable:
|
||||
@ -290,9 +287,3 @@ examples/peripherals/uart/uart_echo_rs485:
|
||||
examples/peripherals/usb:
|
||||
disable:
|
||||
- if: SOC_USB_PERIPH_NUM != 1
|
||||
|
||||
examples/peripherals/wave_gen:
|
||||
enable:
|
||||
- if: IDF_TARGET == "esp32"
|
||||
temporary: true
|
||||
reason: the other targets are not tested yet
|
||||
|
@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# I2S Basic PDM Mode Example
|
||||
|
||||
@ -99,9 +99,9 @@ This example is going to show how to use the PDM TX and RX mode.
|
||||
#### PDM TX
|
||||
|
||||
* An earphone or a speaker
|
||||
* An audio power amplifier that can input PDM signal. If the power amplifier can only receive the analog signal without PDM clock, a low-pass passive or active filter is required to restore the PDM data wave into analog signal, before it is transmitted to the power amplifier.
|
||||
* An audio power amplifier that can input PDM signal. If the power amplifier can only receive the analog signal without PDM clock (i.e. DAC line mode, otherwise codec line mode), a low-pass passive or active filter is required to restore the PDM data wave into analog signal, before it is transmitted to the power amplifier.
|
||||
|
||||
**MAX98358**
|
||||
**MAX98358 (codec case)**
|
||||
|
||||
Please refer to the [Datasheet of MAX98358](https://datasheets.maximintegrated.com/en/ds/MAX98358.pdf) for more details.
|
||||
|
||||
@ -121,7 +121,7 @@ Please refer to the [Datasheet of MAX98358](https://datasheets.maximintegrated.c
|
||||
└────────────────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
**NS4150**
|
||||
**NS4150 (dac case)**
|
||||
|
||||
Please refer to the NS4150 datasheet for more details.
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
set(srcs "i2s_pdm_example_main.c")
|
||||
|
||||
if(CONFIG_SOC_I2S_SUPPORTS_PDM_TX)
|
||||
if(CONFIG_SOC_I2S_SUPPORTS_PDM_TX AND CONFIG_EXAMPLE_PDM_TX)
|
||||
list(APPEND srcs "i2s_pdm_tx.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_I2S_SUPPORTS_PDM_RX)
|
||||
if(CONFIG_SOC_I2S_SUPPORTS_PDM_RX AND CONFIG_EXAMPLE_PDM_RX)
|
||||
list(APPEND srcs "i2s_pdm_rx.c")
|
||||
endif()
|
||||
|
||||
|
@ -19,4 +19,28 @@ menu "I2S PDM Example Configuration"
|
||||
PDM RX example will show the received data from a PDM microphone.
|
||||
endchoice
|
||||
|
||||
choice EXAMPLE_PDM_TX_LINE_MODE
|
||||
prompt "I2S PDM TX Line Mode"
|
||||
depends on EXAMPLE_PDM_TX && SOC_I2S_HW_VERSION_2
|
||||
default EXAMPLE_PDM_TX_CODEC
|
||||
help
|
||||
Decide to output PDM signal into a PDM codec or a low-pass filter
|
||||
|
||||
config EXAMPLE_PDM_TX_CODEC
|
||||
bool "Codec line mode"
|
||||
help
|
||||
Output PDM signal to a PDM codec. The PDM clock signal is mandatory for PDM codec,
|
||||
the codec can differentiate the left and right sound channels by sampling data
|
||||
on positive or negative edges. That means the data of the left and right channels
|
||||
can coexist on a same data line.
|
||||
|
||||
config EXAMPLE_PDM_TX_DAC
|
||||
bool "DAC line mode"
|
||||
help
|
||||
Output PDM signal to a low-pass filter, so that the low-pass filter can restore the PDM
|
||||
signal to analog wave. Therefore, each data line can only contains one sound channel,
|
||||
if both left and right channels are required, two data lines should be specified as well.
|
||||
Normally the PDM signal is not sufficient in DAC line mode.
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
@ -54,9 +54,15 @@ static i2s_chan_handle_t i2s_example_init_pdm_tx(void)
|
||||
* These two helper macros is defined in 'i2s_pdm.h' which can only be used in PDM TX mode.
|
||||
* They can help to specify the slot and clock configurations for initialization or re-configuring */
|
||||
i2s_pdm_tx_config_t pdm_tx_cfg = {
|
||||
#if CONFIG_EXAMPLE_PDM_TX_DAC
|
||||
.clk_cfg = I2S_PDM_TX_CLK_DAC_DEFAULT_CONFIG(EXAMPLE_PDM_TX_FREQ_HZ),
|
||||
/* The data bit-width of PDM mode is fixed to 16 */
|
||||
.slot_cfg = I2S_PDM_TX_SLOT_DAC_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
|
||||
#else
|
||||
.clk_cfg = I2S_PDM_TX_CLK_DEFAULT_CONFIG(EXAMPLE_PDM_TX_FREQ_HZ),
|
||||
/* The data bit-width of PDM mode is fixed to 16 */
|
||||
.slot_cfg = I2S_PDM_TX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
|
||||
#endif
|
||||
.gpio_cfg = {
|
||||
.clk = EXAMPLE_PDM_TX_CLK_IO,
|
||||
.dout = EXAMPLE_PDM_TX_DOUT_IO,
|
||||
|
@ -9,7 +9,7 @@ from pytest_embedded import Dut
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.esp32c6
|
||||
# @pytest.mark.esp32h2 IDF-6808
|
||||
@pytest.mark.esp32h2
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
|
Loading…
Reference in New Issue
Block a user