diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 480cd98ef..085f19b89 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -42,17 +42,19 @@ static const char* I2S_TAG = "I2S"; ESP_LOGE(I2S_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \ return (ret); \ } -#define I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated -#define I2S_BASE_CLK (2*APB_CLK_FREQ) -#define I2S_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_spinlock[i2s_num]) -#define I2S_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_spinlock[i2s_num]) -#define I2S_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_spinlock[i2s_num]) -#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num]) +#define I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated +#define I2S_BASE_CLK (2*APB_CLK_FREQ) +#define I2S_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_spinlock[i2s_num]) +#define I2S_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_spinlock[i2s_num]) +#define I2S_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_spinlock[i2s_num]) +#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num]) #define I2S_FULL_DUPLEX_SLAVE_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_SLAVE) #define I2S_FULL_DUPLEX_MASTER_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_MASTER) -#define APLL_MIN_FREQ (250000000) -#define APLL_MAX_FREQ (500000000) -#define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware +#define APLL_MIN_FREQ (250000000) +#define APLL_MAX_FREQ (500000000) +#define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware +#define I2S_AD_BCK_FACTOR (2) +#define I2S_PDM_BCK_FACTOR (64) /** * @brief DMA buffer object * @@ -399,11 +401,14 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b } double mclk; + int sdm0, sdm1, sdm2, odir, m_scale = 8; + int fi2s_clk = rate*channel*bits*m_scale; if (p_i2s_obj[i2s_num]->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { //DAC uses bclk as sample clock, not WS. WS can be something arbitrary. //Rate as given to this function is the intended sample rate; //According to the TRM, WS clk equals to the sample rate, and bclk is double the speed of WS - uint32_t b_clk = rate * 2; + uint32_t b_clk = rate * I2S_AD_BCK_FACTOR; + fi2s_clk /= I2S_AD_BCK_FACTOR; int factor2 = 60; mclk = b_clk * factor2; clkmdiv = ((double) I2S_BASE_CLK) / mclk; @@ -415,9 +420,11 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { int fp = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp; int fs = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs; - b_clk = rate * 64 * (fp / fs); + b_clk = rate * I2S_PDM_BCK_FACTOR * (fp / fs); + fi2s_clk /= (I2S_PDM_BCK_FACTOR * (fp / fs)); } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - b_clk = rate * 64 * (I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en + 1); + b_clk = rate * I2S_PDM_BCK_FACTOR * (I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en + 1); + fi2s_clk /= (I2S_PDM_BCK_FACTOR * (I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en + 1)); } int factor2 = 5 ; mclk = b_clk * factor2; @@ -431,8 +438,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b mclk = clkmInteger + denom * clkmDecimals; bck = factor/(bits * channel); } - int sdm0, sdm1, sdm2, odir, m_scale = 8; - int fi2s_clk = rate*channel*bits*m_scale; + if(p_i2s_obj[i2s_num]->use_apll && p_i2s_obj[i2s_num]->fixed_mclk) { fi2s_clk = p_i2s_obj[i2s_num]->fixed_mclk; m_scale = fi2s_clk/bits/rate/channel; @@ -845,6 +851,13 @@ esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate) return i2s_set_clk(i2s_num, rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); } +esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en = dsr; + return i2s_set_clk(i2s_num, p_i2s_obj[i2s_num]->sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); +} + static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_config) { I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index 1f73e1f55..0957e10cc 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -189,6 +189,14 @@ typedef struct { int data_in_num; /*!< DATA in pin*/ } i2s_pin_config_t; +/** + * @brief I2S PDM RX downsample mode + */ +typedef enum { + I2S_PDM_DSR_8S = 0, /*!< downsampling number is 8 for PDM RX mode*/ + I2S_PDM_DSR_16S, /*!< downsampling number is 16 for PDM RX mode*/ + I2S_PDM_DSR_MAX, +} i2s_pdm_dsr_t; typedef intr_handle_t i2s_isr_handle_t; /** @@ -215,6 +223,25 @@ typedef intr_handle_t i2s_isr_handle_t; */ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin); +/** + * @brief Set PDM mode down-sample rate + * In PDM RX mode, there would be 2 rounds of downsample process in hardware. + * In the first downsample process, the sampling number can be 16 or 8. + * In the second downsample process, the sampling number is fixed as 8. + * So the clock frequency in PDM RX mode would be (fpcm * 64) or (fpcm * 128) accordingly. + * @param i2s_num I2S_NUM_0, I2S_NUM_1 + * @param dsr i2s RX down sample rate for PDM mode. + * + * @note After calling this function, it would call i2s_set_clk inside to update the clock frequency. + * Please call this function after I2S driver has been initialized. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NO_MEM Out of memory + */ +esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr); + /** * @brief Set I2S dac mode, I2S built-in DAC is disabled by default * diff --git a/examples/peripherals/i2s_adc_dac/main/app_main.c b/examples/peripherals/i2s_adc_dac/main/app_main.c index 25335bb61..9d3018b4b 100644 --- a/examples/peripherals/i2s_adc_dac/main/app_main.c +++ b/examples/peripherals/i2s_adc_dac/main/app_main.c @@ -67,7 +67,8 @@ void example_i2s_init() .channel_format = EXAMPLE_I2S_FORMAT, .intr_alloc_flags = 0, .dma_buf_count = 2, - .dma_buf_len = 1024 + .dma_buf_len = 1024, + .use_apll = 1, }; //install and start i2s driver i2s_driver_install(i2s_num, &i2s_config, 0, NULL);