From 2f1247e1c4dd8bb9401d6b1256d34dd7319fbe5c Mon Sep 17 00:00:00 2001 From: houwenxiang Date: Mon, 1 Jun 2020 09:47:48 +0800 Subject: [PATCH 1/5] driver: support I2S on ESP32-S3 & ESP32-C3 1. refactor I2S driver. 2. support TDM mode for esp2s3 & esp32c3. --- components/driver/i2s.c | 624 +++++----- components/driver/include/driver/i2s.h | 96 +- .../driver/test/adc_dma_test/test_esp32.c | 10 +- .../driver/test/dac_dma_test/test_esp32.c | 10 +- components/driver/test/test_i2s.c | 173 ++- .../private_include/esp_efuse_utility.h | 10 + components/hal/esp32/include/hal/i2s_ll.h | 1007 ++++++++-------- components/hal/esp32c3/include/hal/i2s_ll.h | 953 ++++++--------- components/hal/esp32s2/include/hal/i2s_ll.h | 836 ++++++-------- components/hal/esp32s3/include/hal/i2s_ll.h | 1028 +++++++---------- components/hal/i2s_hal.c | 437 ++++--- components/hal/include/hal/i2s_hal.h | 376 +++--- components/hal/include/hal/i2s_types.h | 164 ++- components/soc/esp32/i2s_periph.c | 36 +- components/soc/esp32/include/soc/soc_caps.h | 8 +- components/soc/esp32c3/i2s_periph.c | 20 +- .../soc/esp32c3/ld/esp32c3.peripherals.ld | 2 +- components/soc/esp32s2/i2s_periph.c | 20 +- components/soc/esp32s2/include/soc/soc_caps.h | 8 +- components/soc/esp32s3/i2s_periph.c | 30 +- components/soc/esp32s3/include/soc/i2s_caps.h | 23 - components/soc/esp32s3/include/soc/soc_caps.h | 7 +- .../soc/esp32s3/ld/esp32s3.peripherals.ld | 1 + components/soc/include/soc/i2s_periph.h | 18 +- docs/en/api-reference/peripherals/i2s.rst | 34 +- .../classic_bt/a2dp_sink/main/main.c | 22 +- .../coex/a2dp_gatts_coex/main/main.c | 21 +- .../i2s/i2s_adc_dac/main/app_main.c | 12 +- .../i2s/i2s_basic/main/i2s_example_main.c | 19 +- 29 files changed, 2929 insertions(+), 3076 deletions(-) delete mode 100644 components/soc/esp32s3/include/soc/i2s_caps.h diff --git a/components/driver/i2s.c b/components/driver/i2s.c index be3e90b3b7..48fbb5740f 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -53,6 +53,7 @@ static const char* I2S_TAG = "I2S"; #define I2S_AD_BCK_FACTOR (2) #define I2S_PDM_BCK_FACTOR (64) #define I2S_BASE_CLK (2*APB_CLK_FREQ) +#define I2S_MAX_BUFFER_SIZE (4*1024*1024) //the maximum RAM can be allocated /** * @brief DMA buffer object @@ -84,12 +85,12 @@ typedef struct { int channel_num; /*!< Number of channels*/ int bytes_per_sample; /*!< Bytes per sample*/ int bits_per_sample; /*!< Bits per sample*/ + i2s_comm_format_t communication_format; /*!hal)); + i2s_hal_reset_txdma(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_reset_tx_fifo(&(p_i2s_obj[i2s_num]->hal)); +} + +static void i2s_rx_reset(i2s_port_t i2s_num) +{ + // Reset I2S RX module first, and then, reset DMA and FIFO. + i2s_hal_reset_rx(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_reset_rxdma(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_reset_rx_fifo(&(p_i2s_obj[i2s_num]->hal)); +} + +#if SOC_I2S_SUPPORTS_PCM +esp_err_t i2s_pcm_config(i2s_port_t i2s_num, int mode, i2s_pcm_cfg_t pcm_cfg) +{ + if (mode & I2S_MODE_TX) { + i2s_hal_tx_pcm_cfg(&(p_i2s_obj[i2s_num]->hal), pcm_cfg); + } else if(mode & I2S_MODE_RX) { + i2s_hal_rx_pcm_cfg(&(p_i2s_obj[i2s_num]->hal), pcm_cfg); + } + return ESP_OK; +} +#endif + +uint32_t i2s_get_clk(i2s_port_t i2s_num) { I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - i2s_hal_clear_intr_status(&(p_i2s_obj[i2s_num]->hal), clr_mask); - return ESP_OK; -} - -esp_err_t i2s_enable_rx_intr(i2s_port_t i2s_num) -{ - - I2S_ENTER_CRITICAL(); - i2s_hal_enable_rx_intr(&(p_i2s_obj[i2s_num]->hal)); - I2S_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t i2s_disable_rx_intr(i2s_port_t i2s_num) -{ - I2S_ENTER_CRITICAL(); - i2s_hal_disable_rx_intr(&(p_i2s_obj[i2s_num]->hal)); - I2S_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t i2s_disable_tx_intr(i2s_port_t i2s_num) -{ - I2S_ENTER_CRITICAL(); - i2s_hal_disable_tx_intr(&(p_i2s_obj[i2s_num]->hal)); - I2S_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num) -{ - I2S_ENTER_CRITICAL(); - i2s_hal_enable_tx_intr(&(p_i2s_obj[i2s_num]->hal)); - I2S_EXIT_CRITICAL(); - return ESP_OK; -} - -float i2s_get_clk(i2s_port_t i2s_num) -{ - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - return p_i2s_obj[i2s_num]->real_rate; + return p_i2s_obj[i2s_num]->sample_rate; } static esp_err_t i2s_isr_register(i2s_port_t i2s_num, int intr_alloc_flags, void (*fn)(void*), void * arg, i2s_isr_handle_t *handle) @@ -178,6 +167,7 @@ static esp_err_t i2s_isr_register(i2s_port_t i2s_num, int intr_alloc_flags, void return esp_intr_alloc(i2s_periph_signal[i2s_num].irq, intr_alloc_flags, fn, arg, handle); } +#if SOC_I2S_SUPPORTS_APLL static float i2s_apll_get_fi2s(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir) { int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000; @@ -298,34 +288,146 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm return ESP_OK; } +#endif -esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch) +static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, int data_bits, int ch) { - int factor = (256%bits)? 384 : 256; // According to hardware codec requirement(supported 256fs or 384fs) - int clkmInteger, clkmDecimals, bck = 0; - double denom = (double)1 / 64; - int channel = 2; + if (p_i2s_obj[i2s_num]->channel_num != ch) { + p_i2s_obj[i2s_num]->channel_num = (ch == 2) ? 2 : 1; + } + i2s_dma_t *save_tx = NULL, *save_rx = NULL; - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + if (data_bits != p_i2s_obj[i2s_num]->bits_per_sample) { + p_i2s_obj[i2s_num]->bits_per_sample = data_bits; - if (bits % 8 != 0 || bits > I2S_BITS_PER_SAMPLE_32BIT || bits < I2S_BITS_PER_SAMPLE_16BIT) { + // Round bytes_per_sample up to next multiple of 16 bits + int halfwords_per_sample = (data_bits + 15) / 16; + p_i2s_obj[i2s_num]->bytes_per_sample = halfwords_per_sample * 2; + + // Because limited of DMA buffer is 4092 bytes + if (p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num > 4092) { + p_i2s_obj[i2s_num]->dma_buf_len = 4092 / p_i2s_obj[i2s_num]->bytes_per_sample / p_i2s_obj[i2s_num]->channel_num; + } + + // Re-create TX DMA buffer + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + save_tx = p_i2s_obj[i2s_num]->tx; + p_i2s_obj[i2s_num]->tx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); + if (p_i2s_obj[i2s_num]->tx == NULL) { + ESP_LOGE(I2S_TAG, "Failed to create tx dma buffer"); + i2s_driver_uninstall(i2s_num); + return ESP_ERR_NO_MEM; + } + + //destroy old tx dma if exist + if (save_tx) { + i2s_destroy_dma_queue(i2s_num, save_tx); + } + } + + // Re-create RX DMA buffer + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + save_rx = p_i2s_obj[i2s_num]->rx; + p_i2s_obj[i2s_num]->rx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); + if (p_i2s_obj[i2s_num]->rx == NULL){ + ESP_LOGE(I2S_TAG, "Failed to create rx dma buffer"); + i2s_driver_uninstall(i2s_num); + return ESP_ERR_NO_MEM; + } + i2s_hal_set_rx_eof_num(&(p_i2s_obj[i2s_num]->hal), p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample); + //destroy old rx dma if exist + if (save_rx) { + i2s_destroy_dma_queue(i2s_num, save_rx); + } + } + } + return ESP_OK; +} + +static esp_err_t i2s_fbclk_cal(int i2s_num, uint32_t rate, int channel, int channel_bit, uint32_t *sclk, uint32_t *fbck, uint32_t *bck_div) +{ + //Default select I2S_D2CLK (160M) + uint32_t _sclk = I2S_BASE_CLK; + uint32_t _fbck = rate * channel * channel_bit; + uint32_t _bck_div = (256%channel_bit)? 12 : 8; + i2s_clock_src_t clk_src = I2S_CLK_D2CLK; + +//ADC mode only support on ESP32, +#if SOC_I2S_SUPPORTS_ADC_DAC + if ( p_i2s_obj[i2s_num]->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { + _fbck = rate * I2S_AD_BCK_FACTOR * 2; + _bck_div = I2S_AD_BCK_FACTOR; + } +#endif + +#if SOC_I2S_SUPPORTS_PDM + if ( p_i2s_obj[i2s_num]->mode & I2S_MODE_PDM) { +#if SOC_I2S_SUPPORTS_PDM_TX + if ( p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + int fp = 1; + int fs = 1; + i2s_hal_get_tx_pdm_fpfs(&(p_i2s_obj[i2s_num]->hal), &fp, &fs); + _fbck = rate * I2S_PDM_BCK_FACTOR * fp / fs; + } +#endif +#if SOC_I2S_SUPPORTS_PDM_RX + if ( p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + i2s_pdm_dsr_t dsr; + i2s_hal_get_rx_pdm_dsr(&(p_i2s_obj[i2s_num]->hal), &dsr); + _fbck = rate * I2S_PDM_BCK_FACTOR * (dsr == I2S_PDM_DSR_16S ? 2 : 1); + } +#endif + _bck_div = 8; + } +#endif + +#if SOC_I2S_SUPPORTS_APLL + int sdm0 = 0; + int sdm1 = 0; + int sdm2 = 0; + int odir = 0; + //If APLL is specified, try to calculate in APLL + if (p_i2s_obj[i2s_num]->use_apll && i2s_apll_calculate_fi2s(p_i2s_obj[i2s_num]->fixed_mclk, channel_bit, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) { + _sclk = p_i2s_obj[i2s_num]->fixed_mclk; + clk_src = I2S_CLK_APLL; + ESP_LOGD(I2S_TAG, "sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); + rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, odir); + } +#endif + if ((_fbck * _bck_div) > _sclk) { + ESP_LOGE(I2S_TAG, "sample rate is too large\r\n"); + return ESP_ERR_INVALID_ARG; + } + i2s_hal_set_clock_src(&(p_i2s_obj[i2s_num]->hal), clk_src); + *sclk = _sclk; + *fbck = _fbck; + *bck_div = _bck_div; + return ESP_OK; +} + +/* + 1. stop i2s; + 2. calculate mclk, bck, bck_factor + 3. malloc dma buffer; + 4. start i2s +*/ +esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_slot_bits_cfg_t slot_bit_cfg, i2s_slot_channel_cfg_t slot_ch_cfg) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_ARG); + + int data_bits = slot_bit_cfg & 0xffff; + int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT; + int active_slot_num = slot_ch_cfg & 0xffff; + int slot_num = (slot_ch_cfg >> SLOT_CH_SHIFT) == 0 ? ((active_slot_num == I2S_CHANNEL_MONO)) ? 2 : active_slot_num : (slot_ch_cfg >> SLOT_CH_SHIFT); + + if ((data_bits % 8 != 0) || (data_bits > I2S_BITS_PER_SAMPLE_32BIT)) { ESP_LOGE(I2S_TAG, "Invalid bits per sample"); return ESP_ERR_INVALID_ARG; } - - if (p_i2s_obj[i2s_num] == NULL) { - ESP_LOGE(I2S_TAG, "Not initialized yet"); - return ESP_ERR_INVALID_ARG; - } - p_i2s_obj[i2s_num]->sample_rate = rate; - double clkmdiv = (double)I2S_BASE_CLK / (rate * factor); - - if (clkmdiv > 256) { - ESP_LOGE(I2S_TAG, "clkmdiv is too large\r\n"); - return ESP_ERR_INVALID_ARG; - } - + //Stop I2S + i2s_stop(i2s_num); // wait all on-going writing finish if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) && p_i2s_obj[i2s_num]->tx) { xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); @@ -333,162 +435,41 @@ 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_RX) && p_i2s_obj[i2s_num]->rx) { xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); } - - i2s_stop(i2s_num); -#if SOC_I2S_SUPPORTS_ADC_DAC - /* I2S-ADC only support single channel format. */ - if (!(p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN)) { - i2s_hal_set_rx_mode(&(p_i2s_obj[i2s_num]->hal), ch, bits); - } -#else - i2s_hal_set_rx_mode(&(p_i2s_obj[i2s_num]->hal), ch, bits); -#endif - i2s_hal_set_tx_mode(&(p_i2s_obj[i2s_num]->hal), ch, bits); - - if (p_i2s_obj[i2s_num]->channel_num != (int)ch) { - p_i2s_obj[i2s_num]->channel_num = (ch == 2) ? 2 : 1; + //malloc DMA buffer + if (i2s_alloc_dma_buffer(i2s_num, data_bits, active_slot_num) != ESP_OK ) { + return ESP_ERR_NO_MEM; } - if ((int)bits != p_i2s_obj[i2s_num]->bits_per_sample) { - p_i2s_obj[i2s_num]->bits_per_sample = bits; - - // Round bytes_per_sample up to next multiple of 16 bits - int halfwords_per_sample = (bits + 15) / 16; - p_i2s_obj[i2s_num]->bytes_per_sample = halfwords_per_sample * 2; - - // Because limited of DMA buffer is 4092 bytes - if (p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num > 4092) { - p_i2s_obj[i2s_num]->dma_buf_len = 4092 / p_i2s_obj[i2s_num]->bytes_per_sample / p_i2s_obj[i2s_num]->channel_num; - } - // Re-create TX DMA buffer - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - - save_tx = p_i2s_obj[i2s_num]->tx; - - p_i2s_obj[i2s_num]->tx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); - if (p_i2s_obj[i2s_num]->tx == NULL) { - ESP_LOGE(I2S_TAG, "Failed to create tx dma buffer"); - i2s_driver_uninstall(i2s_num); - return ESP_ERR_NO_MEM; - } - i2s_hal_set_out_link_addr(&(p_i2s_obj[i2s_num]->hal), (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0]); - - //destroy old tx dma if exist - if (save_tx) { - i2s_destroy_dma_queue(i2s_num, save_tx); - } - } - // Re-create RX DMA buffer - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - - save_rx = p_i2s_obj[i2s_num]->rx; - - p_i2s_obj[i2s_num]->rx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); - if (p_i2s_obj[i2s_num]->rx == NULL){ - ESP_LOGE(I2S_TAG, "Failed to create rx dma buffer"); - i2s_driver_uninstall(i2s_num); - return ESP_ERR_NO_MEM; - } - i2s_hal_set_in_link(&(p_i2s_obj[i2s_num]->hal), p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample, (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0]); - //destroy old rx dma if exist - if (save_rx) { - i2s_destroy_dma_queue(i2s_num, save_rx); - } - } - - } - - double mclk; - int sdm0, sdm1, sdm2, odir, m_scale = 8; - int fi2s_clk = rate*channel*bits*m_scale; -#if SOC_I2S_SUPPORTS_ADC_DAC - 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 * I2S_AD_BCK_FACTOR; - fi2s_clk /= I2S_AD_BCK_FACTOR; - int factor2 = 60; - mclk = b_clk * factor2; - clkmdiv = ((double) I2S_BASE_CLK) / mclk; - clkmInteger = clkmdiv; - clkmDecimals = (clkmdiv - clkmInteger) / denom; - bck = mclk / b_clk; -#endif -#if SOC_I2S_SUPPORTS_PDM - } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_PDM) { - uint32_t b_clk = 0; - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - uint32_t fp, fs; - i2s_hal_get_tx_pdm(&(p_i2s_obj[i2s_num]->hal), &fp, &fs); - // Recommended set `fp = 960, fs = sample_rate / 100` - fs = rate / 100; - i2s_hal_tx_pdm_cfg(&(p_i2s_obj[i2s_num]->hal), fp, fs); - b_clk = rate * I2S_PDM_BCK_FACTOR * fp / fs; - - } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - uint32_t dsr; - i2s_hal_get_rx_pdm(&(p_i2s_obj[i2s_num]->hal), &dsr); - b_clk = rate * I2S_PDM_BCK_FACTOR * (dsr ? 2 : 1); - } - fi2s_clk = b_clk * m_scale; - int factor2 = 5 ; - mclk = b_clk * factor2; - clkmdiv = ((double) I2S_BASE_CLK) / mclk; - clkmInteger = clkmdiv; - clkmDecimals = (clkmdiv - clkmInteger) / denom; - bck = mclk / b_clk; - } else -#endif - { - clkmInteger = clkmdiv; - clkmDecimals = (clkmdiv - clkmInteger) / denom; - mclk = clkmInteger + denom * clkmDecimals; - bck = factor/(bits * channel); - } - - 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; - } - if(p_i2s_obj[i2s_num]->use_apll && i2s_apll_calculate_fi2s(fi2s_clk, bits, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) { - ESP_LOGD(I2S_TAG, "sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); - rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, odir); - i2s_hal_set_clk_div(&(p_i2s_obj[i2s_num]->hal), 1, 1, 0, m_scale, m_scale); - i2s_hal_set_clock_sel(&(p_i2s_obj[i2s_num]->hal), I2S_CLK_APLL); - double fi2s_rate = i2s_apll_get_fi2s(bits, sdm0, sdm1, sdm2, odir); - p_i2s_obj[i2s_num]->real_rate = fi2s_rate/bits/channel/m_scale; - ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK_M: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", - rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/8, 1, 0); - } else { - i2s_hal_set_clock_sel(&(p_i2s_obj[i2s_num]->hal), I2S_CLK_D2CLK); - i2s_hal_set_clk_div(&(p_i2s_obj[i2s_num]->hal), clkmInteger, 63, clkmDecimals, bck, bck); - double real_rate = (double) (I2S_BASE_CLK / (bck * bits * clkmInteger) / 2); - p_i2s_obj[i2s_num]->real_rate = real_rate; - ESP_LOGI(I2S_TAG, "PLL_D2: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", - rate, real_rate, bits, clkmInteger, bck, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 64, clkmDecimals); + uint32_t i2s_clk = 0; // I2S source clock + uint32_t i2s_bck = 0; // I2S back clock + uint32_t bck_div = 0; // I2S bck div + //calculate bck_div, f_bck and select source clock + if (i2s_fbclk_cal(i2s_num, rate, slot_num, slot_bits, &i2s_clk, &i2s_bck, &bck_div) != ESP_OK) { + return ESP_FAIL; } + //configure i2s clock if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - p_i2s_obj[i2s_num]->tx->curr_ptr = NULL; - p_i2s_obj[i2s_num]->tx->rw_pos = 0; + i2s_hal_tx_clock_config(&(p_i2s_obj[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); + i2s_hal_set_tx_sample_bit(&(p_i2s_obj[i2s_num]->hal), slot_bits, data_bits); + // wait all writing on-going finish + if (p_i2s_obj[i2s_num]->tx) { + xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux); + } } if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - p_i2s_obj[i2s_num]->rx->curr_ptr = NULL; - p_i2s_obj[i2s_num]->rx->rw_pos = 0; - } - - i2s_hal_set_tx_bits_mod(&(p_i2s_obj[i2s_num]->hal), bits); - i2s_hal_set_rx_bits_mod(&(p_i2s_obj[i2s_num]->hal), bits); - - // wait all writing on-going finish - if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) && p_i2s_obj[i2s_num]->tx) { - xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux); - } - if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && p_i2s_obj[i2s_num]->rx) { - xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux); + i2s_hal_rx_clock_config(&(p_i2s_obj[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); + i2s_hal_set_rx_sample_bit(&(p_i2s_obj[i2s_num]->hal), slot_bits, data_bits); + // wait all writing on-going finish + if (p_i2s_obj[i2s_num]->rx) { + xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux); + } } + i2s_slot_bits_cfg_t i2s_slot_bits_cfg = (slot_bits << SLOT_BIT_SHIFT) | data_bits; + i2s_slot_channel_cfg_t i2s_slot_channel_cfg = (slot_num << SLOT_CH_SHIFT) | active_slot_num; + i2s_hal_samples_config(&(p_i2s_obj[i2s_num]->hal), p_i2s_obj[i2s_num]->mode, p_i2s_obj[i2s_num]->communication_format, i2s_slot_bits_cfg, i2s_slot_channel_cfg); + //I2S start i2s_start(i2s_num); + p_i2s_obj[i2s_num]->sample_rate = rate; return ESP_OK; } @@ -504,11 +485,8 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) i2s_event_t i2s_event; int dummy; - portBASE_TYPE high_priority_task_awoken = 0; - - lldesc_t *finish_desc = NULL; - + uint32_t finish_desc = 0; if ((status & I2S_INTR_OUT_DSCR_ERR) || (status & I2S_INTR_IN_DSCR_ERR)) { ESP_EARLY_LOGE(I2S_TAG, "dma error, interrupt status: 0x%08x", status); if (p_i2s->i2s_queue) { @@ -521,7 +499,7 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) } if ((status & I2S_INTR_OUT_EOF) && p_i2s->tx) { - i2s_hal_get_out_eof_des_addr(&(p_i2s->hal), (uint32_t *)&finish_desc); + i2s_hal_get_out_eof_des_addr(&(p_i2s->hal), &finish_desc); // All buffers are empty. This means we have an underflow on our hands. if (xQueueIsQueueFullFromISR(p_i2s->tx->queue)) { xQueueReceiveFromISR(p_i2s->tx->queue, &dummy, &high_priority_task_awoken); @@ -532,7 +510,7 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) memset((void *) dummy, 0, p_i2s->tx->buf_size); } } - xQueueSendFromISR(p_i2s->tx->queue, (void*)(&finish_desc->buf), &high_priority_task_awoken); + xQueueSendFromISR(p_i2s->tx->queue, &(((lldesc_t *)finish_desc)->buf), &high_priority_task_awoken); if (p_i2s->i2s_queue) { i2s_event.type = I2S_EVENT_TX_DONE; if (xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) { @@ -544,11 +522,11 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) if ((status & I2S_INTR_IN_SUC_EOF) && p_i2s->rx) { // All buffers are full. This means we have an overflow. - i2s_hal_get_in_eof_des_addr(&(p_i2s->hal), (uint32_t *)&finish_desc); + i2s_hal_get_in_eof_des_addr(&(p_i2s->hal), &finish_desc); if (xQueueIsQueueFullFromISR(p_i2s->rx->queue)) { xQueueReceiveFromISR(p_i2s->rx->queue, &dummy, &high_priority_task_awoken); } - xQueueSendFromISR(p_i2s->rx->queue, (void*)(&finish_desc->buf), &high_priority_task_awoken); + xQueueSendFromISR(p_i2s->rx->queue, &(((lldesc_t *)finish_desc)->buf), &high_priority_task_awoken); if (p_i2s->i2s_queue) { i2s_event.type = I2S_EVENT_RX_DONE; if (p_i2s->i2s_queue && xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) { @@ -638,7 +616,6 @@ static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, in return NULL; } } - for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) { dma->desc[bux_idx]->owner = 1; dma->desc[bux_idx]->eof = 1; @@ -661,16 +638,27 @@ esp_err_t i2s_start(i2s_port_t i2s_num) I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); //start DMA link I2S_ENTER_CRITICAL(); - i2s_hal_reset(&(p_i2s_obj[i2s_num]->hal)); esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle); i2s_hal_clear_intr_status(&(p_i2s_obj[i2s_num]->hal), I2S_INTR_MAX); if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - i2s_enable_tx_intr(i2s_num); + p_i2s_obj[i2s_num]->tx->curr_ptr = NULL; + p_i2s_obj[i2s_num]->tx->rw_pos = 0; + //attach DMA + i2s_hal_attach_tx_dma(&(p_i2s_obj[i2s_num]->hal)); + i2s_tx_reset(i2s_num); + i2s_hal_enable_tx_intr(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_start_tx_link(&(p_i2s_obj[i2s_num]->hal), (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0]); i2s_hal_start_tx(&(p_i2s_obj[i2s_num]->hal)); } if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - i2s_enable_rx_intr(i2s_num); + p_i2s_obj[i2s_num]->rx->curr_ptr = NULL; + p_i2s_obj[i2s_num]->rx->rw_pos = 0; + //attach DMA + i2s_hal_attach_rx_dma(&(p_i2s_obj[i2s_num]->hal)); + i2s_rx_reset(i2s_num); + i2s_hal_enable_rx_intr(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_start_rx_link(&(p_i2s_obj[i2s_num]->hal), (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0]); i2s_hal_start_rx(&(p_i2s_obj[i2s_num]->hal)); } esp_intr_enable(p_i2s_obj[i2s_num]->i2s_isr_handle); @@ -684,12 +672,14 @@ esp_err_t i2s_stop(i2s_port_t i2s_num) I2S_ENTER_CRITICAL(); esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle); if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + i2s_hal_stop_tx_link(&(p_i2s_obj[i2s_num]->hal)); i2s_hal_stop_tx(&(p_i2s_obj[i2s_num]->hal)); - i2s_disable_tx_intr(i2s_num); + i2s_hal_disable_tx_intr(&(p_i2s_obj[i2s_num]->hal)); } if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + i2s_hal_stop_rx_link(&(p_i2s_obj[i2s_num]->hal)); i2s_hal_stop_rx(&(p_i2s_obj[i2s_num]->hal)); - i2s_disable_rx_intr(i2s_num); + i2s_hal_disable_rx_intr(&(p_i2s_obj[i2s_num]->hal)); } uint32_t mask; i2s_hal_get_intr_status(&(p_i2s_obj[i2s_num]->hal), &mask); @@ -735,6 +725,29 @@ esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel) _i2s_adc_channel = adc_channel; return adc_i2s_mode_init(adc_unit, adc_channel); } + +esp_err_t i2s_adc_enable(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); + I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); + + adc1_dma_mode_acquire(); + _i2s_adc_mode_recover(); + i2s_rx_reset(i2s_num); + 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); +} + +esp_err_t i2s_adc_disable(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); + I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); + + i2s_hal_stop_rx(&(p_i2s_obj[i2s_num]->hal)); + adc1_lock_release(); + return ESP_OK; +} #endif esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) @@ -747,7 +760,6 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) return ESP_ERR_INVALID_ARG; #endif } - if (pin->bck_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->bck_io_num)) { ESP_LOGE(I2S_TAG, "bck_io_num error"); return ESP_FAIL; @@ -764,55 +776,25 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) ESP_LOGE(I2S_TAG, "data_in_num error"); return ESP_FAIL; } - - int bck_sig = -1, ws_sig = -1, data_out_sig = -1, data_in_sig = -1; - //Each IIS hw module has a RX and TX unit. - //For TX unit, the output signal index should be I2SnO_xxx_OUT_IDX - //For TX unit, the input signal index should be I2SnO_xxx_IN_IDX - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { - bck_sig = i2s_periph_signal[i2s_num].o_bck_out_sig; - ws_sig = i2s_periph_signal[i2s_num].o_ws_out_sig; - data_out_sig = i2s_periph_signal[i2s_num].o_data_out_sig; - } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { - bck_sig = i2s_periph_signal[i2s_num].o_bck_in_sig; - ws_sig = i2s_periph_signal[i2s_num].o_ws_in_sig; - data_out_sig = i2s_periph_signal[i2s_num].o_data_out_sig; + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + gpio_matrix_in_check(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0); + gpio_matrix_in_check(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0); + } else { + gpio_matrix_in_check(pin->ws_io_num, i2s_periph_signal[i2s_num].rx_ws_sig, 0); + gpio_matrix_in_check(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0); + } + } else { + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + gpio_matrix_out_check(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0, 0); + gpio_matrix_out_check(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0, 0); + } else { + gpio_matrix_out_check(pin->ws_io_num, i2s_periph_signal[i2s_num].rx_ws_sig, 0, 0); + gpio_matrix_out_check(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0, 0); } } - //For RX unit, the output signal index should be I2SnI_xxx_OUT_IDX - //For RX unit, the input signal index shuld be I2SnI_xxx_IN_IDX - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { - bck_sig = i2s_periph_signal[i2s_num].i_bck_out_sig; - ws_sig = i2s_periph_signal[i2s_num].i_ws_out_sig; - data_in_sig = i2s_periph_signal[i2s_num].i_data_in_sig; - } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { - bck_sig = i2s_periph_signal[i2s_num].i_bck_in_sig; - ws_sig = i2s_periph_signal[i2s_num].i_ws_in_sig; - data_in_sig = i2s_periph_signal[i2s_num].i_data_in_sig; - } - } - //For "full-duplex + slave" mode, we should select RX signal index for ws and bck. - //For "full-duplex + master" mode, we should select TX signal index for ws and bck. - if ((p_i2s_obj[i2s_num]->mode & I2S_FULL_DUPLEX_SLAVE_MODE_MASK) == I2S_FULL_DUPLEX_SLAVE_MODE_MASK) { - bck_sig = i2s_periph_signal[i2s_num].i_bck_in_sig; - ws_sig = i2s_periph_signal[i2s_num].i_ws_in_sig; - } else if ((p_i2s_obj[i2s_num]->mode & I2S_FULL_DUPLEX_MASTER_MODE_MASK) == I2S_FULL_DUPLEX_MASTER_MODE_MASK) { - bck_sig = i2s_periph_signal[i2s_num].o_bck_out_sig; - ws_sig = i2s_periph_signal[i2s_num].o_ws_out_sig; - } - gpio_matrix_out_check(pin->data_out_num, data_out_sig, 0, 0); - gpio_matrix_in_check(pin->data_in_num, data_in_sig, 0); - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { - gpio_matrix_out_check(pin->ws_io_num, ws_sig, 0, 0); - gpio_matrix_out_check(pin->bck_io_num, bck_sig, 0, 0); - } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { - gpio_matrix_in_check(pin->ws_io_num, ws_sig, 0); - gpio_matrix_in_check(pin->bck_io_num, bck_sig, 0); - } - ESP_LOGD(I2S_TAG, "data: out %d, in: %d, ws: %d, bck: %d", data_out_sig, data_in_sig, ws_sig, bck_sig); - + gpio_matrix_out_check(pin->data_out_num, i2s_periph_signal[i2s_num].data_out_sig, 0, 0); + gpio_matrix_in_check(pin->data_in_num, i2s_periph_signal[i2s_num].data_in_sig, 0); return ESP_OK; } @@ -823,16 +805,26 @@ 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); } -#if SOC_I2S_SUPPORTS_PDM +#if SOC_I2S_SUPPORTS_PDM_RX 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_hal_rx_pdm_cfg(&(p_i2s_obj[i2s_num]->hal), dsr); + i2s_hal_set_rx_pdm_dsr(&(p_i2s_obj[i2s_num]->hal), 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); } #endif -static esp_err_t i2s_check_cfg_static(i2s_port_t i2s_num, const i2s_config_t *cfg) +#if SOC_I2S_SUPPORTS_PDM_TX +esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, int sample_rate, int fp, int fs) +{ + I2S_ENTER_CRITICAL(); + i2s_hal_set_tx_pdm_fpfs(&(p_i2s_obj[i2s_num]->hal), fp, fs); + I2S_EXIT_CRITICAL(); + return i2s_set_clk(i2s_num, sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); +} +#endif + +static esp_err_t i2s_check_cfg_static(i2s_port_t i2s_num, const i2s_config_param_t *cfg) { #if SOC_I2S_SUPPORTS_ADC_DAC //We only check if the I2S number is invalid when set to build in ADC and DAC mode. @@ -851,7 +843,7 @@ static esp_err_t i2s_check_cfg_static(i2s_port_t i2s_num, const i2s_config_t *cf return ESP_OK; } -static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_config) +static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_param_t *i2s_config) { I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); I2S_CHECK((i2s_config), "param null", ESP_ERR_INVALID_ARG); @@ -866,20 +858,17 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co adc_power_acquire(); } #endif + p_i2s_obj[i2s_num]->communication_format = i2s_config->communication_format; // configure I2S data port interface. i2s_hal_config_param(&(p_i2s_obj[i2s_num]->hal), i2s_config); if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX)) { i2s_hal_enable_sig_loopback(&(p_i2s_obj[i2s_num]->hal)); if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { - i2s_hal_enable_master_mode(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_enable_master_fd_mode(&(p_i2s_obj[i2s_num]->hal)); } else { - i2s_hal_enable_slave_mode(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_enable_slave_fd_mode(&(p_i2s_obj[i2s_num]->hal)); } } - - p_i2s_obj[i2s_num]->use_apll = i2s_config->use_apll; - p_i2s_obj[i2s_num]->tx_desc_auto_clear = i2s_config->tx_desc_auto_clear; - p_i2s_obj[i2s_num]->fixed_mclk = i2s_config->fixed_mclk; return ESP_OK; } @@ -925,19 +914,23 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, i2s_spinlock[x] = i2s_spinlock_unlocked[0]; } //To make sure hardware is enabled before any hardware register operations. +#if SOC_GDMA_SUPPORTED + periph_module_enable(PERIPH_GDMA_MODULE); +#endif periph_module_enable(i2s_periph_signal[i2s_num].module); + i2s_hal_init(&(p_i2s_obj[i2s_num]->hal), i2s_num); p_i2s_obj[i2s_num]->i2s_num = i2s_num; - p_i2s_obj[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; - p_i2s_obj[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; - p_i2s_obj[i2s_num]->i2s_queue = i2s_queue; - p_i2s_obj[i2s_num]->mode = i2s_config->mode; + p_i2s_obj[i2s_num]->mode = i2s_config->param_cfg.mode; + p_i2s_obj[i2s_num]->channel_num = i2s_config->param_cfg.channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1; + + p_i2s_obj[i2s_num]->i2s_queue = i2s_queue; p_i2s_obj[i2s_num]->bits_per_sample = 0; p_i2s_obj[i2s_num]->bytes_per_sample = 0; // Not initialized yet - p_i2s_obj[i2s_num]->channel_num = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1; - + p_i2s_obj[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; + p_i2s_obj[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; #ifdef CONFIG_PM_ENABLE if (i2s_config->use_apll) { err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i2s_driver", &p_i2s_obj[i2s_num]->pm_lock); @@ -966,13 +959,15 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, return err; } i2s_stop(i2s_num); - err = i2s_param_config(i2s_num, i2s_config); + p_i2s_obj[i2s_num]->use_apll = i2s_config->use_apll; + p_i2s_obj[i2s_num]->fixed_mclk = i2s_config->fixed_mclk; + p_i2s_obj[i2s_num]->tx_desc_auto_clear = i2s_config->tx_desc_auto_clear; + err = i2s_param_config(i2s_num, &(i2s_config->param_cfg)); if (err != ESP_OK) { i2s_driver_uninstall(i2s_num); ESP_LOGE(I2S_TAG, "I2S param configure error"); return err; } - if (i2s_queue) { p_i2s_obj[i2s_num]->i2s_queue = xQueueCreate(queue_size, sizeof(i2s_event_t)); *((QueueHandle_t*) i2s_queue) = p_i2s_obj[i2s_num]->i2s_queue; @@ -980,8 +975,13 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, } else { p_i2s_obj[i2s_num]->i2s_queue = NULL; } + i2s_slot_bits_cfg_t slot_bits_cfg = i2s_config->param_cfg.slot_bits_cfg; + i2s_slot_channel_cfg_t slot_channel_cfg = p_i2s_obj[i2s_num]->channel_num; +#if SOC_I2S_SUPPORTS_TDM + slot_channel_cfg = i2s_config->param_cfg.slot_channel_cfg; +#endif //set clock and start - return i2s_set_clk(i2s_num, i2s_config->sample_rate, i2s_config->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); + return i2s_set_clk(i2s_num, i2s_config->sample_rate, slot_bits_cfg, slot_channel_cfg); } ESP_LOGW(I2S_TAG, "I2S driver already installed"); @@ -1012,11 +1012,14 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) p_i2s_obj[i2s_num]->i2s_queue = NULL; } +#if SOC_I2S_SUPPORTS_APLL if(p_i2s_obj[i2s_num]->use_apll) { // switch back to PLL clock source i2s_hal_set_clock_sel(&(p_i2s_obj[i2s_num]->hal), I2S_CLK_D2CLK); rtc_clk_apll_enable(0, 0, 0, 0, 0); } +#endif + #ifdef CONFIG_PM_ENABLE if (p_i2s_obj[i2s_num]->pm_lock) { esp_pm_lock_delete(p_i2s_obj[i2s_num]->pm_lock); @@ -1026,7 +1029,6 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) free(p_i2s_obj[i2s_num]); p_i2s_obj[i2s_num] = NULL; periph_module_disable(i2s_periph_signal[i2s_num].module); - return ESP_OK; } @@ -1036,7 +1038,7 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by size_t bytes_can_write; *bytes_written = 0; I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((size < SOC_I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); + I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_ERR_INVALID_ARG); xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); #ifdef CONFIG_PM_ENABLE @@ -1071,32 +1073,6 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by return ESP_OK; } -#if SOC_I2S_SUPPORTS_ADC_DAC -esp_err_t i2s_adc_enable(i2s_port_t i2s_num) -{ - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); - I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); - - adc1_dma_mode_acquire(); - _i2s_adc_mode_recover(); - i2s_hal_start_rx(&(p_i2s_obj[i2s_num]->hal)); - i2s_hal_reset(&(p_i2s_obj[i2s_num]->hal)); - 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); -} - -esp_err_t i2s_adc_disable(i2s_port_t i2s_num) -{ - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); - I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); - - i2s_hal_stop_rx(&(p_i2s_obj[i2s_num]->hal)); - adc1_lock_release(); - return ESP_OK; -} -#endif - esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, size_t src_bits, size_t aim_bits, size_t *bytes_written, TickType_t ticks_to_wait) { char *data_ptr; @@ -1105,7 +1081,7 @@ esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, siz *bytes_written = 0; I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); I2S_CHECK((size > 0), "size must greater than zero", ESP_ERR_INVALID_ARG); - I2S_CHECK((aim_bits * size < SOC_I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); + I2S_CHECK((aim_bits * size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); I2S_CHECK((aim_bits >= src_bits), "aim_bits mustn't be less than src_bits", ESP_ERR_INVALID_ARG); I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_ERR_INVALID_ARG); if (src_bits < I2S_BITS_PER_SAMPLE_8BIT || aim_bits < I2S_BITS_PER_SAMPLE_8BIT) { @@ -1167,7 +1143,7 @@ esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_re *bytes_read = 0; dest_byte = (char *)dest; I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((size < SOC_I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); + I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); I2S_CHECK((p_i2s_obj[i2s_num]->rx), "rx NULL", ESP_ERR_INVALID_ARG); xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); #ifdef CONFIG_PM_ENABLE diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index 4ee73b594d..0c5b1c288d 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -28,8 +28,53 @@ extern "C" { #define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */ + +/** + * @brief I2S driver configuration parameters + * + */ +typedef struct { + union { + // Compatible with previous versions. For ESP32-S3, ESP32-C3 and the later chip, you should use `param_cfg` fields to initialize I2S. + struct { + i2s_mode_t mode; /*!< I2S work mode*/ + uint32_t sample_rate; /*!< I2S sample rate*/ + uint32_t bits_per_sample; /*!< I2S bits per sample*/ + i2s_channel_fmt_t channel_format; /*!< I2S channel format */ + i2s_comm_format_t communication_format; /*!< I2S communication format */ + }; + i2s_config_param_t param_cfg; /*!< I2S config paramater */ + }; + int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */ + int dma_buf_count; /*!< I2S DMA Buffer Count */ + int dma_buf_len; /*!< I2S DMA Buffer Length */ + bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */ + bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */ + int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/ +} i2s_driver_config_t; + +typedef i2s_driver_config_t i2s_config_t; typedef intr_handle_t i2s_isr_handle_t; +/** + * @brief I2S event types + * + */ +typedef enum { + I2S_EVENT_DMA_ERROR, + I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/ + I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/ + I2S_EVENT_MAX, /*!< I2S event max index*/ +} i2s_event_type_t; +/** + * @brief Event structure used in I2S event queue + * + */ +typedef struct { + i2s_event_type_t type; /*!< I2S event type */ + size_t size; /*!< I2S data size for I2S_DATA event*/ +} i2s_event_t; + /** * @brief Set I2S pin number * @@ -54,7 +99,7 @@ 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); -#if SOC_I2S_SUPPORTS_PDM +#if SOC_I2S_SUPPORTS_PDM_RX /** * @brief Set PDM mode down-sample rate * In PDM RX mode, there would be 2 rounds of downsample process in hardware. @@ -75,6 +120,30 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin); esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr); #endif +#if SOC_I2S_SUPPORTS_PDM_TX +/** + * @brief Set TX PDM mode up-sample rate + * TX PDM have two type upsampling rate configurations: + * 1: fp = 960, fs = sample_rate / 100, in this case, Fpdm = 128*48000 + * 2: fp = 960, fs = 480, in this case, Fpdm = 128*Fpcm = 128*sample_rate + * If the pdm receiver do not care the pdm serial clock, it's recommended set Fpdm = 128*48000 + * + * @param i2s_num I2S_NUM_0 + * @param sample_rate The sample rate to be set + * @param fp PDM TX upsampling configuration paramater + * @param fs PDM TX upsampling configuration paramater + * + * @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_tx_up_sample(i2s_port_t i2s_num, int sample_rate, int fp, int fs); +#endif + /** * @brief Install and start I2S driver. * @@ -243,6 +312,23 @@ esp_err_t i2s_start(i2s_port_t i2s_num); */ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num); +#if SOC_I2S_SUPPORTS_PCM +/** + * @brief Configure I2S a/u-law decompress or compress + * + * @param i2s_num I2S_NUM_0 + * + * @param mode I2S mode. I2S_MODE_TX, I2S_MODE_RX + * + * @param pcm_cfg a/u-law decompress or compress configuration paramater + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t i2s_pcm_config(i2s_port_t i2s_num, int mode, i2s_pcm_cfg_t pcm_cfg); +#endif + /** * @brief Set clock & bit width used for I2S RX and TX. * @@ -252,16 +338,16 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num); * * @param rate I2S sample rate (ex: 8000, 44100...) * - * @param bits I2S bit width (I2S_BITS_PER_SAMPLE_16BIT, I2S_BITS_PER_SAMPLE_24BIT, I2S_BITS_PER_SAMPLE_32BIT) + * @param slot_bits i2s slot bit configuration * - * @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO) + * @param sloct_ch I2S slot number configuration * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_NO_MEM Out of memory */ -esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch); +esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_slot_bits_cfg_t slot_bits, i2s_slot_channel_cfg_t sloct_ch); /** * @brief get clock set on particular port number. @@ -271,7 +357,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b * @return * - actual clock set by i2s driver */ -float i2s_get_clk(i2s_port_t i2s_num); +uint32_t i2s_get_clk(i2s_port_t i2s_num); #if SOC_I2S_SUPPORTS_ADC_DAC /** diff --git a/components/driver/test/adc_dma_test/test_esp32.c b/components/driver/test/adc_dma_test/test_esp32.c index 104f88375a..36375596a0 100644 --- a/components/driver/test/adc_dma_test/test_esp32.c +++ b/components/driver/test/adc_dma_test/test_esp32.c @@ -54,10 +54,12 @@ static void example_i2s_init(void) { int i2s_num = EXAMPLE_I2S_NUM; i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, - .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, - .bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS, - .channel_format = EXAMPLE_I2S_FORMAT, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, + .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, + .slot_bits_cfg = EXAMPLE_I2S_SAMPLE_BITS, + .channel_format = EXAMPLE_I2S_FORMAT, + }, .intr_alloc_flags = 0, .dma_buf_count = 2, .dma_buf_len = 1024, diff --git a/components/driver/test/dac_dma_test/test_esp32.c b/components/driver/test/dac_dma_test/test_esp32.c index eba5dfd565..c69843e81c 100644 --- a/components/driver/test/dac_dma_test/test_esp32.c +++ b/components/driver/test/dac_dma_test/test_esp32.c @@ -56,10 +56,12 @@ static void example_i2s_init(void) { int i2s_num = EXAMPLE_I2S_NUM; i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, - .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, - .bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS, - .channel_format = EXAMPLE_I2S_FORMAT, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, + .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, + .slot_bits_cfg = EXAMPLE_I2S_SAMPLE_BITS, + .channel_format = EXAMPLE_I2S_FORMAT, + }, .intr_alloc_flags = 0, .dma_buf_count = 2, .dma_buf_len = 1024, diff --git a/components/driver/test/test_i2s.c b/components/driver/test/test_i2s.c index 41e29cf2dc..025ba78270 100644 --- a/components/driver/test/test_i2s.c +++ b/components/driver/test/test_i2s.c @@ -107,11 +107,20 @@ TEST_CASE("I2S basic driver install, uninstall, set pin test", "[i2s]") { // dac, adc i2s i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 60, .use_apll = 0, @@ -152,11 +161,20 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]") { // master driver installed and send data i2s_config_t master_i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, @@ -218,10 +236,19 @@ TEST_CASE("I2S adc test", "[i2s]") { // init I2S ADC i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .intr_alloc_flags = 0, .dma_buf_count = 2, .dma_buf_len = 1024, @@ -272,11 +299,20 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") { // master driver installed and send data i2s_config_t master_i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, @@ -294,11 +330,20 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") printf("\r\nheap size: %d\n", esp_get_free_heap_size()); i2s_config_t slave_i2s_config = { - .mode = I2S_MODE_SLAVE | I2S_MODE_RX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_SLAVE | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, @@ -357,11 +402,20 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") { // master driver installed and send data i2s_config_t master_i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 1, @@ -379,11 +433,20 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") printf("\r\nheap size: %d\n", esp_get_free_heap_size()); i2s_config_t slave_i2s_config = { - .mode = I2S_MODE_SLAVE | I2S_MODE_TX, // Only RX - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_SLAVE | I2S_MODE_TX, // Only RX + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 1, @@ -442,11 +505,20 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") TEST_CASE("I2S memory leaking test", "[i2s]") { i2s_config_t master_i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, @@ -489,11 +561,20 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]") }; i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 60, .use_apll = true, @@ -510,8 +591,8 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]") for (int i = 0; i < (sizeof(sample_rate_arr)/sizeof(sample_rate_arr[0])); i++) { for (int j = 0; j < (sizeof(bits_per_sample_arr)/sizeof(bits_per_sample_arr[0])); j++) { - i2s_config.sample_rate = sample_rate_arr[i]; - i2s_config.bits_per_sample = bits_per_sample_arr[j]; + i2s_config.param_cfg.sample_rate = sample_rate_arr[i]; + i2s_config.param_cfg.slot_bits_cfg = bits_per_sample_arr[j]; TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config)); diff --git a/components/efuse/esp32c3/private_include/esp_efuse_utility.h b/components/efuse/esp32c3/private_include/esp_efuse_utility.h index 37573eea8f..d2256ab312 100644 --- a/components/efuse/esp32c3/private_include/esp_efuse_utility.h +++ b/components/efuse/esp32c3/private_include/esp_efuse_utility.h @@ -16,6 +16,16 @@ extern "C" { #define ESP_EFUSE_FIELD_CORRESPONDS_CODING_SCHEME(scheme, max_num_bit) +/*-------------------------- I2S CAPS ----------------------------------------*/ +#define SOC_I2S_NUM (1) +#define SOC_I2S_SUPPORTS_PCM (1) +#define SOC_I2S_SUPPORTS_PDM_TX (1) +#define SOC_I2S_SUPPORTS_PDM_RX (0) +#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) +#define SOC_I2S_SUPPORTS_TDM (1) +#define SOC_GDMA_I2S0_DMA_CHANNEL (0) + #ifdef __cplusplus } #endif + diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index 96d4a3f8ec..981a441705 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -1,4 +1,4 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,9 +23,6 @@ #pragma once #include -#include "soc/rtc_periph.h" -#include "soc/rtc.h" -#include "soc/efuse_periph.h" #include "soc/i2s_periph.h" #include "hal/i2s_types.h" @@ -42,19 +39,148 @@ extern "C" { #define I2S_INTR_OUT_DSCR_ERR BIT(14) #define I2S_INTR_MAX (0xFFFFFFFF) + +/* I2S clock configuration structure */ +typedef struct { + uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a) + uint16_t a; + uint16_t b; // The decimal part of module clock devider, the decimal is: b/a + uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div +} i2s_clk_cal_t; + /** - * @brief Reset rx fifo + * @brief Calculate the closest sample rate clock configuration. + * clock relationship: + * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) * - * @param hw Peripheral I2S hardware instance address. + * @param fsclk I2S source clock freq. + * @param fbck BCK freuency. + * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. + * @param cal Point to `i2s_clk_cal_t` structure. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal) { - hw->conf.rx_fifo_reset = 1; - hw->conf.rx_fifo_reset = 0; + int ma = 0; + int mb = 0; + uint32_t mclk = fbck*bck_div; + cal->mclk_div = fsclk / mclk; + cal->bck_div = bck_div; + cal->a = 1; + cal->b = 0; + uint32_t freq_diff = fsclk - mclk * cal->mclk_div; + uint32_t min = ~0; + if (freq_diff == 0) { + return; + } + for (int a = 2; a <= 63; a++) { + for (int b = 1; b < a; b++) { + ma = freq_diff*a; + mb = mclk*b; + if (ma == mb) { + cal->a = a; + cal->b = b; + return; + } + if (abs((mb - ma)) < min) { + cal->a = a; + cal->b = b; + min = abs(mb - ma); + } + } + } } /** - * @brief Reset tx fifo + * @brief I2S module general init, enable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_general_init(i2s_dev_t *hw) +{ + if (hw->clkm_conf.clk_en == 0) { + hw->clkm_conf.clk_en = 1; + hw->conf2.val = 0; + } +} + +/** + * @brief I2S TX module general init. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw) +{ + hw->conf.tx_start = 0; + hw->conf.tx_reset = 1; + hw->conf.tx_reset = 0; + hw->conf.tx_msb_right = 0; + hw->conf.tx_right_first = 0; + hw->conf.tx_slave_mod = 0; + hw->fifo_conf.tx_fifo_mod_force_en = 1; +} + +/** + * @brief I2S RX module general init. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw) +{ + hw->conf.rx_start = 0; + hw->conf.rx_reset = 1; + hw->conf.rx_reset = 0; + hw->conf.rx_msb_right = 0; + hw->conf.rx_right_first = 0; + hw->conf.rx_slave_mod = 0; + hw->fifo_conf.rx_fifo_mod_force_en = 1; +} + +/** + * @brief Enable I2S TX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->conf.tx_slave_mod = slave_en; +} + +/** + * @brief Enable I2S RX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->conf.rx_slave_mod = slave_en; +} + +/** + * @brief Reset I2S TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +{ + hw->conf.tx_reset = 1; + hw->conf.tx_reset = 0; +} + +/** + * @brief Reset I2S RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_rx(i2s_dev_t *hw) +{ + hw->conf.rx_reset = 1; + hw->conf.rx_reset = 0; +} + +/** + * @brief Reset I2S TX FIFO * * @param hw Peripheral I2S hardware instance address. */ @@ -65,40 +191,72 @@ static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) } /** - * @brief Enable rx interrupt + * @brief Reset I2S RX FIFO * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) { - hw->int_ena.in_suc_eof = 1; - hw->int_ena.in_dscr_err = 1; + hw->conf.rx_fifo_reset = 1; + hw->conf.rx_fifo_reset = 0; } /** - * @brief Disable rx interrupt + * @brief Set TX source clock * * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock */ -static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { - hw->int_ena.in_suc_eof = 0; - hw->int_ena.in_dscr_err = 0; + //0: disable APLL clock, I2S module will using PLL_D2_CLK(160M) as source clock + //1: Enable APLL clock, I2S module will using APLL as source clock + hw->clkm_conf.clka_en = (src == 1) ? 1 : 0; } /** - * @brief Disable tx interrupt + * @brief Set RX source clock * * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock */ -static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { - hw->int_ena.out_eof = 0; - hw->int_ena.out_dscr_err = 0; + //0: disable APLL clock, I2S module will using PLL_D2_CLK(160M) as source clock + //1: Enable APLL clock, I2S module will using APLL as source clock + hw->clkm_conf.clka_en = (src == 1) ? 1 : 0; } /** - * @brief Enable tx interrupt + * @brief Configure I2S TX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +{ + hw->clkm_conf.clkm_div_num = set->mclk_div; + hw->clkm_conf.clkm_div_b = set->b; + hw->clkm_conf.clkm_div_a = set->a; + hw->sample_rate_conf.tx_bck_div_num = set->bck_div; +} + +/** + * @brief Configure I2S RX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +{ + hw->clkm_conf.clkm_div_num = set->mclk_div; + hw->clkm_conf.clkm_div_b = set->b; + hw->clkm_conf.clkm_div_a = set->a; + hw->sample_rate_conf.rx_bck_div_num = set->bck_div; +} + +/** + * @brief Enable TX interrupt * * @param hw Peripheral I2S hardware instance address. */ @@ -109,14 +267,58 @@ static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) } /** - * @brief Reset dma in + * @brief Disable TX interrupt * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) +static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) { - hw->lc_conf.in_rst = 1; - hw->lc_conf.in_rst = 0; + hw->int_ena.out_eof = 0; + hw->int_ena.out_dscr_err = 0; +} + +/** + * @brief Enable RX interrupt + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +{ + hw->int_ena.in_suc_eof = 1; + hw->int_ena.in_dscr_err = 1; +} + +/** + * @brief Disable RX interrupt + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +{ + hw->int_ena.in_suc_eof = 0; + hw->int_ena.in_dscr_err = 0; +} + +/** + * @brief Get I2S interrupt status + * + * @param hw Peripheral I2S hardware instance address. + * @param int_stat Pointer to module interrupt status + */ +static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *int_stat) +{ + *int_stat = hw->int_st.val; +} + +/** + * @brief Clear I2S interrupt status + * + * @param hw Peripheral I2S hardware instance address. + * @param clr_mask Interrupt mask to clear interrupt status + */ +static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t clr_mask) +{ + hw->int_clr.val = clr_mask; } /** @@ -131,39 +333,18 @@ static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) } /** - * @brief Reset tx + * @brief Reset dma in * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) { - hw->conf.tx_reset = 1; - hw->conf.tx_reset = 0; + hw->lc_conf.in_rst = 1; + hw->lc_conf.in_rst = 0; } /** - * @brief Reset rx - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_rx(i2s_dev_t *hw) -{ - hw->conf.rx_reset = 1; - hw->conf.rx_reset = 0; -} - -/** - * @brief Start out link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_out_link(i2s_dev_t *hw) -{ - hw->out_link.start = 1; -} - -/** - * @brief Start tx + * @brief Start TX module * * @param hw Peripheral I2S hardware instance address. */ @@ -173,17 +354,7 @@ static inline void i2s_ll_start_tx(i2s_dev_t *hw) } /** - * @brief Start in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_in_link(i2s_dev_t *hw) -{ - hw->in_link.start = 1; -} - -/** - * @brief Start rx + * @brief Start RX module * * @param hw Peripheral I2S hardware instance address. */ @@ -192,6 +363,50 @@ static inline void i2s_ll_start_rx(i2s_dev_t *hw) hw->conf.rx_start = 1; } +/** + * @brief Configure TX DMA descriptor address and start TX DMA + * + * @param hw Peripheral I2S hardware instance address. + * @param link_addr DMA descriptor link address. + */ +static inline void i2s_ll_start_tx_link(i2s_dev_t *hw, uint32_t link_addr) +{ + hw->out_link.addr = link_addr; + hw->out_link.start = 1; +} + +/** + * @brief Configure RX DMA descriptor address and start RX DMA + * + * @param hw Peripheral I2S hardware instance address. + * @param link_addr DMA descriptor link address. + */ +static inline void i2s_ll_start_rx_link(i2s_dev_t *hw, uint32_t link_addr) +{ + hw->in_link.addr = link_addr; + hw->in_link.start = 1; +} + +/** + * @brief Stop TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_stop_tx(i2s_dev_t *hw) +{ + hw->conf.tx_start = 0; +} + +/** + * @brief Stop RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +{ + hw->conf.rx_start = 0; +} + /** * @brief Stop out link * @@ -202,16 +417,6 @@ static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) hw->out_link.stop = 1; } -/** - * @brief Stop tx - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_tx(i2s_dev_t *hw) -{ - hw->conf.tx_start = 0; -} - /** * @brief Stop in link * @@ -223,435 +428,78 @@ static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) } /** - * @brief Stop rx + * @brief Get I2S out eof descriptor address * * @param hw Peripheral I2S hardware instance address. + * @param eof_addr Pointer to accept out eof des address */ -static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) { - hw->conf.rx_start = 0; + *eof_addr = hw->out_eof_des_addr; } /** - * @brief Enable dma + * @brief Get I2S in eof descriptor address * * @param hw Peripheral I2S hardware instance address. + * @param eof_addr Pointer to accept in eof des address */ -static inline void i2s_ll_enable_dma(i2s_dev_t *hw) +static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) { - //Enable and configure DMA - typeof(hw->lc_conf) lc_conf; - lc_conf.val = 0; - lc_conf.out_eof_mode = 1; - hw->lc_conf.val = lc_conf.val; + *eof_addr = hw->in_eof_des_addr; } /** - * @brief Get I2S interrupt status + * @brief Configure the received length to trigger in_suc_eof interrupt * * @param hw Peripheral I2S hardware instance address. - * @param val value to get interrupt status + * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->int_st.val; -} - -/** - * @brief Clear I2S interrupt status - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to clear interrupt status - */ -static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val) -{ - hw->int_clr.val = val; -} - -/** - * @brief Get I2S out eof des address - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get out eof des address - */ -static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->out_eof_des_addr; -} - -/** - * @brief Get I2S in eof des address - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get in eof des address - */ -static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->in_eof_des_addr; -} - -/** - * @brief Get I2S tx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx fifo mode - */ -static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->fifo_conf.tx_fifo_mod; -} - -/** - * @brief Set I2S tx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mode - */ -static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->fifo_conf.tx_fifo_mod = val; -} - -/** - * @brief Get I2S rx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx fifo mode - */ -static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->fifo_conf.rx_fifo_mod; -} - -/** - * @brief Set I2S rx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mode - */ -static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->fifo_conf.rx_fifo_mod = val; -} - -/** - * @brief Set I2S tx chan mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx chan mode - */ -static inline void i2s_ll_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf_chan.tx_chan_mod = val; -} - -/** - * @brief Set I2S rx chan mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx chan mode - */ -static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf_chan.rx_chan_mod = val; -} - -/** - * @brief Set I2S out link address - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set out link address - */ -static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val) -{ - hw->out_link.addr = val; -} - -/** - * @brief Set I2S in link address - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set in link address - */ -static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val) -{ - hw->in_link.addr = val; -} - -/** - * @brief Set I2S rx eof num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx eof num - */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) { // On ESP32, the eof_num count in words. - hw->rx_eof_num = val / 4; + hw->rx_eof_num = eof_num / 4; } /** - * @brief Set I2S clkm div num + * @brief Congfigure TX slot bit and audio data bit, on ESP32, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div num + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - hw->clkm_conf.clkm_div_num = val; + hw->fifo_conf.tx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); + hw->sample_rate_conf.tx_bits_mod = data_bit; } /** - * @brief Set I2S clkm div b + * @brief Congfigure RX slot bit and audio data bit, on ESP32, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div b + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - hw->clkm_conf.clkm_div_b = val; + hw->fifo_conf.rx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); + hw->sample_rate_conf.rx_bits_mod = data_bit; } /** - * @brief Set I2S clkm div a + * @brief Enable I2S DMA * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div a + * @param ena Set true to enable DMA */ -static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_dma_enable(i2s_dev_t *hw, bool ena) { - hw->clkm_conf.clkm_div_a = val; -} - -/** - * @brief Set I2S tx bck div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bck div num - */ -static inline void i2s_ll_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.tx_bck_div_num = val; -} - -/** - * @brief Set I2S rx bck div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bck div num - */ -static inline void i2s_ll_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.rx_bck_div_num = val; -} - -/** - * @brief Set I2S clk sel - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clk sel - */ -static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val) -{ - hw->clkm_conf.clka_en = (val == 1) ? 1 : 0; -} - -/** - * @brief Set I2S tx bits mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bits mod - */ -static inline void i2s_ll_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.tx_bits_mod = val; -} - -/** - * @brief Set I2S rx bits mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bits mod - */ -static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.rx_bits_mod = val; -} - -/** - * @brief Set I2S dscr en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set dscr en - */ -static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val) -{ - hw->fifo_conf.dscr_en = val; -} - -/** - * @brief Set I2S lcd en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set lcd en - */ -static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val) -{ - hw->conf2.lcd_en = val; -} - -/** - * @brief Set I2S camera en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set camera en - */ -static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val) -{ - hw->conf2.camera_en = val; -} - -/** - * @brief Set I2S tx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mod force en - */ -static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - hw->fifo_conf.tx_fifo_mod_force_en = val; -} - -/** - * @brief Set I2S rx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mod force en - */ -static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - hw->fifo_conf.rx_fifo_mod_force_en = val; -} - -/** - * @brief Set I2S tx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx right first - */ -static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_right_first = val; -} - -/** - * @brief Set I2S rx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx right first - */ -static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_right_first = val; -} - -/** - * @brief Set I2S tx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx slave mod - */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_slave_mod = val; -} - -/** - * @brief Set I2S rx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx slave mod - */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_slave_mod = val; -} - -/** - * @brief Get I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx msb right - */ -static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->conf.tx_msb_right; -} - -/** - * @brief Get I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx msb right - */ -static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->conf.rx_msb_right; -} - -/** - * @brief Set I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx msb right - */ -static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_msb_right = val; -} - -/** - * @brief Set I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx msb right - */ -static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_msb_right = val; -} - -/** - * @brief Set I2S tx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx mono - */ -static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_mono = val; -} - -/** - * @brief Set I2S rx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx mono - */ -static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_mono = val; -} - -/** - * @brief Set I2S sig loopback - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set sig loopback - */ -static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.sig_loopback = val; + if (ena && !hw->fifo_conf.dscr_en) { + hw->fifo_conf.dscr_en = 1; + } else if (!ena && hw->fifo_conf.dscr_en) { + hw->fifo_conf.dscr_en = 0; + } } /** @@ -742,6 +590,159 @@ static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) hw->conf.rx_msb_shift = 0; } +/** + * @brief Enable TX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_tx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) +{ + int data_bit = hw->sample_rate_conf.tx_bits_mod; + if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) { + hw->fifo_conf.tx_fifo_mod = 0 + mono_ena; + } else { + hw->fifo_conf.tx_fifo_mod = 2 + mono_ena; + } + hw->conf_chan.tx_chan_mod = mono_ena; +} + +/** + * @brief Enable RX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_rx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) +{ + int data_bit = hw->sample_rate_conf.rx_bits_mod; + if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) { + hw->fifo_conf.rx_fifo_mod = 0 + mono_ena; + } else { + hw->fifo_conf.rx_fifo_mod = 2 + mono_ena; + } + hw->conf_chan.rx_chan_mod = mono_ena; +} + +/** + * @brief Enable I2S loopback mode + * + * @param hw Peripheral I2S hardware instance address. + * @param loopback_en Set true to enable loopback mode. + */ +static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool loopback_en) +{ + hw->conf.sig_loopback = loopback_en; +} + +/** + * @brief Set default RX PDM mode + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw) +{ + hw->pdm_conf.rx_sinc_dsr_16_en = 0; + hw->pdm_conf.pdm2pcm_conv_en = 1; + hw->pdm_conf.rx_pdm_en = 1; +} + +/** + * @brief Configure RX PDM downsample + * + * @param hw Peripheral I2S hardware instance address. + * @param dsr PDM downsample configuration paramater + */ +static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) +{ + hw->pdm_conf.rx_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_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) +{ + *dsr = hw->pdm_conf.rx_sinc_dsr_16_en; +} + +/** + * @brief Enable I2S RX PDM mode + * + * @param hw Peripheral I2S hardware instance address. + * @param pdm_ena Set true to enable RX PDM mode + */ +static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_ena) +{ + hw->pdm_conf.rx_pdm_en = pdm_ena; +} + +/** + * @brief Configure I2S TX pdm + * + * @param hw Peripheral I2S hardware instance address. + * @param sample_rate The sample rate to be set. + */ +static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) +{ + uint32_t fp = 960; + uint32_t fs = sample_rate / 100; + typeof(hw->pdm_conf) pdm_conf_reg = hw->pdm_conf; + pdm_conf_reg.tx_sinc_osr2 = fp/fs; + pdm_conf_reg.tx_prescale = 0; + pdm_conf_reg.tx_hp_in_shift = 1; + pdm_conf_reg.tx_lp_in_shift = 1; + pdm_conf_reg.tx_sinc_in_shift = 1; + pdm_conf_reg.tx_sigmadelta_in_shift = 1; + pdm_conf_reg.pcm2pdm_conv_en = 1; + pdm_conf_reg.tx_pdm_en = 1; + hw->pdm_conf.val = pdm_conf_reg.val; + hw->pdm_freq_conf.tx_pdm_fp = fp; + hw->pdm_freq_conf.tx_pdm_fs = fs; +} + +/** + * @brief Configure I2S TX PDM sample rate + * Fpdm = 64*Fpcm*fp/fs + * + * @param hw Peripheral I2S hardware instance address. + * @param fp The fp value of TX PDM filter module group0. + * @param fs The fs value of TX PDM filter module group0. + */ +static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) +{ + hw->pdm_freq_conf.tx_pdm_fp = fp; + hw->pdm_freq_conf.tx_pdm_fs = fs; + hw->pdm_conf.tx_sinc_osr2 = fp / fs; +} + +/** + * @brief Get I2S TX PDM configuration + * + * @param hw Peripheral I2S hardware instance address. + * @param fp Pointer to accept TX PDM fp configuration paramater + * @param fs Pointer to accept TX PDM fs configuration paramater + */ +static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) +{ + *fp = hw->pdm_freq_conf.tx_pdm_fp; + *fs = hw->pdm_freq_conf.tx_pdm_fs; +} + +/** + * @brief Enable I2S TX PDM mode + * + * @param hw Peripheral I2S hardware instance address. + * @param pdm_ena Set true to enable TX PDM mode + */ +static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_ena) +{ + hw->pdm_conf.tx_pdm_en = pdm_ena; +} + /** * @brief Enable I2S build in ADC mode * @@ -751,8 +752,12 @@ static inline void i2s_ll_build_in_adc_ena(i2s_dev_t *hw) { hw->conf2.lcd_en = 1; hw->conf2.camera_en = 0; + hw->conf.rx_right_first = 0; hw->conf.rx_msb_shift = 0; + hw->conf.rx_mono = 0; hw->conf.rx_short_sync = 0; + hw->fifo_conf.rx_fifo_mod = 1; + hw->conf_chan.rx_chan_mod = 1; } /** @@ -769,82 +774,6 @@ static inline void i2s_ll_build_in_dac_ena(i2s_dev_t *hw) hw->conf.tx_short_sync = 0; } - -/** - * @brief Enable I2S RX PDM mode - * - * @param hw Peripheral I2S hardware instance address. - * @param pdm_en Set true to enable rx PDM mode - */ -static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_en) -{ - hw->pdm_conf.rx_pdm_en = pdm_en; -} - -/** - * @brief Enable I2S tx pdm mode - * - * @param hw Peripheral I2S hardware instance address. - * @param pdm_en Set true to enable tx PDM mode - */ -static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_en) -{ - hw->pdm_conf.tx_pdm_en = pdm_en; -} - -/** - * @brief Configure I2S tx PDM filter module group0 - * - * @param hw Peripheral I2S hardware instance address. - * @param fp The fp value of TX PDM filter module group0. - * @param fs The fs value of TX PDM filter module group0. - */ -static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t fp, uint32_t fs) -{ - hw->pdm_freq_conf.tx_pdm_fp = fp; - hw->pdm_freq_conf.tx_pdm_fs = fs; - hw->pdm_conf.tx_sinc_osr2 = fp/fs; - hw->pdm_conf.pcm2pdm_conv_en = 1; - hw->pdm_conf.tx_pdm_en = 1; -} - -/** - * @brief Configure I2S rx PDM - * - * @param hw Peripheral I2S hardware instance address. - * @param dsr Down-sampling rate value of rx PDM - */ -static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw, uint32_t dsr) -{ - hw->pdm_conf.rx_sinc_dsr_16_en = dsr; - hw->pdm_conf.pdm2pcm_conv_en = 1; - hw->pdm_conf.rx_pdm_en = 1; -} - -/** - * @brief Get I2S tx PDM configuration - * - * @param hw Peripheral I2S hardware instance address. - * @param fp Pointer to store tx PDM fp configuration - * @param fs Pointer to store tx PDM fs configuration - */ -static inline void i2s_ll_get_tx_pdm(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) -{ - *fp = hw->pdm_freq_conf.tx_pdm_fp; - *fs = hw->pdm_freq_conf.tx_pdm_fs; -} - -/** - * @brief Get I2S rx PDM configuration - * - * @param hw Peripheral I2S hardware instance address. - * @param dsr Pointer to stoe the rx PDM down-sample rate configuration - */ -static inline void i2s_ll_get_rx_pdm(i2s_dev_t *hw, uint32_t *dsr) -{ - *dsr = hw->pdm_conf.rx_sinc_dsr_16_en; -} - #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index 4a6042cf12..f9d7331a87 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,18 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +// The LL layer for I2C register operations /******************************************************************************* * NOTICE * The hal is not public api, don't use in application code. - * See readme.md in soc/include/hal/readme.md + * See readme.md in hal/include/hal/readme.md ******************************************************************************/ -// The LL layer for ESP32-S3 I2S register operations - #pragma once - #include -#include #include "soc/i2s_periph.h" #include "hal/i2s_types.h" @@ -31,880 +28,688 @@ extern "C" { #endif -// Get I2S hardware instance with giving i2s num -#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL) -#define I2S_INTR_IN_SUC_EOF BIT(9) -#define I2S_INTR_OUT_EOF BIT(12) -#define I2S_INTR_IN_DSCR_ERR BIT(13) -#define I2S_INTR_OUT_DSCR_ERR BIT(14) -#define I2S_INTR_MAX (0xFFFFFFFF) +#define I2S_LL_GET_HW(num) (&I2S0) +#define I2S_INTR_OUT_DSCR_ERR (0x1 << 6) +#define I2S_INTR_OUT_EOF (0x1 << 4) +#define I2S_INTR_IN_DSCR_ERR (0x1 << 5) +#define I2S_INTR_IN_SUC_EOF (0x1 << 1) +#define I2S_INTR_MAX (~0) + +#define I2S_TDM_CH_MASK (0xffff) + +/* I2S clock configuration structure */ +typedef struct { + uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a) + uint16_t a; + uint16_t b; // The decimal part of module clock devider, the decimal is: b/a + uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div +} i2s_clk_cal_t; /** - * @brief Reset rx fifo + * @brief Calculate the closest sample rate clock configuration. + * clock relationship: + * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) * - * @param hw Peripheral I2S hardware instance address. + * @param fsclk I2S source clock freq. + * @param fbck BCK freuency. + * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. + * @param cal Point to `i2s_clk_cal_t` structure. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal) { - abort(); // TODO ESP32-C3 IDF-2098 - - + int ma = 0; + int mb = 0; + uint32_t mclk = fbck*bck_div; + cal->mclk_div = fsclk / mclk; + cal->bck_div = bck_div; + cal->a = 1; + cal->b = 0; + uint32_t freq_diff = fsclk - mclk * cal->mclk_div; + uint32_t min = freq_diff * 512; + if (freq_diff == 0) { + return; + } + for (int a = 2; a <= 512; a++) { + for (int b = 1; b < a; b++) { + ma = freq_diff*a; + mb = mclk*b; + if (ma == mb) { + cal->a = a; + cal->b = b; + return; + } + if (abs((mb - ma)) < min) { + cal->a = a; + cal->b = b; + min = abs(mb - ma); + } + } + } } /** - * @brief Reset tx fifo + * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_general_init(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->tx_clkm_conf.clk_en = 1; } /** - * @brief Enable rx interrupt + * @brief Reset I2S TX module, enable default source clock and set to TDM mode. * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->tx_conf.tx_start = 0; + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; + hw->tx_conf.tx_slave_mod = 0; + hw->tx_conf.tx_tdm_en = 1; + hw->tx_conf.tx_pdm_en = 0; + hw->tx_clkm_conf.tx_clk_active = 1; + hw->tx_clkm_conf.tx_clk_sel = 2; } /** - * @brief Disable rx interrupt + * @brief Reset I2S RX module, enable default source clock and set to TDM mode. * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->rx_conf.rx_start = 0; + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; + hw->rx_conf.rx_slave_mod = 0; + hw->rx_conf.rx_tdm_en = 1; + hw->rx_conf.rx_pdm_en = 0; + hw->rx_clkm_conf.rx_clk_active = 1; + hw->rx_clkm_conf.rx_clk_sel = 2; + hw->rx_clkm_conf.mclk_sel = 0; } /** - * @brief Disable tx interrupt + * @brief Enable I2S TX slave mode * * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->tx_conf.tx_slave_mod = slave_en; } /** - * @brief Enable tx interrupt + * @brief Enable I2S RX slave mode * * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->rx_conf.rx_slave_mod = slave_en; } /** - * @brief Reset dma in - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-C3 IDF-2098 - - -} - -/** - * @brief Reset dma out - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-C3 IDF-2098 - - -} - -/** - * @brief Reset tx + * @brief Reset I2S TX module * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_reset_tx(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; } /** - * @brief Reset rx + * @brief Reset I2S RX module * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_reset_rx(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; } /** - * @brief Start out link + * @brief Reset I2S TX FIFO * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_out_link(i2s_dev_t *hw) +static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_fifo_reset = 1; + hw->tx_conf.tx_fifo_reset = 0; } /** - * @brief Start tx + * @brief Reset I2S RX FIFO + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +{ + hw->rx_conf.rx_fifo_reset = 1; + hw->rx_conf.rx_fifo_reset = 0; +} + +/** + * @brief Set TX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` + */ +static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + hw->tx_clkm_conf.tx_clk_sel = 2; +} + +/** + * @brief Set RX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` + */ +static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + hw->rx_clkm_conf.rx_clk_sel = 2; +} + +/** + * @brief Configure I2S TX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +{ + if (set->a == 0 || set->b == 0) { + hw->tx_clkm_div_conf.tx_clkm_div_x = 0; + hw->tx_clkm_div_conf.tx_clkm_div_y = 0; + hw->tx_clkm_div_conf.tx_clkm_div_z = 0; + } else { + if(set->b > set->a/2) { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/(set->a-set->b) -1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%(set->a-set->b); + hw->tx_clkm_div_conf.tx_clkm_div_z = set->a-set->b; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 1; + } else { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/set->b-1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%set->b+1; + hw->tx_clkm_div_conf.tx_clkm_div_z = set->b; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0; + } + } + hw->tx_clkm_conf.tx_clkm_div_num = set->mclk_div; + hw->tx_conf1.tx_bck_div_num = set->bck_div-1; +} + +/** + * @brief Configure I2S RX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +{ + if (set->a == 0 || set->b == 0) { + hw->rx_clkm_div_conf.rx_clkm_div_x = 0; + hw->rx_clkm_div_conf.rx_clkm_div_y = 0; + hw->rx_clkm_div_conf.rx_clkm_div_z = 0; + } else { + if(set->b > set->a/2) { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/(set->a-set->b)-1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%(set->a-set->b); + hw->rx_clkm_div_conf.rx_clkm_div_z = set->a-set->b; + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 1; + } else { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/set->b-1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%set->b+1; + hw->rx_clkm_div_conf.rx_clkm_div_z = set->b; + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0; + } + } + hw->rx_clkm_conf.rx_clkm_div_num = set->mclk_div; + hw->rx_conf1.rx_bck_div_num = set->bck_div-1; +} + +/** + * @brief Start I2S TX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_start_tx(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_update = 0; + hw->tx_conf.tx_update = 1; + hw->tx_conf.tx_start = 1; } /** - * @brief Start in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_in_link(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Start rx + * @brief Start I2S RX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_start_rx(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf.rx_update = 0; + hw->rx_conf.rx_update = 1; + hw->rx_conf.rx_start = 1; } /** - * @brief Stop out link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Stop tx + * @brief Stop I2S TX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_stop_tx(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_start = 0; } /** - * @brief Stop in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Stop rx + * @brief Stop I2S RX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf.rx_start = 0; } /** - * @brief Enable dma + * @brief Configure TX WS signal width * * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle */ -static inline void i2s_ll_enable_dma(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) { - abort(); // TODO ESP32-C3 IDF-2098 - // //Enable and configure DMA - // typeof(hw->lc_conf) lc_conf; - // lc_conf.val = 0; - // lc_conf.out_eof_mode = 1; - + hw->tx_conf1.tx_tdm_ws_width = width-1; } /** - * @brief Get I2S interrupt status + * @brief Configure RX WS signal width * * @param hw Peripheral I2S hardware instance address. - * @param val value to get interrupt status + * @param width WS width in BCK cycle */ -static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->int_st.val; + hw->rx_conf1.rx_tdm_ws_width = width-1; } /** - * @brief Clear I2S interrupt status + * @brief Configure the received length to trigger in_suc_eof interrupt * * @param hw Peripheral I2S hardware instance address. - * @param val value to clear interrupt status + * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_eof_num.rx_eof_num = eof_num; } /** - * @brief Get I2S out eof des address + * @brief Congfigure TX slot bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get out eof des address + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->out_eof_des_addr; + hw->tx_conf1.tx_bits_mod = data_bit - 1; + hw->tx_conf1.tx_tdm_chan_bits = sample_bit-1; } /** - * @brief Get I2S in eof des address + * @brief Congfigure RX slot bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get in eof des address + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->in_eof_des_addr; + hw->rx_conf1.rx_bits_mod = data_bit - 1; + hw->rx_conf1.rx_tdm_chan_bits = sample_bit-1; } /** - * @brief Get I2S tx fifo mode + * @brief Configure RX half_sample_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx fifo mode + * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->fifo_conf.tx_fifo_mod; + hw->tx_conf1.tx_half_sample_bits = half_sample_bits-1; } /** - * @brief Set I2S tx fifo mode + * @brief Configure RX half_sample_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mode + * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf1.rx_half_sample_bits = half_sample_bits-1; } /** - * @brief Get I2S rx fifo mode + * @brief Enable TX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx fifo mode + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_tx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->fifo_conf.rx_fifo_mod; + hw->tx_conf1.tx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S rx fifo mode + * @brief Enable RX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mode + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf1.rx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S tx chan mode + * @brief Configure TX total slot number * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx chan mode + * @param total_num Total slot number */ -static inline void i2s_ll_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_slot_mun(i2s_dev_t *hw, int total_num) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num-1; } /** - * @brief Set I2S rx chan mode + * @brief Configure RX total slot number * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx chan mode + * @param total_num Total slot number */ -static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_slot_mun(i2s_dev_t *hw, int total_num) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num-1; } /** - * @brief Set I2S out link address + * @brief Set the bimap of the active TX slot, only the active slot can launch audio data. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set out link address + * @param */ -static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) { - abort(); // TODO ESP32-C3 IDF-2098 - + typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK; + tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK; + hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set I2S in link address + * @brief Set the bimap of the active RX slot, only the active slot can receive audio data. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set in link address + * @param */ -static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) { - abort(); // TODO ESP32-C3 IDF-2098 - + typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK; + tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK; + hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set I2S rx eof num + * @brief Set TX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx eof num + * @param */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_ws_idle_pol = ws_pol_level; } /** - * @brief Get I2S tx pdm fp + * @brief Set RX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx pdm fp + * @param */ -static inline void i2s_ll_get_tx_pdm_fp(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->pdm_freq_conf.tx_pdm_fp; + hw->rx_conf.rx_ws_idle_pol = ws_pol_level; } /** - * @brief Get I2S tx pdm fs + * @brief Enable TX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx pdm fs + * @param pdm_enable Set true to TX enable PDM mode */ -static inline void i2s_ll_get_tx_pdm_fs(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->pdm_freq_conf.tx_pdm_fs; + if (pdm_enable) { + hw->tx_conf.tx_tdm_en = 0; + hw->tx_conf.tx_pdm_en = 1; + } else { + hw->tx_conf.tx_pdm_en = 0; + hw->tx_conf.tx_tdm_en = 1; + } } /** - * @brief Set I2S tx pdm fp + * @brief Configure I2S TX pdm * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm fp + * @param sample_rate The sample rate to be set. */ -static inline void i2s_ll_set_tx_pdm_fp(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) { - abort(); // TODO ESP32-C3 IDF-2098 - + uint32_t fp = 960; + uint32_t fs = sample_rate / 100; + typeof(hw->tx_pcm2pdm_conf) pdm_conf_reg = hw->tx_pcm2pdm_conf; + typeof(hw->tx_pcm2pdm_conf1) pdm_conf1_reg = hw->tx_pcm2pdm_conf1; + pdm_conf_reg.pcm2pdm_conv_en = 1; + pdm_conf_reg.tx_pdm_prescale = 0; + pdm_conf_reg.tx_pdm_hp_in_shift = 1; + pdm_conf_reg.tx_pdm_lp_in_shift = 1; + pdm_conf_reg.tx_pdm_sinc_in_shift = 1; + pdm_conf_reg.tx_pdm_sigmadelta_in_shift = 1; + pdm_conf_reg.tx_pdm_sinc_osr2 = fp/fs; + pdm_conf_reg.tx_pdm_dac_mode_en = 1; + pdm_conf_reg.tx_pdm_sigmadelta_dither = 0; + pdm_conf_reg.tx_pdm_sigmadelta_dither2 = 0; + pdm_conf_reg.tx_pdm_dac_2out_en = 1; + pdm_conf1_reg.tx_pdm_fp = fp; + pdm_conf1_reg.tx_pdm_fs = fs; + pdm_conf1_reg.tx_iir_hp_mult12_5 = 7; + pdm_conf1_reg.tx_iir_hp_mult12_0 =6; + pdm_conf_reg.tx_pdm_hp_bypass = 0; + hw->tx_pcm2pdm_conf = pdm_conf_reg; + hw->tx_pcm2pdm_conf1 = pdm_conf1_reg; } /** - * @brief Set I2S tx pdm fs + * @brief Configure I2S TX PDM sample rate + * Fpdm = 64*Fpcm*fp/fs * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm fs + * @param fp The fp value of TX PDM filter module group0. + * @param fs The fs value of TX PDM filter module group0. */ -static inline void i2s_ll_set_tx_pdm_fs(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp; + hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs; + hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = fp / fs; } /** - * @brief Get I2S rx sinc dsr 16 en + * @brief Get I2S TX PDM configuration * * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx sinc dsr 16 en + * @param fp Pointer to accept TX PDM fp configuration paramater + * @param fs Pointer to accept TX PDM fs configuration paramater */ -static inline void i2s_ll_get_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool *val) +static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->pdm_conf.rx_sinc_dsr_16_en; + *fp = hw->tx_pcm2pdm_conf1.tx_pdm_fp; + *fs = hw->tx_pcm2pdm_conf1.tx_pdm_fs; } /** - * @brief Set I2S clkm div num + * @brief Enable RX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div num + * @param pdm_enable Set true to RX enable PDM mode */ -static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { - abort(); // TODO ESP32-C3 IDF-2098 - + if (pdm_enable) { + hw->rx_conf.rx_tdm_en = 0; + hw->rx_conf.rx_pdm_en = 1; + } else { + hw->rx_conf.rx_pdm_en = 0; + hw->rx_conf.rx_tdm_en = 1; + } } /** - * @brief Set I2S clkm div b + * @brief Configura TX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div b + * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) { - abort(); // TODO ESP32-C3 IDF-2098 - + if (pcm_cfg == I2S_PCM_DISABLE) { + hw->tx_conf.tx_pcm_bypass = 1; + } else { + hw->tx_conf.tx_pcm_conf = pcm_cfg; + hw->tx_conf.tx_pcm_bypass = 0; + } } /** - * @brief Set I2S clkm div a + * @brief Configure RX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div a + * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) { - abort(); // TODO ESP32-C3 IDF-2098 - + if (pcm_cfg == I2S_PCM_DISABLE) { + hw->rx_conf.rx_pcm_bypass = 1; + } else { + hw->rx_conf.rx_pcm_conf = pcm_cfg; + hw->rx_conf.rx_pcm_bypass = 0; + } } /** - * @brief Set I2S tx bck div num + * @brief Enable TX audio data left alignment * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bck div num + * @param ena Set true to enable left alignment */ -static inline void i2s_ll_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_left_align_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_left_align = ena; } /** - * @brief Set I2S rx bck div num + * @brief Enable RX audio data left alignment * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bck div num + * @param ena Set true to enable left alignment */ -static inline void i2s_ll_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_left_align_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf.rx_left_align = ena; } /** - * @brief Set I2S clk sel + * @brief Enable TX big endian mode * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clk sel + * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_big_endian_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf.rx_big_endian = ena; } /** - * @brief Set I2S tx bits mod + * @brief Enable RX big endian mode * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bits mod + * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_big_endian_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_big_endian = ena; } /** - * @brief Set I2S rx bits mod + * @brief Configure TX bit order * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bits mod + * @param lsb_order_ena Set true to enable LSB bit order */ -static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_bit_order = lsb_order_ena; } /** - * @brief Set I2S rx sinc dsr 16 en + * @brief Configure RX bit order * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx sinc dsr 16 en + * @param lsb_order_ena Set true to enable LSB bit order */ -static inline void i2s_ll_set_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool val) +static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf.rx_bit_order = lsb_order_ena; } /** - * @brief Set I2S dscr en + * @brief Configure single data * * @param hw Peripheral I2S hardware instance address. - * @param val value to set dscr en + * @param data Single data to be set */ -static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val) +static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->conf_single_data = data; } /** - * @brief Set I2S lcd en + * @brief Enable loopback mode * * @param hw Peripheral I2S hardware instance address. - * @param val value to set lcd en + * @param ena Set true to enable loopback mode. */ -static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val) +static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S camera en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set camera en - */ -static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S pcm2pdm conv en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set pcm2pdm conv en - */ -static inline void i2s_ll_set_pcm2pdm_conv_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S TX to MSB Alignment Standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_format_msb_align(i2s_dev_t *hw) -{ -} - - -static inline void i2s_ll_set_rx_format_msb_align(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_long(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_short(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to philip standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_format_philip(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_short(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to philip standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_format_philip(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S pdm2pcm conv en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set pdm2pcm conv en - */ -static inline void i2s_ll_set_pdm2pcm_conv_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S rx pdm en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx pdm en - */ -static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S tx pdm en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm en - */ -static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S tx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mod force en - */ -static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S rx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mod force en - */ -static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S tx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx right first - */ -static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S rx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx right first - */ -static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S tx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx slave mod - */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S rx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx slave mod - */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Get I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx msb right - */ -static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->conf.tx_msb_right; -} - -/** - * @brief Get I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx msb right - */ -static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->conf.rx_msb_right; -} - -/** - * @brief Set I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx msb right - */ -static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx msb right - */ -static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S tx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx mono - */ -static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S rx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx mono - */ -static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S tx sinc osr2 - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx sinc osr2 - */ -static inline void i2s_ll_set_tx_sinc_osr2(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S sig loopback - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set sig loopback - */ -static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.sig_loopback = ena; } #ifdef __cplusplus diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index 3e0a7eeb20..fc683436e2 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -1,4 +1,4 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -39,19 +39,148 @@ extern "C" { #define I2S_INTR_OUT_DSCR_ERR BIT(14) #define I2S_INTR_MAX (0xFFFFFFFF) +/* I2S clock configuration structure */ +typedef struct { + uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a) + uint16_t a; + uint16_t b; // The decimal part of module clock devider, the decimal is: b/a + uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div +} i2s_clk_cal_t; + /** - * @brief Reset rx fifo + * @brief Calculate the closest sample rate clock configuration. + * clock relationship: + * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) * - * @param hw Peripheral I2S hardware instance address. + * @param fsclk I2S source clock freq. + * @param fbck BCK freuency. + * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. + * @param cal Point to `i2s_clk_cal_t` structure. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal) { - hw->conf.rx_fifo_reset = 1; - hw->conf.rx_fifo_reset = 0; + int ma = 0; + int mb = 0; + uint32_t mclk = fbck*bck_div; + cal->mclk_div = fsclk / mclk; + cal->bck_div = bck_div; + cal->a = 1; + cal->b = 0; + uint32_t freq_diff = fsclk - mclk * cal->mclk_div; + uint32_t min = ~0; + if (freq_diff == 0) { + return; + } + for (int a = 2; a <= 63; a++) { + for (int b = 1; b < a; b++) { + ma = freq_diff*a; + mb = mclk*b; + if (ma == mb) { + cal->a = a; + cal->b = b; + return; + } + if (abs((mb - ma)) < min) { + cal->a = a; + cal->b = b; + min = abs(mb - ma); + } + } + } } /** - * @brief Reset tx fifo + * @brief I2S module general init, enable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_general_init(i2s_dev_t *hw) +{ + if (hw->clkm_conf.clk_en == 0) { + hw->clkm_conf.clk_sel = 2; + hw->clkm_conf.clk_en = 1; + hw->conf2.val = 0; + } +} + +/** + * @brief I2S TX module general init. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw) +{ + hw->conf.tx_start = 0; + hw->conf.tx_reset = 1; + hw->conf.tx_reset = 0; + hw->conf.tx_msb_right = 0; + hw->conf.tx_right_first = 0; + hw->conf.tx_slave_mod = 0; + hw->fifo_conf.tx_fifo_mod_force_en = 1; +} + +/** + * @brief I2S RX module general init. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw) +{ + hw->conf.rx_start = 0; + hw->conf.rx_reset = 1; + hw->conf.rx_reset = 0; + hw->conf.rx_msb_right = 0; + hw->conf.rx_right_first = 0; + hw->conf.rx_slave_mod = 0; + hw->fifo_conf.rx_fifo_mod_force_en = 1; +} + +/** + * @brief Enable I2S TX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->conf.tx_slave_mod = slave_en; +} + +/** + * @brief Enable I2S RX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->conf.rx_slave_mod = slave_en; +} + +/** + * @brief Reset TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +{ + hw->conf.tx_reset = 1; + hw->conf.tx_reset = 0; +} + +/** + * @brief Reset RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_rx(i2s_dev_t *hw) +{ + hw->conf.rx_reset = 1; + hw->conf.rx_reset = 0; +} + +/** + * @brief Reset TX FIFO * * @param hw Peripheral I2S hardware instance address. */ @@ -62,40 +191,68 @@ static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) } /** - * @brief Enable rx interrupt + * @brief Reset RX FIFO * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) { - hw->int_ena.in_suc_eof = 1; - hw->int_ena.in_dscr_err = 1; + hw->conf.rx_fifo_reset = 1; + hw->conf.rx_fifo_reset = 0; } /** - * @brief Disable rx interrupt + * @brief Set TX source clock * * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock */ -static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { - hw->int_ena.in_suc_eof = 0; - hw->int_ena.in_dscr_err = 0; + hw->clkm_conf.clk_sel = (src == 1) ? 1 : 2; } /** - * @brief Disable tx interrupt + * @brief Set RX source clock * * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock */ -static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { - hw->int_ena.out_eof = 0; - hw->int_ena.out_dscr_err = 0; + hw->clkm_conf.clk_sel = (src == 1) ? 1 : 2; } /** - * @brief Enable tx interrupt + * @brief Configure I2S TX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +{ + hw->clkm_conf.clkm_div_num = set->mclk_div; + hw->clkm_conf.clkm_div_b = set->b; + hw->clkm_conf.clkm_div_a = set->a; + hw->sample_rate_conf.tx_bck_div_num = set->bck_div; +} + +/** + * @brief Configure I2S RX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +{ + hw->clkm_conf.clkm_div_num = set->mclk_div; + hw->clkm_conf.clkm_div_b = set->b; + hw->clkm_conf.clkm_div_a = set->a; + hw->sample_rate_conf.rx_bck_div_num = set->bck_div; +} + +/** + * @brief Enable TX interrupt * * @param hw Peripheral I2S hardware instance address. */ @@ -106,14 +263,58 @@ static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) } /** - * @brief Reset dma in + * @brief Disable TX interrupt * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) +static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) { - hw->lc_conf.in_rst = 1; - hw->lc_conf.in_rst = 0; + hw->int_ena.out_eof = 0; + hw->int_ena.out_dscr_err = 0; +} + +/** + * @brief Enable RX interrupt + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +{ + hw->int_ena.in_suc_eof = 1; + hw->int_ena.in_dscr_err = 1; +} + +/** + * @brief Disable RX interrupt + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +{ + hw->int_ena.in_suc_eof = 0; + hw->int_ena.in_dscr_err = 0; +} + +/** + * @brief Get I2S interrupt status + * + * @param hw Peripheral I2S hardware instance address. + * @param intr_mask Pointer to accept interrupt status + */ +static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *intr_mask) +{ + *intr_mask = hw->int_st.val; +} + +/** + * @brief Clear I2S interrupt status + * + * @param hw Peripheral I2S hardware instance address. + * @param clr_mask Interrupt mask to be cleared. + */ +static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t clr_mask) +{ + hw->int_clr.val = clr_mask; } /** @@ -128,39 +329,18 @@ static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) } /** - * @brief Reset tx + * @brief Reset dma in * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) { - hw->conf.tx_reset = 1; - hw->conf.tx_reset = 0; + hw->lc_conf.in_rst = 1; + hw->lc_conf.in_rst = 0; } /** - * @brief Reset rx - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_rx(i2s_dev_t *hw) -{ - hw->conf.rx_reset = 1; - hw->conf.rx_reset = 0; -} - -/** - * @brief Start out link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_out_link(i2s_dev_t *hw) -{ - hw->out_link.start = 1; -} - -/** - * @brief Start tx + * @brief Start TX module * * @param hw Peripheral I2S hardware instance address. */ @@ -170,17 +350,7 @@ static inline void i2s_ll_start_tx(i2s_dev_t *hw) } /** - * @brief Start in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_in_link(i2s_dev_t *hw) -{ - hw->in_link.start = 1; -} - -/** - * @brief Start rx + * @brief Start RX module * * @param hw Peripheral I2S hardware instance address. */ @@ -189,6 +359,50 @@ static inline void i2s_ll_start_rx(i2s_dev_t *hw) hw->conf.rx_start = 1; } +/** + * @brief Configure TX DMA descriptor address and start TX DMA + * + * @param hw Peripheral I2S hardware instance address. + * @param link_addr DMA descriptor link address. + */ +static inline void i2s_ll_start_tx_link(i2s_dev_t *hw, uint32_t link_addr) +{ + hw->out_link.addr = link_addr; + hw->out_link.start = 1; +} + +/** + * @brief Configure RX DMA descriptor address and start TX DMA + * + * @param hw Peripheral I2S hardware instance address. + * @param link_addr DMA descriptor link address. + */ +static inline void i2s_ll_start_rx_link(i2s_dev_t *hw, uint32_t link_addr) +{ + hw->in_link.addr = link_addr; + hw->in_link.start = 1; +} + +/** + * @brief Stop TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_stop_tx(i2s_dev_t *hw) +{ + hw->conf.tx_start = 0; +} + +/** + * @brief Stop RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +{ + hw->conf.rx_start = 0; +} + /** * @brief Stop out link * @@ -199,16 +413,6 @@ static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) hw->out_link.stop = 1; } -/** - * @brief Stop tx - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_tx(i2s_dev_t *hw) -{ - hw->conf.tx_start = 0; -} - /** * @brief Stop in link * @@ -220,456 +424,77 @@ static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) } /** - * @brief Stop rx + * @brief Get I2S out eof descriptor address * * @param hw Peripheral I2S hardware instance address. + * @param eof_addr Pointer to accept out eof des address */ -static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) { - hw->conf.rx_start = 0; + *eof_addr = hw->out_eof_des_addr; } /** - * @brief Enable dma + * @brief Get I2S in eof descriptor address * * @param hw Peripheral I2S hardware instance address. + * @param eof_addr Pointer to accept in eof des address */ -static inline void i2s_ll_enable_dma(i2s_dev_t *hw) +static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) { - //Enable and configure DMA - typeof(hw->lc_conf) lc_conf; - lc_conf.val = 0; - lc_conf.out_eof_mode = 1; - hw->lc_conf.val = lc_conf.val; + *eof_addr = hw->in_eof_des_addr; } /** - * @brief Get I2S interrupt status + * @brief Configure the received length to trigger in_suc_eof interrupt * * @param hw Peripheral I2S hardware instance address. - * @param val value to get interrupt status + * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t eof_num) { - *val = hw->int_st.val; + hw->rx_eof_num = eof_num; } /** - * @brief Clear I2S interrupt status + * @brief Congfigure TX slot bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to clear interrupt status + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - hw->int_clr.val = val; + hw->fifo_conf.tx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); + hw->sample_rate_conf.tx_bits_mod = data_bit; } /** - * @brief Get I2S out eof des address + * @brief Congfigure RX slot bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get out eof des address + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - *val = hw->out_eof_des_addr; + hw->fifo_conf.rx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); + hw->sample_rate_conf.rx_bits_mod = data_bit; } /** - * @brief Get I2S in eof des address + * @brief Enable I2S DMA * * @param hw Peripheral I2S hardware instance address. - * @param val value to get in eof des address + * @param ena Set true to enable DMA */ -static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_dma_enable(i2s_dev_t *hw, bool ena) { - *val = hw->in_eof_des_addr; -} - -/** - * @brief Get I2S tx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx fifo mode - */ -static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->fifo_conf.tx_fifo_mod; -} - -/** - * @brief Set I2S tx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mode - */ -static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->fifo_conf.tx_fifo_mod = val; -} - -/** - * @brief Get I2S rx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx fifo mode - */ -static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->fifo_conf.rx_fifo_mod; -} - -/** - * @brief Set I2S rx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mode - */ -static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->fifo_conf.rx_fifo_mod = val; -} - -/** - * @brief Set I2S tx chan mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx chan mode - */ -static inline void i2s_ll_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf_chan.tx_chan_mod = val; -} - -/** - * @brief Set I2S rx chan mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx chan mode - */ -static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf_chan.rx_chan_mod = val; -} - -/** - * @brief Set I2S tx dma equal - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx dma equal - */ -static inline void i2s_ll_set_tx_dma_equal(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_dma_equal = val; -} - -/** - * @brief Set I2S rx dma equal - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx dma equal - */ -static inline void i2s_ll_set_rx_dma_equal(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_dma_equal = val; -} - -/** - * @brief Set I2S out link address - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set out link address - */ -static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val) -{ - hw->out_link.addr = val; -} - -/** - * @brief Set I2S in link address - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set in link address - */ -static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val) -{ - hw->in_link.addr = val; -} - -/** - * @brief Set I2S rx eof num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx eof num - */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val) -{ - hw->rx_eof_num = val; -} - -/** - * @brief Set I2S clkm div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div num - */ -static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val) -{ - hw->clkm_conf.clkm_div_num = val; -} - -/** - * @brief Set I2S clkm div b - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div b - */ -static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val) -{ - hw->clkm_conf.clkm_div_b = val; -} - -/** - * @brief Set I2S clkm div a - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div a - */ -static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val) -{ - hw->clkm_conf.clkm_div_a = val; -} - -/** - * @brief Set I2S tx bck div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bck div num - */ -static inline void i2s_ll_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.tx_bck_div_num = val; -} - -/** - * @brief Set I2S rx bck div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bck div num - */ -static inline void i2s_ll_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.rx_bck_div_num = val; -} - -/** - * @brief Set I2S clk sel - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clk sel - */ -static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val) -{ - hw->clkm_conf.clk_sel = (val == 1) ? 1 : 2; -} - -/** - * @brief Set I2S tx bits mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bits mod - */ -static inline void i2s_ll_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.tx_bits_mod = val; -} - -/** - * @brief Set I2S rx bits mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bits mod - */ -static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.rx_bits_mod = val; -} - -/** - * @brief Set I2S dscr en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set dscr en - */ -static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val) -{ - hw->fifo_conf.dscr_en = val; -} - -/** - * @brief Set I2S lcd en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set lcd en - */ -static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val) -{ - hw->conf2.lcd_en = val; -} - -/** - * @brief Set I2S camera en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set camera en - */ -static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val) -{ - hw->conf2.camera_en = val; -} - -/** - * @brief Set I2S tx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mod force en - */ -static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - hw->fifo_conf.tx_fifo_mod_force_en = val; -} - -/** - * @brief Set I2S rx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mod force en - */ -static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - hw->fifo_conf.rx_fifo_mod_force_en = val; -} - -/** - * @brief Set I2S tx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx right first - */ -static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_right_first = val; -} - -/** - * @brief Set I2S rx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx right first - */ -static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_right_first = val; -} - -/** - * @brief Set I2S tx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx slave mod - */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_slave_mod = val; -} - -/** - * @brief Set I2S rx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx slave mod - */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_slave_mod = val; -} - -/** - * @brief Get I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx msb right - */ -static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->conf.tx_msb_right; -} - -/** - * @brief Get I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx msb right - */ -static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->conf.rx_msb_right; -} - -/** - * @brief Set I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx msb right - */ -static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_msb_right = val; -} - -/** - * @brief Set I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx msb right - */ -static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_msb_right = val; -} - -/** - * @brief Set I2S tx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx mono - */ -static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_mono = val; -} - -/** - * @brief Set I2S rx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx mono - */ -static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_mono = val; -} - -/** - * @brief Set I2S sig loopback - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set sig loopback - */ -static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.sig_loopback = val; + if (ena && !hw->fifo_conf.dscr_en) { + hw->fifo_conf.dscr_en = 1; + } else if (!ena && hw->fifo_conf.dscr_en) { + hw->fifo_conf.dscr_en = 0; + } } /** @@ -760,6 +585,53 @@ static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) hw->conf.rx_msb_shift = 0; } +/** + * @brief Enable TX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_tx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) +{ + int data_bit = hw->sample_rate_conf.tx_bits_mod; + if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) { + hw->fifo_conf.tx_fifo_mod = 0 + mono_ena; + } else { + hw->fifo_conf.tx_fifo_mod = 2 + mono_ena; + } + hw->conf.tx_dma_equal = mono_ena; + hw->conf_chan.tx_chan_mod = mono_ena; +} + +/** + * @brief Enable RX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_rx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) +{ + int data_bit = hw->sample_rate_conf.rx_bits_mod; + if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) { + hw->fifo_conf.rx_fifo_mod = 0 + mono_ena; + } else { + hw->fifo_conf.rx_fifo_mod = 2 + mono_ena; + } + hw->conf.rx_dma_equal = mono_ena; + hw->conf_chan.rx_chan_mod = mono_ena; +} + +/** + * @brief Enable I2S loopback mode + * + * @param hw Peripheral I2S hardware instance address. + * @param loopback_en Set true to enable loopback mode. + */ +static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool loopback_en) +{ + hw->conf.sig_loopback = loopback_en; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 645e84793e..618b204d2d 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,16 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +// The LL layer for I2C register operations /******************************************************************************* * NOTICE * The hal is not public api, don't use in application code. * See readme.md in hal/include/hal/readme.md ******************************************************************************/ -// The LL layer for ESP32-S3 I2S register operations - #pragma once - #include #include "soc/i2s_periph.h" #include "hal/i2s_types.h" @@ -30,28 +28,157 @@ extern "C" { #endif -// Get I2S hardware instance with giving i2s num -#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL) -#define I2S_INTR_IN_SUC_EOF BIT(9) -#define I2S_INTR_OUT_EOF BIT(12) -#define I2S_INTR_IN_DSCR_ERR BIT(13) -#define I2S_INTR_OUT_DSCR_ERR BIT(14) -#define I2S_INTR_MAX (0xFFFFFFFF) +#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : &I2S1) +#define I2S_INTR_OUT_DSCR_ERR (0x1 << 6) +#define I2S_INTR_OUT_EOF (0x1 << 4) +#define I2S_INTR_IN_DSCR_ERR (0x1 << 5) +#define I2S_INTR_IN_SUC_EOF (0x1 << 1) +#define I2S_INTR_MAX (~0) + +#define I2S_TDM_CH_MASK (0xffff) + +/* I2S clock configuration structure */ +typedef struct { + uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a) + uint16_t a; + uint16_t b; // The decimal part of module clock devider, the decimal is: b/a + uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div +} i2s_clk_cal_t; /** - * @brief Reset rx fifo + * @brief Calculate the closest sample rate clock configuration. + * clock relationship: + * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) * - * @param hw Peripheral I2S hardware instance address. + * @param fsclk I2S source clock freq. + * @param fbck BCK freuency. + * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. + * @param cal Point to `i2s_clk_cal_t` structure. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal) { - hw->rx_conf.rx_fifo_reset = 1; - hw->rx_conf.rx_fifo_reset = 0; + int ma = 0; + int mb = 0; + uint32_t mclk = fbck*bck_div; + cal->mclk_div = fsclk / mclk; + cal->bck_div = bck_div; + cal->a = 1; + cal->b = 0; + uint32_t freq_diff = fsclk - mclk * cal->mclk_div; + uint32_t min = freq_diff * 512; + if (freq_diff == 0) { + return; + } + for (int a = 2; a <= 512; a++) { + for (int b = 1; b < a; b++) { + ma = freq_diff*a; + mb = mclk*b; + if (ma == mb) { + cal->a = a; + cal->b = b; + return; + } + if (abs((mb - ma)) < min) { + cal->a = a; + cal->b = b; + min = abs(mb - ma); + } + } + } } /** - * @brief Reset tx fifo + * @brief I2S module general init, enable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_general_init(i2s_dev_t *hw) +{ + hw->tx_clkm_conf.clk_en = 1; +} + +/** + * @brief Reset I2S TX module, enable default source clock and set to TDM mode. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw) +{ + hw->tx_conf.tx_start = 0; + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; + hw->tx_conf.tx_slave_mod = 0; + hw->tx_conf.tx_tdm_en = 1; + hw->tx_conf.tx_pdm_en = 0; + hw->tx_clkm_conf.tx_clk_active = 1; + hw->tx_clkm_conf.tx_clk_sel = 2; +} + +/** + * @brief Reset I2S RX module, enable default source clock and set to TDM mode. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw) +{ + hw->rx_conf.rx_start = 0; + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; + hw->rx_conf.rx_slave_mod = 0; + hw->rx_conf.rx_tdm_en = 1; + hw->rx_conf.rx_pdm_en = 0; + hw->rx_clkm_conf.rx_clk_active = 1; + hw->rx_clkm_conf.rx_clk_sel = 2; + hw->rx_clkm_conf.mclk_sel = 0; +} + +/** + * @brief Enable I2S TX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->tx_conf.tx_slave_mod = slave_en; +} + +/** + * @brief Enable I2S RX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->rx_conf.rx_slave_mod = slave_en; +} + +/** + * @brief Reset I2S TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +{ + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; +} + +/** + * @brief Reset I2S RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_rx(i2s_dev_t *hw) +{ + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; +} + +/** + * @brief Reset I2S TX FIFO * * @param hw Peripheral I2S hardware instance address. */ @@ -62,787 +189,502 @@ static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) } /** - * @brief Enable rx interrupt + * @brief Reset I2S RX FIFO * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) { + hw->rx_conf.rx_fifo_reset = 1; + hw->rx_conf.rx_fifo_reset = 0; } /** - * @brief Disable rx interrupt + * @brief Set TX source clock * * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` */ -static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { + hw->tx_clkm_conf.tx_clk_sel = 2; } /** - * @brief Disable tx interrupt + * @brief Set RX source clock * * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` */ -static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { + hw->rx_clkm_conf.rx_clk_sel = 2; } /** - * @brief Enable tx interrupt + * @brief Configure I2S TX clock devider * * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) { + if (set->a == 0 || set->b == 0) { + hw->tx_clkm_div_conf.tx_clkm_div_x = 0; + hw->tx_clkm_div_conf.tx_clkm_div_y = 0; + hw->tx_clkm_div_conf.tx_clkm_div_z = 0; + } else { + if(set->b > set->a/2) { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/(set->a-set->b) -1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%(set->a-set->b); + hw->tx_clkm_div_conf.tx_clkm_div_z = set->a-set->b; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 1; + } else { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/set->b-1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%set->b+1; + hw->tx_clkm_div_conf.tx_clkm_div_z = set->b; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0; + } + } + hw->tx_clkm_conf.tx_clkm_div_num = set->mclk_div; + hw->tx_conf1.tx_bck_div_num = set->bck_div-1; } /** - * @brief Reset dma in + * @brief Configure I2S RX clock devider * * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) { + if (set->a == 0 || set->b == 0) { + hw->rx_clkm_div_conf.rx_clkm_div_x = 0; + hw->rx_clkm_div_conf.rx_clkm_div_y = 0; + hw->rx_clkm_div_conf.rx_clkm_div_z = 0; + } else { + if(set->b > set->a/2) { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/(set->a-set->b)-1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%(set->a-set->b); + hw->rx_clkm_div_conf.rx_clkm_div_z = set->a-set->b; + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 1; + } else { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/set->b-1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%set->b+1; + hw->rx_clkm_div_conf.rx_clkm_div_z = set->b; + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0; + } + } + hw->rx_clkm_conf.rx_clkm_div_num = set->mclk_div; + hw->rx_conf1.rx_bck_div_num = set->bck_div-1; } /** - * @brief Reset dma out - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) -{ -} - -/** - * @brief Reset tx - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_tx(i2s_dev_t *hw) -{ -} - -/** - * @brief Reset rx - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_rx(i2s_dev_t *hw) -{ -} - -/** - * @brief Start out link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_out_link(i2s_dev_t *hw) -{ -} - -/** - * @brief Start tx + * @brief Start I2S TX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_start_tx(i2s_dev_t *hw) { + hw->tx_conf.tx_update = 0; + hw->tx_conf.tx_update = 1; + hw->tx_conf.tx_start = 1; } /** - * @brief Start in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_in_link(i2s_dev_t *hw) -{ -} - -/** - * @brief Start rx + * @brief Start I2S RX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_start_rx(i2s_dev_t *hw) { + hw->rx_conf.rx_update = 0; + hw->rx_conf.rx_update = 1; + hw->rx_conf.rx_start = 1; } /** - * @brief Stop out link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) -{ -} - -/** - * @brief Stop tx + * @brief Stop I2S TX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_stop_tx(i2s_dev_t *hw) { + hw->tx_conf.tx_start = 0; } /** - * @brief Stop in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) -{ -} - -/** - * @brief Stop rx + * @brief Stop I2S RX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) { + hw->rx_conf.rx_start = 0; } /** - * @brief Enable dma + * @brief Configure TX WS signal width * * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle */ -static inline void i2s_ll_enable_dma(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) { + hw->tx_conf1.tx_tdm_ws_width = width-1; } /** - * @brief Get I2S interrupt status + * @brief Configure RX WS signal width * * @param hw Peripheral I2S hardware instance address. - * @param val value to get interrupt status + * @param width WS width in BCK cycle */ -static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) { - *val = hw->int_st.val; + hw->rx_conf1.rx_tdm_ws_width = width-1; } /** - * @brief Clear I2S interrupt status + * @brief Configure the received length to trigger in_suc_eof interrupt * * @param hw Peripheral I2S hardware instance address. - * @param val value to clear interrupt status + * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) { - hw->int_clr.val = val; + hw->rx_eof_num.rx_eof_num = eof_num; } /** - * @brief Get I2S out eof des address + * @brief Congfigure TX slot bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get out eof des address + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { + hw->tx_conf1.tx_bits_mod = data_bit - 1; + hw->tx_conf1.tx_tdm_chan_bits = sample_bit-1; } /** - * @brief Get I2S in eof des address + * @brief Congfigure RX slot bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get in eof des address + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { + hw->rx_conf1.rx_bits_mod = data_bit - 1; + hw->rx_conf1.rx_tdm_chan_bits = sample_bit-1; } /** - * @brief Get I2S tx fifo mode + * @brief Configure RX half_sample_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx fifo mode + * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { + hw->tx_conf1.tx_half_sample_bits = half_sample_bits-1; } /** - * @brief Set I2S tx fifo mode + * @brief Configure RX half_sample_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mode + * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { + hw->rx_conf1.rx_half_sample_bits = half_sample_bits-1; } /** - * @brief Get I2S rx fifo mode + * @brief Enable TX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx fifo mode + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_tx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) { + hw->tx_conf1.tx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S rx fifo mode + * @brief Enable RX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mode + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) { + hw->rx_conf1.rx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S tx chan mode + * @brief Configure TX total slot number * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx chan mode + * @param total_num Total slot number */ -static inline void i2s_ll_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_slot_mun(i2s_dev_t *hw, int total_num) { + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num-1; } /** - * @brief Set I2S rx chan mode + * @brief Configure RX total slot number * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx chan mode + * @param total_num Total slot number */ -static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_slot_mun(i2s_dev_t *hw, int total_num) { + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num-1; } /** - * @brief Set I2S out link address + * @brief Set the bimap of the active TX slot, only the active slot can launch audio data. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set out link address + * @param */ -static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) { + typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK; + tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK; + hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set I2S in link address + * @brief Set the bimap of the active RX slot, only the active slot can receive audio data. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set in link address + * @param */ -static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) { + typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK; + tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK; + hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set I2S rx eof num + * @brief Set TX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx eof num + * @param */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { + hw->tx_conf.tx_ws_idle_pol = ws_pol_level; } /** - * @brief Get I2S tx pdm fp + * @brief Set RX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx pdm fp + * @param */ -static inline void i2s_ll_get_tx_pdm_fp(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { + hw->rx_conf.rx_ws_idle_pol = ws_pol_level; } /** - * @brief Get I2S tx pdm fs + * @brief Enable TX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx pdm fs + * @param pdm_enable Set true to TX enable PDM mode */ -static inline void i2s_ll_get_tx_pdm_fs(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { + if (pdm_enable) { + hw->tx_conf.tx_tdm_en = 0; + hw->tx_conf.tx_pdm_en = 1; + } else { + hw->tx_conf.tx_pdm_en = 0; + hw->tx_conf.tx_tdm_en = 1; + } } /** - * @brief Set I2S tx pdm fp + * @brief Enable RX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm fp + * @param pdm_enable Set true to RX enable PDM mode */ -static inline void i2s_ll_set_tx_pdm_fp(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { + if (pdm_enable) { + hw->rx_conf.rx_tdm_en = 0; + hw->rx_conf.rx_pdm_en = 1; + } else { + hw->rx_conf.rx_pdm_en = 0; + hw->rx_conf.rx_tdm_en = 1; + } } /** - * @brief Set I2S tx pdm fs - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm fs - */ -static inline void i2s_ll_set_tx_pdm_fs(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Get I2S rx sinc dsr 16 en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx sinc dsr 16 en - */ -static inline void i2s_ll_get_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool *val) -{ -} - -/** - * @brief Set I2S clkm div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div num - */ -static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S clkm div b - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div b - */ -static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S clkm div a - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div a - */ -static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx bck div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bck div num - */ -static inline void i2s_ll_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx bck div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bck div num - */ -static inline void i2s_ll_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S clk sel - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clk sel - */ -static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx bits mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bits mod - */ -static inline void i2s_ll_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx bits mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bits mod - */ -static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx sinc dsr 16 en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx sinc dsr 16 en - */ -static inline void i2s_ll_set_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S dscr en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set dscr en - */ -static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S lcd en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set lcd en - */ -static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S camera en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set camera en - */ -static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S pcm2pdm conv en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set pcm2pdm conv en - */ -static inline void i2s_ll_set_pcm2pdm_conv_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S pdm2pcm conv en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set pdm2pcm conv en - */ -static inline void i2s_ll_set_pdm2pcm_conv_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S rx pdm en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx pdm en - */ -static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S tx pdm en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm en - */ -static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S tx msb shift - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx msb shift - */ -static inline void i2s_ll_set_tx_msb_shift(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx msb shift - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx msb shift - */ -static inline void i2s_ll_set_rx_msb_shift(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx short sync - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx short sync - */ -static inline void i2s_ll_set_tx_short_sync(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx short sync - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx short sync - */ -static inline void i2s_ll_set_rx_short_sync(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mod force en - */ -static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S rx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mod force en - */ -static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S tx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx right first - */ -static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx right first - */ -static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx slave mod - */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx slave mod - */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Get I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx msb right - */ -static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ -} - -/** - * @brief Get I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx msb right - */ -static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ -} - -/** - * @brief Set I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx msb right - */ -static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx msb right - */ -static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx mono - */ -static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx mono - */ -static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx sinc osr2 - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx sinc osr2 - */ -static inline void i2s_ll_set_tx_sinc_osr2(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S sig loopback - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set sig loopback - */ -static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S TX to philip standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_format_philip(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to philip standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_format_philip(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to MSB Alignment Standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_format_msb_align(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to MSB Alignment Standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_format_msb_align(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_short(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_short(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_long(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) -{ -} - -/** - * @brief Configure I2S TX pdm - * - * @param sample_rate The sample rate to be set. - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) -{ -} - -/** - * @brief Configure I2S TX pdm + * @brief Set default RX PDM mode * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw) { + hw->rx_conf.rx_tdm_en = 0; + hw->rx_conf.rx_pdm2pcm_en = 1; + hw->rx_conf.rx_sinc_dsr_16_en = 0; + hw->rx_conf.rx_pdm_en = 1; } /** - * @brief Enable I2S build in ADC mode + * @brief Configure RX PDM downsample * * @param hw Peripheral I2S hardware instance address. + * @param dsr PDM downsample configuration paramater */ -static inline void i2s_ll_build_in_adc_ena(i2s_dev_t *hw) +static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) { + hw->rx_conf.rx_sinc_dsr_16_en = dsr; } /** - * @brief Enable I2S build in DAC mode + * @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_build_in_dac_ena(i2s_dev_t *hw) +static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) { + *dsr = hw->rx_conf.rx_sinc_dsr_16_en; +} + +/** + * @brief Configura TX a/u-law decompress or compress + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm_cfg PCM configuration paramater + */ +static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) +{ + if (pcm_cfg == I2S_PCM_DISABLE) { + hw->tx_conf.tx_pcm_bypass = 1; + } else { + hw->tx_conf.tx_pcm_conf = pcm_cfg; + hw->tx_conf.tx_pcm_bypass = 0; + } +} + +/** + * @brief Configure RX a/u-law decompress or compress + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm_cfg PCM configuration paramater + */ +static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) +{ + if (pcm_cfg == I2S_PCM_DISABLE) { + hw->rx_conf.rx_pcm_bypass = 1; + } else { + hw->rx_conf.rx_pcm_conf = pcm_cfg; + hw->rx_conf.rx_pcm_bypass = 0; + } +} + +/** + * @brief Enable TX audio data left alignment + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable left alignment + */ +static inline void i2s_ll_tx_left_align_enable(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.tx_left_align = ena; +} + +/** + * @brief Enable RX audio data left alignment + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable left alignment + */ +static inline void i2s_ll_rx_left_align_enable(i2s_dev_t *hw, bool ena) +{ + hw->rx_conf.rx_left_align = ena; +} + +/** + * @brief Enable TX big endian mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable big endian mode + */ +static inline void i2s_ll_rx_big_endian_enable(i2s_dev_t *hw, bool ena) +{ + hw->rx_conf.rx_big_endian = ena; +} + +/** + * @brief Enable RX big endian mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable big endian mode + */ +static inline void i2s_ll_tx_big_endian_enable(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.tx_big_endian = ena; +} + +/** + * @brief Configure TX bit order + * + * @param hw Peripheral I2S hardware instance address. + * @param lsb_order_ena Set true to enable LSB bit order + */ +static inline void i2s_ll_tx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) +{ + hw->tx_conf.tx_bit_order = lsb_order_ena; +} + +/** + * @brief Configure RX bit order + * + * @param hw Peripheral I2S hardware instance address. + * @param lsb_order_ena Set true to enable LSB bit order + */ +static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) +{ + hw->rx_conf.rx_bit_order = lsb_order_ena; +} + +/** + * @brief Configure single data + * + * @param hw Peripheral I2S hardware instance address. + * @param data Single data to be set + */ +static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) +{ + hw->conf_single_data = data; +} + +/** + * @brief Enable loopback mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable loopback mode. + */ +static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.sig_loopback = ena; } #ifdef __cplusplus diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index f994add41b..c3c008ce5e 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -1,4 +1,4 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,230 +12,291 @@ // See the License for the specific language governing permissions and // limitations under the License. + // The HAL layer for I2S (common part) #include "soc/soc.h" #include "soc/soc_caps.h" +#include "soc/gdma_channel.h" #include "hal/i2s_hal.h" -#define I2S_TX_PDM_FP_DEF 960 // Set to the recommended value(960) in TRM -#define I2S_RX_PDM_DSR_DEF 0 +#define I2S_MODE_I2S (I2S_MODE_MASTER|I2S_MODE_SLAVE|I2S_MODE_TX|I2S_MODE_RX) /*!< I2S normal mode*/ -void i2s_hal_set_tx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits) +void i2s_hal_reset_tx(i2s_hal_context_t *hal) { - if (bits <= I2S_BITS_PER_SAMPLE_16BIT) { - i2s_ll_set_tx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1); - } else { - i2s_ll_set_tx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 2 : 3); - } - i2s_ll_set_tx_chan_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1); -#if SOC_I2S_SUPPORTS_DMA_EQUAL - i2s_ll_set_tx_dma_equal(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1); -#endif -} - -void i2s_hal_set_rx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits) -{ - if (bits <= I2S_BITS_PER_SAMPLE_16BIT) { - i2s_ll_set_rx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1); - } else { - i2s_ll_set_rx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 2 : 3); - } - i2s_ll_set_rx_chan_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1); -#if SOC_I2S_SUPPORTS_DMA_EQUAL - i2s_ll_set_rx_dma_equal(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1); -#endif -} - -void i2s_hal_set_in_link(i2s_hal_context_t *hal, uint32_t bytes_num, uint32_t addr) -{ - i2s_ll_set_in_link_addr(hal->dev, addr); - i2s_ll_set_rx_eof_num(hal->dev, bytes_num); -} - -#if SOC_I2S_SUPPORTS_PDM -void i2s_hal_tx_pdm_cfg(i2s_hal_context_t *hal, uint32_t fp, uint32_t fs) -{ - i2s_ll_tx_pdm_cfg(hal->dev, fp, fs); -} - -void i2s_hal_get_tx_pdm(i2s_hal_context_t *hal, uint32_t *fp, uint32_t *fs) -{ - i2s_ll_get_tx_pdm(hal->dev, fp, fs); -} - -void i2s_hal_rx_pdm_cfg(i2s_hal_context_t *hal, uint32_t dsr) -{ - i2s_ll_rx_pdm_cfg(hal->dev, dsr); -} - -void i2s_hal_get_rx_pdm(i2s_hal_context_t *hal, uint32_t *dsr) -{ - i2s_ll_get_rx_pdm(hal->dev, dsr); -} -#endif - -void i2s_hal_set_clk_div(i2s_hal_context_t *hal, int div_num, int div_a, int div_b, int tx_bck_div, int rx_bck_div) -{ - i2s_ll_set_clkm_div_num(hal->dev, div_num); - i2s_ll_set_clkm_div_a(hal->dev, div_a); - i2s_ll_set_clkm_div_b(hal->dev, div_b); - i2s_ll_set_tx_bck_div_num(hal->dev, tx_bck_div); - i2s_ll_set_rx_bck_div_num(hal->dev, rx_bck_div); -} - -void i2s_hal_set_tx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits) -{ - i2s_ll_set_tx_bits_mod(hal->dev, bits); -} - -void i2s_hal_set_rx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits) -{ - i2s_ll_set_rx_bits_mod(hal->dev, bits); -} - -void i2s_hal_reset(i2s_hal_context_t *hal) -{ - // Reset I2S TX/RX module first, and then, reset DMA and FIFO. i2s_ll_reset_tx(hal->dev); +} + +void i2s_hal_reset_rx(i2s_hal_context_t *hal) +{ i2s_ll_reset_rx(hal->dev); - i2s_ll_reset_dma_in(hal->dev); - i2s_ll_reset_dma_out(hal->dev); - i2s_ll_reset_rx_fifo(hal->dev); +} + +void i2s_hal_reset_tx_fifo(i2s_hal_context_t *hal) +{ i2s_ll_reset_tx_fifo(hal->dev); } +void i2s_hal_reset_rx_fifo(i2s_hal_context_t *hal) +{ + i2s_ll_reset_rx_fifo(hal->dev); +} + void i2s_hal_start_tx(i2s_hal_context_t *hal) { - i2s_ll_start_out_link(hal->dev); i2s_ll_start_tx(hal->dev); } void i2s_hal_start_rx(i2s_hal_context_t *hal) { - i2s_ll_start_in_link(hal->dev); i2s_ll_start_rx(hal->dev); } void i2s_hal_stop_tx(i2s_hal_context_t *hal) { - i2s_ll_stop_out_link(hal->dev); i2s_ll_stop_tx(hal->dev); } void i2s_hal_stop_rx(i2s_hal_context_t *hal) { - i2s_ll_stop_in_link(hal->dev); i2s_ll_stop_rx(hal->dev); } -void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_config_t *i2s_config) +void i2s_hal_set_tx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit) { - switch (i2s_config->communication_format) { + i2s_ll_set_tx_sample_bit(hal->dev, slot_bit, data_bit); +} + +void i2s_hal_set_rx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit) +{ + i2s_ll_set_rx_sample_bit(hal->dev, slot_bit, data_bit); +} + +void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel) +{ + i2s_ll_set_tx_clk_src(hal->dev, sel); + i2s_ll_set_rx_clk_src(hal->dev, sel); +} + +void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor) +{ + i2s_clk_cal_t clk_set = {0}; + i2s_ll_clk_cal(sclk, fbck, factor, &clk_set); + i2s_ll_set_tx_clk(hal->dev, &clk_set); +} + +void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor) +{ + i2s_clk_cal_t clk_set = {0}; + i2s_ll_clk_cal(sclk, fbck, factor, &clk_set); + i2s_ll_set_rx_clk(hal->dev, &clk_set); +} + +void i2s_hal_set_rx_eof_num(i2s_hal_context_t *hal, uint32_t eof_byte) +{ + i2s_ll_set_rx_eof_num(hal->dev, eof_byte); +} + +void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal) +{ + i2s_ll_set_tx_slave_mod(hal->dev, 0); //TX master + i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave +} + +void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal) +{ + i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave + i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave +} + +#if SOC_I2S_SUPPORTS_PCM +void i2s_hal_tx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg) +{ + i2s_ll_tx_pcm_cfg(hal->dev, cfg); +} + +void i2s_hal_rx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg) +{ + i2s_ll_rx_pcm_cfg(hal->dev, cfg); +} +#endif + +void i2s_hal_enable_sig_loopback(i2s_hal_context_t *hal) +{ + i2s_ll_loop_back_ena(hal->dev, 1); +} + +#if SOC_I2S_SUPPORTS_PDM_TX +void i2s_hal_set_tx_pdm_fpfs(i2s_hal_context_t *hal, int fp, int fs) +{ + i2s_ll_set_tx_pdm_fpfs(hal->dev, fp, fs); +} + +void i2s_hal_get_tx_pdm_fpfs(i2s_hal_context_t *hal, int *fp, int *fs) +{ + i2s_ll_get_tx_pdm_fpfs(hal->dev, (uint32_t *)fp, (uint32_t *)fs); +} +#endif + +#if SOC_I2S_SUPPORTS_PDM_RX +void i2s_hal_set_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t dsr) +{ + i2s_ll_set_pdm_rx_dsr(hal->dev, dsr); +} + +void i2s_hal_get_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t *dsr) +{ + i2s_ll_get_pdm_rx_dsr(hal->dev, dsr); +} +#endif + +void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num) +{ + //Get hardware instance. + hal->dev = I2S_LL_GET_HW(i2s_num); +#if SOC_GDMA_SUPPORTED + hal->dma = &GDMA; + if (i2s_num == 0) { + hal->dma_ch = SOC_GDMA_I2S0_DMA_CHANNEL; + hal->dma_peri_sel = SOC_GDMA_TRIG_PERIPH_I2S0; + } +#if SOC_I2S_NUM > 1 + if (i2s_num == 1) { + hal->dma_ch = SOC_GDMA_I2S1_DMA_CHANNEL; + hal->dma_peri_sel = SOC_GDMA_TRIG_PERIPH_I2S1; + } +#endif + gdma_ll_enable_m2m_mode(hal->dma, hal->dma_ch, false); +#endif + i2s_ll_general_init(hal->dev); +} + +static void i2s_hal_format_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg) +{ + int active_slot_num = slot_ch_cfg & 0xffff; +#if !SOC_I2S_SUPPORTS_TDM + switch (format) { case I2S_COMM_FORMAT_STAND_MSB: - if (i2s_config->mode & I2S_MODE_TX) { + if (i2s_mode & I2S_MODE_TX) { i2s_ll_set_tx_format_msb_align(hal->dev); } - if (i2s_config->mode & I2S_MODE_RX) { + if (i2s_mode & I2S_MODE_RX) { i2s_ll_set_rx_format_msb_align(hal->dev); } break; case I2S_COMM_FORMAT_STAND_PCM_SHORT: - if (i2s_config->mode & I2S_MODE_TX) { - i2s_ll_set_tx_pcm_long(hal->dev); - } - if (i2s_config->mode & I2S_MODE_RX) { - i2s_ll_set_rx_pcm_long(hal->dev); - } - break; - case I2S_COMM_FORMAT_STAND_PCM_LONG: - if (i2s_config->mode & I2S_MODE_TX) { + if (i2s_mode & I2S_MODE_TX) { i2s_ll_set_tx_pcm_short(hal->dev); } - if (i2s_config->mode & I2S_MODE_RX) { + if (i2s_mode & I2S_MODE_RX) { i2s_ll_set_rx_pcm_short(hal->dev); } break; + case I2S_COMM_FORMAT_STAND_PCM_LONG: + if (i2s_mode & I2S_MODE_TX) { + i2s_ll_set_tx_pcm_long(hal->dev); + } + if (i2s_mode & I2S_MODE_RX) { + i2s_ll_set_rx_pcm_long(hal->dev); + } + break; default: //I2S_COMM_FORMAT_STAND_I2S - if (i2s_config->mode & I2S_MODE_TX) { + if (i2s_mode & I2S_MODE_TX) { i2s_ll_set_tx_format_philip(hal->dev); } - if (i2s_config->mode & I2S_MODE_RX) { + if (i2s_mode & I2S_MODE_RX) { i2s_ll_set_rx_format_philip(hal->dev); } break; } + if (active_slot_num == I2S_CHANNEL_MONO) { + if (i2s_mode & I2S_MODE_TX) { + i2s_ll_tx_mono_mode_ena(hal->dev, active_slot_num == I2S_CHANNEL_MONO); + } + if (i2s_mode & I2S_MODE_RX) { + i2s_ll_rx_mono_mode_ena(hal->dev, active_slot_num == I2S_CHANNEL_MONO); + } + } +#else + int data_bits = slot_bit_cfg & 0xffff; + int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT; + int slot_num = ((slot_ch_cfg >> SLOT_CH_SHIFT) == 0 || (active_slot_num == I2S_CHANNEL_MONO)) ? 2 : (slot_ch_cfg >> SLOT_CH_SHIFT); + bool msb_shift_en = false; + int tdm_ws_width = 0; + switch (format) { + case I2S_COMM_FORMAT_STAND_MSB: + msb_shift_en = false; + tdm_ws_width = slot_num*slot_bits/2; + break; + case I2S_COMM_FORMAT_STAND_PCM_SHORT: + msb_shift_en = false; + tdm_ws_width = 1; + break; + case I2S_COMM_FORMAT_STAND_PCM_LONG: + msb_shift_en = false; + tdm_ws_width = slot_bits; + break; + default: //I2S_COMM_FORMAT_STAND_I2S + msb_shift_en = true; + tdm_ws_width = slot_num*slot_bits/2; + break; + } + if (i2s_mode & I2S_MODE_TX) { + i2s_ll_tx_msb_shift_enable(hal->dev, msb_shift_en); + i2s_ll_set_tx_tdm_ws_width(hal->dev, tdm_ws_width); + i2s_ll_set_tx_half_sample_bit(hal->dev, slot_num*slot_bits/2); + } + if (i2s_mode & I2S_MODE_RX) { + i2s_ll_rx_msb_shift_enable(hal->dev, msb_shift_en); + i2s_ll_set_rx_tdm_ws_width(hal->dev, tdm_ws_width); + i2s_ll_set_rx_half_sample_bit(hal->dev, slot_num*slot_bits/2); + } +#endif } -void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config) +void i2s_hal_samples_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t communication_format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg) { - //reset i2s - i2s_ll_reset_tx(hal->dev); - i2s_ll_reset_rx(hal->dev); - - //reset dma - i2s_ll_reset_dma_in(hal->dev); - i2s_ll_reset_dma_out(hal->dev); - - i2s_ll_enable_dma(hal->dev); - - i2s_ll_set_lcd_en(hal->dev, 0); - i2s_ll_set_camera_en(hal->dev, 0); - - i2s_ll_set_dscr_en(hal->dev, 0); - - i2s_ll_set_tx_chan_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1)); // 0-two channel;1-right;2-left;3-righ;4-left - i2s_ll_set_tx_fifo_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1); // 0-right&left channel;1-one channel - i2s_ll_set_tx_mono(hal->dev, 0); - - i2s_ll_set_rx_chan_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1)); // 0-two channel;1-right;2-left;3-righ;4-left - i2s_ll_set_rx_fifo_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1); // 0-right&left channel;1-one channel - i2s_ll_set_rx_mono(hal->dev, 0); - - i2s_ll_set_dscr_en(hal->dev, 1); //connect dma to fifo - - i2s_ll_stop_tx(hal->dev); - i2s_ll_stop_rx(hal->dev); + int active_slot_num = slot_ch_cfg & 0xffff; + int data_bits = slot_bit_cfg & 0xffff; + int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT; + int slot_num = ((slot_ch_cfg >> SLOT_CH_SHIFT) == 0 || (active_slot_num == I2S_CHANNEL_MONO)) ? 2 : (slot_ch_cfg >> SLOT_CH_SHIFT); +#if SOC_I2S_SUPPORTS_TDM + if (i2s_mode & I2S_MODE_TX) { + i2s_ll_set_tx_slot_mun(hal->dev, slot_num); + i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits); + } + if (i2s_mode & I2S_MODE_RX) { + i2s_ll_set_rx_slot_mun(hal->dev, slot_num); + i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits); + } +#else + if (i2s_mode & I2S_MODE_TX) { + i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits); + } + if (i2s_mode & I2S_MODE_RX) { + i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits); + } +#endif + //I2S standards config: Philip, MSB or PCM, Only I2S mode should do this configuration. + if ((i2s_mode & (~(I2S_MODE_I2S))) == 0) { + i2s_hal_format_config(hal, i2s_mode, communication_format, slot_bit_cfg, slot_ch_cfg); + } +} +void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_param_t *i2s_config) +{ if (i2s_config->mode & I2S_MODE_TX) { - i2s_ll_set_tx_msb_right(hal->dev, 0); - i2s_ll_set_tx_right_first(hal->dev, 0); - - i2s_ll_set_tx_slave_mod(hal->dev, 0); // Master - i2s_ll_set_tx_fifo_mod_force_en(hal->dev, 1); - + i2s_ll_tx_gen_init(hal->dev); if (i2s_config->mode & I2S_MODE_SLAVE) { i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave } } - if (i2s_config->mode & I2S_MODE_RX) { - i2s_ll_set_rx_msb_right(hal->dev, 0); - i2s_ll_set_rx_right_first(hal->dev, 0); - i2s_ll_set_rx_slave_mod(hal->dev, 0); // Master - i2s_ll_set_rx_fifo_mod_force_en(hal->dev, 1); - + i2s_ll_rx_gen_init(hal->dev); if (i2s_config->mode & I2S_MODE_SLAVE) { i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave } } - -#if SOC_I2S_SUPPORTS_PDM - if (!(i2s_config->mode & I2S_MODE_PDM)) { - i2s_ll_set_rx_pdm_en(hal->dev, 0); - i2s_ll_set_tx_pdm_en(hal->dev, 0); - } else { - if (i2s_config->mode & I2S_MODE_TX) { - i2s_ll_tx_pdm_cfg(hal->dev, I2S_TX_PDM_FP_DEF, i2s_config->sample_rate/100); - } - if(i2s_config->mode & I2S_MODE_RX) { - i2s_ll_rx_pdm_cfg(hal->dev, I2S_RX_PDM_DSR_DEF); - } - // PDM mode have nothing to do with communication format configuration. - return; - } -#endif - #if SOC_I2S_SUPPORTS_ADC_DAC if (i2s_config->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { if (i2s_config->mode & I2S_MODE_DAC_BUILT_IN) { @@ -243,32 +304,54 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config } if (i2s_config->mode & I2S_MODE_ADC_BUILT_IN) { i2s_ll_build_in_adc_ena(hal->dev); - i2s_ll_set_rx_chan_mod(hal->dev, 1); - i2s_ll_set_rx_fifo_mod(hal->dev, 1); - i2s_ll_set_rx_mono(hal->dev, 0); } // Buildin ADC and DAC have nothing to do with communication format configuration. return; } #endif - i2s_hal_format_config(hal, i2s_config); -} +#if SOC_I2S_SUPPORTS_PDM + if (!(i2s_config->mode & I2S_MODE_PDM)) { +#if SOC_I2S_SUPPORTS_PDM_RX + if (i2s_config->mode & I2S_MODE_RX) { + i2s_ll_set_rx_pdm_en(hal->dev, false); + } +#endif +#if SOC_I2S_SUPPORTS_PDM_TX + if (i2s_config->mode & I2S_MODE_TX) { + i2s_ll_set_tx_pdm_en(hal->dev, false); + } +#endif + } else { +#if SOC_I2S_SUPPORTS_PDM_TX + if (i2s_config->mode & I2S_MODE_TX) { + i2s_ll_tx_pdm_cfg(hal->dev, i2s_config->sample_rate); + } +#endif -void i2s_hal_enable_master_mode(i2s_hal_context_t *hal) -{ - i2s_ll_set_tx_slave_mod(hal->dev, 0); //MASTER Slave - i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave -} +#if SOC_I2S_SUPPORTS_PDM_RX + if(i2s_config->mode & I2S_MODE_RX) { + i2s_ll_rx_pdm_cfg(hal->dev); + } +#endif + } +#endif -void i2s_hal_enable_slave_mode(i2s_hal_context_t *hal) -{ - i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave - i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave -} +#if SOC_I2S_SUPPORTS_TDM + if (i2s_config->mode & I2S_MODE_TX) { + i2s_ll_set_tx_active_slot_mask(hal->dev, i2s_config->active_slot_mask); + i2s_ll_tx_left_align_enable(hal->dev, i2s_config->left_align_en); + i2s_ll_tx_big_endian_enable(hal->dev, i2s_config->big_edin_en); + i2s_ll_tx_set_bit_order(hal->dev, i2s_config->bit_order_msb_en); + } + if (i2s_config->mode & I2S_MODE_RX) { + i2s_ll_set_rx_active_slot_mask(hal->dev, i2s_config->active_slot_mask); + i2s_ll_rx_left_align_enable(hal->dev, i2s_config->left_align_en); + i2s_ll_rx_big_endian_enable(hal->dev, i2s_config->big_edin_en); + i2s_ll_rx_set_bit_order(hal->dev, i2s_config->bit_order_msb_en); + } +#endif -void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num) -{ - //Get hardware instance. - hal->dev = I2S_LL_GET_HW(i2s_num); + //Configure I2S slot number,sample bit. + i2s_hal_samples_config(hal, i2s_config->mode, i2s_config->communication_format, i2s_config->slot_bits_cfg, i2s_config->slot_channel_cfg); } diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index 6964bfdf94..fab3a34ee2 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -1,4 +1,4 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -25,8 +25,11 @@ #include "soc/i2s_periph.h" #include "soc/soc_caps.h" -#include "hal/i2s_ll.h" #include "hal/i2s_types.h" +#include "hal/i2s_ll.h" +#if SOC_GDMA_SUPPORTED +#include "hal/gdma_ll.h" +#endif #ifdef __cplusplus extern "C" { @@ -37,162 +40,91 @@ extern "C" { */ typedef struct { i2s_dev_t *dev; +#if SOC_GDMA_SUPPORTED + gdma_dev_t *dma; + int dma_ch; + int dma_peri_sel; +#endif uint32_t version; } i2s_hal_context_t; -/** - * @brief Get I2S interrupt status - * - * @param hal Context of the HAL layer - * @param status interrupt status - */ -#define i2s_hal_get_intr_status(hal, status) i2s_ll_get_intr_status((hal)->dev, status) /** - * @brief Clear I2S interrupt status + * @brief Reset I2S TX channel * * @param hal Context of the HAL layer - * @param mask interrupt status mask */ -#define i2s_hal_clear_intr_status(hal, mask) i2s_ll_clear_intr_status((hal)->dev, mask) +void i2s_hal_reset_tx(i2s_hal_context_t *hal); /** - * @brief Get I2S out eof des address + * @brief Reset I2S TX fifo * * @param hal Context of the HAL layer - * @param addr out eof des address */ -#define i2s_hal_get_out_eof_des_addr(hal, addr) i2s_ll_get_out_eof_des_addr((hal)->dev, addr) +void i2s_hal_reset_tx_fifo(i2s_hal_context_t *hal); /** - * @brief Get I2S in eof des address + * @brief Reset I2S RX channel * * @param hal Context of the HAL layer - * @param addr in eof des address */ -#define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_get_in_eof_des_addr((hal)->dev, addr) +void i2s_hal_reset_rx(i2s_hal_context_t *hal); /** - * @brief Enable I2S rx interrupt + * @brief Reset I2S RX fifo * * @param hal Context of the HAL layer */ -#define i2s_hal_enable_rx_intr(hal) i2s_ll_enable_rx_intr((hal)->dev) +void i2s_hal_reset_rx_fifo(i2s_hal_context_t *hal); /** - * @brief Disable I2S rx interrupt + * @brief Init the I2S hal. This function should be called first before other hal layer function is called * * @param hal Context of the HAL layer + * @param i2s_num The uart port number, the max port number is (I2S_NUM_MAX -1) */ -#define i2s_hal_disable_rx_intr(hal) i2s_ll_disable_rx_intr((hal)->dev) +void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num); /** - * @brief Disable I2S tx interrupt + * @brief Configure I2S source clock * * @param hal Context of the HAL layer + * @param sel The source clock index */ -#define i2s_hal_disable_tx_intr(hal) i2s_ll_disable_tx_intr((hal)->dev) +void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel); /** - * @brief Enable I2S tx interrupt + * @brief Configure communication format * * @param hal Context of the HAL layer + * @param i2s_mode I2S mode. Using the ored mask of I2S_MODE_MASTER, I2S_MODE_SLAVE, I2S_MODE_TX, I2S_MODE_RX + * @param communication_format I2S communication format. Can be a value of `i2s_comm_format_t`. + * @param slot_bit_cfg I2S slot bit configuration + * @param slot_ch_cfg I2S slot channel configuration */ -#define i2s_hal_enable_tx_intr(hal) i2s_ll_enable_tx_intr((hal)->dev) +void i2s_hal_samples_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t communication_format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg); /** - * @brief Set I2S tx mode + * @brief Config I2S param * * @param hal Context of the HAL layer - * @param ch i2s channel - * @param bits bits per sample + * @param i2s_config I2S paramater configuration structer, refer to `i2s_config_param_t` */ -void i2s_hal_set_tx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits); +void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_param_t *i2s_config); /** - * @brief Set I2S rx mode + * @brief Enable I2S master full-duplex mode * * @param hal Context of the HAL layer - * @param ch i2s channel - * @param bits bits per sample */ -void i2s_hal_set_rx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits); +void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal); /** - * @brief Set I2S out link address - * - * @param hal Context of the HAL layer - * @param addr out link address - */ -#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr) - -/** - * @brief Set I2S out link address - * - * @param hal Context of the HAL layer - * @param addr out link address - */ -#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr) - -/** - * @brief Set I2S out link address - * - * @param hal Context of the HAL layer - * @param addr out link address - */ -#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr) - -/** - * @brief Set I2S in link - * - * @param hal Context of the HAL layer - * @param rx_eof_num in link eof num - * @param addr in link address - */ -void i2s_hal_set_in_link(i2s_hal_context_t *hal, uint32_t rx_eof_num, uint32_t addr); - -/** - * @brief Set I2S clk div - * - * @param hal Context of the HAL layer - * @param div_num i2s clkm div num - * @param div_a i2s clkm div a - * @param div_b i2s clkm div b - * @param tx_bck_div tx bck div num - * @param rx_bck_div rx bck div num - */ -void i2s_hal_set_clk_div(i2s_hal_context_t *hal, int div_num, int div_a, int div_b, int tx_bck_div, int rx_bck_div); - -/** - * @brief Set I2S clock sel - * - * @param hal Context of the HAL layer - * @param sel clock sel - */ -#define i2s_hal_set_clock_sel(hal, sel) i2s_ll_set_clk_sel((hal)->dev, sel) - -/** - * @brief Set I2S tx bits mod - * - * @param hal Context of the HAL layer - * @param bits bit width per sample. - */ -void i2s_hal_set_tx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits); - -/** - * @brief Set I2S rx bits mod - * - * @param hal Context of the HAL layer - * @param bits bit width per sample. - */ -void i2s_hal_set_rx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits); - -/** - * @brief Reset I2S TX & RX module, including DMA and FIFO + * @brief Enable I2S slave full-duplex mode * * @param hal Context of the HAL layer */ -void i2s_hal_reset(i2s_hal_context_t *hal); +void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal); /** * @brief Start I2S tx @@ -223,76 +155,256 @@ void i2s_hal_stop_tx(i2s_hal_context_t *hal); void i2s_hal_stop_rx(i2s_hal_context_t *hal); /** - * @brief Config I2S param + * @brief Set the received data length to trigger `in_suc_eof` interrupt. * * @param hal Context of the HAL layer - * @param i2s_config I2S configurations - see i2s_config_t struct + * @param eof_byte The byte length that trigger in_suc_eof interrupt. */ -void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config); +void i2s_hal_set_rx_eof_num(i2s_hal_context_t *hal, uint32_t eof_byte); /** - * @brief Enable I2S sig loopback + * @brief Set I2S TX sample bit * * @param hal Context of the HAL layer + * @param slot_bit I2S TX slot bit + * @param data_bit The sample data bit lengh. */ -#define i2s_hal_enable_sig_loopback(hal) i2s_ll_set_sig_loopback((hal)->dev, 1) +void i2s_hal_set_tx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit); /** - * @brief Enable I2S master mode + * @brief Set I2S RX sample bit * * @param hal Context of the HAL layer + * @param slot_bit I2S RX slot bit + * @param data_bit The sample data bit lengh. */ -void i2s_hal_enable_master_mode(i2s_hal_context_t *hal); +void i2s_hal_set_rx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit); /** - * @brief Enable I2S slave mode + * @brief Configure I2S TX module clock devider * * @param hal Context of the HAL layer + * @param sclk I2S source clock freq + * @param fbck I2S bck freq + * @param factor bck factor, factor=sclk/fbck */ -void i2s_hal_enable_slave_mode(i2s_hal_context_t *hal); +void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor); /** - * @brief Init the I2S hal and set the I2S to the default configuration. This function should be called first before other hal layer function is called + * @brief Configure I2S RX module clock devider * * @param hal Context of the HAL layer - * @param i2s_num The uart port number, the max port number is (I2S_NUM_MAX -1) + * @param sclk I2S source clock freq + * @param fbck I2S bck freq + * @param factor bck factor, factor=sclk/fbck */ -void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num); +void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor); -#if SOC_I2S_SUPPORTS_PDM +#if SOC_I2S_SUPPORTS_PCM /** - * @brief Set I2S tx pdm + * @brief Configure I2S TX PCM encoder or decoder. * * @param hal Context of the HAL layer - * @param fp tx pdm fp - * @param fs tx pdm fs + * @param cfg PCM configure paramater, refer to `i2s_pcm_cfg_t` */ -void i2s_hal_tx_pdm_cfg(i2s_hal_context_t *hal, uint32_t fp, uint32_t fs); +void i2s_hal_tx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg); /** - * @brief Get I2S tx pdm + * @brief Configure I2S RX PCM encoder or decoder. * * @param hal Context of the HAL layer - * @param dsr rx pdm dsr + * @param cfg PCM configure paramater, refer to `i2s_pcm_cfg_t` */ -void i2s_hal_rx_pdm_cfg(i2s_hal_context_t *hal, uint32_t dsr); +void i2s_hal_rx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg); +#endif /** - * @brief Get I2S tx pdm configuration + * @brief Enable loopback mode * * @param hal Context of the HAL layer - * @param fp Pointer to receive tx PDM fp configuration - * @param fs Pointer to receive tx PDM fs configuration */ -void i2s_hal_get_tx_pdm(i2s_hal_context_t *hal, uint32_t *fp, uint32_t *fs); +void i2s_hal_enable_sig_loopback(i2s_hal_context_t *hal); + +#if SOC_I2S_SUPPORTS_PDM_TX +/** + * @brief Configure I2S TX PDM sample rate + * Fpdm = 64*Fpcm*fp/fs + * + * @param hal Context of the HAL layer + * @param fp TX PDM fp paramater configuration + * @param fs TX PDM fs paramater configuration + */ +void i2s_hal_set_tx_pdm_fpfs(i2s_hal_context_t *hal, int fp, int fs); /** - * @brief Get I2S rx pdm configuration + * @brief Get I2S TX PDM configuration * * @param hal Context of the HAL layer - * @param dsr rx pdm dsr + * @param fp Pointer to accept TX PDM fp paramater configuration + * @param fs Pointer to accept TX PDM fs paramater configuration */ -void i2s_hal_get_rx_pdm(i2s_hal_context_t *hal, uint32_t *dsr); +void i2s_hal_get_tx_pdm_fpfs(i2s_hal_context_t *hal, int *fp, int *fs); +#endif + +#if SOC_I2S_SUPPORTS_PDM_RX + +/** + * @brief Configure RX PDM downsample + * + * @param hal Context of the HAL layer + * @param dsr PDM downsample configuration paramater + */ +void i2s_hal_set_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t dsr); + +/** + * @brief Get RX PDM downsample configuration + * + * @param hal Context of the HAL layer + * @param dsr Pointer to accept PDM downsample configuration + */ +void i2s_hal_get_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t *dsr); +#endif + +#if !SOC_GDMA_SUPPORTED +/** + * @brief Enable I2S TX DMA + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_attach_tx_dma(hal) i2s_ll_dma_enable((hal)->dev,true) + +/** + * @brief Enable I2S RX DMA + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_attach_rx_dma(hal) i2s_ll_dma_enable((hal)->dev,true) + +/** + * @brief Get I2S interrupt status + * + * @param hal Context of the HAL layer + * @param status Pointer to accept I2S interrupt status + */ +#define i2s_hal_get_intr_status(hal, status) i2s_ll_get_intr_status((hal)->dev, status) + +/** + * @brief Get I2S interrupt status + * + * @param hal Context of the HAL layer + * @param mask Interrupt mask to be cleared. + */ +#define i2s_hal_clear_intr_status(hal, mask) i2s_ll_clear_intr_status((hal)->dev, mask) + +/** + * @brief Enable I2S RX interrupt + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_enable_rx_intr(hal) i2s_ll_enable_rx_intr((hal)->dev) + +/** + * @brief Disable I2S RX interrupt + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_disable_rx_intr(hal) i2s_ll_disable_rx_intr((hal)->dev) + +/** + * @brief Disable I2S TX interrupt + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_disable_tx_intr(hal) i2s_ll_disable_tx_intr((hal)->dev) + +/** + * @brief Enable I2S TX interrupt + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_enable_tx_intr(hal) i2s_ll_enable_tx_intr((hal)->dev) + +/** + * @brief Configure TX DMA descriptor address and start TX DMA + * + * @param hal Context of the HAL layer + * @param link_addr DMA descriptor link address. + */ +#define i2s_hal_start_tx_link(hal, link_addr) i2s_ll_start_tx_link((hal)->dev, link_addr) + +/** + * @brief Configure RX DMA descriptor address and start RX DMA + * + * @param hal Context of the HAL layer + * @param link_addr DMA descriptor link address. + */ +#define i2s_hal_start_rx_link(hal, link_addr) i2s_ll_start_rx_link((hal)->dev, link_addr) + +/** + * @brief Stop TX DMA link + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_stop_tx_link(hal) i2s_ll_stop_out_link((hal)->dev) + +/** + * @brief Stop RX DMA link + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_stop_rx_link(hal) i2s_ll_stop_in_link((hal)->dev) + +/** + * @brief Reset RX DMA + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_reset_rxdma(hal) i2s_ll_reset_dma_in((hal)->dev) + +/** + * @brief Reset TX DMA + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_reset_txdma(hal) i2s_ll_reset_dma_out((hal)->dev) + +/** + * @brief Get I2S out eof descriptor address + * + * @param hal Context of the HAL layer + * @param addr Pointer to accept out eof des address + */ +#define i2s_hal_get_out_eof_des_addr(hal, addr) i2s_ll_get_out_eof_des_addr((hal)->dev, addr) + +/** + * @brief Get I2S in suc eof descriptor address + * + * @param hal Context of the HAL layer + * @param addr Pointer to accept in suc eof des address + */ +#define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_get_in_eof_des_addr((hal)->dev, addr) +#else +#define i2s_hal_attach_tx_dma(hal) gdma_ll_tx_connect_to_periph((hal)->dma, (hal)->dma_ch, (hal)->dma_peri_sel) +#define i2s_hal_attach_rx_dma(hal) gdma_ll_rx_connect_to_periph((hal)->dma, (hal)->dma_ch, (hal)->dma_peri_sel) +#define i2s_hal_get_intr_status(hal, status) (*status = (gdma_ll_get_interrupt_status((hal)->dma, (hal)->dma_ch))) +#define i2s_hal_clear_intr_status(hal, mask) gdma_ll_clear_interrupt_status((hal)->dma, (hal)->dma_ch, mask) +#define i2s_hal_enable_rx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_IN_DSCR_ERR|I2S_INTR_IN_SUC_EOF, 1) +#define i2s_hal_disable_rx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_IN_DSCR_ERR|I2S_INTR_IN_SUC_EOF, 0) +#define i2s_hal_enable_tx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_OUT_DSCR_ERR|I2S_INTR_OUT_EOF, 1) +#define i2s_hal_disable_tx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_OUT_DSCR_ERR|I2S_INTR_OUT_EOF, 0) +#define i2s_hal_start_tx_link(hal, link_addr) do{\ + gdma_ll_tx_set_desc_addr((hal)->dma,(hal)->dma_ch,link_addr);\ + gdma_ll_tx_start((hal)->dma,(hal)->dma_ch);}while(0) +#define i2s_hal_start_rx_link(hal, link_addr) do{\ + gdma_ll_rx_set_desc_addr((hal)->dma,(hal)->dma_ch,link_addr);\ + gdma_ll_rx_start((hal)->dma,(hal)->dma_ch);}while(0) + +#define i2s_hal_stop_tx_link(hal) gdma_ll_tx_stop((hal)->dma,(hal)->dma_ch) +#define i2s_hal_stop_rx_link(hal) gdma_ll_rx_stop((hal)->dma, (hal)->dma_ch) +#define i2s_hal_reset_rxdma(hal) gdma_ll_rx_reset_channel((hal)->dma, (hal)->dma_ch) +#define i2s_hal_reset_txdma(hal) gdma_ll_tx_reset_channel((hal)->dma, (hal)->dma_ch) +#define i2s_hal_get_out_eof_des_addr(hal, addr) (*addr = (gdma_ll_tx_get_eof_desc_addr((hal)->dma, (hal)->dma_ch))) +#define i2s_hal_get_in_eof_des_addr(hal, addr) (*addr = (gdma_ll_rx_get_success_eof_desc_addr((hal)->dma, (hal)->dma_ch))) #endif #ifdef __cplusplus diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index ba150cc7b3..e9d0fac8e4 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ #include #include +#include #include #include "soc/soc_caps.h" @@ -39,12 +40,47 @@ typedef enum { * */ typedef enum { - I2S_BITS_PER_SAMPLE_8BIT = 8, /*!< I2S bits per sample: 8-bits*/ - I2S_BITS_PER_SAMPLE_16BIT = 16, /*!< I2S bits per sample: 16-bits*/ - I2S_BITS_PER_SAMPLE_24BIT = 24, /*!< I2S bits per sample: 24-bits*/ - I2S_BITS_PER_SAMPLE_32BIT = 32, /*!< I2S bits per sample: 32-bits*/ + I2S_BITS_PER_SAMPLE_8BIT = 8, + I2S_BITS_PER_SAMPLE_16BIT = 16, + I2S_BITS_PER_SAMPLE_24BIT = 24, + I2S_BITS_PER_SAMPLE_32BIT = 32, } i2s_bits_per_sample_t; +/** + * @brief I2S bit width per slot. + * + */ +typedef enum { + I2S_BITS_PER_SLOT_8BIT = (8), /*!< slot bit 8*/ + I2S_BITS_PER_SLOT_16BIT = (16), /*!< slot bit 16*/ + I2S_BITS_PER_SLOT_24BIT = (24), /*!< slot bit 24*/ + I2S_BITS_PER_SLOT_32BIT = (32), /*!< slot bit 32*/ + I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU = (0), /*!< slot bit equals to data bit*/ +} i2s_bits_per_slot_t; + +#define SLOT_BIT_SHIFT (16) //slot bit shift +#define SLOT_CH_SHIFT (16) //slot channel shift + +/** + * @brief I2S slot bit configuration paramater. The low 16bit is the audio_data_bit_width and the high 16bit is the slot_bit_width. + * e.g.: If set to (I2S_BITS_PER_SLOT_24BIT << SLOT_BIT_SHIFT) | I2S_BITS_PER_SAMPLE_16BIT, the audio data bit is 16bit and the slot bit is 24bit. + * + * + * @note: If the slot_bit_width is set to `I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU`, then the slot_bit_width equals to audio_data_bit_width. + * + */ +typedef uint32_t i2s_slot_bits_cfg_t; /*!< slot bit configuration*/ + +/** + * @brief I2S slot channel configuration paramater. The low 16bit is the active_slot_number and the high 16bit is the total_slot_num. + * The audio data only launch in active slot, otherwise, launch 0 or single data in inactive slot. + * e.g.: If set to (4 << SLOT_CH_SHIFT) | 2, the active_slot_number is 2 and the total_slot_num 4. + * + * @note: If the total_slot_num is set to 0, then the total_slot_num equals to active_slot_number. + * + */ +typedef uint32_t i2s_slot_channel_cfg_t; /*!< slot channel configuration*/ + /** * @brief I2S channel. * @@ -54,25 +90,46 @@ typedef enum { I2S_CHANNEL_STEREO = 2 /*!< I2S 2 channel (stereo)*/ } i2s_channel_t; + +#if SOC_I2S_SUPPORTS_TDM +/** + * @brief Bit map of active slot. + * For TX module, only the active slot send the audio data, the inactive slot send a constant(configurable). + * For RX module, only receive the audio data in active slot, the data in inactive slot will be ignored. + * + * @note the bit map of active slot can not exceed (0x1< 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/ -} i2s_config_t; - -/** - * @brief I2S event types - * - */ -typedef enum { - I2S_EVENT_DMA_ERROR, - I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/ - I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/ - I2S_EVENT_MAX, /*!< I2S event max index*/ -} i2s_event_type_t; +#if SOC_I2S_SUPPORTS_TDM + i2s_slot_channel_cfg_t slot_channel_cfg; /*!< slot number configuration, low 16bit is the valid slot number; high 16bit is the total slot number, if set to 0, total slot number equals to valid slot number*/ + uint32_t active_slot_mask; /*!< active slot bit mask, using the ored mask of `i2s_tdm_active_slot_t`*/ + bool left_align_en; /*!< Set to enable left aligment*/ + bool big_edin_en; /*!< Set to enable big edin*/ + bool bit_order_msb_en; /*!< Set to enable msb order*/ +#endif +} i2s_config_param_t; #if SOC_I2S_SUPPORTS_ADC_DAC /** * @brief I2S DAC mode for i2s_set_dac_mode. * - * @note PDM and built-in DAC functions are only supported on I2S0 for current ESP32 chip. + * @note Built-in DAC functions are only supported on I2S0 for current ESP32 chip. */ typedef enum { I2S_DAC_CHANNEL_DISABLE = 0, /*!< Disable I2S built-in DAC signals*/ @@ -159,15 +206,6 @@ typedef enum { } i2s_dac_mode_t; #endif //SOC_I2S_SUPPORTS_ADC_DAC -/** - * @brief Event structure used in I2S event queue - * - */ -typedef struct { - i2s_event_type_t type; /*!< I2S event type */ - size_t size; /*!< I2S data size for I2S_DATA event*/ -} i2s_event_t; - /** * @brief I2S pin number for i2s_set_pin * @@ -179,7 +217,21 @@ typedef struct { int data_in_num; /*!< DATA in pin*/ } i2s_pin_config_t; -#if SOC_I2S_SUPPORTS_PDM +#if SOC_I2S_SUPPORTS_PCM +/** + * @brief A/U-law decompress or compress configuration. + * + */ +typedef enum { + I2S_PCM_A_DECOMPRESS=0, /*!< A-law decompress*/ + I2S_PCM_A_COMPRESS, /*!< A-law compress*/ + I2S_PCM_U_DECOMPRESS, /*!< U-law decompress*/ + I2S_PCM_U_COMPRESS, /*!< U-law compress*/ + I2S_PCM_DISABLE, /*!< Disable A/U law decopress or compress*/ +} i2s_pcm_cfg_t; +#endif + +#if SOC_I2S_SUPPORTS_PDM_RX /** * @brief I2S PDM RX downsample mode */ @@ -188,7 +240,9 @@ typedef enum { I2S_PDM_DSR_16S, /*!< downsampling number is 16 for PDM RX mode*/ I2S_PDM_DSR_MAX, } i2s_pdm_dsr_t; +#endif +#if SOC_I2S_SUPPORTS_PDM /** * @brief PDM PCM convter enable/disable. * diff --git a/components/soc/esp32/i2s_periph.c b/components/soc/esp32/i2s_periph.c index 84985aaf6a..f7a3c8ebc6 100644 --- a/components/soc/esp32/i2s_periph.c +++ b/components/soc/esp32/i2s_periph.c @@ -1,9 +1,9 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at - +// // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -20,30 +20,22 @@ */ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { { - .o_bck_in_sig = I2S0O_BCK_IN_IDX, - .o_ws_in_sig = I2S0O_WS_IN_IDX, - .o_bck_out_sig = I2S0O_BCK_OUT_IDX, - .o_ws_out_sig = I2S0O_WS_OUT_IDX, - .o_data_out_sig = I2S0O_DATA_OUT23_IDX, - .i_bck_in_sig = I2S0I_BCK_OUT_IDX, - .i_ws_in_sig = I2S0I_WS_OUT_IDX, - .i_bck_out_sig = I2S0I_BCK_IN_IDX, - .i_ws_out_sig = I2S0I_WS_IN_IDX, - .i_data_in_sig = I2S0I_DATA_IN15_IDX, + .rx_bck_sig = I2S0I_BCK_IN_IDX, + .tx_bck_sig = I2S0O_BCK_OUT_IDX, + .tx_ws_sig = I2S0O_WS_OUT_IDX, + .rx_ws_sig = I2S0I_WS_IN_IDX, + .data_out_sig = I2S0O_DATA_OUT23_IDX, + .data_in_sig = I2S0I_DATA_IN15_IDX, .irq = ETS_I2S0_INTR_SOURCE, .module = PERIPH_I2S0_MODULE, }, { - .o_bck_in_sig = I2S1O_BCK_IN_IDX, - .o_ws_in_sig = I2S1O_WS_IN_IDX, - .o_bck_out_sig = I2S1O_BCK_OUT_IDX, - .o_ws_out_sig = I2S1O_WS_OUT_IDX, - .o_data_out_sig = I2S1O_DATA_OUT23_IDX, - .i_bck_in_sig = I2S1I_BCK_OUT_IDX, - .i_ws_in_sig = I2S1I_WS_OUT_IDX, - .i_bck_out_sig = I2S1I_BCK_IN_IDX, - .i_ws_out_sig = I2S1I_WS_IN_IDX, - .i_data_in_sig = I2S1I_DATA_IN15_IDX, + .rx_bck_sig = I2S1I_BCK_IN_IDX, + .tx_bck_sig = I2S1O_BCK_OUT_IDX, + .tx_ws_sig = I2S1O_WS_OUT_IDX, + .rx_ws_sig = I2S1I_WS_IN_IDX, + .data_out_sig = I2S1O_DATA_OUT23_IDX, + .data_in_sig = I2S1I_DATA_IN15_IDX, .irq = ETS_I2S1_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, } diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index dd6f994b1a..a4c2a5c07e 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -136,12 +136,12 @@ /*-------------------------- I2S CAPS ----------------------------------------*/ // ESP32 have 2 I2S #define SOC_I2S_NUM (2) - -#define SOC_I2S_SUPPORTS_PDM (1) // ESP32 support PDM +#define SOC_I2S_SUPPORTS_PDM_TX (1) +#define SOC_I2S_SUPPORTS_PDM_RX (1) +#define SOC_I2S_SUPPORTS_PDM (1) // (SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) #define SOC_I2S_SUPPORTS_ADC_DAC (1) // ESP32 support ADC and DAC -#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated - +#define SOC_I2S_SUPPORTS_APLL (1)// ESP32 support APLL #define SOC_I2S_APLL_MIN_FREQ (250000000) #define SOC_I2S_APLL_MAX_FREQ (500000000) #define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware diff --git a/components/soc/esp32c3/i2s_periph.c b/components/soc/esp32c3/i2s_periph.c index b20ff7fbf8..4a19e3972a 100644 --- a/components/soc/esp32c3/i2s_periph.c +++ b/components/soc/esp32c3/i2s_periph.c @@ -20,19 +20,13 @@ */ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { { - // TODO ESP32-C3 IDF-2098 - - // .o_bck_in_sig = I2S0O_BCK_IN_IDX, - // .o_ws_in_sig = I2S0O_WS_IN_IDX, - // .o_bck_out_sig = I2S0O_BCK_OUT_IDX, - // .o_ws_out_sig = I2S0O_WS_OUT_IDX, - // .o_data_out_sig = I2S0O_SD_OUT_IDX, - // .i_bck_in_sig = I2S0I_BCK_OUT_IDX, - // .i_ws_in_sig = I2S0I_WS_OUT_IDX, - // .i_bck_out_sig = I2S0I_BCK_IN_IDX, - // .i_ws_out_sig = I2S0I_WS_IN_IDX, - // .i_data_in_sig = I2S0I_SD_IN_IDX, - .irq = ETS_I2S1_INTR_SOURCE, + .rx_bck_sig = I2SI_BCK_IN_IDX, + .tx_bck_sig = I2SO_BCK_OUT_IDX, + .tx_ws_sig = I2SO_WS_OUT_IDX, + .rx_ws_sig = I2SI_WS_IN_IDX, + .data_out_sig = I2SO_SD_OUT_IDX, + .data_in_sig = I2SI_SD_IN_IDX, + .irq = ETS_DMA_CH0_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32c3/ld/esp32c3.peripherals.ld b/components/soc/esp32c3/ld/esp32c3.peripherals.ld index 494cbb9b6b..710ae9aeea 100644 --- a/components/soc/esp32c3/ld/esp32c3.peripherals.ld +++ b/components/soc/esp32c3/ld/esp32c3.peripherals.ld @@ -7,7 +7,7 @@ PROVIDE ( SIGMADELTA = 0x60004f00 ); PROVIDE ( RTCCNTL = 0x60008000 ); PROVIDE ( RTCIO = 0x60008400 ); PROVIDE ( HINF = 0x6000B000 ); -PROVIDE ( I2S1 = 0x6002d000 ); +PROVIDE ( I2S0 = 0x6002d000 ); PROVIDE ( I2C0 = 0x60013000 ); PROVIDE ( UHCI0 = 0x60014000 ); PROVIDE ( UHCI1 = 0x6000c000 ); diff --git a/components/soc/esp32s2/i2s_periph.c b/components/soc/esp32s2/i2s_periph.c index 5029a68c8a..e4cfd8b976 100644 --- a/components/soc/esp32s2/i2s_periph.c +++ b/components/soc/esp32s2/i2s_periph.c @@ -1,9 +1,9 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at - +// // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -20,16 +20,12 @@ */ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { { - .o_bck_in_sig = I2S0O_BCK_IN_IDX, - .o_ws_in_sig = I2S0O_WS_IN_IDX, - .o_bck_out_sig = I2S0O_BCK_OUT_IDX, - .o_ws_out_sig = I2S0O_WS_OUT_IDX, - .o_data_out_sig = I2S0O_DATA_OUT23_IDX, - .i_bck_in_sig = I2S0I_BCK_OUT_IDX, - .i_ws_in_sig = I2S0I_WS_OUT_IDX, - .i_bck_out_sig = I2S0I_BCK_IN_IDX, - .i_ws_out_sig = I2S0I_WS_IN_IDX, - .i_data_in_sig = I2S0I_DATA_IN15_IDX, + .rx_bck_sig = I2S0I_BCK_IN_IDX, + .tx_bck_sig = I2S0O_BCK_OUT_IDX, + .tx_ws_sig = I2S0O_WS_OUT_IDX, + .rx_ws_sig = I2S0I_WS_IN_IDX, + .data_out_sig = I2S0O_DATA_OUT23_IDX, + .data_in_sig = I2S0I_DATA_IN15_IDX, .irq = ETS_I2S0_INTR_SOURCE, .module = PERIPH_I2S0_MODULE, } diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 0f633b8ef7..30b85dc4b2 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -135,13 +135,9 @@ #define SOC_I2C_SUPPORT_APB (1) /*-------------------------- I2S CAPS ----------------------------------------*/ -// ESP32-S2 have 2 I2S +// ESP32-S2 have 1 I2S #define SOC_I2S_NUM (1) - -#define SOC_I2S_SUPPORTS_DMA_EQUAL (1) // ESP32-S2 need dma equal - -#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated - +#define SOC_I2S_SUPPORTS_APLL (1)// ESP32-S2 support APLL #define SOC_I2S_APLL_MIN_FREQ (250000000) #define SOC_I2S_APLL_MAX_FREQ (500000000) #define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware diff --git a/components/soc/esp32s3/i2s_periph.c b/components/soc/esp32s3/i2s_periph.c index 52f714edf7..3d4a7cd6ef 100644 --- a/components/soc/esp32s3/i2s_periph.c +++ b/components/soc/esp32s3/i2s_periph.c @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,17 +20,23 @@ */ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { { - .o_bck_in_sig = I2S0O_BCK_IN_IDX, - .o_ws_in_sig = I2S0O_WS_IN_IDX, - .o_bck_out_sig = I2S0O_BCK_OUT_IDX, - .o_ws_out_sig = I2S0O_WS_OUT_IDX, - .o_data_out_sig = I2S0O_SD_OUT_IDX, - .i_bck_in_sig = I2S0I_BCK_OUT_IDX, - .i_ws_in_sig = I2S0I_WS_OUT_IDX, - .i_bck_out_sig = I2S0I_BCK_IN_IDX, - .i_ws_out_sig = I2S0I_WS_IN_IDX, - .i_data_in_sig = I2S0I_SD_IN_IDX, - .irq = ETS_I2S0_INTR_SOURCE, + .rx_bck_sig = I2S0I_BCK_IN_IDX, + .tx_bck_sig = I2S0O_BCK_OUT_IDX, + .tx_ws_sig = I2S0O_WS_OUT_IDX, + .rx_ws_sig = I2S0I_WS_IN_IDX, + .data_out_sig = I2S0O_SD_OUT_IDX, + .data_in_sig = I2S0I_SD_IN_IDX, + .irq = ETS_DMA_CH0_INTR_SOURCE, .module = PERIPH_I2S0_MODULE, + }, + { + .rx_bck_sig = I2S1I_BCK_IN_IDX, + .tx_bck_sig = I2S1O_BCK_OUT_IDX, + .tx_ws_sig = I2S1O_WS_OUT_IDX, + .rx_ws_sig = I2S1I_WS_IN_IDX, + .data_out_sig = I2S1O_SD_OUT_IDX, + .data_in_sig = I2S1I_SD_IN_IDX, + .irq = ETS_DMA_CH3_INTR_SOURCE, + .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32s3/include/soc/i2s_caps.h b/components/soc/esp32s3/include/soc/i2s_caps.h deleted file mode 100644 index cd21be8893..0000000000 --- a/components/soc/esp32s3/include/soc/i2s_caps.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#define SOC_I2S_APLL_MIN_FREQ (250000000) -#define SOC_I2S_APLL_MAX_FREQ (500000000) -#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware -#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated - -// ESP32-S3 have 1 I2S -#define SOC_I2S_NUM (1) diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 40942446cc..b570069965 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -63,7 +63,12 @@ #include "i2c_caps.h" /*-------------------------- I2S CAPS ----------------------------------------*/ -#include "i2s_caps.h" +#define SOC_I2S_NUM (2) +#define SOC_I2S_SUPPORTS_PCM (1) +#define SOC_I2S_SUPPORTS_PDM_TX (0) +#define SOC_I2S_SUPPORTS_PDM_RX (1) +#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) +#define SOC_I2S_SUPPORTS_TDM (1) /*-------------------------- LEDC CAPS ---------------------------------------*/ #include "ledc_caps.h" diff --git a/components/soc/esp32s3/ld/esp32s3.peripherals.ld b/components/soc/esp32s3/ld/esp32s3.peripherals.ld index 5b15a44618..bae22f0205 100644 --- a/components/soc/esp32s3/ld/esp32s3.peripherals.ld +++ b/components/soc/esp32s3/ld/esp32s3.peripherals.ld @@ -8,6 +8,7 @@ PROVIDE ( RTCIO = 0x60008400 ); PROVIDE ( SENS = 0x60008800 ); PROVIDE ( HINF = 0x6000B000 ); PROVIDE ( I2S0 = 0x6000F000 ); +PROVIDE ( I2S1 = 0x6002D000 ); PROVIDE ( UART1 = 0x60010000 ); PROVIDE ( I2C0 = 0x60013000 ); PROVIDE ( UHCI0 = 0x60014000 ); diff --git a/components/soc/include/soc/i2s_periph.h b/components/soc/include/soc/i2s_periph.h index a2b9c54274..1c3248e4ff 100644 --- a/components/soc/include/soc/i2s_periph.h +++ b/components/soc/include/soc/i2s_periph.h @@ -1,4 +1,4 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -27,16 +27,12 @@ extern "C" { Stores a bunch of per-I2S-peripheral data. */ typedef struct { - const uint8_t o_bck_in_sig; - const uint8_t o_ws_in_sig; - const uint8_t o_bck_out_sig; - const uint8_t o_ws_out_sig; - const uint8_t o_data_out_sig; - const uint8_t i_bck_in_sig; - const uint8_t i_ws_in_sig; - const uint8_t i_bck_out_sig; - const uint8_t i_ws_out_sig; - const uint8_t i_data_in_sig; + const uint8_t tx_bck_sig; + const uint8_t rx_bck_sig; + const uint8_t tx_ws_sig; + const uint8_t rx_ws_sig; + const uint8_t data_out_sig; + const uint8_t data_in_sig; const uint8_t irq; const periph_module_t module; } i2s_signal_conn_t; diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index feb582dc25..cef7378ad2 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -75,11 +75,13 @@ Configuration example: static const int i2s_num = 0; // i2s port number static const i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = 44100, - .bits_per_sample = 16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = 44100, + .slot_bits_cfg = 16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, + }, .intr_alloc_flags = 0, // default interrupt priority .dma_buf_count = 8, .dma_buf_len = 64, @@ -154,11 +156,13 @@ I2S configuration static const int i2s_num = 0; // i2s port number static const i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = 44100, - .bits_per_sample = 16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = 44100, + .slot_bits_cfg = 16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, + }, .intr_alloc_flags = 0, // default interrupt priority .dma_buf_count = 8, .dma_buf_len = 64, @@ -194,10 +198,12 @@ Configuring I2S to use internal DAC for analog output static const int i2s_num = 0; // i2s port number static const i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, - .sample_rate = 44100, - .bits_per_sample = 16, /* the DAC module will only take the 8bits from MSB */ - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, + .sample_rate = 44100, + .slot_bits_cfg = 16, /* the DAC module will only take the 8bits from MSB */ + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + }, .intr_alloc_flags = 0, // default interrupt priority .dma_buf_count = 8, .dma_buf_len = 64, diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c index c6b37034d9..fc6530d68e 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c @@ -53,15 +53,25 @@ void app_main(void) ESP_ERROR_CHECK(err); i2s_config_t i2s_config = { + .param_cfg = { #ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, #else - .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX + .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX #endif - .sample_rate = 44100, - .bits_per_sample = 16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = I2S_COMM_FORMAT_STAND_MSB, + .sample_rate = 44100, + .slot_bits_cfg = 16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = I2S_COMM_FORMAT_STAND_MSB, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, + .dma_buf_count = 6, .dma_buf_len = 60, .intr_alloc_flags = 0, //Default interrupt priority diff --git a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c index 82b3390f95..fd4db45b2e 100644 --- a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c +++ b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c @@ -684,15 +684,24 @@ void app_main(void) ESP_ERROR_CHECK(err); i2s_config_t i2s_config = { + .param_cfg = { #ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, #else - .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX + .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX #endif - .communication_format = I2S_COMM_FORMAT_STAND_MSB, - .sample_rate = 44100, - .bits_per_sample = 16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = I2S_COMM_FORMAT_STAND_MSB, + .sample_rate = 44100, + .slot_bits_cfg = 16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 60, .intr_alloc_flags = 0, //Default interrupt priority diff --git a/examples/peripherals/i2s/i2s_adc_dac/main/app_main.c b/examples/peripherals/i2s/i2s_adc_dac/main/app_main.c index 8d5f20db86..b7f00fa1ad 100644 --- a/examples/peripherals/i2s/i2s_adc_dac/main/app_main.c +++ b/examples/peripherals/i2s/i2s_adc_dac/main/app_main.c @@ -63,11 +63,13 @@ void example_i2s_init(void) { int i2s_num = EXAMPLE_I2S_NUM; i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN, - .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, - .bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS, - .communication_format = I2S_COMM_FORMAT_STAND_MSB, - .channel_format = EXAMPLE_I2S_FORMAT, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN, + .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, + .slot_bits_cfg = EXAMPLE_I2S_SAMPLE_BITS, + .communication_format = I2S_COMM_FORMAT_STAND_MSB, + .channel_format = EXAMPLE_I2S_FORMAT, + }, .intr_alloc_flags = 0, .dma_buf_count = 2, .dma_buf_len = 1024, diff --git a/examples/peripherals/i2s/i2s_basic/main/i2s_example_main.c b/examples/peripherals/i2s/i2s_basic/main/i2s_example_main.c index 0eca7953df..00c0d62013 100644 --- a/examples/peripherals/i2s/i2s_basic/main/i2s_example_main.c +++ b/examples/peripherals/i2s/i2s_basic/main/i2s_example_main.c @@ -87,11 +87,20 @@ void app_main(void) //if 2-channels, 16-bit each channel, total buffer is 360*4 = 1440 bytes //if 2-channels, 24/32-bit each channel, total buffer is 360*8 = 2880 bytes i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX - .sample_rate = SAMPLE_RATE, - .bits_per_sample = 16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = I2S_COMM_FORMAT_STAND_MSB, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = (I2S_BITS_PER_SLOT_16BIT << SLOT_BIT_SHIFT) | I2S_BITS_PER_SAMPLE_16BIT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_MSB, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 60, .use_apll = false, From f7f8c9c11fa7caeb51b3d728897f69b81fde79cc Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 15 Jun 2021 15:43:03 +0800 Subject: [PATCH 2/5] driver/i2s: support i2s on c3 and s3 1. Support i2s on esp32c3 and esp32s3 2. Refactor i2s_config_t to avoid breaking change 2. Fix a bug that receiving unavailable values from message queue when dma queue has been re-allocted 4. Support i2s unit test on esp32c3 and esp32s3 --- components/driver/i2s.c | 1030 ++++++++++------- components/driver/include/driver/i2s.h | 85 +- .../driver/test/adc_dma_test/test_esp32.c | 10 +- .../driver/test/dac_dma_test/test_esp32.c | 10 +- components/driver/test/test_i2s.c | 375 +++--- .../private_include/esp_efuse_utility.h | 10 - components/hal/esp32/include/hal/i2s_ll.h | 139 +-- components/hal/esp32c3/include/hal/i2s_ll.h | 204 ++-- components/hal/esp32s2/include/hal/i2s_ll.h | 137 +-- components/hal/esp32s3/include/hal/i2s_ll.h | 275 +++-- components/hal/i2s_hal.c | 421 +++---- components/hal/include/hal/i2s_hal.h | 143 ++- components/hal/include/hal/i2s_types.h | 164 +-- components/soc/esp32c3/i2s_periph.c | 1 - components/soc/esp32c3/include/soc/soc_caps.h | 6 +- components/soc/esp32s3/i2s_periph.c | 2 - .../soc/esp32s3/include/soc/i2s_struct.h | 4 +- components/soc/esp32s3/include/soc/soc_caps.h | 2 +- docs/en/api-reference/peripherals/i2s.rst | 12 +- .../classic_bt/a2dp_sink/main/main.c | 22 +- .../coex/a2dp_gatts_coex/main/main.c | 21 +- .../i2s/i2s_adc_dac/main/app_main.c | 12 +- .../i2s/i2s_basic/main/i2s_example_main.c | 31 +- 23 files changed, 1605 insertions(+), 1511 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 48fbb5740f..645b4c253f 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -23,10 +23,15 @@ #include "adc1_private.h" #endif +#if SOC_GDMA_SUPPORTED +#include "esp_private/gdma.h" +#endif + #include "soc/rtc.h" #include "esp_intr_alloc.h" #include "esp_err.h" +#include "esp_check.h" #include "esp_attr.h" #include "esp_log.h" #include "esp_pm.h" @@ -35,12 +40,7 @@ #include "sdkconfig.h" -static const char* I2S_TAG = "I2S"; - -#define I2S_CHECK(a, str, ret) if (!(a)) { \ - ESP_LOGE(I2S_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \ - return (ret); \ - } +static const char *TAG = "I2S"; #define I2S_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_spinlock[i2s_num]) #define I2S_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_spinlock[i2s_num]) @@ -49,12 +49,16 @@ static const char* I2S_TAG = "I2S"; #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) -//TODO: Refactor to put this logic into LL -#define I2S_AD_BCK_FACTOR (2) -#define I2S_PDM_BCK_FACTOR (64) -#define I2S_BASE_CLK (2*APB_CLK_FREQ) #define I2S_MAX_BUFFER_SIZE (4*1024*1024) //the maximum RAM can be allocated +#if !SOC_GDMA_SUPPORTED +#define I2S_INTR_IN_SUC_EOF BIT(9) +#define I2S_INTR_OUT_EOF BIT(12) +#define I2S_INTR_IN_DSCR_ERR BIT(13) +#define I2S_INTR_OUT_DSCR_ERR BIT(14) +#define I2S_INTR_MAX (~0) +#endif + /** * @brief DMA buffer object * @@ -79,25 +83,31 @@ typedef struct { QueueHandle_t i2s_queue; /*!< I2S queue handler*/ int dma_buf_count; /*!< DMA buffer count, number of buffer*/ int dma_buf_len; /*!< DMA buffer length, length of each buffer*/ - i2s_dma_t *rx; /*!< DMA Tx buffer*/ - i2s_dma_t *tx; /*!< DMA Rx buffer*/ + i2s_dma_t *tx; /*!< DMA Tx buffer*/ + i2s_dma_t *rx; /*!< DMA Rx buffer*/ +#if SOC_GDMA_SUPPORTED + gdma_channel_handle_t rx_dma_chan; /*!< I2S rx gDMA channel handle*/ + gdma_channel_handle_t tx_dma_chan; /*!< I2S tx gDMA channel handle*/ +#else i2s_isr_handle_t i2s_isr_handle; /*!< I2S Interrupt handle*/ +#endif int channel_num; /*!< Number of channels*/ - int bytes_per_sample; /*!< Bytes per sample*/ + int bytes_per_sample; /*!< Bytes per sample*/ int bits_per_sample; /*!< Bits per sample*/ i2s_comm_format_t communication_format; /*!hal)); - i2s_hal_reset_txdma(&(p_i2s_obj[i2s_num]->hal)); - i2s_hal_reset_tx_fifo(&(p_i2s_obj[i2s_num]->hal)); -} - -static void i2s_rx_reset(i2s_port_t i2s_num) -{ - // Reset I2S RX module first, and then, reset DMA and FIFO. - i2s_hal_reset_rx(&(p_i2s_obj[i2s_num]->hal)); - i2s_hal_reset_rxdma(&(p_i2s_obj[i2s_num]->hal)); - i2s_hal_reset_rx_fifo(&(p_i2s_obj[i2s_num]->hal)); -} - #if SOC_I2S_SUPPORTS_PCM -esp_err_t i2s_pcm_config(i2s_port_t i2s_num, int mode, i2s_pcm_cfg_t pcm_cfg) +esp_err_t i2s_pcm_config(i2s_port_t i2s_num, i2s_mode_t mode, i2s_pcm_mode_t pcm_cfg) { + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + if (mode & I2S_MODE_TX) { - i2s_hal_tx_pcm_cfg(&(p_i2s_obj[i2s_num]->hal), pcm_cfg); - } else if(mode & I2S_MODE_RX) { - i2s_hal_rx_pcm_cfg(&(p_i2s_obj[i2s_num]->hal), pcm_cfg); + i2s_hal_tx_pcm_cfg(&(p_i2s[i2s_num]->hal), pcm_cfg); + } else if (mode & I2S_MODE_RX) { + i2s_hal_rx_pcm_cfg(&(p_i2s[i2s_num]->hal), pcm_cfg); + } else { + return ESP_ERR_INVALID_ARG; } return ESP_OK; } #endif -uint32_t i2s_get_clk(i2s_port_t i2s_num) +float i2s_get_clk(i2s_port_t i2s_num) { - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - return p_i2s_obj[i2s_num]->sample_rate; + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + return (float)p_i2s[i2s_num]->sample_rate; } -static esp_err_t i2s_isr_register(i2s_port_t i2s_num, int intr_alloc_flags, void (*fn)(void*), void * arg, i2s_isr_handle_t *handle) +static void i2s_tx_reset(i2s_port_t i2s_num) { - return esp_intr_alloc(i2s_periph_signal[i2s_num].irq, intr_alloc_flags, fn, arg, handle); + p_i2s[i2s_num]->tx->curr_ptr = NULL; + p_i2s[i2s_num]->tx->rw_pos = 0; +#if SOC_GDMA_SUPPORTED + gdma_reset(p_i2s[i2s_num]->tx_dma_chan); +#else + //attach DMA + i2s_hal_attach_tx_dma(&(p_i2s[i2s_num]->hal)); + // Reset I2S TX module first, and then, reset DMA and FIFO. + i2s_hal_reset_tx(&(p_i2s[i2s_num]->hal)); + i2s_hal_reset_txdma(&(p_i2s[i2s_num]->hal)); + i2s_hal_reset_tx_fifo(&(p_i2s[i2s_num]->hal)); +#endif +} + +static void i2s_rx_reset(i2s_port_t i2s_num) +{ + p_i2s[i2s_num]->rx->curr_ptr = NULL; + p_i2s[i2s_num]->rx->rw_pos = 0; +#if SOC_GDMA_SUPPORTED + gdma_reset(p_i2s[i2s_num]->rx_dma_chan); +#else + //attach DMA + i2s_hal_attach_rx_dma(&(p_i2s[i2s_num]->hal)); + // Reset I2S RX module first, and then, reset DMA and FIFO. + i2s_hal_reset_rx(&(p_i2s[i2s_num]->hal)); + i2s_hal_reset_rxdma(&(p_i2s[i2s_num]->hal)); + i2s_hal_reset_rx_fifo(&(p_i2s[i2s_num]->hal)); +#endif +} + +static void i2s_tx_start(i2s_port_t i2s_num) +{ +#if SOC_GDMA_SUPPORTED + gdma_start(p_i2s[i2s_num]->tx_dma_chan, (uint32_t) p_i2s[i2s_num]->tx->desc[0]); +#else + i2s_hal_enable_tx_intr(&(p_i2s[i2s_num]->hal)); + i2s_hal_start_tx_link(&(p_i2s[i2s_num]->hal), (uint32_t) p_i2s[i2s_num]->tx->desc[0]); +#endif + i2s_hal_start_tx(&(p_i2s[i2s_num]->hal)); +} + +static void i2s_rx_start(i2s_port_t i2s_num) +{ +#if SOC_GDMA_SUPPORTED + gdma_start(p_i2s[i2s_num]->rx_dma_chan, (uint32_t) p_i2s[i2s_num]->rx->desc[0]); +#else + i2s_hal_enable_rx_intr(&(p_i2s[i2s_num]->hal)); + i2s_hal_start_rx_link(&(p_i2s[i2s_num]->hal), (uint32_t) p_i2s[i2s_num]->rx->desc[0]); +#endif + i2s_hal_start_rx(&(p_i2s[i2s_num]->hal)); +} + +static void i2s_tx_stop(i2s_port_t i2s_num) +{ +#if SOC_GDMA_SUPPORTED + gdma_stop(p_i2s[i2s_num]->tx_dma_chan); +#else + i2s_hal_stop_tx_link(&(p_i2s[i2s_num]->hal)); + i2s_hal_stop_tx(&(p_i2s[i2s_num]->hal)); + i2s_hal_disable_tx_intr(&(p_i2s[i2s_num]->hal)); +#endif +} + +static void i2s_rx_stop(i2s_port_t i2s_num) +{ +#if SOC_GDMA_SUPPORTED + gdma_stop(p_i2s[i2s_num]->rx_dma_chan); +#else + i2s_hal_stop_rx_link(&(p_i2s[i2s_num]->hal)); + i2s_hal_stop_rx(&(p_i2s[i2s_num]->hal)); + i2s_hal_disable_rx_intr(&(p_i2s[i2s_num]->hal)); +#endif } #if SOC_I2S_SUPPORTS_APLL @@ -183,8 +252,8 @@ static float i2s_apll_get_fi2s(int bits_per_sample, int sdm0, int sdm1, int sdm2 if (fout < SOC_I2S_APLL_MIN_FREQ || fout > SOC_I2S_APLL_MAX_FREQ) { return SOC_I2S_APLL_MAX_FREQ; } - float fpll = fout / (2 * (odir+2)); //== fi2s (N=1, b=0, a=1) - return fpll/2; + float fpll = fout / (2 * (odir + 2)); //== fi2s (N=1, b=0, a=1) + return fpll / 2; } /** @@ -226,7 +295,7 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm int _odir, _sdm0, _sdm1, _sdm2; float avg; float min_rate, max_rate, min_diff; - if (rate/bits_per_sample/2/8 < SOC_I2S_APLL_MIN_RATE) { + if (rate / bits_per_sample / 2 / 8 < SOC_I2S_APLL_MIN_RATE) { return ESP_ERR_INVALID_ARG; } @@ -239,7 +308,7 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) { max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, 0); min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, 31); - avg = (max_rate + min_rate)/2; + avg = (max_rate + min_rate) / 2; if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); *sdm2 = _sdm2; @@ -249,7 +318,7 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm for (_odir = 0; _odir < 32; _odir ++) { max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, *sdm2, _odir); min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, *sdm2, _odir); - avg = (max_rate + min_rate)/2; + avg = (max_rate + min_rate) / 2; if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); *odir = _odir; @@ -259,7 +328,7 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) { max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, *odir); min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, *odir); - avg = (max_rate + min_rate)/2; + avg = (max_rate + min_rate) / 2; if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); *sdm2 = _sdm2; @@ -270,7 +339,7 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm for (_sdm1 = 0; _sdm1 < 256; _sdm1 ++) { max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, _sdm1, *sdm2, *odir); min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, _sdm1, *sdm2, *odir); - avg = (max_rate + min_rate)/2; + avg = (max_rate + min_rate) / 2; if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); *sdm1 = _sdm1; @@ -292,54 +361,52 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, int data_bits, int ch) { - if (p_i2s_obj[i2s_num]->channel_num != ch) { - p_i2s_obj[i2s_num]->channel_num = (ch == 2) ? 2 : 1; + if (p_i2s[i2s_num]->channel_num != ch) { + p_i2s[i2s_num]->channel_num = (ch == 2) ? 2 : 1; } i2s_dma_t *save_tx = NULL, *save_rx = NULL; - if (data_bits != p_i2s_obj[i2s_num]->bits_per_sample) { - p_i2s_obj[i2s_num]->bits_per_sample = data_bits; + if (data_bits != p_i2s[i2s_num]->bits_per_sample) { + p_i2s[i2s_num]->bits_per_sample = data_bits; // Round bytes_per_sample up to next multiple of 16 bits int halfwords_per_sample = (data_bits + 15) / 16; - p_i2s_obj[i2s_num]->bytes_per_sample = halfwords_per_sample * 2; + p_i2s[i2s_num]->bytes_per_sample = halfwords_per_sample * 2; // Because limited of DMA buffer is 4092 bytes - if (p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num > 4092) { - p_i2s_obj[i2s_num]->dma_buf_len = 4092 / p_i2s_obj[i2s_num]->bytes_per_sample / p_i2s_obj[i2s_num]->channel_num; + if (p_i2s[i2s_num]->dma_buf_len * p_i2s[i2s_num]->bytes_per_sample * p_i2s[i2s_num]->channel_num > 4092) { + p_i2s[i2s_num]->dma_buf_len = 4092 / p_i2s[i2s_num]->bytes_per_sample / p_i2s[i2s_num]->channel_num; } // Re-create TX DMA buffer - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - save_tx = p_i2s_obj[i2s_num]->tx; - p_i2s_obj[i2s_num]->tx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); - if (p_i2s_obj[i2s_num]->tx == NULL) { - ESP_LOGE(I2S_TAG, "Failed to create tx dma buffer"); - i2s_driver_uninstall(i2s_num); - return ESP_ERR_NO_MEM; - } - + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + save_tx = p_i2s[i2s_num]->tx; //destroy old tx dma if exist if (save_tx) { i2s_destroy_dma_queue(i2s_num, save_tx); } - } - - // Re-create RX DMA buffer - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - save_rx = p_i2s_obj[i2s_num]->rx; - p_i2s_obj[i2s_num]->rx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); - if (p_i2s_obj[i2s_num]->rx == NULL){ - ESP_LOGE(I2S_TAG, "Failed to create rx dma buffer"); + p_i2s[i2s_num]->tx = i2s_create_dma_queue(i2s_num, p_i2s[i2s_num]->dma_buf_count, p_i2s[i2s_num]->dma_buf_len); + if (p_i2s[i2s_num]->tx == NULL) { + ESP_LOGE(TAG, "Failed to create tx dma buffer"); i2s_driver_uninstall(i2s_num); return ESP_ERR_NO_MEM; } - i2s_hal_set_rx_eof_num(&(p_i2s_obj[i2s_num]->hal), p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample); + } + // Re-create RX DMA buffer + if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { + save_rx = p_i2s[i2s_num]->rx; //destroy old rx dma if exist if (save_rx) { i2s_destroy_dma_queue(i2s_num, save_rx); } + p_i2s[i2s_num]->rx = i2s_create_dma_queue(i2s_num, p_i2s[i2s_num]->dma_buf_count, p_i2s[i2s_num]->dma_buf_len); + if (p_i2s[i2s_num]->rx == NULL) { + ESP_LOGE(TAG, "Failed to create rx dma buffer"); + i2s_driver_uninstall(i2s_num); + return ESP_ERR_NO_MEM; + } + i2s_hal_set_rx_eof_num(&(p_i2s[i2s_num]->hal), p_i2s[i2s_num]->dma_buf_len * p_i2s[i2s_num]->channel_num * p_i2s[i2s_num]->bytes_per_sample); } } return ESP_OK; @@ -348,39 +415,39 @@ static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, int data_bits, int ch) static esp_err_t i2s_fbclk_cal(int i2s_num, uint32_t rate, int channel, int channel_bit, uint32_t *sclk, uint32_t *fbck, uint32_t *bck_div) { //Default select I2S_D2CLK (160M) - uint32_t _sclk = I2S_BASE_CLK; + uint32_t _sclk = I2S_LL_BASE_CLK; uint32_t _fbck = rate * channel * channel_bit; - uint32_t _bck_div = (256%channel_bit)? 12 : 8; + uint32_t _bck_div = (256 % channel_bit) ? 12 : 8; i2s_clock_src_t clk_src = I2S_CLK_D2CLK; //ADC mode only support on ESP32, #if SOC_I2S_SUPPORTS_ADC_DAC - if ( p_i2s_obj[i2s_num]->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { - _fbck = rate * I2S_AD_BCK_FACTOR * 2; - _bck_div = I2S_AD_BCK_FACTOR; + if ( p_i2s[i2s_num]->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { + _fbck = rate * I2S_LL_AD_BCK_FACTOR * 2; + _bck_div = I2S_LL_AD_BCK_FACTOR; } -#endif +#endif // SOC_I2S_SUPPORTS_ADC_DAC #if SOC_I2S_SUPPORTS_PDM - if ( p_i2s_obj[i2s_num]->mode & I2S_MODE_PDM) { + if ( p_i2s[i2s_num]->mode & I2S_MODE_PDM) { #if SOC_I2S_SUPPORTS_PDM_TX - if ( p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + if ( p_i2s[i2s_num]->mode & I2S_MODE_TX) { int fp = 1; int fs = 1; - i2s_hal_get_tx_pdm_fpfs(&(p_i2s_obj[i2s_num]->hal), &fp, &fs); - _fbck = rate * I2S_PDM_BCK_FACTOR * fp / fs; + i2s_hal_get_tx_pdm_fpfs(&(p_i2s[i2s_num]->hal), &fp, &fs); + _fbck = rate * I2S_LL_PDM_BCK_FACTOR * fp / fs; } -#endif +#endif //SOC_I2S_SUPPORTS_PDM_TX #if SOC_I2S_SUPPORTS_PDM_RX - if ( p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + if ( p_i2s[i2s_num]->mode & I2S_MODE_RX) { i2s_pdm_dsr_t dsr; - i2s_hal_get_rx_pdm_dsr(&(p_i2s_obj[i2s_num]->hal), &dsr); - _fbck = rate * I2S_PDM_BCK_FACTOR * (dsr == I2S_PDM_DSR_16S ? 2 : 1); + i2s_hal_get_rx_pdm_dsr(&(p_i2s[i2s_num]->hal), &dsr); + _fbck = rate * I2S_LL_PDM_BCK_FACTOR * (dsr == I2S_PDM_DSR_16S ? 2 : 1); } -#endif +#endif // SOC_I2S_SUPPORTS_PDM_RX _bck_div = 8; } -#endif +#endif // SOC_I2S_SUPPORTS_PDM #if SOC_I2S_SUPPORTS_APLL int sdm0 = 0; @@ -388,52 +455,100 @@ static esp_err_t i2s_fbclk_cal(int i2s_num, uint32_t rate, int channel, int chan int sdm2 = 0; int odir = 0; //If APLL is specified, try to calculate in APLL - if (p_i2s_obj[i2s_num]->use_apll && i2s_apll_calculate_fi2s(p_i2s_obj[i2s_num]->fixed_mclk, channel_bit, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) { - _sclk = p_i2s_obj[i2s_num]->fixed_mclk; + if (p_i2s[i2s_num]->use_apll && i2s_apll_calculate_fi2s(p_i2s[i2s_num]->fixed_mclk, channel_bit, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) { + _sclk = p_i2s[i2s_num]->fixed_mclk; clk_src = I2S_CLK_APLL; - ESP_LOGD(I2S_TAG, "sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); + ESP_LOGD(TAG, "sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, odir); } -#endif +#endif // SOC_I2S_SUPPORTS_APLL if ((_fbck * _bck_div) > _sclk) { - ESP_LOGE(I2S_TAG, "sample rate is too large\r\n"); + ESP_LOGE(TAG, "sample rate is too large\r\n"); return ESP_ERR_INVALID_ARG; } - i2s_hal_set_clock_src(&(p_i2s_obj[i2s_num]->hal), clk_src); + i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), clk_src); *sclk = _sclk; *fbck = _fbck; *bck_div = _bck_div; return ESP_OK; } -/* - 1. stop i2s; - 2. calculate mclk, bck, bck_factor - 3. malloc dma buffer; - 4. start i2s -*/ -esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_slot_bits_cfg_t slot_bit_cfg, i2s_slot_channel_cfg_t slot_ch_cfg) +static uint32_t i2s_get_active_chan_num(i2s_hal_config_t *hal_cfg) { - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_ARG); + switch (hal_cfg->chan_fmt) { + case I2S_CHANNEL_FMT_RIGHT_LEFT: //fall through + case I2S_CHANNEL_FMT_ALL_RIGHT: //fall through + case I2S_CHANNEL_FMT_ALL_LEFT: + return 2; + case I2S_CHANNEL_FMT_ONLY_RIGHT: //fall through + case I2S_CHANNEL_FMT_ONLY_LEFT: + return 1; +#if SOC_I2S_SUPPORTS_TDM + case I2S_CHANNEL_FMT_TDM: { + uint32_t num = 0; + uint32_t max_chan = 0; + uint32_t chan_mask = hal_cfg->chan_cfg.chan_mask; - int data_bits = slot_bit_cfg & 0xffff; - int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT; - int active_slot_num = slot_ch_cfg & 0xffff; - int slot_num = (slot_ch_cfg >> SLOT_CH_SHIFT) == 0 ? ((active_slot_num == I2S_CHANNEL_MONO)) ? 2 : active_slot_num : (slot_ch_cfg >> SLOT_CH_SHIFT); + for (int i = 0; chan_mask && i < 16; i++, chan_mask >>= 1) { + if ((chan_mask & 0x01) == 1) { + num++; + max_chan = i + 1; + } + } + if (max_chan > hal_cfg->chan_cfg.total_chan) { + hal_cfg->chan_cfg.total_chan = max_chan; + } + hal_cfg->chan_cfg.active_chan = num; + return num; + } +#endif + default: + return 0; + } +} + +esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_channel_t ch) +{ + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + ESP_RETURN_ON_FALSE((p_i2s[i2s_num] != NULL), ESP_ERR_INVALID_ARG, TAG, "Not initialized yet"); + + i2s_hal_config_t *cfg = &p_i2s[i2s_num]->hal_cfg; + int data_bits = 0; + int slot_bits = 0; + int active_slot_num = 0; + int slot_num = 0; + + cfg->ch = ch; + cfg->sample_rate = rate; + cfg->bits_cfg.val = bits_cfg; + + cfg->bits_cfg.chan_bits = cfg->bits_cfg.chan_bits < cfg->bits_cfg.sample_bits ? + cfg->bits_cfg.sample_bits : cfg->bits_cfg.chan_bits; + slot_bits = cfg->bits_cfg.chan_bits; + data_bits = cfg->bits_cfg.sample_bits; + +#if SOC_I2S_SUPPORTS_TDM + cfg->chan_cfg.chan_mask = ch & 0xFFFF; + active_slot_num = i2s_get_active_chan_num(cfg); + slot_num = cfg->chan_cfg.total_chan; +#else + active_slot_num = i2s_get_active_chan_num(cfg); + slot_num = ch == I2S_CHANNEL_MONO ? 2 : active_slot_num; +#endif + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); if ((data_bits % 8 != 0) || (data_bits > I2S_BITS_PER_SAMPLE_32BIT)) { - ESP_LOGE(I2S_TAG, "Invalid bits per sample"); + ESP_LOGE(TAG, "Invalid bits per sample"); return ESP_ERR_INVALID_ARG; } //Stop I2S i2s_stop(i2s_num); // wait all on-going writing finish - if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) && p_i2s_obj[i2s_num]->tx) { - xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); + if ((p_i2s[i2s_num]->mode & I2S_MODE_TX) && p_i2s[i2s_num]->tx) { + xSemaphoreTake(p_i2s[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); } - if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && p_i2s_obj[i2s_num]->rx) { - xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); + if ((p_i2s[i2s_num]->mode & I2S_MODE_RX) && p_i2s[i2s_num]->rx) { + xSemaphoreTake(p_i2s[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); } //malloc DMA buffer if (i2s_alloc_dma_buffer(i2s_num, data_bits, active_slot_num) != ESP_OK ) { @@ -448,37 +563,99 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_slot_bits_cfg_t slo return ESP_FAIL; } //configure i2s clock - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - i2s_hal_tx_clock_config(&(p_i2s_obj[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); - i2s_hal_set_tx_sample_bit(&(p_i2s_obj[i2s_num]->hal), slot_bits, data_bits); + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + i2s_hal_tx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); + i2s_hal_set_tx_sample_bit(&(p_i2s[i2s_num]->hal), slot_bits, data_bits); // wait all writing on-going finish - if (p_i2s_obj[i2s_num]->tx) { - xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux); + if (p_i2s[i2s_num]->tx) { + xSemaphoreGive(p_i2s[i2s_num]->tx->mux); } } - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - i2s_hal_rx_clock_config(&(p_i2s_obj[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); - i2s_hal_set_rx_sample_bit(&(p_i2s_obj[i2s_num]->hal), slot_bits, data_bits); + if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { + i2s_hal_rx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); + i2s_hal_set_rx_sample_bit(&(p_i2s[i2s_num]->hal), slot_bits, data_bits); // wait all writing on-going finish - if (p_i2s_obj[i2s_num]->rx) { - xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux); + if (p_i2s[i2s_num]->rx) { + xSemaphoreGive(p_i2s[i2s_num]->rx->mux); } } - i2s_slot_bits_cfg_t i2s_slot_bits_cfg = (slot_bits << SLOT_BIT_SHIFT) | data_bits; - i2s_slot_channel_cfg_t i2s_slot_channel_cfg = (slot_num << SLOT_CH_SHIFT) | active_slot_num; - i2s_hal_samples_config(&(p_i2s_obj[i2s_num]->hal), p_i2s_obj[i2s_num]->mode, p_i2s_obj[i2s_num]->communication_format, i2s_slot_bits_cfg, i2s_slot_channel_cfg); + i2s_hal_samples_config(&(p_i2s[i2s_num]->hal), &(p_i2s[i2s_num]->hal_cfg)); + // Reset message queue to avoid receiving unavailable values because the old dma queque has been destroyed + if (p_i2s[i2s_num]->tx) { + xQueueReset(p_i2s[i2s_num]->tx->queue); + } + if (p_i2s[i2s_num]->rx) { + xQueueReset(p_i2s[i2s_num]->rx->queue); + } + //I2S start i2s_start(i2s_num); - p_i2s_obj[i2s_num]->sample_rate = rate; + p_i2s[i2s_num]->sample_rate = rate; return ESP_OK; } +#if SOC_GDMA_SUPPORTED +static bool IRAM_ATTR i2s_dma_rx_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) +{ + i2s_obj_t *p_i2s = (i2s_obj_t *) user_data; + portBASE_TYPE high_priority_task_awoken = 0; + BaseType_t ret = 0; + int dummy; + i2s_event_t i2s_event; + uint32_t finish_desc; + + if (p_i2s->rx) { + finish_desc = event_data->rx_eof_desc_addr; + if (xQueueIsQueueFullFromISR(p_i2s->rx->queue)) { + xQueueReceiveFromISR(p_i2s->rx->queue, &dummy, &high_priority_task_awoken); + } + ret = xQueueSendFromISR(p_i2s->rx->queue, &(((lldesc_t *)finish_desc)->buf), &high_priority_task_awoken); + if (p_i2s->i2s_queue) { + i2s_event.type = (ret == pdPASS) ? I2S_EVENT_RX_DONE : I2S_EVENT_RX_Q_OVF; + if (p_i2s->i2s_queue && xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) { + xQueueReceiveFromISR(p_i2s->i2s_queue, &dummy, &high_priority_task_awoken); + } + xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken); + } + } + return high_priority_task_awoken; +} + +static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) +{ + i2s_obj_t *p_i2s = (i2s_obj_t *) user_data; + portBASE_TYPE high_priority_task_awoken = 0; + BaseType_t ret; + int dummy; + i2s_event_t i2s_event; + uint32_t finish_desc; + if (p_i2s->tx) { + finish_desc = event_data->tx_eof_desc_addr; + if (xQueueIsQueueFullFromISR(p_i2s->tx->queue)) { + xQueueReceiveFromISR(p_i2s->tx->queue, &dummy, &high_priority_task_awoken); + if (p_i2s->tx_desc_auto_clear) { + memset((void *) dummy, 0, p_i2s->tx->buf_size); + } + } + ret = xQueueSendFromISR(p_i2s->tx->queue, &(((lldesc_t *)finish_desc)->buf), &high_priority_task_awoken); + if (p_i2s->i2s_queue) { + i2s_event.type = (ret == pdPASS) ? I2S_EVENT_TX_DONE : I2S_EVENT_TX_Q_OVF; + if (xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) { + xQueueReceiveFromISR(p_i2s->i2s_queue, &dummy, &high_priority_task_awoken); + } + xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken); + } + } + return high_priority_task_awoken; +} + +#else static void IRAM_ATTR i2s_intr_handler_default(void *arg) { - i2s_obj_t *p_i2s = (i2s_obj_t*) arg; + i2s_obj_t *p_i2s = (i2s_obj_t *) arg; uint32_t status; i2s_hal_get_intr_status(&(p_i2s->hal), &status); - if(status == 0) { + if (status == 0) { //Avoid spurious interrupt return; } @@ -488,7 +665,7 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) portBASE_TYPE high_priority_task_awoken = 0; uint32_t finish_desc = 0; if ((status & I2S_INTR_OUT_DSCR_ERR) || (status & I2S_INTR_IN_DSCR_ERR)) { - ESP_EARLY_LOGE(I2S_TAG, "dma error, interrupt status: 0x%08x", status); + ESP_EARLY_LOGE(TAG, "dma error, interrupt status: 0x%08x", status); if (p_i2s->i2s_queue) { i2s_event.type = I2S_EVENT_DMA_ERROR; if (xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) { @@ -541,19 +718,20 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) portYIELD_FROM_ISR(); } } +#endif static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma) { int bux_idx; - if (p_i2s_obj[i2s_num] == NULL) { - ESP_LOGE(I2S_TAG, "Not initialized yet"); + if (p_i2s[i2s_num] == NULL) { + ESP_LOGE(TAG, "Not initialized yet"); return ESP_ERR_INVALID_ARG; } if (dma == NULL) { - ESP_LOGE(I2S_TAG, "dma is NULL"); + ESP_LOGE(TAG, "dma is NULL"); return ESP_ERR_INVALID_ARG; } - for (bux_idx = 0; bux_idx < p_i2s_obj[i2s_num]->dma_buf_count; bux_idx++) { + for (bux_idx = 0; bux_idx < p_i2s[i2s_num]->dma_buf_count; bux_idx++) { if (dma->desc && dma->desc[bux_idx]) { free(dma->desc[bux_idx]); } @@ -567,6 +745,7 @@ static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma) if (dma->desc) { free(dma->desc); } + ESP_LOGI(TAG, "DMA queue destroyed"); vQueueDelete(dma->queue); vSemaphoreDelete(dma->mux); free(dma); @@ -576,42 +755,42 @@ static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma) static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, int dma_buf_len) { int bux_idx; - int sample_size = p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num; - i2s_dma_t *dma = (i2s_dma_t*) malloc(sizeof(i2s_dma_t)); + int sample_size = p_i2s[i2s_num]->bytes_per_sample * p_i2s[i2s_num]->channel_num; + i2s_dma_t *dma = (i2s_dma_t *) malloc(sizeof(i2s_dma_t)); if (dma == NULL) { - ESP_LOGE(I2S_TAG, "Error malloc i2s_dma_t"); + ESP_LOGE(TAG, "Error malloc i2s_dma_t"); return NULL; } memset(dma, 0, sizeof(i2s_dma_t)); - dma->buf = (char **)malloc(sizeof(char*) * dma_buf_count); + dma->buf = (char **)malloc(sizeof(char *) * dma_buf_count); if (dma->buf == NULL) { - ESP_LOGE(I2S_TAG, "Error malloc dma buffer pointer"); + ESP_LOGE(TAG, "Error malloc dma buffer pointer"); free(dma); return NULL; } - memset(dma->buf, 0, sizeof(char*) * dma_buf_count); + memset(dma->buf, 0, sizeof(char *) * dma_buf_count); for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) { - dma->buf[bux_idx] = (char*) heap_caps_calloc(1, dma_buf_len * sample_size, MALLOC_CAP_DMA); + dma->buf[bux_idx] = (char *) heap_caps_calloc(1, dma_buf_len * sample_size, MALLOC_CAP_DMA); if (dma->buf[bux_idx] == NULL) { - ESP_LOGE(I2S_TAG, "Error malloc dma buffer"); + ESP_LOGE(TAG, "Error malloc dma buffer"); i2s_destroy_dma_queue(i2s_num, dma); return NULL; } - ESP_LOGD(I2S_TAG, "Addr[%d] = %d", bux_idx, (int)dma->buf[bux_idx]); + ESP_LOGD(TAG, "Addr[%d] = %d", bux_idx, (int)dma->buf[bux_idx]); } - dma->desc = (lldesc_t**) malloc(sizeof(lldesc_t*) * dma_buf_count); + dma->desc = (lldesc_t **) malloc(sizeof(lldesc_t *) * dma_buf_count); if (dma->desc == NULL) { - ESP_LOGE(I2S_TAG, "Error malloc dma description"); + ESP_LOGE(TAG, "Error malloc dma description"); i2s_destroy_dma_queue(i2s_num, dma); return NULL; } for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) { - dma->desc[bux_idx] = (lldesc_t*) heap_caps_malloc(sizeof(lldesc_t), MALLOC_CAP_DMA); + dma->desc[bux_idx] = (lldesc_t *) heap_caps_malloc(sizeof(lldesc_t), MALLOC_CAP_DMA); if (dma->desc[bux_idx] == NULL) { - ESP_LOGE(I2S_TAG, "Error malloc dma description entry"); + ESP_LOGE(TAG, "Error malloc dma description entry"); i2s_destroy_dma_queue(i2s_num, dma); return NULL; } @@ -626,64 +805,54 @@ static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, in dma->desc[bux_idx]->offset = 0; dma->desc[bux_idx]->empty = (uint32_t)((bux_idx < (dma_buf_count - 1)) ? (dma->desc[bux_idx + 1]) : dma->desc[0]); } - dma->queue = xQueueCreate(dma_buf_count - 1, sizeof(char*)); + dma->queue = xQueueCreate(dma_buf_count - 1, sizeof(char *)); dma->mux = xSemaphoreCreateMutex(); dma->buf_size = dma_buf_len * sample_size; - ESP_LOGI(I2S_TAG, "DMA Malloc info, datalen=blocksize=%d, dma_buf_count=%d", dma_buf_len * sample_size, dma_buf_count); + ESP_LOGI(TAG, "DMA Malloc info, datalen=blocksize=%d, dma_buf_count=%d", dma_buf_len * sample_size, dma_buf_count); return dma; } esp_err_t i2s_start(i2s_port_t i2s_num) { - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); //start DMA link I2S_ENTER_CRITICAL(); - esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle); - i2s_hal_clear_intr_status(&(p_i2s_obj[i2s_num]->hal), I2S_INTR_MAX); - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - p_i2s_obj[i2s_num]->tx->curr_ptr = NULL; - p_i2s_obj[i2s_num]->tx->rw_pos = 0; - //attach DMA - i2s_hal_attach_tx_dma(&(p_i2s_obj[i2s_num]->hal)); +#if !SOC_GDMA_SUPPORTED + esp_intr_disable(p_i2s[i2s_num]->i2s_isr_handle); + i2s_hal_clear_intr_status(&(p_i2s[i2s_num]->hal), I2S_INTR_MAX); +#endif + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { i2s_tx_reset(i2s_num); - i2s_hal_enable_tx_intr(&(p_i2s_obj[i2s_num]->hal)); - i2s_hal_start_tx_link(&(p_i2s_obj[i2s_num]->hal), (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0]); - i2s_hal_start_tx(&(p_i2s_obj[i2s_num]->hal)); + i2s_tx_start(i2s_num); } - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - p_i2s_obj[i2s_num]->rx->curr_ptr = NULL; - p_i2s_obj[i2s_num]->rx->rw_pos = 0; - //attach DMA - i2s_hal_attach_rx_dma(&(p_i2s_obj[i2s_num]->hal)); + if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { i2s_rx_reset(i2s_num); - i2s_hal_enable_rx_intr(&(p_i2s_obj[i2s_num]->hal)); - i2s_hal_start_rx_link(&(p_i2s_obj[i2s_num]->hal), (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0]); - i2s_hal_start_rx(&(p_i2s_obj[i2s_num]->hal)); + i2s_rx_start(i2s_num); } - esp_intr_enable(p_i2s_obj[i2s_num]->i2s_isr_handle); +#if !SOC_GDMA_SUPPORTED + esp_intr_enable(p_i2s[i2s_num]->i2s_isr_handle); +#endif I2S_EXIT_CRITICAL(); return ESP_OK; } esp_err_t i2s_stop(i2s_port_t i2s_num) { - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); I2S_ENTER_CRITICAL(); - esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle); - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - i2s_hal_stop_tx_link(&(p_i2s_obj[i2s_num]->hal)); - i2s_hal_stop_tx(&(p_i2s_obj[i2s_num]->hal)); - i2s_hal_disable_tx_intr(&(p_i2s_obj[i2s_num]->hal)); +#if !SOC_GDMA_SUPPORTED + esp_intr_disable(p_i2s[i2s_num]->i2s_isr_handle); +#endif + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + i2s_tx_stop(i2s_num); } - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - i2s_hal_stop_rx_link(&(p_i2s_obj[i2s_num]->hal)); - i2s_hal_stop_rx(&(p_i2s_obj[i2s_num]->hal)); - i2s_hal_disable_rx_intr(&(p_i2s_obj[i2s_num]->hal)); + if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { + i2s_rx_stop(i2s_num); } - uint32_t mask; - i2s_hal_get_intr_status(&(p_i2s_obj[i2s_num]->hal), &mask); - i2s_hal_clear_intr_status(&(p_i2s_obj[i2s_num]->hal), mask); +#if !SOC_GDMA_SUPPORTED + i2s_hal_clear_intr_status(&(p_i2s[i2s_num]->hal), I2S_INTR_MAX); +#endif I2S_EXIT_CRITICAL(); return ESP_OK; } @@ -691,7 +860,7 @@ esp_err_t i2s_stop(i2s_port_t i2s_num) #if SOC_I2S_SUPPORTS_ADC_DAC esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode) { - I2S_CHECK((dac_mode < I2S_DAC_CHANNEL_MAX), "i2s dac mode error", ESP_ERR_INVALID_ARG); + ESP_RETURN_ON_FALSE((dac_mode < I2S_DAC_CHANNEL_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s dac mode error"); if (dac_mode == I2S_DAC_CHANNEL_DISABLE) { dac_output_disable(DAC_CHANNEL_1); dac_output_disable(DAC_CHANNEL_2); @@ -713,13 +882,13 @@ esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode) static esp_err_t _i2s_adc_mode_recover(void) { - I2S_CHECK(((_i2s_adc_unit != -1) && (_i2s_adc_channel != -1)), "i2s ADC recover error, not initialized...", ESP_ERR_INVALID_ARG); + ESP_RETURN_ON_FALSE(((_i2s_adc_unit != -1) && (_i2s_adc_channel != -1)), ESP_ERR_INVALID_ARG, TAG, "i2s ADC recover error, not initialized..."); return adc_i2s_mode_init(_i2s_adc_unit, _i2s_adc_channel); } esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel) { - I2S_CHECK((adc_unit < ADC_UNIT_2), "i2s ADC unit error, only support ADC1 for now", ESP_ERR_INVALID_ARG); + ESP_RETURN_ON_FALSE((adc_unit < ADC_UNIT_2), ESP_ERR_INVALID_ARG, TAG, "i2s ADC unit error, only support ADC1 for now"); // For now, we only support SAR ADC1. _i2s_adc_unit = adc_unit; _i2s_adc_channel = adc_channel; @@ -728,23 +897,23 @@ esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel) esp_err_t i2s_adc_enable(i2s_port_t i2s_num) { - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); - I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + ESP_RETURN_ON_FALSE((p_i2s[i2s_num] != NULL), ESP_ERR_INVALID_STATE, TAG, "Not initialized yet"); + ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), ESP_ERR_INVALID_STATE, TAG, "i2s built-in adc not enabled"); adc1_dma_mode_acquire(); _i2s_adc_mode_recover(); i2s_rx_reset(i2s_num); - 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); + return i2s_set_clk(i2s_num, p_i2s[i2s_num]->sample_rate, p_i2s[i2s_num]->bits_per_sample, p_i2s[i2s_num]->channel_num); } esp_err_t i2s_adc_disable(i2s_port_t i2s_num) { - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); - I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + ESP_RETURN_ON_FALSE((p_i2s[i2s_num] != NULL), ESP_ERR_INVALID_STATE, TAG, "Not initialized yet"); + ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), ESP_ERR_INVALID_STATE, TAG, "i2s built-in adc not enabled"); - i2s_hal_stop_rx(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_stop_rx(&(p_i2s[i2s_num]->hal)); adc1_lock_release(); return ESP_OK; } @@ -752,7 +921,7 @@ esp_err_t i2s_adc_disable(i2s_port_t i2s_num) esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) { - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); if (pin == NULL) { #if SOC_I2S_SUPPORTS_ADC_DAC return i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); @@ -761,56 +930,56 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) #endif } if (pin->bck_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->bck_io_num)) { - ESP_LOGE(I2S_TAG, "bck_io_num error"); + ESP_LOGE(TAG, "bck_io_num error"); return ESP_FAIL; } if (pin->ws_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->ws_io_num)) { - ESP_LOGE(I2S_TAG, "ws_io_num error"); + ESP_LOGE(TAG, "ws_io_num error"); return ESP_FAIL; } if (pin->data_out_num != -1 && !GPIO_IS_VALID_OUTPUT_GPIO(pin->data_out_num)) { - ESP_LOGE(I2S_TAG, "data_out_num error"); + ESP_LOGE(TAG, "data_out_num error"); return ESP_FAIL; } if (pin->data_in_num != -1 && !GPIO_IS_VALID_GPIO(pin->data_in_num)) { - ESP_LOGE(I2S_TAG, "data_in_num error"); + ESP_LOGE(TAG, "data_in_num error"); return ESP_FAIL; } - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - gpio_matrix_in_check(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0); - gpio_matrix_in_check(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0); + if (p_i2s[i2s_num]->mode & I2S_MODE_SLAVE) { + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + gpio_matrix_in_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0); + gpio_matrix_in_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0); } else { - gpio_matrix_in_check(pin->ws_io_num, i2s_periph_signal[i2s_num].rx_ws_sig, 0); - gpio_matrix_in_check(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0); + gpio_matrix_in_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].rx_ws_sig, 0); + gpio_matrix_in_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0); } } else { - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - gpio_matrix_out_check(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0, 0); - gpio_matrix_out_check(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0, 0); + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + gpio_matrix_out_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0, 0); + gpio_matrix_out_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0, 0); } else { - gpio_matrix_out_check(pin->ws_io_num, i2s_periph_signal[i2s_num].rx_ws_sig, 0, 0); - gpio_matrix_out_check(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0, 0); + gpio_matrix_out_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].rx_ws_sig, 0, 0); + gpio_matrix_out_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0, 0); } } - gpio_matrix_out_check(pin->data_out_num, i2s_periph_signal[i2s_num].data_out_sig, 0, 0); - gpio_matrix_in_check(pin->data_in_num, i2s_periph_signal[i2s_num].data_in_sig, 0); + gpio_matrix_out_check_and_set(pin->data_out_num, i2s_periph_signal[i2s_num].data_out_sig, 0, 0); + gpio_matrix_in_check_and_set(pin->data_in_num, i2s_periph_signal[i2s_num].data_in_sig, 0); return ESP_OK; } esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate) { - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((p_i2s_obj[i2s_num]->bytes_per_sample > 0), "bits_per_sample not set", ESP_ERR_INVALID_ARG); - return i2s_set_clk(i2s_num, rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->bytes_per_sample > 0), ESP_ERR_INVALID_ARG, TAG, "bits_per_sample not set"); + return i2s_set_clk(i2s_num, rate, p_i2s[i2s_num]->bits_per_sample, p_i2s[i2s_num]->channel_num); } #if SOC_I2S_SUPPORTS_PDM_RX 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_hal_set_rx_pdm_dsr(&(p_i2s_obj[i2s_num]->hal), 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); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + i2s_hal_set_rx_pdm_dsr(&(p_i2s[i2s_num]->hal), dsr); + return i2s_set_clk(i2s_num, p_i2s[i2s_num]->sample_rate, p_i2s[i2s_num]->bits_per_sample, p_i2s[i2s_num]->channel_num); } #endif @@ -818,39 +987,40 @@ esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr) esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, int sample_rate, int fp, int fs) { I2S_ENTER_CRITICAL(); - i2s_hal_set_tx_pdm_fpfs(&(p_i2s_obj[i2s_num]->hal), fp, fs); + i2s_hal_set_tx_pdm_fpfs(&(p_i2s[i2s_num]->hal), fp, fs); I2S_EXIT_CRITICAL(); - return i2s_set_clk(i2s_num, sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); + return i2s_set_clk(i2s_num, sample_rate, p_i2s[i2s_num]->bits_per_sample, p_i2s[i2s_num]->channel_num); } #endif -static esp_err_t i2s_check_cfg_static(i2s_port_t i2s_num, const i2s_config_param_t *cfg) +static esp_err_t i2s_check_cfg_static(i2s_port_t i2s_num) { + i2s_hal_config_t *cfg = &p_i2s[i2s_num]->hal_cfg; #if SOC_I2S_SUPPORTS_ADC_DAC //We only check if the I2S number is invalid when set to build in ADC and DAC mode. - I2S_CHECK(!((cfg->mode & I2S_MODE_ADC_BUILT_IN) && (i2s_num != I2S_NUM_0)), "I2S ADC built-in only support on I2S0", ESP_ERR_INVALID_ARG); - I2S_CHECK(!((cfg->mode & I2S_MODE_DAC_BUILT_IN) && (i2s_num != I2S_NUM_0)), "I2S DAC built-in only support on I2S0", ESP_ERR_INVALID_ARG); + ESP_RETURN_ON_FALSE(!((cfg->mode & I2S_MODE_ADC_BUILT_IN) && (i2s_num != I2S_NUM_0)), ESP_ERR_INVALID_ARG, TAG, "I2S ADC built-in only support on I2S0"); + ESP_RETURN_ON_FALSE(!((cfg->mode & I2S_MODE_DAC_BUILT_IN) && (i2s_num != I2S_NUM_0)), ESP_ERR_INVALID_ARG, TAG, "I2S DAC built-in only support on I2S0"); return ESP_OK; #endif #if SOC_I2S_SUPPORTS_PDM //We only check if the I2S number is invalid when set to PDM mode. - I2S_CHECK(!((cfg->mode & I2S_MODE_PDM) && (i2s_num != I2S_NUM_0)), "I2S DAC PDM only support on I2S0", ESP_ERR_INVALID_ARG); + ESP_RETURN_ON_FALSE(!((cfg->mode & I2S_MODE_PDM) && (i2s_num != I2S_NUM_0)), ESP_ERR_INVALID_ARG, TAG, "I2S DAC PDM only support on I2S0"); return ESP_OK; #endif - I2S_CHECK(cfg->communication_format && (cfg->communication_format < I2S_COMM_FORMAT_STAND_MAX), "invalid communication formats", ESP_ERR_INVALID_ARG); - I2S_CHECK(!((cfg->communication_format & I2S_COMM_FORMAT_STAND_MSB) && (cfg->communication_format & I2S_COMM_FORMAT_STAND_PCM_LONG)), "multiple communication formats specified", ESP_ERR_INVALID_ARG); + ESP_RETURN_ON_FALSE(cfg->comm_fmt && (cfg->comm_fmt < I2S_COMM_FORMAT_STAND_MAX), ESP_ERR_INVALID_ARG, TAG, "invalid communication formats"); + ESP_RETURN_ON_FALSE(!((cfg->comm_fmt & I2S_COMM_FORMAT_STAND_MSB) && (cfg->comm_fmt & I2S_COMM_FORMAT_STAND_PCM_LONG)), ESP_ERR_INVALID_ARG, TAG, "multiple communication formats specified"); return ESP_OK; } -static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_param_t *i2s_config) +static esp_err_t i2s_param_config(i2s_port_t i2s_num) { - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((i2s_config), "param null", ESP_ERR_INVALID_ARG); - I2S_CHECK((i2s_check_cfg_static(i2s_num, i2s_config) == ESP_OK), "param check error", ESP_ERR_INVALID_ARG); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + ESP_RETURN_ON_FALSE((i2s_check_cfg_static(i2s_num) == ESP_OK), ESP_ERR_INVALID_ARG, TAG, "param check error"); + i2s_hal_config_t *cfg = &p_i2s[i2s_num]->hal_cfg; #if SOC_I2S_SUPPORTS_ADC_DAC - if(i2s_config->mode & I2S_MODE_ADC_BUILT_IN) { + if (cfg->mode & I2S_MODE_ADC_BUILT_IN) { //in ADC built-in mode, we need to call i2s_set_adc_mode to //initialize the specific ADC channel. //in the current stage, we only support ADC1 and single channel mode. @@ -858,15 +1028,15 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_param_t * adc_power_acquire(); } #endif - p_i2s_obj[i2s_num]->communication_format = i2s_config->communication_format; + p_i2s[i2s_num]->communication_format = cfg->comm_fmt; // configure I2S data port interface. - i2s_hal_config_param(&(p_i2s_obj[i2s_num]->hal), i2s_config); - if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX)) { - i2s_hal_enable_sig_loopback(&(p_i2s_obj[i2s_num]->hal)); - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { - i2s_hal_enable_master_fd_mode(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_config_param(&(p_i2s[i2s_num]->hal), cfg); + if ((p_i2s[i2s_num]->mode & I2S_MODE_RX) && (p_i2s[i2s_num]->mode & I2S_MODE_TX)) { + i2s_hal_enable_sig_loopback(&(p_i2s[i2s_num]->hal)); + if (p_i2s[i2s_num]->mode & I2S_MODE_MASTER) { + i2s_hal_enable_master_fd_mode(&(p_i2s[i2s_num]->hal)); } else { - i2s_hal_enable_slave_fd_mode(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_enable_slave_fd_mode(&(p_i2s[i2s_num]->hal)); } } return ESP_OK; @@ -874,161 +1044,235 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_param_t * esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num) { - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - if (p_i2s_obj[i2s_num]->rx && p_i2s_obj[i2s_num]->rx->buf != NULL && p_i2s_obj[i2s_num]->rx->buf_size != 0) { - for (int i = 0; i < p_i2s_obj[i2s_num]->dma_buf_count; i++) { - memset(p_i2s_obj[i2s_num]->rx->buf[i], 0, p_i2s_obj[i2s_num]->rx->buf_size); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + if (p_i2s[i2s_num]->rx && p_i2s[i2s_num]->rx->buf != NULL && p_i2s[i2s_num]->rx->buf_size != 0) { + for (int i = 0; i < p_i2s[i2s_num]->dma_buf_count; i++) { + memset(p_i2s[i2s_num]->rx->buf[i], 0, p_i2s[i2s_num]->rx->buf_size); } } - if (p_i2s_obj[i2s_num]->tx && p_i2s_obj[i2s_num]->tx->buf != NULL && p_i2s_obj[i2s_num]->tx->buf_size != 0) { + if (p_i2s[i2s_num]->tx && p_i2s[i2s_num]->tx->buf != NULL && p_i2s[i2s_num]->tx->buf_size != 0) { int bytes_left = 0; - bytes_left = (p_i2s_obj[i2s_num]->tx->buf_size - p_i2s_obj[i2s_num]->tx->rw_pos) % 4; + bytes_left = (p_i2s[i2s_num]->tx->buf_size - p_i2s[i2s_num]->tx->rw_pos) % 4; if (bytes_left) { size_t zero_bytes = 0, bytes_written; i2s_write(i2s_num, (void *)&zero_bytes, bytes_left, &bytes_written, portMAX_DELAY); } - for (int i = 0; i < p_i2s_obj[i2s_num]->dma_buf_count; i++) { - memset(p_i2s_obj[i2s_num]->tx->buf[i], 0, p_i2s_obj[i2s_num]->tx->buf_size); + for (int i = 0; i < p_i2s[i2s_num]->dma_buf_count; i++) { + memset(p_i2s[i2s_num]->tx->buf[i], 0, p_i2s[i2s_num]->tx->buf_size); } } return ESP_OK; } -esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue) +esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void *i2s_queue) { - esp_err_t err; - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((i2s_config != NULL), "I2S configuration must not NULL", ESP_ERR_INVALID_ARG); - I2S_CHECK((i2s_config->dma_buf_count >= 2 && i2s_config->dma_buf_count <= 128), "I2S buffer count less than 128 and more than 2", ESP_ERR_INVALID_ARG); - I2S_CHECK((i2s_config->dma_buf_len >= 8 && i2s_config->dma_buf_len <= 1024), "I2S buffer length at most 1024 and more than 8", ESP_ERR_INVALID_ARG); - if (p_i2s_obj[i2s_num] == NULL) { - p_i2s_obj[i2s_num] = (i2s_obj_t*) malloc(sizeof(i2s_obj_t)); - if (p_i2s_obj[i2s_num] == NULL) { - ESP_LOGE(I2S_TAG, "Malloc I2S driver error"); - return ESP_ERR_NO_MEM; - } - memset(p_i2s_obj[i2s_num], 0, sizeof(i2s_obj_t)); + esp_err_t ret = ESP_FAIL; + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + ESP_RETURN_ON_FALSE((i2s_config != NULL), ESP_ERR_INVALID_ARG, TAG, "I2S configuration must not NULL"); + ESP_RETURN_ON_FALSE((i2s_config->dma_buf_count >= 2 && i2s_config->dma_buf_count <= 128), ESP_ERR_INVALID_ARG, TAG, "I2S buffer count less than 128 and more than 2"); + ESP_RETURN_ON_FALSE((i2s_config->dma_buf_len >= 8 && i2s_config->dma_buf_len <= 1024), ESP_ERR_INVALID_ARG, TAG, "I2S buffer length at most 1024 and more than 8"); + if (p_i2s[i2s_num] != NULL) { + ESP_LOGW(TAG, "I2S driver already installed"); + return ESP_OK; + } - portMUX_TYPE i2s_spinlock_unlocked[1] = {portMUX_INITIALIZER_UNLOCKED}; - for (int x = 0; x < I2S_NUM_MAX; x++) { - i2s_spinlock[x] = i2s_spinlock_unlocked[0]; - } - //To make sure hardware is enabled before any hardware register operations. -#if SOC_GDMA_SUPPORTED - periph_module_enable(PERIPH_GDMA_MODULE); + p_i2s[i2s_num] = (i2s_obj_t *) calloc(1, sizeof(i2s_obj_t)); + if (p_i2s[i2s_num] == NULL) { + ESP_LOGE(TAG, "Malloc I2S driver error"); + return ESP_ERR_NO_MEM; + } + + portMUX_TYPE i2s_spinlock_unlocked[1] = {portMUX_INITIALIZER_UNLOCKED}; + for (int x = 0; x < I2S_NUM_MAX; x++) { + i2s_spinlock[x] = i2s_spinlock_unlocked[0]; + } + //To make sure hardware is enabled before any hardware register operations. + periph_module_enable(i2s_periph_signal[i2s_num].module); + i2s_hal_init(&(p_i2s[i2s_num]->hal), i2s_num); + + // Set I2S HAL configurations + p_i2s[i2s_num]->hal_cfg.mode = i2s_config->mode; + p_i2s[i2s_num]->hal_cfg.sample_rate = i2s_config->sample_rate; + p_i2s[i2s_num]->hal_cfg.comm_fmt = i2s_config->communication_format; + p_i2s[i2s_num]->hal_cfg.chan_fmt = i2s_config->channel_format; + p_i2s[i2s_num]->hal_cfg.bits_cfg.sample_bits = i2s_config->bits_per_sample; + p_i2s[i2s_num]->hal_cfg.bits_cfg.chan_bits = i2s_config->bits_per_slot; +#if SOC_I2S_SUPPORTS_TDM + switch (i2s_config->channel_format) { + case I2S_CHANNEL_FMT_RIGHT_LEFT: + case I2S_CHANNEL_FMT_ALL_RIGHT: + case I2S_CHANNEL_FMT_ALL_LEFT: + p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1; + p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 2; + p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 2; + break; + case I2S_CHANNEL_FMT_ONLY_RIGHT: + p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0; + p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 1; + p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 1; + break; + case I2S_CHANNEL_FMT_ONLY_LEFT: + p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1; + p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 1; + p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 1; + break; + case I2S_CHANNEL_FMT_TDM: + ESP_RETURN_ON_FALSE((i2s_config->tdm_chan_cfg.chan_mask != 0), ESP_ERR_INVALID_ARG, TAG, "i2s all channel are disabled"); + p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_chan_cfg.chan_mask; + i2s_get_active_chan_num(&p_i2s[i2s_num]->hal_cfg); + break; + default: + ESP_LOGE(TAG, "wrong i2s channel format, uninstalled i2s."); + goto err; + } + p_i2s[i2s_num]->hal_cfg.flags.val = i2s_config->tdm_flags.val; #endif - periph_module_enable(i2s_periph_signal[i2s_num].module); - i2s_hal_init(&(p_i2s_obj[i2s_num]->hal), i2s_num); + // Set I2S driver configurations + p_i2s[i2s_num]->i2s_num = i2s_num; + p_i2s[i2s_num]->mode = i2s_config->mode; + p_i2s[i2s_num]->channel_num = i2s_get_active_chan_num(&p_i2s[i2s_num]->hal_cfg); + p_i2s[i2s_num]->i2s_queue = i2s_queue; + p_i2s[i2s_num]->bits_per_sample = 0; + p_i2s[i2s_num]->bytes_per_sample = 0; // Not initialized yet + p_i2s[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; + p_i2s[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; - p_i2s_obj[i2s_num]->i2s_num = i2s_num; - p_i2s_obj[i2s_num]->mode = i2s_config->param_cfg.mode; - - p_i2s_obj[i2s_num]->channel_num = i2s_config->param_cfg.channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1; - - p_i2s_obj[i2s_num]->i2s_queue = i2s_queue; - p_i2s_obj[i2s_num]->bits_per_sample = 0; - p_i2s_obj[i2s_num]->bytes_per_sample = 0; // Not initialized yet - p_i2s_obj[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; - p_i2s_obj[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; #ifdef CONFIG_PM_ENABLE if (i2s_config->use_apll) { - err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i2s_driver", &p_i2s_obj[i2s_num]->pm_lock); + ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i2s_driver", &p_i2s[i2s_num]->pm_lock); } else { - err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "i2s_driver", &p_i2s_obj[i2s_num]->pm_lock); + ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "i2s_driver", &p_i2s[i2s_num]->pm_lock); } - if (err != ESP_OK) { - free(p_i2s_obj[i2s_num]); - p_i2s_obj[i2s_num] = NULL; - ESP_LOGE(I2S_TAG, "I2S pm lock error"); - return err; + if (ret != ESP_OK) { + free(p_i2s[i2s_num]); + p_i2s[i2s_num] = NULL; + ESP_LOGE(TAG, "I2S pm lock error"); + return ret; } #endif //CONFIG_PM_ENABLE - - //initial interrupt - err = i2s_isr_register(i2s_num, i2s_config->intr_alloc_flags, i2s_intr_handler_default, p_i2s_obj[i2s_num], &p_i2s_obj[i2s_num]->i2s_isr_handle); - if (err != ESP_OK) { -#ifdef CONFIG_PM_ENABLE - if (p_i2s_obj[i2s_num]->pm_lock) { - esp_pm_lock_delete(p_i2s_obj[i2s_num]->pm_lock); - } +#if SOC_GDMA_SUPPORTED + ret = ESP_OK; + gdma_trigger_t trig = {.periph = GDMA_TRIG_PERIPH_I2S}; +#if SOC_I2S_NUM > 1 + trig.instance_id = (i2s_num == I2S_NUM_0) ? SOC_GDMA_TRIG_PERIPH_I2S0 : SOC_GDMA_TRIG_PERIPH_I2S1; +#else + trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S0; #endif - free(p_i2s_obj[i2s_num]); - p_i2s_obj[i2s_num] = NULL; - ESP_LOGE(I2S_TAG, "Register I2S Interrupt error"); - return err; - } - i2s_stop(i2s_num); - p_i2s_obj[i2s_num]->use_apll = i2s_config->use_apll; - p_i2s_obj[i2s_num]->fixed_mclk = i2s_config->fixed_mclk; - p_i2s_obj[i2s_num]->tx_desc_auto_clear = i2s_config->tx_desc_auto_clear; - err = i2s_param_config(i2s_num, &(i2s_config->param_cfg)); - if (err != ESP_OK) { - i2s_driver_uninstall(i2s_num); - ESP_LOGE(I2S_TAG, "I2S param configure error"); - return err; - } - if (i2s_queue) { - p_i2s_obj[i2s_num]->i2s_queue = xQueueCreate(queue_size, sizeof(i2s_event_t)); - *((QueueHandle_t*) i2s_queue) = p_i2s_obj[i2s_num]->i2s_queue; - ESP_LOGI(I2S_TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_i2s_obj[i2s_num]->i2s_queue)); - } else { - p_i2s_obj[i2s_num]->i2s_queue = NULL; - } - i2s_slot_bits_cfg_t slot_bits_cfg = i2s_config->param_cfg.slot_bits_cfg; - i2s_slot_channel_cfg_t slot_channel_cfg = p_i2s_obj[i2s_num]->channel_num; -#if SOC_I2S_SUPPORTS_TDM - slot_channel_cfg = i2s_config->param_cfg.slot_channel_cfg; -#endif - //set clock and start - return i2s_set_clk(i2s_num, i2s_config->sample_rate, slot_bits_cfg, slot_channel_cfg); + gdma_channel_alloc_config_t dma_cfg = {.flags.reserve_sibling = 1}; + if ( p_i2s[i2s_num]->mode & I2S_MODE_RX) { + dma_cfg.direction = GDMA_CHANNEL_DIRECTION_RX; + ESP_GOTO_ON_ERROR(gdma_new_channel(&dma_cfg, &p_i2s[i2s_num]->rx_dma_chan), err, TAG, "Register rx dma channel error"); + ESP_GOTO_ON_ERROR(gdma_connect(p_i2s[i2s_num]->rx_dma_chan, trig), err, TAG, "Connect rx dma channel error"); + gdma_rx_event_callbacks_t cb = {.on_recv_eof = i2s_dma_rx_callback}; + gdma_register_rx_event_callbacks(p_i2s[i2s_num]->rx_dma_chan, &cb, p_i2s[i2s_num]); + } + if ( p_i2s[i2s_num]->mode & I2S_MODE_TX) { + dma_cfg.direction = GDMA_CHANNEL_DIRECTION_TX; + ESP_GOTO_ON_ERROR(gdma_new_channel(&dma_cfg, &p_i2s[i2s_num]->tx_dma_chan), err, TAG, "Register tx dma channel error"); + ESP_GOTO_ON_ERROR(gdma_connect(p_i2s[i2s_num]->tx_dma_chan, trig), err, TAG, "Connect tx dma channel error"); + gdma_tx_event_callbacks_t cb = {.on_trans_eof = i2s_dma_tx_callback}; + gdma_register_tx_event_callbacks(p_i2s[i2s_num]->tx_dma_chan, &cb, p_i2s[i2s_num]); + } +#else + //initial interrupt + ret = esp_intr_alloc(i2s_periph_signal[i2s_num].irq, i2s_config->intr_alloc_flags, i2s_intr_handler_default, p_i2s[i2s_num], &p_i2s[i2s_num]->i2s_isr_handle); + ESP_GOTO_ON_ERROR(ret, err, TAG, "Register I2S Interrupt error"); +#endif // SOC_GDMA_SUPPORTED + i2s_stop(i2s_num); + p_i2s[i2s_num]->use_apll = i2s_config->use_apll; + p_i2s[i2s_num]->fixed_mclk = i2s_config->fixed_mclk; + p_i2s[i2s_num]->tx_desc_auto_clear = i2s_config->tx_desc_auto_clear; + ret = i2s_param_config(i2s_num); + ESP_GOTO_ON_ERROR(ret, err, TAG, "I2S param configure error"); + if (i2s_queue) { + p_i2s[i2s_num]->i2s_queue = xQueueCreate(queue_size, sizeof(i2s_event_t)); + ESP_GOTO_ON_ERROR(ret, err, TAG, "I2S queue create failed"); + *((QueueHandle_t *) i2s_queue) = p_i2s[i2s_num]->i2s_queue; + ESP_LOGI(TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_i2s[i2s_num]->i2s_queue)); + } else { + p_i2s[i2s_num]->i2s_queue = NULL; } - ESP_LOGW(I2S_TAG, "I2S driver already installed"); - return ESP_OK; + //set clock and start +#if SOC_I2S_SUPPORTS_TDM + ret = i2s_set_clk(i2s_num, i2s_config->sample_rate, + p_i2s[i2s_num]->hal_cfg.bits_cfg.val, + (i2s_channel_t)p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan); +#else + ret = i2s_set_clk(i2s_num, i2s_config->sample_rate, + p_i2s[i2s_num]->hal_cfg.bits_cfg.val, + I2S_CHANNEL_STEREO); +#endif + ESP_GOTO_ON_ERROR(ret, err, TAG, "I2S set clock failed"); + return ret; + +err: +#ifdef CONFIG_PM_ENABLE + if (p_i2s[i2s_num]->pm_lock) { + esp_pm_lock_delete(p_i2s[i2s_num]->pm_lock); + } +#endif + i2s_driver_uninstall(i2s_num); + return ret; } esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) { - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - if (p_i2s_obj[i2s_num] == NULL) { - ESP_LOGI(I2S_TAG, "already uninstalled"); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + if (p_i2s[i2s_num] == NULL) { + ESP_LOGI(TAG, "already uninstalled"); return ESP_OK; } i2s_stop(i2s_num); - esp_intr_free(p_i2s_obj[i2s_num]->i2s_isr_handle); - - if (p_i2s_obj[i2s_num]->tx != NULL && p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - i2s_destroy_dma_queue(i2s_num, p_i2s_obj[i2s_num]->tx); - p_i2s_obj[i2s_num]->tx = NULL; +#if SOC_I2S_SUPPORTS_ADC_DAC + i2s_set_dac_mode(I2S_DAC_CHANNEL_DISABLE); +#endif +#if SOC_GDMA_SUPPORTED + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + gdma_disconnect(p_i2s[i2s_num]->tx_dma_chan); + gdma_del_channel(p_i2s[i2s_num]->tx_dma_chan); } - if (p_i2s_obj[i2s_num]->rx != NULL && p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - i2s_destroy_dma_queue(i2s_num, p_i2s_obj[i2s_num]->rx); - p_i2s_obj[i2s_num]->rx = NULL; + if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { + gdma_disconnect(p_i2s[i2s_num]->rx_dma_chan); + gdma_del_channel(p_i2s[i2s_num]->rx_dma_chan); + } +#else + esp_intr_free(p_i2s[i2s_num]->i2s_isr_handle); +#endif + if (p_i2s[i2s_num]->tx != NULL && p_i2s[i2s_num]->mode & I2S_MODE_TX) { + i2s_destroy_dma_queue(i2s_num, p_i2s[i2s_num]->tx); + p_i2s[i2s_num]->tx = NULL; + } + if (p_i2s[i2s_num]->rx != NULL && p_i2s[i2s_num]->mode & I2S_MODE_RX) { + i2s_destroy_dma_queue(i2s_num, p_i2s[i2s_num]->rx); + p_i2s[i2s_num]->rx = NULL; } - if (p_i2s_obj[i2s_num]->i2s_queue) { - vQueueDelete(p_i2s_obj[i2s_num]->i2s_queue); - p_i2s_obj[i2s_num]->i2s_queue = NULL; + if (p_i2s[i2s_num]->i2s_queue) { + vQueueDelete(p_i2s[i2s_num]->i2s_queue); + p_i2s[i2s_num]->i2s_queue = NULL; } #if SOC_I2S_SUPPORTS_APLL - if(p_i2s_obj[i2s_num]->use_apll) { + if (p_i2s[i2s_num]->use_apll) { // switch back to PLL clock source - i2s_hal_set_clock_sel(&(p_i2s_obj[i2s_num]->hal), I2S_CLK_D2CLK); + i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), I2S_CLK_D2CLK); rtc_clk_apll_enable(0, 0, 0, 0, 0); } #endif #ifdef CONFIG_PM_ENABLE - if (p_i2s_obj[i2s_num]->pm_lock) { - esp_pm_lock_delete(p_i2s_obj[i2s_num]->pm_lock); + if (p_i2s[i2s_num]->pm_lock) { + esp_pm_lock_delete(p_i2s[i2s_num]->pm_lock); } #endif - free(p_i2s_obj[i2s_num]); - p_i2s_obj[i2s_num] = NULL; + free(p_i2s[i2s_num]); + p_i2s[i2s_num] = NULL; +#if !SOC_GDMA_SUPPORTED periph_module_disable(i2s_periph_signal[i2s_num].module); +#endif return ESP_OK; } @@ -1037,39 +1281,39 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by char *data_ptr, *src_byte; size_t bytes_can_write; *bytes_written = 0; - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); - I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_ERR_INVALID_ARG); - xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + ESP_RETURN_ON_FALSE((size < I2S_MAX_BUFFER_SIZE), ESP_ERR_INVALID_ARG, TAG, "size is too large"); + ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->tx), ESP_ERR_INVALID_ARG, TAG, "tx NULL"); + xSemaphoreTake(p_i2s[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); #ifdef CONFIG_PM_ENABLE - esp_pm_lock_acquire(p_i2s_obj[i2s_num]->pm_lock); + esp_pm_lock_acquire(p_i2s[i2s_num]->pm_lock); #endif src_byte = (char *)src; while (size > 0) { - if (p_i2s_obj[i2s_num]->tx->rw_pos == p_i2s_obj[i2s_num]->tx->buf_size || p_i2s_obj[i2s_num]->tx->curr_ptr == NULL) { - if (xQueueReceive(p_i2s_obj[i2s_num]->tx->queue, &p_i2s_obj[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) { + if (p_i2s[i2s_num]->tx->rw_pos == p_i2s[i2s_num]->tx->buf_size || p_i2s[i2s_num]->tx->curr_ptr == NULL) { + if (xQueueReceive(p_i2s[i2s_num]->tx->queue, &p_i2s[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) { break; } - p_i2s_obj[i2s_num]->tx->rw_pos = 0; + p_i2s[i2s_num]->tx->rw_pos = 0; } - ESP_LOGD(I2S_TAG, "size: %d, rw_pos: %d, buf_size: %d, curr_ptr: %d", size, p_i2s_obj[i2s_num]->tx->rw_pos, p_i2s_obj[i2s_num]->tx->buf_size, (int)p_i2s_obj[i2s_num]->tx->curr_ptr); - data_ptr = (char*)p_i2s_obj[i2s_num]->tx->curr_ptr; - data_ptr += p_i2s_obj[i2s_num]->tx->rw_pos; - bytes_can_write = p_i2s_obj[i2s_num]->tx->buf_size - p_i2s_obj[i2s_num]->tx->rw_pos; + ESP_LOGD(TAG, "size: %d, rw_pos: %d, buf_size: %d, curr_ptr: %d", size, p_i2s[i2s_num]->tx->rw_pos, p_i2s[i2s_num]->tx->buf_size, (int)p_i2s[i2s_num]->tx->curr_ptr); + data_ptr = (char *)p_i2s[i2s_num]->tx->curr_ptr; + data_ptr += p_i2s[i2s_num]->tx->rw_pos; + bytes_can_write = p_i2s[i2s_num]->tx->buf_size - p_i2s[i2s_num]->tx->rw_pos; if (bytes_can_write > size) { bytes_can_write = size; } memcpy(data_ptr, src_byte, bytes_can_write); size -= bytes_can_write; src_byte += bytes_can_write; - p_i2s_obj[i2s_num]->tx->rw_pos += bytes_can_write; + p_i2s[i2s_num]->tx->rw_pos += bytes_can_write; (*bytes_written) += bytes_can_write; } #ifdef CONFIG_PM_ENABLE - esp_pm_lock_release(p_i2s_obj[i2s_num]->pm_lock); + esp_pm_lock_release(p_i2s[i2s_num]->pm_lock); #endif - xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux); + xSemaphoreGive(p_i2s[i2s_num]->tx->mux); return ESP_OK; } @@ -1079,44 +1323,44 @@ esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, siz int bytes_can_write, tail; int src_bytes, aim_bytes, zero_bytes; *bytes_written = 0; - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((size > 0), "size must greater than zero", ESP_ERR_INVALID_ARG); - I2S_CHECK((aim_bits * size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); - I2S_CHECK((aim_bits >= src_bits), "aim_bits mustn't be less than src_bits", ESP_ERR_INVALID_ARG); - I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_ERR_INVALID_ARG); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + ESP_RETURN_ON_FALSE((size > 0), ESP_ERR_INVALID_ARG, TAG, "size must greater than zero"); + ESP_RETURN_ON_FALSE((aim_bits * size < I2S_MAX_BUFFER_SIZE), ESP_ERR_INVALID_ARG, TAG, "size is too large"); + ESP_RETURN_ON_FALSE((aim_bits >= src_bits), ESP_ERR_INVALID_ARG, TAG, "aim_bits mustn't be less than src_bits"); + ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->tx), ESP_ERR_INVALID_ARG, TAG, "tx NULL"); if (src_bits < I2S_BITS_PER_SAMPLE_8BIT || aim_bits < I2S_BITS_PER_SAMPLE_8BIT) { - ESP_LOGE(I2S_TAG,"bits mustn't be less than 8, src_bits %d aim_bits %d", src_bits, aim_bits); + ESP_LOGE(TAG, "bits mustn't be less than 8, src_bits %d aim_bits %d", src_bits, aim_bits); return ESP_ERR_INVALID_ARG; } if (src_bits > I2S_BITS_PER_SAMPLE_32BIT || aim_bits > I2S_BITS_PER_SAMPLE_32BIT) { - ESP_LOGE(I2S_TAG,"bits mustn't be greater than 32, src_bits %d aim_bits %d", src_bits, aim_bits); + ESP_LOGE(TAG, "bits mustn't be greater than 32, src_bits %d aim_bits %d", src_bits, aim_bits); return ESP_ERR_INVALID_ARG; } if ((src_bits == I2S_BITS_PER_SAMPLE_16BIT || src_bits == I2S_BITS_PER_SAMPLE_32BIT) && (size % 2 != 0)) { - ESP_LOGE(I2S_TAG,"size must be a even number while src_bits is even, src_bits %d size %d", src_bits, size); + ESP_LOGE(TAG, "size must be a even number while src_bits is even, src_bits %d size %d", src_bits, size); return ESP_ERR_INVALID_ARG; } if (src_bits == I2S_BITS_PER_SAMPLE_24BIT && (size % 3 != 0)) { - ESP_LOGE(I2S_TAG,"size must be a multiple of 3 while src_bits is 24, size %d", size); + ESP_LOGE(TAG, "size must be a multiple of 3 while src_bits is 24, size %d", size); return ESP_ERR_INVALID_ARG; } src_bytes = src_bits / 8; aim_bytes = aim_bits / 8; zero_bytes = aim_bytes - src_bytes; - xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); + xSemaphoreTake(p_i2s[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); size = size * aim_bytes / src_bytes; - ESP_LOGD(I2S_TAG,"aim_bytes %d src_bytes %d size %d", aim_bytes, src_bytes, size); + ESP_LOGD(TAG, "aim_bytes %d src_bytes %d size %d", aim_bytes, src_bytes, size); while (size > 0) { - if (p_i2s_obj[i2s_num]->tx->rw_pos == p_i2s_obj[i2s_num]->tx->buf_size || p_i2s_obj[i2s_num]->tx->curr_ptr == NULL) { - if (xQueueReceive(p_i2s_obj[i2s_num]->tx->queue, &p_i2s_obj[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) { + if (p_i2s[i2s_num]->tx->rw_pos == p_i2s[i2s_num]->tx->buf_size || p_i2s[i2s_num]->tx->curr_ptr == NULL) { + if (xQueueReceive(p_i2s[i2s_num]->tx->queue, &p_i2s[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) { break; } - p_i2s_obj[i2s_num]->tx->rw_pos = 0; + p_i2s[i2s_num]->tx->rw_pos = 0; } - data_ptr = (char*)p_i2s_obj[i2s_num]->tx->curr_ptr; - data_ptr += p_i2s_obj[i2s_num]->tx->rw_pos; - bytes_can_write = p_i2s_obj[i2s_num]->tx->buf_size - p_i2s_obj[i2s_num]->tx->rw_pos; + data_ptr = (char *)p_i2s[i2s_num]->tx->curr_ptr; + data_ptr += p_i2s[i2s_num]->tx->rw_pos; + bytes_can_write = p_i2s[i2s_num]->tx->buf_size - p_i2s[i2s_num]->tx->rw_pos; if (bytes_can_write > (int)size) { bytes_can_write = size; } @@ -1130,9 +1374,9 @@ esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, siz (*bytes_written) += (aim_bytes - zero_bytes); } size -= bytes_can_write; - p_i2s_obj[i2s_num]->tx->rw_pos += bytes_can_write; + p_i2s[i2s_num]->tx->rw_pos += bytes_can_write; } - xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux); + xSemaphoreGive(p_i2s[i2s_num]->tx->mux); return ESP_OK; } @@ -1142,35 +1386,35 @@ esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_re int bytes_can_read; *bytes_read = 0; dest_byte = (char *)dest; - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); - I2S_CHECK((p_i2s_obj[i2s_num]->rx), "rx NULL", ESP_ERR_INVALID_ARG); - xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + ESP_RETURN_ON_FALSE((size < I2S_MAX_BUFFER_SIZE), ESP_ERR_INVALID_ARG, TAG, "size is too large"); + ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->rx), ESP_ERR_INVALID_ARG, TAG, "rx NULL"); + xSemaphoreTake(p_i2s[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); #ifdef CONFIG_PM_ENABLE - esp_pm_lock_acquire(p_i2s_obj[i2s_num]->pm_lock); + esp_pm_lock_acquire(p_i2s[i2s_num]->pm_lock); #endif while (size > 0) { - if (p_i2s_obj[i2s_num]->rx->rw_pos == p_i2s_obj[i2s_num]->rx->buf_size || p_i2s_obj[i2s_num]->rx->curr_ptr == NULL) { - if (xQueueReceive(p_i2s_obj[i2s_num]->rx->queue, &p_i2s_obj[i2s_num]->rx->curr_ptr, ticks_to_wait) == pdFALSE) { + if (p_i2s[i2s_num]->rx->rw_pos == p_i2s[i2s_num]->rx->buf_size || p_i2s[i2s_num]->rx->curr_ptr == NULL) { + if (xQueueReceive(p_i2s[i2s_num]->rx->queue, &p_i2s[i2s_num]->rx->curr_ptr, ticks_to_wait) == pdFALSE) { break; } - p_i2s_obj[i2s_num]->rx->rw_pos = 0; + p_i2s[i2s_num]->rx->rw_pos = 0; } - data_ptr = (char*)p_i2s_obj[i2s_num]->rx->curr_ptr; - data_ptr += p_i2s_obj[i2s_num]->rx->rw_pos; - bytes_can_read = p_i2s_obj[i2s_num]->rx->buf_size - p_i2s_obj[i2s_num]->rx->rw_pos; + data_ptr = (char *)p_i2s[i2s_num]->rx->curr_ptr; + data_ptr += p_i2s[i2s_num]->rx->rw_pos; + bytes_can_read = p_i2s[i2s_num]->rx->buf_size - p_i2s[i2s_num]->rx->rw_pos; if (bytes_can_read > (int)size) { bytes_can_read = size; } memcpy(dest_byte, data_ptr, bytes_can_read); size -= bytes_can_read; dest_byte += bytes_can_read; - p_i2s_obj[i2s_num]->rx->rw_pos += bytes_can_read; + p_i2s[i2s_num]->rx->rw_pos += bytes_can_read; (*bytes_read) += bytes_can_read; } #ifdef CONFIG_PM_ENABLE - esp_pm_lock_release(p_i2s_obj[i2s_num]->pm_lock); + esp_pm_lock_release(p_i2s[i2s_num]->pm_lock); #endif - xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux); + xSemaphoreGive(p_i2s[i2s_num]->rx->mux); return ESP_OK; } diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index 0c5b1c288d..04b0ed30d7 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -28,42 +28,70 @@ extern "C" { #define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */ +/** + * @brief I2S port number, the max port number is (I2S_NUM_MAX -1). + */ +typedef enum { + I2S_NUM_0 = 0, /*!< I2S port 0 */ +#if SOC_I2S_NUM > 1 + I2S_NUM_1 = 1, /*!< I2S port 1 */ +#endif + I2S_NUM_MAX, /*!< I2S port max */ +} i2s_port_t; + +/** + * @brief I2S pin number for i2s_set_pin + * + */ +typedef struct { + int bck_io_num; /*!< BCK in out pin*/ + int ws_io_num; /*!< WS in out pin*/ + int data_out_num; /*!< DATA out pin*/ + int data_in_num; /*!< DATA in pin*/ +} i2s_pin_config_t; + +#if SOC_I2S_SUPPORTS_TDM +typedef i2s_hal_chan_cfg_t tdm_chan_cfg_t; +typedef i2s_hal_tdm_flags_t tdm_flags_t; +#endif /** * @brief I2S driver configuration parameters * */ typedef struct { - union { - // Compatible with previous versions. For ESP32-S3, ESP32-C3 and the later chip, you should use `param_cfg` fields to initialize I2S. - struct { - i2s_mode_t mode; /*!< I2S work mode*/ - uint32_t sample_rate; /*!< I2S sample rate*/ - uint32_t bits_per_sample; /*!< I2S bits per sample*/ - i2s_channel_fmt_t channel_format; /*!< I2S channel format */ - i2s_comm_format_t communication_format; /*!< I2S communication format */ - }; - i2s_config_param_t param_cfg; /*!< I2S config paramater */ - }; - int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */ - int dma_buf_count; /*!< I2S DMA Buffer Count */ - int dma_buf_len; /*!< I2S DMA Buffer Length */ - bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */ - bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */ - int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/ + + i2s_mode_t mode; /*!< I2S work mode */ + uint32_t sample_rate; /*!< I2S sample rate */ + i2s_bits_per_sample_t bits_per_sample; /*!< I2S sample bits in one channel */ + i2s_channel_fmt_t channel_format; /*!< I2S channel format.*/ + i2s_comm_format_t communication_format; /*!< I2S communication format */ + int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */ + int dma_buf_count; /*!< I2S DMA Buffer Count */ + int dma_buf_len; /*!< I2S DMA Buffer Length */ + bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */ + bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */ + int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/ + i2s_bits_per_slot_t bits_per_slot; /*!< I2S total bits in one channel, Should not be smaller than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */ +#if SOC_I2S_SUPPORTS_TDM + tdm_chan_cfg_t tdm_chan_cfg; /*!< I2S TDM channel configurations*/ + tdm_flags_t tdm_flags; /*!< I2S TDM flags*/ +#endif } i2s_driver_config_t; typedef i2s_driver_config_t i2s_config_t; typedef intr_handle_t i2s_isr_handle_t; /** - * @brief I2S event types + * @brief I2S event queue types * */ typedef enum { I2S_EVENT_DMA_ERROR, I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/ I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/ + I2S_EVENT_TX_Q_OVF, /*!< I2S DMA sent queue overflow*/ + I2S_EVENT_RX_Q_OVF, /*!< I2S DMA receive queue overflow*/ I2S_EVENT_MAX, /*!< I2S event max index*/ } i2s_event_type_t; /** @@ -123,7 +151,7 @@ esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr); #if SOC_I2S_SUPPORTS_PDM_TX /** * @brief Set TX PDM mode up-sample rate - * TX PDM have two type upsampling rate configurations: + * TX PDM can only be set to the following two upsampling rate configurations: * 1: fp = 960, fs = sample_rate / 100, in this case, Fpdm = 128*48000 * 2: fp = 960, fs = 480, in this case, Fpdm = 128*Fpcm = 128*sample_rate * If the pdm receiver do not care the pdm serial clock, it's recommended set Fpdm = 128*48000 @@ -162,7 +190,7 @@ esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, int sample_rate, int fp, * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_NO_MEM Out of memory */ -esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue); +esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void *i2s_queue); /** * @brief Uninstall I2S driver. @@ -326,7 +354,7 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num); * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ -esp_err_t i2s_pcm_config(i2s_port_t i2s_num, int mode, i2s_pcm_cfg_t pcm_cfg); +esp_err_t i2s_pcm_config(i2s_port_t i2s_num, i2s_mode_t mode, i2s_pcm_mode_t pcm_cfg); #endif /** @@ -334,20 +362,27 @@ esp_err_t i2s_pcm_config(i2s_port_t i2s_num, int mode, i2s_pcm_cfg_t pcm_cfg); * * Similar to i2s_set_sample_rates(), but also sets bit width. * + * 1. stop i2s; + * 2. calculate mclk, bck, bck_factor + * 3. malloc dma buffer; + * 4. start i2s + * * @param i2s_num I2S_NUM_0, I2S_NUM_1 * * @param rate I2S sample rate (ex: 8000, 44100...) * - * @param slot_bits i2s slot bit configuration + * @param bits_cfg I2S bits configuation + * the low 16 bits is for data bits per sample in one channel (see 'i2s_bits_per_sample_t') + * the high 16 bits is for total bits in one channel (see 'i2s_bits_per_slot_t') * - * @param sloct_ch I2S slot number configuration + * @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO) * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_NO_MEM Out of memory */ -esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_slot_bits_cfg_t slot_bits, i2s_slot_channel_cfg_t sloct_ch); +esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_channel_t ch); /** * @brief get clock set on particular port number. @@ -357,7 +392,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_slot_bits_cfg_t slo * @return * - actual clock set by i2s driver */ -uint32_t i2s_get_clk(i2s_port_t i2s_num); +float i2s_get_clk(i2s_port_t i2s_num); #if SOC_I2S_SUPPORTS_ADC_DAC /** diff --git a/components/driver/test/adc_dma_test/test_esp32.c b/components/driver/test/adc_dma_test/test_esp32.c index 36375596a0..104f88375a 100644 --- a/components/driver/test/adc_dma_test/test_esp32.c +++ b/components/driver/test/adc_dma_test/test_esp32.c @@ -54,12 +54,10 @@ static void example_i2s_init(void) { int i2s_num = EXAMPLE_I2S_NUM; i2s_config_t i2s_config = { - .param_cfg = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, - .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, - .slot_bits_cfg = EXAMPLE_I2S_SAMPLE_BITS, - .channel_format = EXAMPLE_I2S_FORMAT, - }, + .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, + .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, + .bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS, + .channel_format = EXAMPLE_I2S_FORMAT, .intr_alloc_flags = 0, .dma_buf_count = 2, .dma_buf_len = 1024, diff --git a/components/driver/test/dac_dma_test/test_esp32.c b/components/driver/test/dac_dma_test/test_esp32.c index c69843e81c..eba5dfd565 100644 --- a/components/driver/test/dac_dma_test/test_esp32.c +++ b/components/driver/test/dac_dma_test/test_esp32.c @@ -56,12 +56,10 @@ static void example_i2s_init(void) { int i2s_num = EXAMPLE_I2S_NUM; i2s_config_t i2s_config = { - .param_cfg = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, - .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, - .slot_bits_cfg = EXAMPLE_I2S_SAMPLE_BITS, - .channel_format = EXAMPLE_I2S_FORMAT, - }, + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, + .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, + .bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS, + .channel_format = EXAMPLE_I2S_FORMAT, .intr_alloc_flags = 0, .dma_buf_count = 2, .dma_buf_len = 1024, diff --git a/components/driver/test/test_i2s.c b/components/driver/test/test_i2s.c index 025ba78270..65274e30b6 100644 --- a/components/driver/test/test_i2s.c +++ b/components/driver/test/test_i2s.c @@ -21,22 +21,51 @@ #include "math.h" #include "esp_rom_gpio.h" -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3, ESP32C3) - #define SAMPLE_RATE (36000) #define SAMPLE_BITS (16) + +#if CONFIG_IDF_TARGET_ESP32 #define MASTER_BCK_IO 15 +#define MASTER_WS_IO 25 #define SLAVE_BCK_IO 19 #define SLAVE_WS_IO 26 #define DATA_IN_IO 21 - -#if CONFIG_IDF_TARGET_ESP32 -#define MASTER_WS_IO 25 #define DATA_OUT_IO 22 #define ADC1_CHANNEL_4_IO 32 +#define I2S0_DATA_OUT_IDX I2S0O_DATA_OUT23_IDX +#define I2S0_DATA_IN_IDX I2S0I_DATA_IN15_IDX +#define I2S1_DATA_OUT_IDX I2S1O_DATA_OUT23_IDX +#define I2S1_DATA_IN_IDX I2S1I_DATA_IN15_IDX #elif CONFIG_IDF_TARGET_ESP32S2 +#define MASTER_BCK_IO 15 #define MASTER_WS_IO 28 +#define SLAVE_BCK_IO 19 +#define SLAVE_WS_IO 26 +#define DATA_IN_IO 21 #define DATA_OUT_IO 20 +#define I2S0_DATA_OUT_IDX I2S0O_DATA_OUT23_IDX +#define I2S0_DATA_IN_IDX I2S0I_DATA_IN15_IDX +#elif CONFIG_IDF_TARGET_ESP32C3 +// TODO: change pins +#define MASTER_BCK_IO 4 +#define MASTER_WS_IO 5 +#define SLAVE_BCK_IO 14 +#define SLAVE_WS_IO 15 +#define DATA_IN_IO 19 +#define DATA_OUT_IO 18 +#define I2S0_DATA_OUT_IDX I2SO_SD_OUT_IDX +#define I2S0_DATA_IN_IDX I2SI_SD_IN_IDX +#elif CONFIG_IDF_TARGET_ESP32S3 +#define MASTER_BCK_IO 4 +#define MASTER_WS_IO 5 +#define SLAVE_BCK_IO 14 +#define SLAVE_WS_IO 15 +#define DATA_IN_IO 19 +#define DATA_OUT_IO 18 +#define I2S0_DATA_OUT_IDX I2S0O_SD_OUT_IDX +#define I2S0_DATA_IN_IDX I2S0I_SD_IN_IDX +#define I2S1_DATA_OUT_IDX I2S1O_SD_OUT_IDX +#define I2S1_DATA_IN_IDX I2S1I_SD_IN_IDX #endif #define PERCENT_DIFF 0.0001 @@ -67,8 +96,8 @@ static void i2s_test_io_config(int mode) esp_rom_gpio_connect_out_signal(MASTER_WS_IO, I2S0I_WS_OUT_IDX, 0, 0); esp_rom_gpio_connect_in_signal(MASTER_WS_IO, I2S1O_WS_IN_IDX, 0); - esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S1O_DATA_OUT23_IDX, 0, 0); - esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0I_DATA_IN15_IDX, 0); + esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S1_DATA_OUT_IDX, 0, 0); + esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0_DATA_IN_IDX, 0); } break; @@ -79,14 +108,14 @@ static void i2s_test_io_config(int mode) esp_rom_gpio_connect_out_signal(MASTER_WS_IO, I2S0O_WS_OUT_IDX, 0, 0); esp_rom_gpio_connect_in_signal(MASTER_WS_IO, I2S1I_WS_IN_IDX, 0); - esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0O_DATA_OUT23_IDX, 0, 0); - esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S1I_DATA_IN15_IDX, 0); + esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0_DATA_OUT_IDX, 0, 0); + esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S1_DATA_IN_IDX, 0); } break; #endif case I2S_TEST_MODE_LOOPBACK: { - esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0O_DATA_OUT23_IDX, 0, 0); - esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0I_DATA_IN15_IDX, 0); + esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0_DATA_OUT_IDX, 0, 0); + esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0_DATA_IN_IDX, 0); } break; @@ -107,35 +136,17 @@ TEST_CASE("I2S basic driver install, uninstall, set pin test", "[i2s]") { // dac, adc i2s i2s_config_t i2s_config = { - .param_cfg = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = SAMPLE_RATE, - .slot_bits_cfg = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, -#if SOC_I2S_SUPPORTS_TDM - .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, - .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, - .left_align_en = false, - .big_edin_en = false, - .bit_order_msb_en = false, -#endif - }, + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, .dma_buf_count = 6, .dma_buf_len = 60, .use_apll = 0, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 , }; -#if CONFIG_IDF_TARGET_ESP32 - //install and start i2s driver - TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); - //for internal DAC, this will enable both of the internal channels - TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, NULL)); - //stop & destroy i2s driver - TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0)); -#endif - // normal i2s i2s_pin_config_t pin_config = { .bck_io_num = MASTER_BCK_IO, @@ -161,20 +172,11 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]") { // master driver installed and send data i2s_config_t master_i2s_config = { - .param_cfg = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX, - .sample_rate = SAMPLE_RATE, - .slot_bits_cfg = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, -#if SOC_I2S_SUPPORTS_TDM - .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, - .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, - .left_align_en = false, - .big_edin_en = false, - .bit_order_msb_en = false, -#endif - }, + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, @@ -230,89 +232,17 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]") i2s_driver_uninstall(I2S_NUM_0); } -#if !DISABLED_FOR_TARGETS(ESP32S2) -/* ESP32S2 has only single I2S port and hence following test cases are not applicable */ -TEST_CASE("I2S adc test", "[i2s]") -{ - // init I2S ADC - i2s_config_t i2s_config = { - .param_cfg = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, - .sample_rate = SAMPLE_RATE, - .slot_bits_cfg = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, -#if SOC_I2S_SUPPORTS_TDM - .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, - .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, - .left_align_en = false, - .big_edin_en = false, - .bit_order_msb_en = false, -#endif - }, - .intr_alloc_flags = 0, - .dma_buf_count = 2, - .dma_buf_len = 1024, - .use_apll = 0, - }; - // install and start I2S driver - i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); - // init ADC pad - i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_4); - // enable adc sampling, ADC_WIDTH_BIT_12, ADC_ATTEN_DB_11 hard-coded in adc_i2s_mode_init - i2s_adc_enable(I2S_NUM_0); - // init read buffer - uint16_t* i2sReadBuffer = (uint16_t*)calloc(1024, sizeof(uint16_t)); - size_t bytesRead; - - for (int loop = 0; loop < 10; loop++) { - for (int level = 0; level <= 1; level++) { - if (level == 0) { - gpio_set_pull_mode(ADC1_CHANNEL_4_IO, GPIO_PULLDOWN_ONLY); - } else { - gpio_set_pull_mode(ADC1_CHANNEL_4_IO, GPIO_PULLUP_ONLY); - } - vTaskDelay(200 / portTICK_RATE_MS); - // read data from adc, will block until buffer is full - i2s_read(I2S_NUM_0, (void*)i2sReadBuffer, 1024 * sizeof(uint16_t), &bytesRead, portMAX_DELAY); - - // calc average - int64_t adcSumValue = 0; - for (size_t i = 0; i < 1024; i++) { - adcSumValue += i2sReadBuffer[i] & 0xfff; - } - int adcAvgValue = adcSumValue / 1024; - printf("adc average val: %d\n", adcAvgValue); - - if (level == 0) { - TEST_ASSERT_LESS_THAN(100, adcAvgValue); - } else { - TEST_ASSERT_GREATER_THAN(4000, adcAvgValue); - } - } - } - i2s_adc_disable(I2S_NUM_0); - free(i2sReadBuffer); - i2s_driver_uninstall(I2S_NUM_0); -} - +#if !DISABLED_FOR_TARGETS(ESP32S2, ESP32C3) +/* ESP32S2 and ESP32C3 has only single I2S port and hence following test cases are not applicable */ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") { // master driver installed and send data i2s_config_t master_i2s_config = { - .param_cfg = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = SAMPLE_RATE, - .slot_bits_cfg = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, -#if SOC_I2S_SUPPORTS_TDM - .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, - .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, - .left_align_en = false, - .big_edin_en = false, - .bit_order_msb_en = false, -#endif - }, + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, @@ -330,20 +260,11 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") printf("\r\nheap size: %d\n", esp_get_free_heap_size()); i2s_config_t slave_i2s_config = { - .param_cfg = { - .mode = I2S_MODE_SLAVE | I2S_MODE_RX, - .sample_rate = SAMPLE_RATE, - .slot_bits_cfg = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, -#if SOC_I2S_SUPPORTS_TDM - .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, - .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, - .left_align_en = false, - .big_edin_en = false, - .bit_order_msb_en = false, -#endif - }, + .mode = I2S_MODE_SLAVE | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, @@ -374,6 +295,7 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") int end_position = 0; // write data to slave i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t)*400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS); + printf("write data size: %d\n", i2s_bytes_write); while(!flag){ i2s_read(I2S_NUM_1, i2s_read_buff + length, sizeof(uint8_t)*500, &bytes_read, 1000/portMAX_DELAY); if(bytes_read>0) { @@ -402,20 +324,11 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") { // master driver installed and send data i2s_config_t master_i2s_config = { - .param_cfg = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX, - .sample_rate = SAMPLE_RATE, - .slot_bits_cfg = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, -#if SOC_I2S_SUPPORTS_TDM - .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, - .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, - .left_align_en = false, - .big_edin_en = false, - .bit_order_msb_en = false, -#endif - }, + .mode = I2S_MODE_MASTER | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 1, @@ -433,20 +346,11 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") printf("\r\nheap size: %d\n", esp_get_free_heap_size()); i2s_config_t slave_i2s_config = { - .param_cfg = { - .mode = I2S_MODE_SLAVE | I2S_MODE_TX, // Only RX - .sample_rate = SAMPLE_RATE, - .slot_bits_cfg = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = I2S_COMM_FORMAT_STAND_I2S, -#if SOC_I2S_SUPPORTS_TDM - .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, - .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, - .left_align_en = false, - .big_edin_en = false, - .bit_order_msb_en = false, -#endif - }, + .mode = I2S_MODE_SLAVE | I2S_MODE_TX, // Only RX + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = I2S_COMM_FORMAT_STAND_I2S, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 1, @@ -474,7 +378,7 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") } // slave write data to master i2s_write(I2S_NUM_1, data_wr, sizeof(uint8_t)*400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS); - + printf("write data size: %d\n", i2s_bytes_write); int flag=0; // break loop flag int end_position = 0; // write data to slave @@ -505,20 +409,11 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") TEST_CASE("I2S memory leaking test", "[i2s]") { i2s_config_t master_i2s_config = { - .param_cfg = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX, - .sample_rate = SAMPLE_RATE, - .slot_bits_cfg = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, -#if SOC_I2S_SUPPORTS_TDM - .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, - .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, - .left_align_en = false, - .big_edin_en = false, - .bit_order_msb_en = false, -#endif - }, + .mode = I2S_MODE_MASTER | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, @@ -561,20 +456,11 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]") }; i2s_config_t i2s_config = { - .param_cfg = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = SAMPLE_RATE, - .slot_bits_cfg = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, -#if SOC_I2S_SUPPORTS_TDM - .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, - .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, - .left_align_en = false, - .big_edin_en = false, - .bit_order_msb_en = false, -#endif - }, + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, .dma_buf_count = 6, .dma_buf_len = 60, .use_apll = true, @@ -591,8 +477,8 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]") for (int i = 0; i < (sizeof(sample_rate_arr)/sizeof(sample_rate_arr[0])); i++) { for (int j = 0; j < (sizeof(bits_per_sample_arr)/sizeof(bits_per_sample_arr[0])); j++) { - i2s_config.param_cfg.sample_rate = sample_rate_arr[i]; - i2s_config.param_cfg.slot_bits_cfg = bits_per_sample_arr[j]; + i2s_config.sample_rate = sample_rate_arr[i]; + i2s_config.bits_per_sample = bits_per_sample_arr[j]; TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config)); @@ -606,4 +492,93 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]") TEST_ASSERT(initial_size == esp_get_free_heap_size()); } +#if DISABLED_FOR_TARGETS(ESP32) +/* Only ESP32 need I2S adc/dac test */ +TEST_CASE("I2S adc test", "[i2s]") +{ + // init I2S ADC + i2s_config_t i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .intr_alloc_flags = 0, + .dma_buf_count = 2, + .dma_buf_len = 1024, + .use_apll = 0, + }; + // install and start I2S driver + i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); + // init ADC pad + i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_4); + // enable adc sampling, ADC_WIDTH_BIT_12, ADC_ATTEN_DB_11 hard-coded in adc_i2s_mode_init + i2s_adc_enable(I2S_NUM_0); + // init read buffer + uint16_t* i2sReadBuffer = (uint16_t*)calloc(1024, sizeof(uint16_t)); + size_t bytesRead; + + for (int loop = 0; loop < 10; loop++) { + for (int level = 0; level <= 1; level++) { + if (level == 0) { + gpio_set_pull_mode(ADC1_CHANNEL_4_IO, GPIO_PULLDOWN_ONLY); + } else { + gpio_set_pull_mode(ADC1_CHANNEL_4_IO, GPIO_PULLUP_ONLY); + } + vTaskDelay(200 / portTICK_RATE_MS); + // read data from adc, will block until buffer is full + i2s_read(I2S_NUM_0, (void*)i2sReadBuffer, 1024 * sizeof(uint16_t), &bytesRead, portMAX_DELAY); + + // calc average + int64_t adcSumValue = 0; + for (size_t i = 0; i < 1024; i++) { + adcSumValue += i2sReadBuffer[i] & 0xfff; + } + int adcAvgValue = adcSumValue / 1024; + printf("adc average val: %d\n", adcAvgValue); + + if (level == 0) { + if (adcAvgValue > 100) { + i2s_adc_disable(I2S_NUM_0); + free(i2sReadBuffer); + i2s_driver_uninstall(I2S_NUM_0); + TEST_ASSERT_LESS_THAN(100, adcAvgValue); + } + } else { + if (adcAvgValue < 4000) { + i2s_adc_disable(I2S_NUM_0); + free(i2sReadBuffer); + i2s_driver_uninstall(I2S_NUM_0); + TEST_ASSERT_GREATER_THAN(4000, adcAvgValue); + } + } + } + } + + i2s_adc_disable(I2S_NUM_0); + free(i2sReadBuffer); + i2s_driver_uninstall(I2S_NUM_0); +} + +TEST_CASE("I2S dac test", "[i2s]") +{ + // dac, adc i2s + i2s_config_t i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .dma_buf_count = 6, + .dma_buf_len = 60, + .use_apll = 0, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 , + }; + + //install and start i2s driver + TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); + //for internal DAC, this will enable both of the internal channels + TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, NULL)); + //stop & destroy i2s driver + TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0)); +} #endif diff --git a/components/efuse/esp32c3/private_include/esp_efuse_utility.h b/components/efuse/esp32c3/private_include/esp_efuse_utility.h index d2256ab312..37573eea8f 100644 --- a/components/efuse/esp32c3/private_include/esp_efuse_utility.h +++ b/components/efuse/esp32c3/private_include/esp_efuse_utility.h @@ -16,16 +16,6 @@ extern "C" { #define ESP_EFUSE_FIELD_CORRESPONDS_CODING_SCHEME(scheme, max_num_bit) -/*-------------------------- I2S CAPS ----------------------------------------*/ -#define SOC_I2S_NUM (1) -#define SOC_I2S_SUPPORTS_PCM (1) -#define SOC_I2S_SUPPORTS_PDM_TX (1) -#define SOC_I2S_SUPPORTS_PDM_RX (0) -#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) -#define SOC_I2S_SUPPORTS_TDM (1) -#define SOC_GDMA_I2S0_DMA_CHANNEL (0) - #ifdef __cplusplus } #endif - diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index 981a441705..79fa062f1c 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -33,12 +33,12 @@ extern "C" { // Get I2S hardware instance with giving i2s num #define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : (((num) == 1) ? (&I2S1) : NULL)) -#define I2S_INTR_IN_SUC_EOF BIT(9) -#define I2S_INTR_OUT_EOF BIT(12) -#define I2S_INTR_IN_DSCR_ERR BIT(13) -#define I2S_INTR_OUT_DSCR_ERR BIT(14) -#define I2S_INTR_MAX (0xFFFFFFFF) +#define I2S_LL_AD_BCK_FACTOR (2) +#define I2S_LL_PDM_BCK_FACTOR (64) +#define I2S_LL_BASE_CLK (2*APB_CLK_FREQ) +#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (6) +#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) /* I2S clock configuration structure */ typedef struct { @@ -46,56 +46,14 @@ typedef struct { uint16_t a; uint16_t b; // The decimal part of module clock devider, the decimal is: b/a uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div -} i2s_clk_cal_t; - -/** - * @brief Calculate the closest sample rate clock configuration. - * clock relationship: - * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) - * - * @param fsclk I2S source clock freq. - * @param fbck BCK freuency. - * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. - * @param cal Point to `i2s_clk_cal_t` structure. - */ -static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal) -{ - int ma = 0; - int mb = 0; - uint32_t mclk = fbck*bck_div; - cal->mclk_div = fsclk / mclk; - cal->bck_div = bck_div; - cal->a = 1; - cal->b = 0; - uint32_t freq_diff = fsclk - mclk * cal->mclk_div; - uint32_t min = ~0; - if (freq_diff == 0) { - return; - } - for (int a = 2; a <= 63; a++) { - for (int b = 1; b < a; b++) { - ma = freq_diff*a; - mb = mclk*b; - if (ma == mb) { - cal->a = a; - cal->b = b; - return; - } - if (abs((mb - ma)) < min) { - cal->a = a; - cal->b = b; - min = abs(mb - ma); - } - } - } -} +} i2s_ll_clk_cal_t; /** * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_general_init(i2s_dev_t *hw) +static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { if (hw->clkm_conf.clk_en == 0) { hw->clkm_conf.clk_en = 1; @@ -104,37 +62,70 @@ static inline void i2s_ll_general_init(i2s_dev_t *hw) } /** - * @brief I2S TX module general init. + * @brief I2S tx msb right enable * * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable tx msb right */ -static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw) +static inline void i2s_ll_tx_msb_right_en(i2s_dev_t *hw, bool enable) { - hw->conf.tx_start = 0; - hw->conf.tx_reset = 1; - hw->conf.tx_reset = 0; - hw->conf.tx_msb_right = 0; - hw->conf.tx_right_first = 0; - hw->conf.tx_slave_mod = 0; - hw->fifo_conf.tx_fifo_mod_force_en = 1; + hw->conf.tx_msb_right = enable; } /** - * @brief I2S RX module general init. + * @brief I2S rx msb right enable * * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable rx msb right */ -static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw) +static inline void i2s_ll_rx_msb_right_en(i2s_dev_t *hw, bool enable) { - hw->conf.rx_start = 0; - hw->conf.rx_reset = 1; - hw->conf.rx_reset = 0; - hw->conf.rx_msb_right = 0; - hw->conf.rx_right_first = 0; - hw->conf.rx_slave_mod = 0; - hw->fifo_conf.rx_fifo_mod_force_en = 1; + hw->conf.rx_msb_right = enable; } +/** + * @brief I2S tx right channel first + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable send right channel first + */ +static inline void i2s_ll_tx_right_first_en(i2s_dev_t *hw, bool enable) +{ + hw->conf.tx_right_first = enable; +} + +/** + * @brief I2S rx right channel first + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable receive right channel first + */ +static inline void i2s_ll_rx_right_first_en(i2s_dev_t *hw, bool enable) +{ + hw->conf.rx_right_first = enable; +} + +/** + * @brief I2S tx fifo module force enable + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable tx fifo module + */ +static inline void i2s_ll_tx_fifo_mod_force_en(i2s_dev_t *hw, bool enable) +{ + hw->fifo_conf.tx_fifo_mod_force_en = enable; +} + +/** + * @brief I2S rx fifo module force enable + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable rx fifo module + */ +static inline void i2s_ll_rx_fifo_mod_force_en(i2s_dev_t *hw, bool enable) +{ + hw->fifo_conf.rx_fifo_mod_force_en = enable; +} /** * @brief Enable I2S TX slave mode * @@ -233,7 +224,7 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { hw->clkm_conf.clkm_div_num = set->mclk_div; hw->clkm_conf.clkm_div_b = set->b; @@ -247,7 +238,7 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { hw->clkm_conf.clkm_div_num = set->mclk_div; hw->clkm_conf.clkm_div_b = set->b; @@ -495,11 +486,7 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i */ static inline void i2s_ll_dma_enable(i2s_dev_t *hw, bool ena) { - if (ena && !hw->fifo_conf.dscr_en) { - hw->fifo_conf.dscr_en = 1; - } else if (!ena && hw->fifo_conf.dscr_en) { - hw->fifo_conf.dscr_en = 0; - } + hw->fifo_conf.dscr_en = ena; } /** @@ -666,7 +653,7 @@ static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) */ static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) { - *dsr = hw->pdm_conf.rx_sinc_dsr_16_en; + *dsr = hw->pdm_conf.rx_sinc_dsr_16_en; } /** @@ -691,7 +678,7 @@ static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) uint32_t fp = 960; uint32_t fs = sample_rate / 100; typeof(hw->pdm_conf) pdm_conf_reg = hw->pdm_conf; - pdm_conf_reg.tx_sinc_osr2 = fp/fs; + pdm_conf_reg.tx_sinc_osr2 = fp / fs; pdm_conf_reg.tx_prescale = 0; pdm_conf_reg.tx_hp_in_shift = 1; pdm_conf_reg.tx_lp_in_shift = 1; diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index f9d7331a87..dc568148af 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -1,4 +1,4 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// The LL layer for I2C register operations +// The LL layer for I2S register operations /******************************************************************************* * NOTICE * The hal is not public api, don't use in application code. @@ -29,14 +29,14 @@ extern "C" { #endif -#define I2S_LL_GET_HW(num) (&I2S0) -#define I2S_INTR_OUT_DSCR_ERR (0x1 << 6) -#define I2S_INTR_OUT_EOF (0x1 << 4) -#define I2S_INTR_IN_DSCR_ERR (0x1 << 5) -#define I2S_INTR_IN_SUC_EOF (0x1 << 1) -#define I2S_INTR_MAX (~0) +#define I2S_LL_GET_HW(num) (&I2S0) -#define I2S_TDM_CH_MASK (0xffff) +#define I2S_LL_TDM_CH_MASK (0xffff) +#define I2S_LL_PDM_BCK_FACTOR (64) +#define I2S_LL_BASE_CLK (2*APB_CLK_FREQ) + +#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9) +#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) /* I2S clock configuration structure */ typedef struct { @@ -44,95 +44,58 @@ typedef struct { uint16_t a; uint16_t b; // The decimal part of module clock devider, the decimal is: b/a uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div -} i2s_clk_cal_t; - -/** - * @brief Calculate the closest sample rate clock configuration. - * clock relationship: - * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) - * - * @param fsclk I2S source clock freq. - * @param fbck BCK freuency. - * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. - * @param cal Point to `i2s_clk_cal_t` structure. - */ -static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal) -{ - int ma = 0; - int mb = 0; - uint32_t mclk = fbck*bck_div; - cal->mclk_div = fsclk / mclk; - cal->bck_div = bck_div; - cal->a = 1; - cal->b = 0; - uint32_t freq_diff = fsclk - mclk * cal->mclk_div; - uint32_t min = freq_diff * 512; - if (freq_diff == 0) { - return; - } - for (int a = 2; a <= 512; a++) { - for (int b = 1; b < a; b++) { - ma = freq_diff*a; - mb = mclk*b; - if (ma == mb) { - cal->a = a; - cal->b = b; - return; - } - if (abs((mb - ma)) < min) { - cal->a = a; - cal->b = b; - min = abs(mb - ma); - } - } - } -} +} i2s_ll_clk_cal_t; /** * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_general_init(i2s_dev_t *hw) +static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { hw->tx_clkm_conf.clk_en = 1; } /** - * @brief Reset I2S TX module, enable default source clock and set to TDM mode. + * @brief Enable I2S tx module clock * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw) +static inline void i2s_ll_enable_tx_clock(i2s_dev_t *hw) { - hw->tx_conf.tx_start = 0; - hw->tx_conf.tx_reset = 1; - hw->tx_conf.tx_reset = 0; - hw->tx_conf.tx_slave_mod = 0; - hw->tx_conf.tx_tdm_en = 1; - hw->tx_conf.tx_pdm_en = 0; hw->tx_clkm_conf.tx_clk_active = 1; - hw->tx_clkm_conf.tx_clk_sel = 2; } /** - * @brief Reset I2S RX module, enable default source clock and set to TDM mode. + * @brief Enable I2S rx module clock * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw) +static inline void i2s_ll_enable_rx_clock(i2s_dev_t *hw) { - hw->rx_conf.rx_start = 0; - hw->rx_conf.rx_reset = 1; - hw->rx_conf.rx_reset = 0; - hw->rx_conf.rx_slave_mod = 0; - hw->rx_conf.rx_tdm_en = 1; - hw->rx_conf.rx_pdm_en = 0; hw->rx_clkm_conf.rx_clk_active = 1; - hw->rx_clkm_conf.rx_clk_sel = 2; +} + +/** + * @brief I2S mclk use tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_mclk_use_tx_clk(i2s_dev_t *hw) +{ hw->rx_clkm_conf.mclk_sel = 0; } +/** + * @brief I2S mclk use rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_mclk_use_rx_clk(i2s_dev_t *hw) +{ + hw->rx_clkm_conf.mclk_sel = 1; +} + /** * @brief Enable I2S TX slave mode * @@ -203,7 +166,7 @@ static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) * @brief Set TX source clock * * @param hw Peripheral I2S hardware instance address. - * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` + * @param src I2S source clock. */ static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { @@ -227,27 +190,27 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { if (set->a == 0 || set->b == 0) { hw->tx_clkm_div_conf.tx_clkm_div_x = 0; hw->tx_clkm_div_conf.tx_clkm_div_y = 0; hw->tx_clkm_div_conf.tx_clkm_div_z = 0; } else { - if(set->b > set->a/2) { - hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/(set->a-set->b) -1; - hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%(set->a-set->b); - hw->tx_clkm_div_conf.tx_clkm_div_z = set->a-set->b; + if (set->b > set->a / 2) { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / (set->a - set->b) - 1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % (set->a - set->b); + hw->tx_clkm_div_conf.tx_clkm_div_z = set->a - set->b; hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 1; } else { - hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/set->b-1; - hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%set->b+1; + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / set->b - 1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % set->b + 1; hw->tx_clkm_div_conf.tx_clkm_div_z = set->b; hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0; } } hw->tx_clkm_conf.tx_clkm_div_num = set->mclk_div; - hw->tx_conf1.tx_bck_div_num = set->bck_div-1; + hw->tx_conf1.tx_bck_div_num = set->bck_div - 1; } /** @@ -256,27 +219,27 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { if (set->a == 0 || set->b == 0) { hw->rx_clkm_div_conf.rx_clkm_div_x = 0; hw->rx_clkm_div_conf.rx_clkm_div_y = 0; hw->rx_clkm_div_conf.rx_clkm_div_z = 0; } else { - if(set->b > set->a/2) { - hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/(set->a-set->b)-1; - hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%(set->a-set->b); - hw->rx_clkm_div_conf.rx_clkm_div_z = set->a-set->b; + if (set->b > set->a / 2) { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / (set->a - set->b) - 1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % (set->a - set->b); + hw->rx_clkm_div_conf.rx_clkm_div_z = set->a - set->b; hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 1; } else { - hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/set->b-1; - hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%set->b+1; + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / set->b - 1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % set->b + 1; hw->rx_clkm_div_conf.rx_clkm_div_z = set->b; hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0; } } hw->rx_clkm_conf.rx_clkm_div_num = set->mclk_div; - hw->rx_conf1.rx_bck_div_num = set->bck_div-1; + hw->rx_conf1.rx_bck_div_num = set->bck_div - 1; } /** @@ -331,7 +294,7 @@ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) */ static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) { - hw->tx_conf1.tx_tdm_ws_width = width-1; + hw->tx_conf1.tx_tdm_ws_width = width - 1; } /** @@ -342,7 +305,7 @@ static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) */ static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) { - hw->rx_conf1.rx_tdm_ws_width = width-1; + hw->rx_conf1.rx_tdm_ws_width = width - 1; } /** @@ -366,7 +329,7 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { hw->tx_conf1.tx_bits_mod = data_bit - 1; - hw->tx_conf1.tx_tdm_chan_bits = sample_bit-1; + hw->tx_conf1.tx_tdm_chan_bits = sample_bit - 1; } /** @@ -379,7 +342,7 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { hw->rx_conf1.rx_bits_mod = data_bit - 1; - hw->rx_conf1.rx_tdm_chan_bits = sample_bit-1; + hw->rx_conf1.rx_tdm_chan_bits = sample_bit - 1; } /** @@ -390,7 +353,7 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i */ static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { - hw->tx_conf1.tx_half_sample_bits = half_sample_bits-1; + hw->tx_conf1.tx_half_sample_bits = half_sample_bits - 1; } /** @@ -401,7 +364,7 @@ static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_ */ static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { - hw->rx_conf1.rx_half_sample_bits = half_sample_bits-1; + hw->rx_conf1.rx_half_sample_bits = half_sample_bits - 1; } /** @@ -432,9 +395,9 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab * @param hw Peripheral I2S hardware instance address. * @param total_num Total slot number */ -static inline void i2s_ll_set_tx_slot_mun(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_set_tx_slot_num(i2s_dev_t *hw, int total_num) { - hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num-1; + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; } /** @@ -443,22 +406,22 @@ static inline void i2s_ll_set_tx_slot_mun(i2s_dev_t *hw, int total_num) * @param hw Peripheral I2S hardware instance address. * @param total_num Total slot number */ -static inline void i2s_ll_set_rx_slot_mun(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_set_rx_slot_num(i2s_dev_t *hw, int total_num) { - hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num-1; + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; } /** * @brief Set the bimap of the active TX slot, only the active slot can launch audio data. * * @param hw Peripheral I2S hardware instance address. - * @param + * @param slot_mask mask of tx active slot */ static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) { typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; - tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK; - tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK; + tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; } @@ -466,13 +429,13 @@ static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_m * @brief Set the bimap of the active RX slot, only the active slot can receive audio data. * * @param hw Peripheral I2S hardware instance address. - * @param + * @param slot_mask mask of rx active slot */ static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) { typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; - tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK; - tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK; + tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; } @@ -480,7 +443,7 @@ static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_m * @brief Set TX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param + * @param ws_pol_level pin level of WS(output) when receiving left channel data */ static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { @@ -491,7 +454,7 @@ static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) * @brief Set RX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param + * @param ws_pol_level pin level of WS(input) when receiving left channel data */ static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { @@ -533,7 +496,7 @@ static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) pdm_conf_reg.tx_pdm_lp_in_shift = 1; pdm_conf_reg.tx_pdm_sinc_in_shift = 1; pdm_conf_reg.tx_pdm_sigmadelta_in_shift = 1; - pdm_conf_reg.tx_pdm_sinc_osr2 = fp/fs; + pdm_conf_reg.tx_pdm_sinc_osr2 = fp / fs; pdm_conf_reg.tx_pdm_dac_mode_en = 1; pdm_conf_reg.tx_pdm_sigmadelta_dither = 0; pdm_conf_reg.tx_pdm_sigmadelta_dither2 = 0; @@ -541,7 +504,7 @@ static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) pdm_conf1_reg.tx_pdm_fp = fp; pdm_conf1_reg.tx_pdm_fs = fs; pdm_conf1_reg.tx_iir_hp_mult12_5 = 7; - pdm_conf1_reg.tx_iir_hp_mult12_0 =6; + pdm_conf1_reg.tx_iir_hp_mult12_0 = 6; pdm_conf_reg.tx_pdm_hp_bypass = 0; hw->tx_pcm2pdm_conf = pdm_conf_reg; hw->tx_pcm2pdm_conf1 = pdm_conf1_reg; @@ -583,13 +546,8 @@ static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t */ static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { - if (pdm_enable) { - hw->rx_conf.rx_tdm_en = 0; - hw->rx_conf.rx_pdm_en = 1; - } else { - hw->rx_conf.rx_pdm_en = 0; - hw->rx_conf.rx_tdm_en = 1; - } + hw->rx_conf.rx_pdm_en = pdm_enable; + hw->rx_conf.rx_tdm_en = !pdm_enable; } /** @@ -598,7 +556,7 @@ static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) +static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) { if (pcm_cfg == I2S_PCM_DISABLE) { hw->tx_conf.tx_pcm_bypass = 1; @@ -614,7 +572,7 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) +static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) { if (pcm_cfg == I2S_PCM_DISABLE) { hw->rx_conf.rx_pcm_bypass = 1; @@ -690,6 +648,18 @@ static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) hw->rx_conf.rx_bit_order = lsb_order_ena; } +/** + * @brief Configure TX skip mask enable + * + * @param hw Peripheral I2S hardware instance address. + * @param skip_mask_ena Set true to skip inactive channels. + */ +static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena) +{ + hw->tx_tdm_ctrl.tx_tdm_skip_msk_en = skip_mask_ena; +} + + /** * @brief Configure single data * diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index fc683436e2..e1f677cf32 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -31,13 +31,12 @@ extern "C" { #endif // Get I2S hardware instance with giving i2s num -#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL) +#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL) -#define I2S_INTR_IN_SUC_EOF BIT(9) -#define I2S_INTR_OUT_EOF BIT(12) -#define I2S_INTR_IN_DSCR_ERR BIT(13) -#define I2S_INTR_OUT_DSCR_ERR BIT(14) -#define I2S_INTR_MAX (0xFFFFFFFF) +#define I2S_LL_BASE_CLK (2*APB_CLK_FREQ) + +#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (6) +#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) /* I2S clock configuration structure */ typedef struct { @@ -45,56 +44,14 @@ typedef struct { uint16_t a; uint16_t b; // The decimal part of module clock devider, the decimal is: b/a uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div -} i2s_clk_cal_t; - -/** - * @brief Calculate the closest sample rate clock configuration. - * clock relationship: - * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) - * - * @param fsclk I2S source clock freq. - * @param fbck BCK freuency. - * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. - * @param cal Point to `i2s_clk_cal_t` structure. - */ -static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal) -{ - int ma = 0; - int mb = 0; - uint32_t mclk = fbck*bck_div; - cal->mclk_div = fsclk / mclk; - cal->bck_div = bck_div; - cal->a = 1; - cal->b = 0; - uint32_t freq_diff = fsclk - mclk * cal->mclk_div; - uint32_t min = ~0; - if (freq_diff == 0) { - return; - } - for (int a = 2; a <= 63; a++) { - for (int b = 1; b < a; b++) { - ma = freq_diff*a; - mb = mclk*b; - if (ma == mb) { - cal->a = a; - cal->b = b; - return; - } - if (abs((mb - ma)) < min) { - cal->a = a; - cal->b = b; - min = abs(mb - ma); - } - } - } -} +} i2s_ll_clk_cal_t; /** * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_general_init(i2s_dev_t *hw) +static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { if (hw->clkm_conf.clk_en == 0) { hw->clkm_conf.clk_sel = 2; @@ -104,35 +61,69 @@ static inline void i2s_ll_general_init(i2s_dev_t *hw) } /** - * @brief I2S TX module general init. + * @brief I2S tx msb right enable * * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable tx msb right */ -static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw) +static inline void i2s_ll_tx_msb_right_en(i2s_dev_t *hw, bool enable) { - hw->conf.tx_start = 0; - hw->conf.tx_reset = 1; - hw->conf.tx_reset = 0; - hw->conf.tx_msb_right = 0; - hw->conf.tx_right_first = 0; - hw->conf.tx_slave_mod = 0; - hw->fifo_conf.tx_fifo_mod_force_en = 1; + hw->conf.tx_msb_right = enable; } /** - * @brief I2S RX module general init. + * @brief I2S rx msb right enable * * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable rx msb right */ -static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw) +static inline void i2s_ll_rx_msb_right_en(i2s_dev_t *hw, bool enable) { - hw->conf.rx_start = 0; - hw->conf.rx_reset = 1; - hw->conf.rx_reset = 0; - hw->conf.rx_msb_right = 0; - hw->conf.rx_right_first = 0; - hw->conf.rx_slave_mod = 0; - hw->fifo_conf.rx_fifo_mod_force_en = 1; + hw->conf.rx_msb_right = enable; +} + +/** + * @brief I2S tx right channel first + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable send right channel first + */ +static inline void i2s_ll_tx_right_first_en(i2s_dev_t *hw, bool enable) +{ + hw->conf.tx_right_first = enable; +} + +/** + * @brief I2S rx right channel first + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable receive right channel first + */ +static inline void i2s_ll_rx_right_first_en(i2s_dev_t *hw, bool enable) +{ + hw->conf.rx_right_first = enable; +} + +/** + * @brief I2S tx fifo module force enable + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable tx fifo module + */ +static inline void i2s_ll_tx_fifo_mod_force_en(i2s_dev_t *hw, bool enable) +{ + hw->fifo_conf.tx_fifo_mod_force_en = enable; +} + +/** + * @brief I2S rx fifo module force enable + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable rx fifo module + */ +static inline void i2s_ll_rx_fifo_mod_force_en(i2s_dev_t *hw, bool enable) +{ + hw->fifo_conf.rx_fifo_mod_force_en = enable; } /** @@ -229,7 +220,7 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { hw->clkm_conf.clkm_div_num = set->mclk_div; hw->clkm_conf.clkm_div_b = set->b; @@ -243,7 +234,7 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { hw->clkm_conf.clkm_div_num = set->mclk_div; hw->clkm_conf.clkm_div_b = set->b; @@ -490,11 +481,7 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i */ static inline void i2s_ll_dma_enable(i2s_dev_t *hw, bool ena) { - if (ena && !hw->fifo_conf.dscr_en) { - hw->fifo_conf.dscr_en = 1; - } else if (!ena && hw->fifo_conf.dscr_en) { - hw->fifo_conf.dscr_en = 0; - } + hw->fifo_conf.dscr_en = ena; } /** diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 618b204d2d..85b91dc077 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -1,4 +1,4 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// The LL layer for I2C register operations +// The LL layer for I2S register operations /******************************************************************************* * NOTICE * The hal is not public api, don't use in application code. @@ -30,13 +30,13 @@ extern "C" { #define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : &I2S1) -#define I2S_INTR_OUT_DSCR_ERR (0x1 << 6) -#define I2S_INTR_OUT_EOF (0x1 << 4) -#define I2S_INTR_IN_DSCR_ERR (0x1 << 5) -#define I2S_INTR_IN_SUC_EOF (0x1 << 1) -#define I2S_INTR_MAX (~0) -#define I2S_TDM_CH_MASK (0xffff) +#define I2S_LL_TDM_CH_MASK (0xffff) +#define I2S_LL_PDM_BCK_FACTOR (64) +#define I2S_LL_BASE_CLK (2*APB_CLK_FREQ) + +#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9) +#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) /* I2S clock configuration structure */ typedef struct { @@ -44,95 +44,58 @@ typedef struct { uint16_t a; uint16_t b; // The decimal part of module clock devider, the decimal is: b/a uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div -} i2s_clk_cal_t; - -/** - * @brief Calculate the closest sample rate clock configuration. - * clock relationship: - * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) - * - * @param fsclk I2S source clock freq. - * @param fbck BCK freuency. - * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. - * @param cal Point to `i2s_clk_cal_t` structure. - */ -static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal) -{ - int ma = 0; - int mb = 0; - uint32_t mclk = fbck*bck_div; - cal->mclk_div = fsclk / mclk; - cal->bck_div = bck_div; - cal->a = 1; - cal->b = 0; - uint32_t freq_diff = fsclk - mclk * cal->mclk_div; - uint32_t min = freq_diff * 512; - if (freq_diff == 0) { - return; - } - for (int a = 2; a <= 512; a++) { - for (int b = 1; b < a; b++) { - ma = freq_diff*a; - mb = mclk*b; - if (ma == mb) { - cal->a = a; - cal->b = b; - return; - } - if (abs((mb - ma)) < min) { - cal->a = a; - cal->b = b; - min = abs(mb - ma); - } - } - } -} +} i2s_ll_clk_cal_t; /** * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_general_init(i2s_dev_t *hw) +static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { hw->tx_clkm_conf.clk_en = 1; } /** - * @brief Reset I2S TX module, enable default source clock and set to TDM mode. + * @brief Enable I2S tx module clock * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw) +static inline void i2s_ll_enable_tx_clock(i2s_dev_t *hw) { - hw->tx_conf.tx_start = 0; - hw->tx_conf.tx_reset = 1; - hw->tx_conf.tx_reset = 0; - hw->tx_conf.tx_slave_mod = 0; - hw->tx_conf.tx_tdm_en = 1; - hw->tx_conf.tx_pdm_en = 0; hw->tx_clkm_conf.tx_clk_active = 1; - hw->tx_clkm_conf.tx_clk_sel = 2; } /** - * @brief Reset I2S RX module, enable default source clock and set to TDM mode. + * @brief Enable I2S rx module clock * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw) +static inline void i2s_ll_enable_rx_clock(i2s_dev_t *hw) { - hw->rx_conf.rx_start = 0; - hw->rx_conf.rx_reset = 1; - hw->rx_conf.rx_reset = 0; - hw->rx_conf.rx_slave_mod = 0; - hw->rx_conf.rx_tdm_en = 1; - hw->rx_conf.rx_pdm_en = 0; hw->rx_clkm_conf.rx_clk_active = 1; - hw->rx_clkm_conf.rx_clk_sel = 2; +} + +/** + * @brief I2S mclk use tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_mclk_use_tx_clk(i2s_dev_t *hw) +{ hw->rx_clkm_conf.mclk_sel = 0; } +/** + * @brief I2S mclk use rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_mclk_use_rx_clk(i2s_dev_t *hw) +{ + hw->rx_clkm_conf.mclk_sel = 1; +} + /** * @brief Enable I2S TX slave mode * @@ -204,6 +167,7 @@ static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` + * TX and RX share the same clock setting */ static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { @@ -215,6 +179,7 @@ static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * * @param hw Peripheral I2S hardware instance address. * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` + * TX and RX share the same clock setting */ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { @@ -227,27 +192,27 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { if (set->a == 0 || set->b == 0) { hw->tx_clkm_div_conf.tx_clkm_div_x = 0; hw->tx_clkm_div_conf.tx_clkm_div_y = 0; hw->tx_clkm_div_conf.tx_clkm_div_z = 0; } else { - if(set->b > set->a/2) { - hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/(set->a-set->b) -1; - hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%(set->a-set->b); - hw->tx_clkm_div_conf.tx_clkm_div_z = set->a-set->b; + if (set->b > set->a / 2) { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / (set->a - set->b) - 1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % (set->a - set->b); + hw->tx_clkm_div_conf.tx_clkm_div_z = set->a - set->b; hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 1; } else { - hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/set->b-1; - hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%set->b+1; + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / set->b - 1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % set->b + 1; hw->tx_clkm_div_conf.tx_clkm_div_z = set->b; hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0; } } hw->tx_clkm_conf.tx_clkm_div_num = set->mclk_div; - hw->tx_conf1.tx_bck_div_num = set->bck_div-1; + hw->tx_conf1.tx_bck_div_num = set->bck_div - 1; } /** @@ -256,27 +221,27 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { if (set->a == 0 || set->b == 0) { hw->rx_clkm_div_conf.rx_clkm_div_x = 0; hw->rx_clkm_div_conf.rx_clkm_div_y = 0; hw->rx_clkm_div_conf.rx_clkm_div_z = 0; } else { - if(set->b > set->a/2) { - hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/(set->a-set->b)-1; - hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%(set->a-set->b); - hw->rx_clkm_div_conf.rx_clkm_div_z = set->a-set->b; + if (set->b > set->a / 2) { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / (set->a - set->b) - 1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % (set->a - set->b); + hw->rx_clkm_div_conf.rx_clkm_div_z = set->a - set->b; hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 1; } else { - hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/set->b-1; - hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%set->b+1; + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / set->b - 1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % set->b + 1; hw->rx_clkm_div_conf.rx_clkm_div_z = set->b; hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0; } } hw->rx_clkm_conf.rx_clkm_div_num = set->mclk_div; - hw->rx_conf1.rx_bck_div_num = set->bck_div-1; + hw->rx_conf1.rx_bck_div_num = set->bck_div - 1; } /** @@ -331,7 +296,7 @@ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) */ static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) { - hw->tx_conf1.tx_tdm_ws_width = width-1; + hw->tx_conf1.tx_tdm_ws_width = width - 1; } /** @@ -342,7 +307,7 @@ static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) */ static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) { - hw->rx_conf1.rx_tdm_ws_width = width-1; + hw->rx_conf1.rx_tdm_ws_width = width - 1; } /** @@ -366,7 +331,7 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { hw->tx_conf1.tx_bits_mod = data_bit - 1; - hw->tx_conf1.tx_tdm_chan_bits = sample_bit-1; + hw->tx_conf1.tx_tdm_chan_bits = sample_bit - 1; } /** @@ -379,7 +344,7 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { hw->rx_conf1.rx_bits_mod = data_bit - 1; - hw->rx_conf1.rx_tdm_chan_bits = sample_bit-1; + hw->rx_conf1.rx_tdm_chan_bits = sample_bit - 1; } /** @@ -390,7 +355,7 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i */ static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { - hw->tx_conf1.tx_half_sample_bits = half_sample_bits-1; + hw->tx_conf1.tx_half_sample_bits = half_sample_bits - 1; } /** @@ -401,7 +366,7 @@ static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_ */ static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { - hw->rx_conf1.rx_half_sample_bits = half_sample_bits-1; + hw->rx_conf1.rx_half_sample_bits = half_sample_bits - 1; } /** @@ -432,9 +397,9 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab * @param hw Peripheral I2S hardware instance address. * @param total_num Total slot number */ -static inline void i2s_ll_set_tx_slot_mun(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_set_tx_slot_num(i2s_dev_t *hw, int total_num) { - hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num-1; + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; } /** @@ -443,22 +408,22 @@ static inline void i2s_ll_set_tx_slot_mun(i2s_dev_t *hw, int total_num) * @param hw Peripheral I2S hardware instance address. * @param total_num Total slot number */ -static inline void i2s_ll_set_rx_slot_mun(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_set_rx_slot_num(i2s_dev_t *hw, int total_num) { - hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num-1; + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; } /** * @brief Set the bimap of the active TX slot, only the active slot can launch audio data. * * @param hw Peripheral I2S hardware instance address. - * @param + * @param slot_mask mask of tx active slot */ static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) { typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; - tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK; - tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK; + tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; } @@ -466,13 +431,13 @@ static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_m * @brief Set the bimap of the active RX slot, only the active slot can receive audio data. * * @param hw Peripheral I2S hardware instance address. - * @param + * @param slot_mask mask of rx active slot */ static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) { typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; - tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK; - tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK; + tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; } @@ -480,7 +445,7 @@ static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_m * @brief Set TX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param + * @param ws_pol_level pin level of WS(output) when receiving left channel data */ static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { @@ -491,7 +456,7 @@ static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) * @brief Set RX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param + * @param ws_pol_level pin level of WS(input) when receiving left channel data */ static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { @@ -506,13 +471,8 @@ static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) */ static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { - if (pdm_enable) { - hw->tx_conf.tx_tdm_en = 0; - hw->tx_conf.tx_pdm_en = 1; - } else { - hw->tx_conf.tx_pdm_en = 0; - hw->tx_conf.tx_tdm_en = 1; - } + hw->tx_conf.tx_pdm_en = pdm_enable; + hw->tx_conf.tx_tdm_en = !pdm_enable; } /** @@ -523,13 +483,68 @@ static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable) */ static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { - if (pdm_enable) { - hw->rx_conf.rx_tdm_en = 0; - hw->rx_conf.rx_pdm_en = 1; - } else { - hw->rx_conf.rx_pdm_en = 0; - hw->rx_conf.rx_tdm_en = 1; - } + hw->rx_conf.rx_pdm_en = pdm_enable; + hw->rx_conf.rx_tdm_en = !pdm_enable; +} + +/** + * @brief Configure I2S TX PDM sample rate + * Fpdm = 64*Fpcm*fp/fs + * + * @param hw Peripheral I2S hardware instance address. + * @param fp The fp value of TX PDM filter module group0. + * @param fs The fs value of TX PDM filter module group0. + */ +static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) +{ + hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp; + hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs; + hw->tx_pcm2pdm_conf.tx_sinc_osr2 = fp / fs; +} + +/** + * @brief Get I2S TX PDM configuration + * + * @param hw Peripheral I2S hardware instance address. + * @param fp Pointer to accept TX PDM fp configuration paramater + * @param fs Pointer to accept TX PDM fs configuration paramater + */ +static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) +{ + *fp = hw->tx_pcm2pdm_conf1.tx_pdm_fp; + *fs = hw->tx_pcm2pdm_conf1.tx_pdm_fs; +} + +/** + * @brief Configure I2S TX pdm + * + * @param hw Peripheral I2S hardware instance address. + * @param sample_rate The sample rate to be set. + */ +static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) +{ + uint32_t fp = 960; + uint32_t fs = sample_rate / 100; + typeof(hw->tx_pcm2pdm_conf) pdm_conf_reg = hw->tx_pcm2pdm_conf; + typeof(hw->tx_pcm2pdm_conf1) pdm_conf1_reg = hw->tx_pcm2pdm_conf1; + pdm_conf_reg.pcm2pdm_conv_en = 1; + pdm_conf_reg.tx_prescale = 0; + pdm_conf_reg.tx_hp_in_shift = 1; + pdm_conf_reg.tx_lp_in_shift = 1; + pdm_conf_reg.tx_sinc_in_shift = 1; + pdm_conf_reg.tx_sigmadelta_in_shift = 1; + pdm_conf_reg.tx_sinc_osr2 = fp / fs; + pdm_conf_reg.tx_dac_mode_en = 1; + pdm_conf_reg.tx_sigmadelta_dither = 0; + pdm_conf_reg.tx_sigmadelta_dither2 = 0; + pdm_conf_reg.tx_dac_2out_en = 1; + pdm_conf1_reg.tx_pdm_fp = fp; + pdm_conf1_reg.tx_pdm_fs = fs; + pdm_conf1_reg.tx_iir_hp_mult12_5 = 7; + pdm_conf1_reg.tx_iir_hp_mult12_0 = 6; + pdm_conf_reg.tx_hp_bypass = 0; + hw->tx_pcm2pdm_conf = pdm_conf_reg; + hw->tx_pcm2pdm_conf1 = pdm_conf1_reg; } /** @@ -541,7 +556,7 @@ static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw) { hw->rx_conf.rx_tdm_en = 0; hw->rx_conf.rx_pdm2pcm_en = 1; - hw->rx_conf.rx_sinc_dsr_16_en = 0; + hw->rx_conf.rx_pdm_sinc_dsr_16_en = 0; hw->rx_conf.rx_pdm_en = 1; } @@ -553,7 +568,7 @@ static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw) */ static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) { - hw->rx_conf.rx_sinc_dsr_16_en = dsr; + hw->rx_conf.rx_pdm_sinc_dsr_16_en = dsr; } /** @@ -564,7 +579,7 @@ static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) */ static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) { - *dsr = hw->rx_conf.rx_sinc_dsr_16_en; + *dsr = hw->rx_conf.rx_pdm_sinc_dsr_16_en; } /** @@ -573,7 +588,7 @@ static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) +static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) { if (pcm_cfg == I2S_PCM_DISABLE) { hw->tx_conf.tx_pcm_bypass = 1; @@ -589,7 +604,7 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) +static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) { if (pcm_cfg == I2S_PCM_DISABLE) { hw->rx_conf.rx_pcm_bypass = 1; @@ -665,6 +680,18 @@ static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) hw->rx_conf.rx_bit_order = lsb_order_ena; } +/** + * @brief Configure TX skip mask enable + * + * @param hw Peripheral I2S hardware instance address. + * @param skip_mask_ena Set true to skip inactive channels. + */ +static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena) +{ + hw->tx_tdm_ctrl.tx_tdm_skip_msk_en = skip_mask_ena; +} + + /** * @brief Configure single data * @@ -673,7 +700,7 @@ static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) */ static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) { - hw->conf_single_data = data; + hw->conf_signal_data = data; } /** diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index c3c008ce5e..49726d8204 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -17,59 +17,50 @@ #include "soc/soc.h" #include "soc/soc_caps.h" -#include "soc/gdma_channel.h" #include "hal/i2s_hal.h" #define I2S_MODE_I2S (I2S_MODE_MASTER|I2S_MODE_SLAVE|I2S_MODE_TX|I2S_MODE_RX) /*!< I2S normal mode*/ -void i2s_hal_reset_tx(i2s_hal_context_t *hal) +/** + * @brief Calculate the closest sample rate clock configuration. + * clock relationship: + * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) + * + * @param fsclk I2S source clock freq. + * @param fbck BCK freuency. + * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. + * @param cal Point to `i2s_ll_clk_cal_t` structure. + */ +static void i2s_hal_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_ll_clk_cal_t *cal) { - i2s_ll_reset_tx(hal->dev); -} - -void i2s_hal_reset_rx(i2s_hal_context_t *hal) -{ - i2s_ll_reset_rx(hal->dev); -} - -void i2s_hal_reset_tx_fifo(i2s_hal_context_t *hal) -{ - i2s_ll_reset_tx_fifo(hal->dev); -} - -void i2s_hal_reset_rx_fifo(i2s_hal_context_t *hal) -{ - i2s_ll_reset_rx_fifo(hal->dev); -} - -void i2s_hal_start_tx(i2s_hal_context_t *hal) -{ - i2s_ll_start_tx(hal->dev); -} - -void i2s_hal_start_rx(i2s_hal_context_t *hal) -{ - i2s_ll_start_rx(hal->dev); -} - -void i2s_hal_stop_tx(i2s_hal_context_t *hal) -{ - i2s_ll_stop_tx(hal->dev); -} - -void i2s_hal_stop_rx(i2s_hal_context_t *hal) -{ - i2s_ll_stop_rx(hal->dev); -} - -void i2s_hal_set_tx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit) -{ - i2s_ll_set_tx_sample_bit(hal->dev, slot_bit, data_bit); -} - -void i2s_hal_set_rx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit) -{ - i2s_ll_set_rx_sample_bit(hal->dev, slot_bit, data_bit); + int ma = 0; + int mb = 0; + uint32_t mclk = fbck * bck_div; + cal->mclk_div = fsclk / mclk; + cal->bck_div = bck_div; + cal->a = 1; + cal->b = 0; + uint32_t freq_diff = fsclk - mclk * cal->mclk_div; + uint32_t min = ~0; + if (freq_diff == 0) { + return; + } + for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) { + for (int b = 1; b < a; b++) { + ma = freq_diff * a; + mb = mclk * b; + if (ma == mb) { + cal->a = a; + cal->b = b; + return; + } + if (abs((mb - ma)) < min) { + cal->a = a; + cal->b = b; + min = abs(mb - ma); + } + } + } } void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel) @@ -80,23 +71,18 @@ void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel) void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor) { - i2s_clk_cal_t clk_set = {0}; - i2s_ll_clk_cal(sclk, fbck, factor, &clk_set); + i2s_ll_clk_cal_t clk_set = {0}; + i2s_hal_clk_cal(sclk, fbck, factor, &clk_set); i2s_ll_set_tx_clk(hal->dev, &clk_set); } void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor) { - i2s_clk_cal_t clk_set = {0}; - i2s_ll_clk_cal(sclk, fbck, factor, &clk_set); + i2s_ll_clk_cal_t clk_set = {0}; + i2s_hal_clk_cal(sclk, fbck, factor, &clk_set); i2s_ll_set_rx_clk(hal->dev, &clk_set); } -void i2s_hal_set_rx_eof_num(i2s_hal_context_t *hal, uint32_t eof_byte) -{ - i2s_ll_set_rx_eof_num(hal->dev, eof_byte); -} - void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal) { i2s_ll_set_tx_slave_mod(hal->dev, 0); //TX master @@ -109,200 +95,175 @@ void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal) i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave } -#if SOC_I2S_SUPPORTS_PCM -void i2s_hal_tx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg) -{ - i2s_ll_tx_pcm_cfg(hal->dev, cfg); -} - -void i2s_hal_rx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg) -{ - i2s_ll_rx_pcm_cfg(hal->dev, cfg); -} -#endif - -void i2s_hal_enable_sig_loopback(i2s_hal_context_t *hal) -{ - i2s_ll_loop_back_ena(hal->dev, 1); -} - -#if SOC_I2S_SUPPORTS_PDM_TX -void i2s_hal_set_tx_pdm_fpfs(i2s_hal_context_t *hal, int fp, int fs) -{ - i2s_ll_set_tx_pdm_fpfs(hal->dev, fp, fs); -} - -void i2s_hal_get_tx_pdm_fpfs(i2s_hal_context_t *hal, int *fp, int *fs) -{ - i2s_ll_get_tx_pdm_fpfs(hal->dev, (uint32_t *)fp, (uint32_t *)fs); -} -#endif - -#if SOC_I2S_SUPPORTS_PDM_RX -void i2s_hal_set_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t dsr) -{ - i2s_ll_set_pdm_rx_dsr(hal->dev, dsr); -} - -void i2s_hal_get_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t *dsr) -{ - i2s_ll_get_pdm_rx_dsr(hal->dev, dsr); -} -#endif - void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num) { //Get hardware instance. hal->dev = I2S_LL_GET_HW(i2s_num); -#if SOC_GDMA_SUPPORTED - hal->dma = &GDMA; - if (i2s_num == 0) { - hal->dma_ch = SOC_GDMA_I2S0_DMA_CHANNEL; - hal->dma_peri_sel = SOC_GDMA_TRIG_PERIPH_I2S0; - } -#if SOC_I2S_NUM > 1 - if (i2s_num == 1) { - hal->dma_ch = SOC_GDMA_I2S1_DMA_CHANNEL; - hal->dma_peri_sel = SOC_GDMA_TRIG_PERIPH_I2S1; - } -#endif - gdma_ll_enable_m2m_mode(hal->dma, hal->dma_ch, false); -#endif - i2s_ll_general_init(hal->dev); + i2s_ll_enable_clock(hal->dev); } -static void i2s_hal_format_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg) +static void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) { - int active_slot_num = slot_ch_cfg & 0xffff; #if !SOC_I2S_SUPPORTS_TDM - switch (format) { - case I2S_COMM_FORMAT_STAND_MSB: - if (i2s_mode & I2S_MODE_TX) { - i2s_ll_set_tx_format_msb_align(hal->dev); - } - if (i2s_mode & I2S_MODE_RX) { - i2s_ll_set_rx_format_msb_align(hal->dev); - } - break; - case I2S_COMM_FORMAT_STAND_PCM_SHORT: - if (i2s_mode & I2S_MODE_TX) { - i2s_ll_set_tx_pcm_short(hal->dev); - } - if (i2s_mode & I2S_MODE_RX) { - i2s_ll_set_rx_pcm_short(hal->dev); - } - break; - case I2S_COMM_FORMAT_STAND_PCM_LONG: - if (i2s_mode & I2S_MODE_TX) { - i2s_ll_set_tx_pcm_long(hal->dev); - } - if (i2s_mode & I2S_MODE_RX) { - i2s_ll_set_rx_pcm_long(hal->dev); - } - break; - default: //I2S_COMM_FORMAT_STAND_I2S - if (i2s_mode & I2S_MODE_TX) { - i2s_ll_set_tx_format_philip(hal->dev); - } - if (i2s_mode & I2S_MODE_RX) { - i2s_ll_set_rx_format_philip(hal->dev); - } - break; - } - if (active_slot_num == I2S_CHANNEL_MONO) { - if (i2s_mode & I2S_MODE_TX) { - i2s_ll_tx_mono_mode_ena(hal->dev, active_slot_num == I2S_CHANNEL_MONO); + switch (hal_cfg->comm_fmt) { + case I2S_COMM_FORMAT_STAND_MSB: + if (hal_cfg->mode & I2S_MODE_TX) { + i2s_ll_set_tx_format_msb_align(hal->dev); } - if (i2s_mode & I2S_MODE_RX) { - i2s_ll_rx_mono_mode_ena(hal->dev, active_slot_num == I2S_CHANNEL_MONO); + if (hal_cfg->mode & I2S_MODE_RX) { + i2s_ll_set_rx_format_msb_align(hal->dev); + } + break; + case I2S_COMM_FORMAT_STAND_PCM_SHORT: + if (hal_cfg->mode & I2S_MODE_TX) { + i2s_ll_set_tx_pcm_short(hal->dev); + } + if (hal_cfg->mode & I2S_MODE_RX) { + i2s_ll_set_rx_pcm_short(hal->dev); + } + break; + case I2S_COMM_FORMAT_STAND_PCM_LONG: + if (hal_cfg->mode & I2S_MODE_TX) { + i2s_ll_set_tx_pcm_long(hal->dev); + } + if (hal_cfg->mode & I2S_MODE_RX) { + i2s_ll_set_rx_pcm_long(hal->dev); + } + break; + default: //I2S_COMM_FORMAT_STAND_I2S + if (hal_cfg->mode & I2S_MODE_TX) { + i2s_ll_set_tx_format_philip(hal->dev); + } + if (hal_cfg->mode & I2S_MODE_RX) { + i2s_ll_set_rx_format_philip(hal->dev); + } + break; + } + if (hal_cfg->ch == I2S_CHANNEL_MONO) { + if (hal_cfg->mode & I2S_MODE_TX) { + i2s_ll_tx_mono_mode_ena(hal->dev, true); + } + if (hal_cfg->mode & I2S_MODE_RX) { + i2s_ll_rx_mono_mode_ena(hal->dev, true); } } #else - int data_bits = slot_bit_cfg & 0xffff; - int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT; - int slot_num = ((slot_ch_cfg >> SLOT_CH_SHIFT) == 0 || (active_slot_num == I2S_CHANNEL_MONO)) ? 2 : (slot_ch_cfg >> SLOT_CH_SHIFT); + int slot_bits = hal_cfg->bits_cfg.chan_bits; + int slot_num = hal_cfg->chan_cfg.total_chan; bool msb_shift_en = false; int tdm_ws_width = 0; - switch (format) { - case I2S_COMM_FORMAT_STAND_MSB: - msb_shift_en = false; - tdm_ws_width = slot_num*slot_bits/2; - break; - case I2S_COMM_FORMAT_STAND_PCM_SHORT: - msb_shift_en = false; - tdm_ws_width = 1; - break; - case I2S_COMM_FORMAT_STAND_PCM_LONG: - msb_shift_en = false; - tdm_ws_width = slot_bits; - break; - default: //I2S_COMM_FORMAT_STAND_I2S - msb_shift_en = true; - tdm_ws_width = slot_num*slot_bits/2; - break; + switch (hal_cfg->comm_fmt) { + case I2S_COMM_FORMAT_STAND_MSB: + msb_shift_en = false; + tdm_ws_width = slot_num * slot_bits / 2; + break; + case I2S_COMM_FORMAT_STAND_PCM_SHORT: + msb_shift_en = false; + tdm_ws_width = 1; + break; + case I2S_COMM_FORMAT_STAND_PCM_LONG: + msb_shift_en = false; + tdm_ws_width = slot_bits; + break; + default: //I2S_COMM_FORMAT_STAND_I2S + msb_shift_en = true; + tdm_ws_width = slot_num * slot_bits / 2; + break; } - if (i2s_mode & I2S_MODE_TX) { + if (hal_cfg->mode & I2S_MODE_TX) { i2s_ll_tx_msb_shift_enable(hal->dev, msb_shift_en); i2s_ll_set_tx_tdm_ws_width(hal->dev, tdm_ws_width); - i2s_ll_set_tx_half_sample_bit(hal->dev, slot_num*slot_bits/2); + i2s_ll_set_tx_half_sample_bit(hal->dev, slot_num * slot_bits / 2); } - if (i2s_mode & I2S_MODE_RX) { + if (hal_cfg->mode & I2S_MODE_RX) { i2s_ll_rx_msb_shift_enable(hal->dev, msb_shift_en); i2s_ll_set_rx_tdm_ws_width(hal->dev, tdm_ws_width); - i2s_ll_set_rx_half_sample_bit(hal->dev, slot_num*slot_bits/2); + i2s_ll_set_rx_half_sample_bit(hal->dev, slot_num * slot_bits / 2); } #endif } -void i2s_hal_samples_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t communication_format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg) +void i2s_hal_samples_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) { - int active_slot_num = slot_ch_cfg & 0xffff; - int data_bits = slot_bit_cfg & 0xffff; - int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT; - int slot_num = ((slot_ch_cfg >> SLOT_CH_SHIFT) == 0 || (active_slot_num == I2S_CHANNEL_MONO)) ? 2 : (slot_ch_cfg >> SLOT_CH_SHIFT); + int data_bits = hal_cfg->bits_cfg.sample_bits; + int slot_bits = hal_cfg->bits_cfg.chan_bits; #if SOC_I2S_SUPPORTS_TDM - if (i2s_mode & I2S_MODE_TX) { - i2s_ll_set_tx_slot_mun(hal->dev, slot_num); + int slot_num = hal_cfg->chan_cfg.total_chan; + if (hal_cfg->mode & I2S_MODE_TX) { + i2s_ll_set_tx_slot_num(hal->dev, slot_num); i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits); } - if (i2s_mode & I2S_MODE_RX) { - i2s_ll_set_rx_slot_mun(hal->dev, slot_num); + if (hal_cfg->mode & I2S_MODE_RX) { + i2s_ll_set_rx_slot_num(hal->dev, slot_num); i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits); } #else - if (i2s_mode & I2S_MODE_TX) { + if (hal_cfg->mode & I2S_MODE_TX) { i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits); } - if (i2s_mode & I2S_MODE_RX) { + if (hal_cfg->mode & I2S_MODE_RX) { i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits); } #endif //I2S standards config: Philip, MSB or PCM, Only I2S mode should do this configuration. - if ((i2s_mode & (~(I2S_MODE_I2S))) == 0) { - i2s_hal_format_config(hal, i2s_mode, communication_format, slot_bit_cfg, slot_ch_cfg); + if ((hal_cfg->mode & (~(I2S_MODE_I2S))) == 0) { + i2s_hal_format_config(hal, hal_cfg); } } -void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_param_t *i2s_config) +void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) { - if (i2s_config->mode & I2S_MODE_TX) { - i2s_ll_tx_gen_init(hal->dev); - if (i2s_config->mode & I2S_MODE_SLAVE) { - i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave - } + bool is_slave = ((hal_cfg->mode & I2S_MODE_SLAVE) > 0); + + if (hal_cfg->mode & I2S_MODE_TX) { + i2s_ll_stop_tx(hal->dev); + i2s_ll_reset_tx(hal->dev); +#if SOC_I2S_SUPPORTS_TDM + i2s_ll_set_tx_pdm_en(hal->dev, false); + i2s_ll_enable_tx_clock(hal->dev); + i2s_ll_set_tx_clk_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default + i2s_ll_mclk_use_tx_clk(hal->dev); + + i2s_ll_set_tx_active_slot_mask(hal->dev, hal_cfg->chan_cfg.chan_mask); + i2s_ll_tx_left_align_enable(hal->dev, hal_cfg->flags.left_align_en); + i2s_ll_tx_big_endian_enable(hal->dev, hal_cfg->flags.big_edin_en); + i2s_ll_tx_set_bit_order(hal->dev, hal_cfg->flags.bit_order_msb_en); + i2s_ll_tx_set_skip_mask(hal->dev, hal_cfg->flags.skip_msk_en); +#else + i2s_ll_tx_msb_right_en(hal->dev, false); + i2s_ll_tx_right_first_en(hal->dev, false); + i2s_ll_tx_fifo_mod_force_en(hal->dev, true); +#endif + i2s_ll_set_tx_slave_mod(hal->dev, is_slave); //TX Slave } - if (i2s_config->mode & I2S_MODE_RX) { - i2s_ll_rx_gen_init(hal->dev); - if (i2s_config->mode & I2S_MODE_SLAVE) { - i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave - } + + + if (hal_cfg->mode & I2S_MODE_RX) { + i2s_ll_stop_rx(hal->dev); + i2s_ll_reset_rx(hal->dev); +#if SOC_I2S_SUPPORTS_TDM + i2s_ll_set_rx_pdm_en(hal->dev, false); + i2s_ll_enable_rx_clock(hal->dev); + i2s_ll_set_rx_clk_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default + i2s_ll_mclk_use_rx_clk(hal->dev); + + i2s_ll_set_rx_active_slot_mask(hal->dev, hal_cfg->chan_cfg.chan_mask); + i2s_ll_rx_left_align_enable(hal->dev, hal_cfg->flags.left_align_en); + i2s_ll_rx_big_endian_enable(hal->dev, hal_cfg->flags.big_edin_en); + i2s_ll_rx_set_bit_order(hal->dev, hal_cfg->flags.bit_order_msb_en); +#else + i2s_ll_rx_msb_right_en(hal->dev, false); + i2s_ll_rx_right_first_en(hal->dev, false); + i2s_ll_rx_fifo_mod_force_en(hal->dev, true); +#endif + i2s_ll_set_rx_slave_mod(hal->dev, is_slave); //RX Slave } #if SOC_I2S_SUPPORTS_ADC_DAC - if (i2s_config->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { - if (i2s_config->mode & I2S_MODE_DAC_BUILT_IN) { + if (hal_cfg->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { + if (hal_cfg->mode & I2S_MODE_DAC_BUILT_IN) { i2s_ll_build_in_dac_ena(hal->dev); } - if (i2s_config->mode & I2S_MODE_ADC_BUILT_IN) { + if (hal_cfg->mode & I2S_MODE_ADC_BUILT_IN) { i2s_ll_build_in_adc_ena(hal->dev); } // Buildin ADC and DAC have nothing to do with communication format configuration. @@ -311,47 +272,27 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_param_t *i2s_ #endif #if SOC_I2S_SUPPORTS_PDM - if (!(i2s_config->mode & I2S_MODE_PDM)) { -#if SOC_I2S_SUPPORTS_PDM_RX - if (i2s_config->mode & I2S_MODE_RX) { - i2s_ll_set_rx_pdm_en(hal->dev, false); - } -#endif + bool is_pdm = ((hal_cfg->mode & I2S_MODE_PDM) > 0); #if SOC_I2S_SUPPORTS_PDM_TX - if (i2s_config->mode & I2S_MODE_TX) { + if (hal_cfg->mode & I2S_MODE_TX) { + if (is_pdm) { + i2s_ll_tx_pdm_cfg(hal->dev, hal_cfg->sample_rate); + } else { i2s_ll_set_tx_pdm_en(hal->dev, false); } -#endif - } else { -#if SOC_I2S_SUPPORTS_PDM_TX - if (i2s_config->mode & I2S_MODE_TX) { - i2s_ll_tx_pdm_cfg(hal->dev, i2s_config->sample_rate); - } -#endif - + } +#endif // SOC_I2S_SUPPORTS_PDM_TX #if SOC_I2S_SUPPORTS_PDM_RX - if(i2s_config->mode & I2S_MODE_RX) { + if (hal_cfg->mode & I2S_MODE_RX) { + if (is_pdm) { i2s_ll_rx_pdm_cfg(hal->dev); + } else { + i2s_ll_set_rx_pdm_en(hal->dev, false); } -#endif } -#endif - -#if SOC_I2S_SUPPORTS_TDM - if (i2s_config->mode & I2S_MODE_TX) { - i2s_ll_set_tx_active_slot_mask(hal->dev, i2s_config->active_slot_mask); - i2s_ll_tx_left_align_enable(hal->dev, i2s_config->left_align_en); - i2s_ll_tx_big_endian_enable(hal->dev, i2s_config->big_edin_en); - i2s_ll_tx_set_bit_order(hal->dev, i2s_config->bit_order_msb_en); - } - if (i2s_config->mode & I2S_MODE_RX) { - i2s_ll_set_rx_active_slot_mask(hal->dev, i2s_config->active_slot_mask); - i2s_ll_rx_left_align_enable(hal->dev, i2s_config->left_align_en); - i2s_ll_rx_big_endian_enable(hal->dev, i2s_config->big_edin_en); - i2s_ll_rx_set_bit_order(hal->dev, i2s_config->bit_order_msb_en); - } -#endif - +#endif // SOC_I2S_SUPPORTS_PDM_RX +#endif // SOC_I2S_SUPPORTS_PDM //Configure I2S slot number,sample bit. - i2s_hal_samples_config(hal, i2s_config->mode, i2s_config->communication_format, i2s_config->slot_bits_cfg, i2s_config->slot_channel_cfg); + i2s_hal_samples_config(hal, hal_cfg); + } diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index fab3a34ee2..d26697f976 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -27,55 +27,103 @@ #include "soc/soc_caps.h" #include "hal/i2s_types.h" #include "hal/i2s_ll.h" -#if SOC_GDMA_SUPPORTED -#include "hal/gdma_ll.h" -#endif #ifdef __cplusplus extern "C" { #endif +/** + * @brief I2S channel bits configurations + * + */ +typedef union { + struct { + uint32_t sample_bits : 16; /*!< I2S sample bits in one channel */ + uint32_t chan_bits : 16; /*!< I2S total bits in one channel. Should not be smaller than 'sample_bits', default '0' means equal to 'sample_bits' */ + }; + uint32_t val; /*!< I2S cannel bits configiration value */ +} i2s_hal_bits_cfg_t; + +#if SOC_I2S_SUPPORTS_TDM +/** + * @brief I2S channel configurations + * + */ +typedef union { + struct { + uint32_t total_chan : 8; /*!< Total number of I2S channels */ + uint32_t active_chan : 8; /*!< Active channel number, it will be set automatically if chan_mask is set */ + uint32_t chan_mask : 16; /*!< Active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<dev) /** * @brief Reset I2S TX fifo * * @param hal Context of the HAL layer */ -void i2s_hal_reset_tx_fifo(i2s_hal_context_t *hal); +#define i2s_hal_reset_tx_fifo(hal) i2s_ll_reset_tx_fifo((hal)->dev) /** * @brief Reset I2S RX channel * * @param hal Context of the HAL layer */ -void i2s_hal_reset_rx(i2s_hal_context_t *hal); +#define i2s_hal_reset_rx(hal) i2s_ll_reset_rx((hal)->dev) /** * @brief Reset I2S RX fifo * * @param hal Context of the HAL layer */ -void i2s_hal_reset_rx_fifo(i2s_hal_context_t *hal); +#define i2s_hal_reset_rx_fifo(hal) i2s_ll_reset_rx_fifo((hal)->dev) /** * @brief Init the I2S hal. This function should be called first before other hal layer function is called @@ -97,20 +145,17 @@ void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel); * @brief Configure communication format * * @param hal Context of the HAL layer - * @param i2s_mode I2S mode. Using the ored mask of I2S_MODE_MASTER, I2S_MODE_SLAVE, I2S_MODE_TX, I2S_MODE_RX - * @param communication_format I2S communication format. Can be a value of `i2s_comm_format_t`. - * @param slot_bit_cfg I2S slot bit configuration - * @param slot_ch_cfg I2S slot channel configuration + * @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t` */ -void i2s_hal_samples_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t communication_format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg); +void i2s_hal_samples_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg); /** * @brief Config I2S param * * @param hal Context of the HAL layer - * @param i2s_config I2S paramater configuration structer, refer to `i2s_config_param_t` + * @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t` */ -void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_param_t *i2s_config); +void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg); /** * @brief Enable I2S master full-duplex mode @@ -131,28 +176,28 @@ void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal); * * @param hal Context of the HAL layer */ -void i2s_hal_start_tx(i2s_hal_context_t *hal); +#define i2s_hal_start_tx(hal) i2s_ll_start_tx((hal)->dev) /** * @brief Start I2S rx * * @param hal Context of the HAL layer */ -void i2s_hal_start_rx(i2s_hal_context_t *hal); +#define i2s_hal_start_rx(hal) i2s_ll_start_rx((hal)->dev) /** * @brief Stop I2S tx * * @param hal Context of the HAL layer */ -void i2s_hal_stop_tx(i2s_hal_context_t *hal); +#define i2s_hal_stop_tx(hal) i2s_ll_stop_tx((hal)->dev) /** * @brief Stop I2S rx * * @param hal Context of the HAL layer */ -void i2s_hal_stop_rx(i2s_hal_context_t *hal); +#define i2s_hal_stop_rx(hal) i2s_ll_stop_rx((hal)->dev) /** * @brief Set the received data length to trigger `in_suc_eof` interrupt. @@ -160,25 +205,25 @@ void i2s_hal_stop_rx(i2s_hal_context_t *hal); * @param hal Context of the HAL layer * @param eof_byte The byte length that trigger in_suc_eof interrupt. */ -void i2s_hal_set_rx_eof_num(i2s_hal_context_t *hal, uint32_t eof_byte); +#define i2s_hal_set_rx_eof_num(hal, eof_byte) i2s_ll_set_rx_eof_num((hal)->dev, eof_byte) /** * @brief Set I2S TX sample bit * * @param hal Context of the HAL layer * @param slot_bit I2S TX slot bit - * @param data_bit The sample data bit lengh. + * @param data_bit The sample data bit length. */ -void i2s_hal_set_tx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit); +#define i2s_hal_set_tx_sample_bit(hal, slot_bit, data_bit) i2s_ll_set_tx_sample_bit((hal)->dev, slot_bit, data_bit) /** * @brief Set I2S RX sample bit * * @param hal Context of the HAL layer * @param slot_bit I2S RX slot bit - * @param data_bit The sample data bit lengh. + * @param data_bit The sample data bit length. */ -void i2s_hal_set_rx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit); +#define i2s_hal_set_rx_sample_bit(hal, slot_bit, data_bit) i2s_ll_set_rx_sample_bit((hal)->dev, slot_bit, data_bit) /** * @brief Configure I2S TX module clock devider @@ -205,17 +250,17 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @brief Configure I2S TX PCM encoder or decoder. * * @param hal Context of the HAL layer - * @param cfg PCM configure paramater, refer to `i2s_pcm_cfg_t` + * @param cfg PCM configure paramater, refer to `i2s_pcm_mode_t` */ -void i2s_hal_tx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg); +#define i2s_hal_tx_pcm_cfg(hal, cfg) i2s_ll_tx_pcm_cfg((hal)->dev, cfg) /** * @brief Configure I2S RX PCM encoder or decoder. * * @param hal Context of the HAL layer - * @param cfg PCM configure paramater, refer to `i2s_pcm_cfg_t` + * @param cfg PCM configure paramater, refer to `i2s_pcm_mode_t` */ -void i2s_hal_rx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg); +#define i2s_hal_rx_pcm_cfg(hal, cfg) i2s_ll_rx_pcm_cfg((hal)->dev, cfg) #endif /** @@ -223,7 +268,7 @@ void i2s_hal_rx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg); * * @param hal Context of the HAL layer */ -void i2s_hal_enable_sig_loopback(i2s_hal_context_t *hal); +#define i2s_hal_enable_sig_loopback(hal) i2s_ll_loop_back_ena((hal)->dev, true) #if SOC_I2S_SUPPORTS_PDM_TX /** @@ -234,7 +279,7 @@ void i2s_hal_enable_sig_loopback(i2s_hal_context_t *hal); * @param fp TX PDM fp paramater configuration * @param fs TX PDM fs paramater configuration */ -void i2s_hal_set_tx_pdm_fpfs(i2s_hal_context_t *hal, int fp, int fs); +#define i2s_hal_set_tx_pdm_fpfs(hal, fp, fs) i2s_ll_set_tx_pdm_fpfs((hal)->dev, fp, fs) /** * @brief Get I2S TX PDM configuration @@ -243,7 +288,7 @@ void i2s_hal_set_tx_pdm_fpfs(i2s_hal_context_t *hal, int fp, int fs); * @param fp Pointer to accept TX PDM fp paramater configuration * @param fs Pointer to accept TX PDM fs paramater configuration */ -void i2s_hal_get_tx_pdm_fpfs(i2s_hal_context_t *hal, int *fp, int *fs); +#define i2s_hal_get_tx_pdm_fpfs(hal, fp, fs) i2s_ll_get_tx_pdm_fpfs((hal)->dev, (uint32_t *)fp, (uint32_t *)fs) #endif #if SOC_I2S_SUPPORTS_PDM_RX @@ -254,7 +299,7 @@ void i2s_hal_get_tx_pdm_fpfs(i2s_hal_context_t *hal, int *fp, int *fs); * @param hal Context of the HAL layer * @param dsr PDM downsample configuration paramater */ -void i2s_hal_set_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t dsr); +#define i2s_hal_set_rx_pdm_dsr(hal, dsr) i2s_ll_set_pdm_rx_dsr((hal)->dev, dsr) /** * @brief Get RX PDM downsample configuration @@ -262,7 +307,7 @@ void i2s_hal_set_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t dsr); * @param hal Context of the HAL layer * @param dsr Pointer to accept PDM downsample configuration */ -void i2s_hal_get_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t *dsr); +#define i2s_hal_get_rx_pdm_dsr(hal, dsr) i2s_ll_get_pdm_rx_dsr((hal)->dev, dsr) #endif #if !SOC_GDMA_SUPPORTED @@ -383,28 +428,6 @@ void i2s_hal_get_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t *dsr); * @param addr Pointer to accept in suc eof des address */ #define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_get_in_eof_des_addr((hal)->dev, addr) -#else -#define i2s_hal_attach_tx_dma(hal) gdma_ll_tx_connect_to_periph((hal)->dma, (hal)->dma_ch, (hal)->dma_peri_sel) -#define i2s_hal_attach_rx_dma(hal) gdma_ll_rx_connect_to_periph((hal)->dma, (hal)->dma_ch, (hal)->dma_peri_sel) -#define i2s_hal_get_intr_status(hal, status) (*status = (gdma_ll_get_interrupt_status((hal)->dma, (hal)->dma_ch))) -#define i2s_hal_clear_intr_status(hal, mask) gdma_ll_clear_interrupt_status((hal)->dma, (hal)->dma_ch, mask) -#define i2s_hal_enable_rx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_IN_DSCR_ERR|I2S_INTR_IN_SUC_EOF, 1) -#define i2s_hal_disable_rx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_IN_DSCR_ERR|I2S_INTR_IN_SUC_EOF, 0) -#define i2s_hal_enable_tx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_OUT_DSCR_ERR|I2S_INTR_OUT_EOF, 1) -#define i2s_hal_disable_tx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_OUT_DSCR_ERR|I2S_INTR_OUT_EOF, 0) -#define i2s_hal_start_tx_link(hal, link_addr) do{\ - gdma_ll_tx_set_desc_addr((hal)->dma,(hal)->dma_ch,link_addr);\ - gdma_ll_tx_start((hal)->dma,(hal)->dma_ch);}while(0) -#define i2s_hal_start_rx_link(hal, link_addr) do{\ - gdma_ll_rx_set_desc_addr((hal)->dma,(hal)->dma_ch,link_addr);\ - gdma_ll_rx_start((hal)->dma,(hal)->dma_ch);}while(0) - -#define i2s_hal_stop_tx_link(hal) gdma_ll_tx_stop((hal)->dma,(hal)->dma_ch) -#define i2s_hal_stop_rx_link(hal) gdma_ll_rx_stop((hal)->dma, (hal)->dma_ch) -#define i2s_hal_reset_rxdma(hal) gdma_ll_rx_reset_channel((hal)->dma, (hal)->dma_ch) -#define i2s_hal_reset_txdma(hal) gdma_ll_tx_reset_channel((hal)->dma, (hal)->dma_ch) -#define i2s_hal_get_out_eof_des_addr(hal, addr) (*addr = (gdma_ll_tx_get_eof_desc_addr((hal)->dma, (hal)->dma_ch))) -#define i2s_hal_get_in_eof_des_addr(hal, addr) (*addr = (gdma_ll_rx_get_success_eof_desc_addr((hal)->dma, (hal)->dma_ch))) #endif #ifdef __cplusplus diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index e9d0fac8e4..5c6ee96ad3 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -24,17 +24,6 @@ extern "C" { #endif -/** - * @brief I2S port number, the max port number is (I2S_NUM_MAX -1). - */ -typedef enum { - I2S_NUM_0 = 0, /*!< I2S port 0 */ -#if SOC_I2S_NUM > 1 - I2S_NUM_1 = 1, /*!< I2S port 1 */ -#endif - I2S_NUM_MAX, /*!< I2S port max */ -} i2s_port_t; - /** * @brief I2S bit width per sample. * @@ -55,81 +44,67 @@ typedef enum { I2S_BITS_PER_SLOT_16BIT = (16), /*!< slot bit 16*/ I2S_BITS_PER_SLOT_24BIT = (24), /*!< slot bit 24*/ I2S_BITS_PER_SLOT_32BIT = (32), /*!< slot bit 32*/ - I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU = (0), /*!< slot bit equals to data bit*/ + I2S_BITS_PER_SLOT_EQU_SAMPLE = (0), /*!< slot bit equals to data bit*/ } i2s_bits_per_slot_t; -#define SLOT_BIT_SHIFT (16) //slot bit shift -#define SLOT_CH_SHIFT (16) //slot channel shift - -/** - * @brief I2S slot bit configuration paramater. The low 16bit is the audio_data_bit_width and the high 16bit is the slot_bit_width. - * e.g.: If set to (I2S_BITS_PER_SLOT_24BIT << SLOT_BIT_SHIFT) | I2S_BITS_PER_SAMPLE_16BIT, the audio data bit is 16bit and the slot bit is 24bit. - * - * - * @note: If the slot_bit_width is set to `I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU`, then the slot_bit_width equals to audio_data_bit_width. - * - */ -typedef uint32_t i2s_slot_bits_cfg_t; /*!< slot bit configuration*/ - -/** - * @brief I2S slot channel configuration paramater. The low 16bit is the active_slot_number and the high 16bit is the total_slot_num. - * The audio data only launch in active slot, otherwise, launch 0 or single data in inactive slot. - * e.g.: If set to (4 << SLOT_CH_SHIFT) | 2, the active_slot_number is 2 and the total_slot_num 4. - * - * @note: If the total_slot_num is set to 0, then the total_slot_num equals to active_slot_number. - * - */ -typedef uint32_t i2s_slot_channel_cfg_t; /*!< slot channel configuration*/ - /** * @brief I2S channel. * */ typedef enum { - I2S_CHANNEL_MONO = 1, /*!< I2S 1 channel (mono)*/ - I2S_CHANNEL_STEREO = 2 /*!< I2S 2 channel (stereo)*/ + // I2S_CHANNEL_MONO and I2S_CHANNEL_STEREO values are changed to be compatible with TDM mode + // The lower 16 bits is for enabling specific channels + // The highest bit in I2S_CHANNEL_MONO is for differentiating I2S_CHANNEL_MONO and I2S_CHANNEL_STEREO because they both use two channels + // Two channels will transmit same data in I2S_CHANNEL_MONO mode, and different data in I2S_CHANNEL_STEREO mode + I2S_CHANNEL_MONO = (0x01 << 31) | 0x03, /*!< I2S channel (mono), two channel enabled */ + I2S_CHANNEL_STEREO = 0x03, /*!< I2S channel (stereo), two channel enabled */ +#if SOC_I2S_SUPPORTS_TDM + // Bit map of active chan. + // There are 16 channels in TDM mode. + // For TX module, only the active channel send the audio data, the inactive channel send a constant(configurable) or will be skiped if 'skip_msk_en' in 'i2s_hal_tdm_flags_t' is set. + // For RX module, only receive the audio data in active channels, the data in inactive channels will be ignored. + // the bit map of active channel can not exceed (0x1< @@ -22,13 +23,15 @@ #define I2S_NUM (0) #define WAVE_FREQ_HZ (100) #define PI (3.14159265) -#define I2S_BCK_IO (GPIO_NUM_13) -#define I2S_WS_IO (GPIO_NUM_15) -#define I2S_DO_IO (GPIO_NUM_21) +#define I2S_BCK_IO (GPIO_NUM_4) +#define I2S_WS_IO (GPIO_NUM_5) +#define I2S_DO_IO (GPIO_NUM_18) #define I2S_DI_IO (-1) #define SAMPLE_PER_CYCLE (SAMPLE_RATE/WAVE_FREQ_HZ) +static const char* TAG = "i2s_example"; + static void setup_triangle_sine_waves(int bits) { int *samples_data = malloc(((bits+8)/16)*SAMPLE_PER_CYCLE*4); @@ -64,7 +67,7 @@ static void setup_triangle_sine_waves(int bits) } } - + ESP_LOGI(TAG, "set clock"); i2s_set_clk(I2S_NUM, SAMPLE_RATE, bits, 2); //Using push // for(i = 0; i < SAMPLE_PER_CYCLE; i++) { @@ -74,6 +77,7 @@ static void setup_triangle_sine_waves(int bits) // i2s_push_sample(0, &samples_data[i*2], 100); // } // or write + ESP_LOGI(TAG, "write data"); i2s_write(I2S_NUM, samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100); free(samples_data); @@ -87,20 +91,11 @@ void app_main(void) //if 2-channels, 16-bit each channel, total buffer is 360*4 = 1440 bytes //if 2-channels, 24/32-bit each channel, total buffer is 360*8 = 2880 bytes i2s_config_t i2s_config = { - .param_cfg = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = SAMPLE_RATE, - .slot_bits_cfg = (I2S_BITS_PER_SLOT_16BIT << SLOT_BIT_SHIFT) | I2S_BITS_PER_SAMPLE_16BIT, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_MSB, -#if SOC_I2S_SUPPORTS_TDM - .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, - .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, - .left_align_en = false, - .big_edin_en = false, - .bit_order_msb_en = false, -#endif - }, + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_MSB, .dma_buf_count = 6, .dma_buf_len = 60, .use_apll = false, From d51b85989b4b5d7611341535d44b435363453f99 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Thu, 17 Jun 2021 18:49:44 +0800 Subject: [PATCH 3/5] doc/i2s: update i2s programming guide on s3 & c3 --- components/driver/i2s.c | 95 +- components/driver/include/driver/i2s.h | 60 +- components/driver/test/test_i2s.c | 4 +- components/hal/CMakeLists.txt | 2 +- components/hal/esp32/include/hal/i2s_ll.h | 8 +- components/hal/esp32c3/include/hal/i2s_ll.h | 41 +- components/hal/esp32h2/include/hal/i2s_ll.h | 885 +++++++----------- components/hal/esp32s2/include/hal/i2s_ll.h | 8 +- components/hal/esp32s3/include/hal/i2s_ll.h | 40 +- components/hal/i2s_hal.c | 44 +- components/hal/include/hal/i2s_hal.h | 54 +- components/hal/include/hal/i2s_types.h | 27 +- components/soc/esp32/include/soc/soc_caps.h | 1 - components/soc/esp32c3/i2s_periph.c | 1 + components/soc/esp32c3/include/soc/soc_caps.h | 1 - components/soc/esp32h2/include/soc/soc_caps.h | 5 +- .../soc/esp32h2/ld/esp32h2.peripherals.ld | 2 +- components/soc/esp32s3/i2s_periph.c | 2 + components/soc/esp32s3/include/soc/soc_caps.h | 1 - docs/en/api-reference/peripherals/i2s.rst | 295 ++++-- 20 files changed, 722 insertions(+), 854 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 645b4c253f..5857e67bd6 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -14,12 +14,13 @@ #include "freertos/semphr.h" #include "soc/lldesc.h" +#include "driver/periph_ctrl.h" #include "driver/gpio.h" #include "driver/i2s.h" #include "hal/gpio_hal.h" +#include "hal/i2s_hal.h" #if SOC_I2S_SUPPORTS_ADC_DAC #include "driver/dac.h" -#include "hal/i2s_hal.h" #include "adc1_private.h" #endif @@ -138,22 +139,6 @@ static void gpio_matrix_in_check_and_set(int gpio, uint32_t signal_idx, bool inv } } -#if SOC_I2S_SUPPORTS_PCM -esp_err_t i2s_pcm_config(i2s_port_t i2s_num, i2s_mode_t mode, i2s_pcm_mode_t pcm_cfg) -{ - ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); - - if (mode & I2S_MODE_TX) { - i2s_hal_tx_pcm_cfg(&(p_i2s[i2s_num]->hal), pcm_cfg); - } else if (mode & I2S_MODE_RX) { - i2s_hal_rx_pcm_cfg(&(p_i2s[i2s_num]->hal), pcm_cfg); - } else { - return ESP_ERR_INVALID_ARG; - } - return ESP_OK; -} -#endif - float i2s_get_clk(i2s_port_t i2s_num) { ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); @@ -428,7 +413,6 @@ static esp_err_t i2s_fbclk_cal(int i2s_num, uint32_t rate, int channel, int chan } #endif // SOC_I2S_SUPPORTS_ADC_DAC -#if SOC_I2S_SUPPORTS_PDM if ( p_i2s[i2s_num]->mode & I2S_MODE_PDM) { #if SOC_I2S_SUPPORTS_PDM_TX if ( p_i2s[i2s_num]->mode & I2S_MODE_TX) { @@ -447,7 +431,6 @@ static esp_err_t i2s_fbclk_cal(int i2s_num, uint32_t rate, int channel, int chan #endif // SOC_I2S_SUPPORTS_PDM_RX _bck_div = 8; } -#endif // SOC_I2S_SUPPORTS_PDM #if SOC_I2S_SUPPORTS_APLL int sdm0 = 0; @@ -487,7 +470,7 @@ static uint32_t i2s_get_active_chan_num(i2s_hal_config_t *hal_cfg) case I2S_CHANNEL_FMT_TDM: { uint32_t num = 0; uint32_t max_chan = 0; - uint32_t chan_mask = hal_cfg->chan_cfg.chan_mask; + uint32_t chan_mask = hal_cfg->chan_mask; for (int i = 0; chan_mask && i < 16; i++, chan_mask >>= 1) { if ((chan_mask & 0x01) == 1) { @@ -495,10 +478,9 @@ static uint32_t i2s_get_active_chan_num(i2s_hal_config_t *hal_cfg) max_chan = i + 1; } } - if (max_chan > hal_cfg->chan_cfg.total_chan) { - hal_cfg->chan_cfg.total_chan = max_chan; + if (max_chan > hal_cfg->total_chan) { + hal_cfg->total_chan = max_chan; } - hal_cfg->chan_cfg.active_chan = num; return num; } #endif @@ -514,9 +496,9 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ i2s_hal_config_t *cfg = &p_i2s[i2s_num]->hal_cfg; int data_bits = 0; - int slot_bits = 0; - int active_slot_num = 0; - int slot_num = 0; + int chan_bits = 0; + int active_chan_num = 0; + int chan_num = 0; cfg->ch = ch; cfg->sample_rate = rate; @@ -524,16 +506,16 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ cfg->bits_cfg.chan_bits = cfg->bits_cfg.chan_bits < cfg->bits_cfg.sample_bits ? cfg->bits_cfg.sample_bits : cfg->bits_cfg.chan_bits; - slot_bits = cfg->bits_cfg.chan_bits; + chan_bits = cfg->bits_cfg.chan_bits; data_bits = cfg->bits_cfg.sample_bits; #if SOC_I2S_SUPPORTS_TDM - cfg->chan_cfg.chan_mask = ch & 0xFFFF; - active_slot_num = i2s_get_active_chan_num(cfg); - slot_num = cfg->chan_cfg.total_chan; + cfg->chan_mask = ch & 0xFFFF; + active_chan_num = i2s_get_active_chan_num(cfg); + chan_num = cfg->total_chan; #else - active_slot_num = i2s_get_active_chan_num(cfg); - slot_num = ch == I2S_CHANNEL_MONO ? 2 : active_slot_num; + active_chan_num = i2s_get_active_chan_num(cfg); + chan_num = ch == I2S_CHANNEL_MONO ? 2 : active_chan_num; #endif ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); @@ -551,7 +533,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ xSemaphoreTake(p_i2s[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); } //malloc DMA buffer - if (i2s_alloc_dma_buffer(i2s_num, data_bits, active_slot_num) != ESP_OK ) { + if (i2s_alloc_dma_buffer(i2s_num, data_bits, active_chan_num) != ESP_OK ) { return ESP_ERR_NO_MEM; } @@ -559,13 +541,13 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ uint32_t i2s_bck = 0; // I2S back clock uint32_t bck_div = 0; // I2S bck div //calculate bck_div, f_bck and select source clock - if (i2s_fbclk_cal(i2s_num, rate, slot_num, slot_bits, &i2s_clk, &i2s_bck, &bck_div) != ESP_OK) { + if (i2s_fbclk_cal(i2s_num, rate, chan_num, chan_bits, &i2s_clk, &i2s_bck, &bck_div) != ESP_OK) { return ESP_FAIL; } //configure i2s clock if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { i2s_hal_tx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); - i2s_hal_set_tx_sample_bit(&(p_i2s[i2s_num]->hal), slot_bits, data_bits); + i2s_hal_set_tx_sample_bit(&(p_i2s[i2s_num]->hal), chan_bits, data_bits); // wait all writing on-going finish if (p_i2s[i2s_num]->tx) { xSemaphoreGive(p_i2s[i2s_num]->tx->mux); @@ -573,7 +555,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ } if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { i2s_hal_rx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); - i2s_hal_set_rx_sample_bit(&(p_i2s[i2s_num]->hal), slot_bits, data_bits); + i2s_hal_set_rx_sample_bit(&(p_i2s[i2s_num]->hal), chan_bits, data_bits); // wait all writing on-going finish if (p_i2s[i2s_num]->rx) { xSemaphoreGive(p_i2s[i2s_num]->rx->mux); @@ -1002,11 +984,9 @@ static esp_err_t i2s_check_cfg_static(i2s_port_t i2s_num) ESP_RETURN_ON_FALSE(!((cfg->mode & I2S_MODE_DAC_BUILT_IN) && (i2s_num != I2S_NUM_0)), ESP_ERR_INVALID_ARG, TAG, "I2S DAC built-in only support on I2S0"); return ESP_OK; #endif -#if SOC_I2S_SUPPORTS_PDM //We only check if the I2S number is invalid when set to PDM mode. ESP_RETURN_ON_FALSE(!((cfg->mode & I2S_MODE_PDM) && (i2s_num != I2S_NUM_0)), ESP_ERR_INVALID_ARG, TAG, "I2S DAC PDM only support on I2S0"); return ESP_OK; -#endif ESP_RETURN_ON_FALSE(cfg->comm_fmt && (cfg->comm_fmt < I2S_COMM_FORMAT_STAND_MAX), ESP_ERR_INVALID_ARG, TAG, "invalid communication formats"); ESP_RETURN_ON_FALSE(!((cfg->comm_fmt & I2S_COMM_FORMAT_STAND_MSB) && (cfg->comm_fmt & I2S_COMM_FORMAT_STAND_PCM_LONG)), ESP_ERR_INVALID_ARG, TAG, "multiple communication formats specified"); @@ -1096,29 +1076,30 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, p_i2s[i2s_num]->hal_cfg.comm_fmt = i2s_config->communication_format; p_i2s[i2s_num]->hal_cfg.chan_fmt = i2s_config->channel_format; p_i2s[i2s_num]->hal_cfg.bits_cfg.sample_bits = i2s_config->bits_per_sample; - p_i2s[i2s_num]->hal_cfg.bits_cfg.chan_bits = i2s_config->bits_per_slot; + p_i2s[i2s_num]->hal_cfg.bits_cfg.chan_bits = i2s_config->bits_per_chan; #if SOC_I2S_SUPPORTS_TDM + int active_chan = 0; switch (i2s_config->channel_format) { case I2S_CHANNEL_FMT_RIGHT_LEFT: case I2S_CHANNEL_FMT_ALL_RIGHT: case I2S_CHANNEL_FMT_ALL_LEFT: - p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1; - p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 2; - p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 2; + p_i2s[i2s_num]->hal_cfg.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1; + p_i2s[i2s_num]->hal_cfg.total_chan = 2; + active_chan = 2; break; case I2S_CHANNEL_FMT_ONLY_RIGHT: - p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0; - p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 1; - p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 1; + p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0; + p_i2s[i2s_num]->hal_cfg.total_chan = 1; + active_chan = 1; break; case I2S_CHANNEL_FMT_ONLY_LEFT: - p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1; - p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 1; - p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 1; + p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1; + p_i2s[i2s_num]->hal_cfg.total_chan = 1; + active_chan = 1; break; case I2S_CHANNEL_FMT_TDM: - ESP_RETURN_ON_FALSE((i2s_config->tdm_chan_cfg.chan_mask != 0), ESP_ERR_INVALID_ARG, TAG, "i2s all channel are disabled"); - p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_chan_cfg.chan_mask; + ESP_RETURN_ON_FALSE((i2s_config->chan_mask != 0), ESP_ERR_INVALID_ARG, TAG, "i2s all channel are disabled"); + p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->chan_mask; i2s_get_active_chan_num(&p_i2s[i2s_num]->hal_cfg); break; default: @@ -1138,6 +1119,18 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, p_i2s[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; p_i2s[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; +#if SOC_I2S_SUPPORTS_PCM + // Set PCM compress type for PCM communication mode + if (p_i2s[i2s_num]->communication_format & I2S_COMM_FORMAT_STAND_PCM_SHORT) { + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + i2s_hal_tx_pcm_cfg(&(p_i2s[i2s_num]->hal), i2s_config->pcm_compress_type); + } + if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { + i2s_hal_rx_pcm_cfg(&(p_i2s[i2s_num]->hal), i2s_config->pcm_compress_type); + } + } +#endif // SOC_I2S_SUPPORTS_PCM + #ifdef CONFIG_PM_ENABLE if (i2s_config->use_apll) { ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i2s_driver", &p_i2s[i2s_num]->pm_lock); @@ -1198,7 +1191,7 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, #if SOC_I2S_SUPPORTS_TDM ret = i2s_set_clk(i2s_num, i2s_config->sample_rate, p_i2s[i2s_num]->hal_cfg.bits_cfg.val, - (i2s_channel_t)p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan); + (i2s_channel_t)active_chan); #else ret = i2s_set_clk(i2s_num, i2s_config->sample_rate, p_i2s[i2s_num]->hal_cfg.bits_cfg.val, diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index 04b0ed30d7..5ec6f2841a 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -13,9 +13,7 @@ #include "soc/i2s_periph.h" #include "soc/rtc_periph.h" #include "soc/soc_caps.h" -#include "hal/i2s_hal.h" #include "hal/i2s_types.h" -#include "driver/periph_ctrl.h" #include "esp_intr_alloc.h" #if SOC_I2S_SUPPORTS_ADC_DAC @@ -50,9 +48,15 @@ typedef struct { int data_in_num; /*!< DATA in pin*/ } i2s_pin_config_t; -#if SOC_I2S_SUPPORTS_TDM -typedef i2s_hal_chan_cfg_t tdm_chan_cfg_t; -typedef i2s_hal_tdm_flags_t tdm_flags_t; +#if SOC_I2S_SUPPORTS_PCM +/** + * @brief I2S PCM configuration + * + */ +typedef struct { + i2s_pcm_compress_t pcm_mode; /*!< I2S PCM a/u-law decompress or compress mode */ +} i2s_pcm_cfg_t; + #endif /** @@ -72,15 +76,30 @@ typedef struct { bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */ bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */ int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/ - i2s_bits_per_slot_t bits_per_slot; /*!< I2S total bits in one channel, Should not be smaller than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */ + i2s_bits_per_chan_t bits_per_chan; /*!< I2S total bits in one channel, Should not be smaller than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */ + +#if SOC_I2S_SUPPORTS_PCM + i2s_pcm_compress_t pcm_compress_type; /*!< I2S PCM a/u-law decompress or compress mode. Set this field if `communication_format` is set to `I2S_COMM_FORMAT_STAND_PCM_SHORT` or `I2S_COMM_FORMAT_STAND_PCM_LONG` */ +#endif // SOC_I2S_SUPPORTS_PCM + #if SOC_I2S_SUPPORTS_TDM - tdm_chan_cfg_t tdm_chan_cfg; /*!< I2S TDM channel configurations*/ - tdm_flags_t tdm_flags; /*!< I2S TDM flags*/ -#endif + i2s_channel_t chan_mask; /*!< I2S active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1< 1 /* ESP32S2 and ESP32C3 has only single I2S port and hence following test cases are not applicable */ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") { @@ -492,7 +492,7 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]") TEST_ASSERT(initial_size == esp_get_free_heap_size()); } -#if DISABLED_FOR_TARGETS(ESP32) +#if SOC_I2S_SUPPORTS_ADC_DAC /* Only ESP32 need I2S adc/dac test */ TEST_CASE("I2S adc test", "[i2s]") { diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index b298d44ae8..04802d9f30 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -14,13 +14,13 @@ if(NOT BOOTLOADER_BUILD) "spi_hal_iram.c" "spi_slave_hal.c" "spi_slave_hal_iram.c" - "i2s_hal.c" "sigmadelta_hal.c" "timer_hal.c" "ledc_hal.c" "ledc_hal_iram.c" "i2c_hal.c" "i2c_hal_iram.c" + "i2s_hal.c" "gpio_hal.c" "uart_hal.c" "uart_hal_iram.c" diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index 79fa062f1c..eaa74bec20 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -453,10 +453,10 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) } /** - * @brief Congfigure TX slot bit and audio data bit, on ESP32, sample_bit should equals to data_bit + * @brief Congfigure TX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) @@ -466,10 +466,10 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i } /** - * @brief Congfigure RX slot bit and audio data bit, on ESP32, sample_bit should equals to data_bit + * @brief Congfigure RX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index dc568148af..94eb7d9077 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -28,7 +28,6 @@ extern "C" { #endif - #define I2S_LL_GET_HW(num) (&I2S0) #define I2S_LL_TDM_CH_MASK (0xffff) @@ -320,10 +319,10 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) } /** - * @brief Congfigure TX slot bit and audio data bit + * @brief Congfigure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) @@ -333,10 +332,10 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i } /** - * @brief Congfigure RX slot bit and audio data bit + * @brief Congfigure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) @@ -390,52 +389,52 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab } /** - * @brief Configure TX total slot number + * @brief Configure TX total chan number * * @param hw Peripheral I2S hardware instance address. - * @param total_num Total slot number + * @param total_num Total chan number */ -static inline void i2s_ll_set_tx_slot_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num) { hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; } /** - * @brief Configure RX total slot number + * @brief Configure RX total chan number * * @param hw Peripheral I2S hardware instance address. - * @param total_num Total slot number + * @param total_num Total chan number */ -static inline void i2s_ll_set_rx_slot_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num) { hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; } /** - * @brief Set the bimap of the active TX slot, only the active slot can launch audio data. + * @brief Set the bimap of the active TX chan, only the active chan can launch audio data. * * @param hw Peripheral I2S hardware instance address. - * @param slot_mask mask of tx active slot + * @param chan_mask mask of tx active chan */ -static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) +static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; - tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set the bimap of the active RX slot, only the active slot can receive audio data. + * @brief Set the bimap of the active RX chan, only the active chan can receive audio data. * * @param hw Peripheral I2S hardware instance address. - * @param slot_mask mask of rx active slot + * @param chan_mask mask of rx active chan */ -static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) +static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; - tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; } @@ -556,7 +555,7 @@ static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) +static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { if (pcm_cfg == I2S_PCM_DISABLE) { hw->tx_conf.tx_pcm_bypass = 1; @@ -572,7 +571,7 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) +static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { if (pcm_cfg == I2S_PCM_DISABLE) { hw->rx_conf.rx_pcm_bypass = 1; diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index c54d7de83a..056cb5ce55 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -21,9 +21,7 @@ // The LL layer for ESP32-S3 I2S register operations #pragma once - #include -#include #include "soc/i2s_periph.h" #include "hal/i2s_types.h" @@ -31,676 +29,657 @@ extern "C" { #endif -// Get I2S hardware instance with giving i2s num -#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL) +#define I2S_LL_GET_HW(num) (&I2S0) -#define I2S_INTR_IN_SUC_EOF BIT(9) -#define I2S_INTR_OUT_EOF BIT(12) -#define I2S_INTR_IN_DSCR_ERR BIT(13) -#define I2S_INTR_OUT_DSCR_ERR BIT(14) -#define I2S_INTR_MAX (0xFFFFFFFF) +#define I2S_LL_TDM_CH_MASK (0xffff) +#define I2S_LL_PDM_BCK_FACTOR (64) +#define I2S_LL_BASE_CLK (2*APB_CLK_FREQ) + +#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9) +#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) + +/* I2S clock configuration structure */ +typedef struct { + uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a) + uint16_t a; + uint16_t b; // The decimal part of module clock devider, the decimal is: b/a + uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div +} i2s_ll_clk_cal_t; /** - * @brief Reset rx fifo + * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->tx_clkm_conf.clk_en = 1; } /** - * @brief Reset tx fifo + * @brief Enable I2S tx module clock * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_enable_tx_clock(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->tx_clkm_conf.tx_clk_active = 1; } /** - * @brief Enable rx interrupt + * @brief Enable I2S rx module clock * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_enable_rx_clock(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->rx_clkm_conf.rx_clk_active = 1; } /** - * @brief Disable rx interrupt + * @brief I2S mclk use tx module clock * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_mclk_use_tx_clk(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->rx_clkm_conf.mclk_sel = 0; } /** - * @brief Disable tx interrupt + * @brief I2S mclk use rx module clock * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_mclk_use_rx_clk(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->rx_clkm_conf.mclk_sel = 1; } /** - * @brief Enable tx interrupt + * @brief Enable I2S TX slave mode * * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->tx_conf.tx_slave_mod = slave_en; } /** - * @brief Reset dma in + * @brief Enable I2S RX slave mode * * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) +static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->rx_conf.rx_slave_mod = slave_en; } /** - * @brief Reset dma out - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-H2 IDF-2098 - - -} - -/** - * @brief Reset tx + * @brief Reset I2S TX module * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_reset_tx(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; } /** - * @brief Reset rx + * @brief Reset I2S RX module * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_reset_rx(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; } /** - * @brief Start out link + * @brief Reset I2S TX FIFO * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_out_link(i2s_dev_t *hw) +static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_fifo_reset = 1; + hw->tx_conf.tx_fifo_reset = 0; } /** - * @brief Start tx + * @brief Reset I2S RX FIFO + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +{ + hw->rx_conf.rx_fifo_reset = 1; + hw->rx_conf.rx_fifo_reset = 0; +} + +/** + * @brief Set TX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock. + */ +static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + hw->tx_clkm_conf.tx_clk_sel = 2; +} + +/** + * @brief Set RX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` + */ +static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + hw->rx_clkm_conf.rx_clk_sel = 2; +} + +/** + * @brief Configure I2S TX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +{ + if (set->a == 0 || set->b == 0) { + hw->tx_clkm_div_conf.tx_clkm_div_x = 0; + hw->tx_clkm_div_conf.tx_clkm_div_y = 0; + hw->tx_clkm_div_conf.tx_clkm_div_z = 0; + } else { + if (set->b > set->a / 2) { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / (set->a - set->b) - 1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % (set->a - set->b); + hw->tx_clkm_div_conf.tx_clkm_div_z = set->a - set->b; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 1; + } else { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / set->b - 1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % set->b + 1; + hw->tx_clkm_div_conf.tx_clkm_div_z = set->b; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0; + } + } + hw->tx_clkm_conf.tx_clkm_div_num = set->mclk_div; + hw->tx_conf1.tx_bck_div_num = set->bck_div - 1; +} + +/** + * @brief Configure I2S RX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +{ + if (set->a == 0 || set->b == 0) { + hw->rx_clkm_div_conf.rx_clkm_div_x = 0; + hw->rx_clkm_div_conf.rx_clkm_div_y = 0; + hw->rx_clkm_div_conf.rx_clkm_div_z = 0; + } else { + if (set->b > set->a / 2) { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / (set->a - set->b) - 1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % (set->a - set->b); + hw->rx_clkm_div_conf.rx_clkm_div_z = set->a - set->b; + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 1; + } else { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / set->b - 1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % set->b + 1; + hw->rx_clkm_div_conf.rx_clkm_div_z = set->b; + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0; + } + } + hw->rx_clkm_conf.rx_clkm_div_num = set->mclk_div; + hw->rx_conf1.rx_bck_div_num = set->bck_div - 1; +} + +/** + * @brief Start I2S TX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_start_tx(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_update = 0; + hw->tx_conf.tx_update = 1; + hw->tx_conf.tx_start = 1; } /** - * @brief Start in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_in_link(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Start rx + * @brief Start I2S RX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_start_rx(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf.rx_update = 0; + hw->rx_conf.rx_update = 1; + hw->rx_conf.rx_start = 1; } /** - * @brief Stop out link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Stop tx + * @brief Stop I2S TX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_stop_tx(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_start = 0; } /** - * @brief Stop in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Stop rx + * @brief Stop I2S RX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf.rx_start = 0; } /** - * @brief Enable dma + * @brief Configure TX WS signal width * * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle */ -static inline void i2s_ll_enable_dma(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) { - abort(); // TODO ESP32-H2 IDF-2098 - // //Enable and configure DMA - // typeof(hw->lc_conf) lc_conf; - // lc_conf.val = 0; - // lc_conf.out_eof_mode = 1; - + hw->tx_conf1.tx_tdm_ws_width = width - 1; } /** - * @brief Get I2S interrupt status + * @brief Configure RX WS signal width * * @param hw Peripheral I2S hardware instance address. - * @param val value to get interrupt status + * @param width WS width in BCK cycle */ -static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->int_st.val; + hw->rx_conf1.rx_tdm_ws_width = width - 1; } /** - * @brief Clear I2S interrupt status + * @brief Configure the received length to trigger in_suc_eof interrupt * * @param hw Peripheral I2S hardware instance address. - * @param val value to clear interrupt status + * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_eof_num.rx_eof_num = eof_num; } /** - * @brief Get I2S out eof des address + * @brief Congfigure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get out eof des address + * @param sample_bit The chan bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->out_eof_des_addr; + hw->tx_conf1.tx_bits_mod = data_bit - 1; + hw->tx_conf1.tx_tdm_chan_bits = sample_bit - 1; } /** - * @brief Get I2S in eof des address + * @brief Congfigure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get in eof des address + * @param sample_bit The chan bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->in_eof_des_addr; + hw->rx_conf1.rx_bits_mod = data_bit - 1; + hw->rx_conf1.rx_tdm_chan_bits = sample_bit - 1; } /** - * @brief Get I2S tx fifo mode + * @brief Configure RX half_sample_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx fifo mode + * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->fifo_conf.tx_fifo_mod; + hw->tx_conf1.tx_half_sample_bits = half_sample_bits - 1; } /** - * @brief Set I2S tx fifo mode + * @brief Configure RX half_sample_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mode + * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf1.rx_half_sample_bits = half_sample_bits - 1; } /** - * @brief Get I2S rx fifo mode + * @brief Enable TX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx fifo mode + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_tx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->fifo_conf.rx_fifo_mod; + hw->tx_conf1.tx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S rx fifo mode + * @brief Enable RX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mode + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf1.rx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S tx chan mode + * @brief Configure TX total chan number * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx chan mode + * @param total_num Total chan number */ -static inline void i2s_ll_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; } /** - * @brief Set I2S rx chan mode + * @brief Configure RX total chan number * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx chan mode + * @param total_num Total chan number */ -static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; } /** - * @brief Set I2S out link address + * @brief Set the bimap of the active TX chan, only the active chan can launch audio data. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set out link address + * @param chan_mask mask of tx active chan */ -static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { - abort(); // TODO ESP32-H2 IDF-2098 - + typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; + hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set I2S in link address + * @brief Set the bimap of the active RX chan, only the active chan can receive audio data. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set in link address + * @param chan_mask mask of rx active chan */ -static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { - abort(); // TODO ESP32-H2 IDF-2098 - + typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; + hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set I2S rx eof num + * @brief Set TX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx eof num + * @param ws_pol_level pin level of WS(output) when receiving left channel data */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_ws_idle_pol = ws_pol_level; } /** - * @brief Get I2S tx pdm fp + * @brief Set RX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx pdm fp + * @param ws_pol_level pin level of WS(input) when receiving left channel data */ -static inline void i2s_ll_get_tx_pdm_fp(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->pdm_freq_conf.tx_pdm_fp; + hw->rx_conf.rx_ws_idle_pol = ws_pol_level; } /** - * @brief Get I2S tx pdm fs + * @brief Enable TX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx pdm fs + * @param pdm_enable Set true to TX enable PDM mode */ -static inline void i2s_ll_get_tx_pdm_fs(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->pdm_freq_conf.tx_pdm_fs; + if (pdm_enable) { + hw->tx_conf.tx_tdm_en = 0; + hw->tx_conf.tx_pdm_en = 1; + } else { + hw->tx_conf.tx_pdm_en = 0; + hw->tx_conf.tx_tdm_en = 1; + } } /** - * @brief Set I2S tx pdm fp + * @brief Configure I2S TX pdm * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm fp + * @param sample_rate The sample rate to be set. */ -static inline void i2s_ll_set_tx_pdm_fp(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) { - abort(); // TODO ESP32-H2 IDF-2098 - + uint32_t fp = 960; + uint32_t fs = sample_rate / 100; + typeof(hw->tx_pcm2pdm_conf) pdm_conf_reg = hw->tx_pcm2pdm_conf; + typeof(hw->tx_pcm2pdm_conf1) pdm_conf1_reg = hw->tx_pcm2pdm_conf1; + pdm_conf_reg.pcm2pdm_conv_en = 1; + pdm_conf_reg.tx_pdm_prescale = 0; + pdm_conf_reg.tx_pdm_hp_in_shift = 1; + pdm_conf_reg.tx_pdm_lp_in_shift = 1; + pdm_conf_reg.tx_pdm_sinc_in_shift = 1; + pdm_conf_reg.tx_pdm_sigmadelta_in_shift = 1; + pdm_conf_reg.tx_pdm_sinc_osr2 = fp / fs; + pdm_conf_reg.tx_pdm_dac_mode_en = 1; + pdm_conf_reg.tx_pdm_sigmadelta_dither = 0; + pdm_conf_reg.tx_pdm_sigmadelta_dither2 = 0; + pdm_conf_reg.tx_pdm_dac_2out_en = 1; + pdm_conf1_reg.tx_pdm_fp = fp; + pdm_conf1_reg.tx_pdm_fs = fs; + pdm_conf1_reg.tx_iir_hp_mult12_5 = 7; + pdm_conf1_reg.tx_iir_hp_mult12_0 = 6; + pdm_conf_reg.tx_pdm_hp_bypass = 0; + hw->tx_pcm2pdm_conf = pdm_conf_reg; + hw->tx_pcm2pdm_conf1 = pdm_conf1_reg; } /** - * @brief Set I2S tx pdm fs + * @brief Configure I2S TX PDM sample rate + * Fpdm = 64*Fpcm*fp/fs * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm fs + * @param fp The fp value of TX PDM filter module group0. + * @param fs The fs value of TX PDM filter module group0. */ -static inline void i2s_ll_set_tx_pdm_fs(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp; + hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs; + hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = fp / fs; } /** - * @brief Get I2S rx sinc dsr 16 en + * @brief Get I2S TX PDM configuration * * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx sinc dsr 16 en + * @param fp Pointer to accept TX PDM fp configuration paramater + * @param fs Pointer to accept TX PDM fs configuration paramater */ -static inline void i2s_ll_get_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool *val) +static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->pdm_conf.rx_sinc_dsr_16_en; + *fp = hw->tx_pcm2pdm_conf1.tx_pdm_fp; + *fs = hw->tx_pcm2pdm_conf1.tx_pdm_fs; } /** - * @brief Set I2S clkm div num + * @brief Enable RX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div num + * @param pdm_enable Set true to RX enable PDM mode */ -static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf.rx_pdm_en = pdm_enable; + hw->rx_conf.rx_tdm_en = !pdm_enable; } /** - * @brief Set I2S clkm div b + * @brief Configura TX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div b + * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { - abort(); // TODO ESP32-H2 IDF-2098 - + if (pcm_cfg == I2S_PCM_DISABLE) { + hw->tx_conf.tx_pcm_bypass = 1; + } else { + hw->tx_conf.tx_pcm_conf = pcm_cfg; + hw->tx_conf.tx_pcm_bypass = 0; + } } /** - * @brief Set I2S clkm div a + * @brief Configure RX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div a + * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { - abort(); // TODO ESP32-H2 IDF-2098 - + if (pcm_cfg == I2S_PCM_DISABLE) { + hw->rx_conf.rx_pcm_bypass = 1; + } else { + hw->rx_conf.rx_pcm_conf = pcm_cfg; + hw->rx_conf.rx_pcm_bypass = 0; + } } /** - * @brief Set I2S tx bck div num + * @brief Enable TX audio data left alignment * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bck div num + * @param ena Set true to enable left alignment */ -static inline void i2s_ll_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_left_align_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_left_align = ena; } /** - * @brief Set I2S rx bck div num + * @brief Enable RX audio data left alignment * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bck div num + * @param ena Set true to enable left alignment */ -static inline void i2s_ll_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_left_align_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf.rx_left_align = ena; } /** - * @brief Set I2S clk sel + * @brief Enable TX big endian mode * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clk sel + * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_big_endian_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf.rx_big_endian = ena; } /** - * @brief Set I2S tx bits mod + * @brief Enable RX big endian mode * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bits mod + * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_big_endian_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_big_endian = ena; } /** - * @brief Set I2S rx bits mod + * @brief Configure TX bit order * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bits mod + * @param lsb_order_ena Set true to enable LSB bit order */ -static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_bit_order = lsb_order_ena; } /** - * @brief Set I2S rx sinc dsr 16 en + * @brief Configure RX bit order * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx sinc dsr 16 en + * @param lsb_order_ena Set true to enable LSB bit order */ -static inline void i2s_ll_set_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool val) +static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf.rx_bit_order = lsb_order_ena; } /** - * @brief Set I2S dscr en + * @brief Configure TX skip mask enable * * @param hw Peripheral I2S hardware instance address. - * @param val value to set dscr en + * @param skip_mask_ena Set true to skip inactive channels. */ -static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val) +static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena) { - abort(); // TODO ESP32-H2 IDF-2098 + hw->tx_tdm_ctrl.tx_tdm_skip_msk_en = skip_mask_ena; +} + +/** + * @brief Configure single data + * + * @param hw Peripheral I2S hardware instance address. + * @param data Single data to be set + */ +static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) +{ + hw->conf_single_data = data; } /** - * @brief Set I2S lcd en + * @brief Enable loopback mode * * @param hw Peripheral I2S hardware instance address. - * @param val value to set lcd en + * @param ena Set true to enable loopback mode. */ -static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S camera en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set camera en - */ -static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S pcm2pdm conv en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set pcm2pdm conv en - */ -static inline void i2s_ll_set_pcm2pdm_conv_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S TX to MSB Alignment Standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_format_msb_align(i2s_dev_t *hw) -{ -} - - -static inline void i2s_ll_set_rx_format_msb_align(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_long(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_short(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to philip standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_format_philip(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_short(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to philip standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_format_philip(i2s_dev_t *hw) +static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool ena) { + hw->tx_conf.sig_loopback = ena; } /** @@ -715,198 +694,6 @@ static inline void i2s_ll_set_pdm2pcm_conv_en(i2s_dev_t *hw, bool val) } -/** - * @brief Set I2S rx pdm en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx pdm en - */ -static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S tx pdm en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm en - */ -static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S tx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mod force en - */ -static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S rx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mod force en - */ -static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S tx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx right first - */ -static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S rx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx right first - */ -static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S tx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx slave mod - */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S rx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx slave mod - */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Get I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx msb right - */ -static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->conf.tx_msb_right; -} - -/** - * @brief Get I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx msb right - */ -static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->conf.rx_msb_right; -} - -/** - * @brief Set I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx msb right - */ -static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx msb right - */ -static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S tx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx mono - */ -static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S rx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx mono - */ -static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S tx sinc osr2 - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx sinc osr2 - */ -static inline void i2s_ll_set_tx_sinc_osr2(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S sig loopback - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set sig loopback - */ -static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index e1f677cf32..5ca3262018 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -448,10 +448,10 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t eof_num) } /** - * @brief Congfigure TX slot bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit + * @brief Congfigure TX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) @@ -461,10 +461,10 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i } /** - * @brief Congfigure RX slot bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit + * @brief Congfigure RX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 85b91dc077..3b2766fe5c 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -322,10 +322,10 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) } /** - * @brief Congfigure TX slot bit and audio data bit + * @brief Congfigure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) @@ -335,10 +335,10 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i } /** - * @brief Congfigure RX slot bit and audio data bit + * @brief Congfigure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) @@ -392,52 +392,52 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab } /** - * @brief Configure TX total slot number + * @brief Configure TX total chan number * * @param hw Peripheral I2S hardware instance address. - * @param total_num Total slot number + * @param total_num Total chan number */ -static inline void i2s_ll_set_tx_slot_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num) { hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; } /** - * @brief Configure RX total slot number + * @brief Configure RX total chan number * * @param hw Peripheral I2S hardware instance address. - * @param total_num Total slot number + * @param total_num Total chan number */ -static inline void i2s_ll_set_rx_slot_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num) { hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; } /** - * @brief Set the bimap of the active TX slot, only the active slot can launch audio data. + * @brief Set the bimap of the active TX chan, only the active chan can launch audio data. * * @param hw Peripheral I2S hardware instance address. - * @param slot_mask mask of tx active slot + * @param chan_mask mask of tx active chan */ -static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) +static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; - tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set the bimap of the active RX slot, only the active slot can receive audio data. + * @brief Set the bimap of the active RX chan, only the active chan can receive audio data. * * @param hw Peripheral I2S hardware instance address. - * @param slot_mask mask of rx active slot + * @param chan_mask mask of rx active chan */ -static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) +static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; - tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; } @@ -588,7 +588,7 @@ static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) +static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { if (pcm_cfg == I2S_PCM_DISABLE) { hw->tx_conf.tx_pcm_bypass = 1; @@ -604,7 +604,7 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) +static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { if (pcm_cfg == I2S_PCM_DISABLE) { hw->rx_conf.rx_pcm_bypass = 1; diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index 49726d8204..bbabba6ba7 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -148,14 +148,14 @@ static void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_hal_config_t } } #else - int slot_bits = hal_cfg->bits_cfg.chan_bits; - int slot_num = hal_cfg->chan_cfg.total_chan; + int chan_bits = hal_cfg->bits_cfg.chan_bits; + int chan_num = hal_cfg->total_chan; bool msb_shift_en = false; int tdm_ws_width = 0; switch (hal_cfg->comm_fmt) { case I2S_COMM_FORMAT_STAND_MSB: msb_shift_en = false; - tdm_ws_width = slot_num * slot_bits / 2; + tdm_ws_width = chan_num * chan_bits / 2; break; case I2S_COMM_FORMAT_STAND_PCM_SHORT: msb_shift_en = false; @@ -163,22 +163,22 @@ static void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_hal_config_t break; case I2S_COMM_FORMAT_STAND_PCM_LONG: msb_shift_en = false; - tdm_ws_width = slot_bits; + tdm_ws_width = chan_bits; break; default: //I2S_COMM_FORMAT_STAND_I2S msb_shift_en = true; - tdm_ws_width = slot_num * slot_bits / 2; + tdm_ws_width = chan_num * chan_bits / 2; break; } if (hal_cfg->mode & I2S_MODE_TX) { i2s_ll_tx_msb_shift_enable(hal->dev, msb_shift_en); i2s_ll_set_tx_tdm_ws_width(hal->dev, tdm_ws_width); - i2s_ll_set_tx_half_sample_bit(hal->dev, slot_num * slot_bits / 2); + i2s_ll_set_tx_half_sample_bit(hal->dev, chan_num * chan_bits / 2); } if (hal_cfg->mode & I2S_MODE_RX) { i2s_ll_rx_msb_shift_enable(hal->dev, msb_shift_en); i2s_ll_set_rx_tdm_ws_width(hal->dev, tdm_ws_width); - i2s_ll_set_rx_half_sample_bit(hal->dev, slot_num * slot_bits / 2); + i2s_ll_set_rx_half_sample_bit(hal->dev, chan_num * chan_bits / 2); } #endif } @@ -186,23 +186,23 @@ static void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_hal_config_t void i2s_hal_samples_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) { int data_bits = hal_cfg->bits_cfg.sample_bits; - int slot_bits = hal_cfg->bits_cfg.chan_bits; + int chan_bits = hal_cfg->bits_cfg.chan_bits; #if SOC_I2S_SUPPORTS_TDM - int slot_num = hal_cfg->chan_cfg.total_chan; + int chan_num = hal_cfg->total_chan; if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_set_tx_slot_num(hal->dev, slot_num); - i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits); + i2s_ll_set_tx_chan_num(hal->dev, chan_num); + i2s_ll_set_tx_sample_bit(hal->dev, chan_bits, data_bits); } if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_set_rx_slot_num(hal->dev, slot_num); - i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits); + i2s_ll_set_rx_chan_num(hal->dev, chan_num); + i2s_ll_set_rx_sample_bit(hal->dev, chan_bits, data_bits); } #else if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits); + i2s_ll_set_tx_sample_bit(hal->dev, chan_bits, data_bits); } if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits); + i2s_ll_set_rx_sample_bit(hal->dev, chan_bits, data_bits); } #endif //I2S standards config: Philip, MSB or PCM, Only I2S mode should do this configuration. @@ -224,7 +224,7 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf i2s_ll_set_tx_clk_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default i2s_ll_mclk_use_tx_clk(hal->dev); - i2s_ll_set_tx_active_slot_mask(hal->dev, hal_cfg->chan_cfg.chan_mask); + i2s_ll_set_tx_active_chan_mask(hal->dev, hal_cfg->chan_mask); i2s_ll_tx_left_align_enable(hal->dev, hal_cfg->flags.left_align_en); i2s_ll_tx_big_endian_enable(hal->dev, hal_cfg->flags.big_edin_en); i2s_ll_tx_set_bit_order(hal->dev, hal_cfg->flags.bit_order_msb_en); @@ -247,7 +247,7 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf i2s_ll_set_rx_clk_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default i2s_ll_mclk_use_rx_clk(hal->dev); - i2s_ll_set_rx_active_slot_mask(hal->dev, hal_cfg->chan_cfg.chan_mask); + i2s_ll_set_rx_active_chan_mask(hal->dev, hal_cfg->chan_mask); i2s_ll_rx_left_align_enable(hal->dev, hal_cfg->flags.left_align_en); i2s_ll_rx_big_endian_enable(hal->dev, hal_cfg->flags.big_edin_en); i2s_ll_rx_set_bit_order(hal->dev, hal_cfg->flags.bit_order_msb_en); @@ -271,11 +271,9 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf } #endif -#if SOC_I2S_SUPPORTS_PDM - bool is_pdm = ((hal_cfg->mode & I2S_MODE_PDM) > 0); #if SOC_I2S_SUPPORTS_PDM_TX if (hal_cfg->mode & I2S_MODE_TX) { - if (is_pdm) { + if (hal_cfg->mode & I2S_MODE_PDM) { i2s_ll_tx_pdm_cfg(hal->dev, hal_cfg->sample_rate); } else { i2s_ll_set_tx_pdm_en(hal->dev, false); @@ -284,15 +282,13 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf #endif // SOC_I2S_SUPPORTS_PDM_TX #if SOC_I2S_SUPPORTS_PDM_RX if (hal_cfg->mode & I2S_MODE_RX) { - if (is_pdm) { + if (hal_cfg->mode & I2S_MODE_PDM) { i2s_ll_rx_pdm_cfg(hal->dev); } else { i2s_ll_set_rx_pdm_en(hal->dev, false); } } #endif // SOC_I2S_SUPPORTS_PDM_RX -#endif // SOC_I2S_SUPPORTS_PDM - //Configure I2S slot number,sample bit. + //Configure I2S chan number,sample bit. i2s_hal_samples_config(hal, hal_cfg); - } diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index d26697f976..be07a92e41 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -44,35 +44,6 @@ typedef union { uint32_t val; /*!< I2S cannel bits configiration value */ } i2s_hal_bits_cfg_t; -#if SOC_I2S_SUPPORTS_TDM -/** - * @brief I2S channel configurations - * - */ -typedef union { - struct { - uint32_t total_chan : 8; /*!< Total number of I2S channels */ - uint32_t active_chan : 8; /*!< Active channel number, it will be set automatically if chan_mask is set */ - uint32_t chan_mask : 16; /*!< Active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<dev, slot_bit, data_bit) +#define i2s_hal_set_tx_sample_bit(hal, chan_bit, data_bit) i2s_ll_set_tx_sample_bit((hal)->dev, chan_bit, data_bit) /** * @brief Set I2S RX sample bit * * @param hal Context of the HAL layer - * @param slot_bit I2S RX slot bit + * @param chan_bit I2S RX chan bit * @param data_bit The sample data bit length. */ -#define i2s_hal_set_rx_sample_bit(hal, slot_bit, data_bit) i2s_ll_set_rx_sample_bit((hal)->dev, slot_bit, data_bit) +#define i2s_hal_set_rx_sample_bit(hal, chan_bit, data_bit) i2s_ll_set_rx_sample_bit((hal)->dev, chan_bit, data_bit) /** * @brief Configure I2S TX module clock devider @@ -250,7 +230,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @brief Configure I2S TX PCM encoder or decoder. * * @param hal Context of the HAL layer - * @param cfg PCM configure paramater, refer to `i2s_pcm_mode_t` + * @param cfg PCM configure paramater, refer to `i2s_pcm_compress_t` */ #define i2s_hal_tx_pcm_cfg(hal, cfg) i2s_ll_tx_pcm_cfg((hal)->dev, cfg) @@ -258,7 +238,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @brief Configure I2S RX PCM encoder or decoder. * * @param hal Context of the HAL layer - * @param cfg PCM configure paramater, refer to `i2s_pcm_mode_t` + * @param cfg PCM configure paramater, refer to `i2s_pcm_compress_t` */ #define i2s_hal_rx_pcm_cfg(hal, cfg) i2s_ll_rx_pcm_cfg((hal)->dev, cfg) #endif diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index 5c6ee96ad3..6b12b4812d 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -36,16 +36,16 @@ typedef enum { } i2s_bits_per_sample_t; /** - * @brief I2S bit width per slot. + * @brief I2S bit width per chan. * */ typedef enum { - I2S_BITS_PER_SLOT_8BIT = (8), /*!< slot bit 8*/ - I2S_BITS_PER_SLOT_16BIT = (16), /*!< slot bit 16*/ - I2S_BITS_PER_SLOT_24BIT = (24), /*!< slot bit 24*/ - I2S_BITS_PER_SLOT_32BIT = (32), /*!< slot bit 32*/ - I2S_BITS_PER_SLOT_EQU_SAMPLE = (0), /*!< slot bit equals to data bit*/ -} i2s_bits_per_slot_t; + I2S_BITS_PER_CHAN_DEFAULT = (0), /*!< chan bit equals to data bit*/ + I2S_BITS_PER_CHAN_8BIT = (8), /*!< chan bit 8*/ + I2S_BITS_PER_CHAN_16BIT = (16), /*!< chan bit 16*/ + I2S_BITS_PER_CHAN_24BIT = (24), /*!< chan bit 24*/ + I2S_BITS_PER_CHAN_32BIT = (32), /*!< chan bit 32*/ +} i2s_bits_per_chan_t; /** * @brief I2S channel. @@ -84,9 +84,6 @@ typedef enum { #endif } i2s_channel_t; - - - /** * @brief I2S communication standard format * @@ -134,10 +131,8 @@ typedef enum { I2S_MODE_DAC_BUILT_IN = (0x1 << 4), /*!< Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB*/ I2S_MODE_ADC_BUILT_IN = (0x1 << 5), /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/ #endif -#if SOC_I2S_SUPPORTS_PDM // PDM functions are only supported on I2S0 (all chips). I2S_MODE_PDM = (0x1 << 6), /*!< I2S PDM mode*/ -#endif } i2s_mode_t; /** @@ -169,12 +164,12 @@ typedef enum { * */ typedef enum { - I2S_PCM_A_DECOMPRESS=0, /*!< A-law decompress*/ + I2S_PCM_DISABLE = 0, /*!< Disable A/U law decopress or compress*/ + I2S_PCM_A_DECOMPRESS, /*!< A-law decompress*/ I2S_PCM_A_COMPRESS, /*!< A-law compress*/ I2S_PCM_U_DECOMPRESS, /*!< U-law decompress*/ I2S_PCM_U_COMPRESS, /*!< U-law compress*/ - I2S_PCM_DISABLE, /*!< Disable A/U law decopress or compress*/ -} i2s_pcm_mode_t; +} i2s_pcm_compress_t; #endif #if SOC_I2S_SUPPORTS_PDM_RX @@ -188,7 +183,6 @@ typedef enum { } i2s_pdm_dsr_t; #endif -#if SOC_I2S_SUPPORTS_PDM /** * @brief PDM PCM convter enable/disable. * @@ -197,7 +191,6 @@ typedef enum { PDM_PCM_CONV_ENABLE, /*!< Enable PDM PCM convert*/ PDM_PCM_CONV_DISABLE, /*!< Disable PDM PCM convert*/ } pdm_pcm_conv_t; -#endif #ifdef __cplusplus diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index a4c2a5c07e..544209a925 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -138,7 +138,6 @@ #define SOC_I2S_NUM (2) #define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_RX (1) -#define SOC_I2S_SUPPORTS_PDM (1) // (SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) #define SOC_I2S_SUPPORTS_ADC_DAC (1) // ESP32 support ADC and DAC #define SOC_I2S_SUPPORTS_APLL (1)// ESP32 support APLL diff --git a/components/soc/esp32c3/i2s_periph.c b/components/soc/esp32c3/i2s_periph.c index 5e6e82a7ab..b4b35836c3 100644 --- a/components/soc/esp32c3/i2s_periph.c +++ b/components/soc/esp32c3/i2s_periph.c @@ -26,6 +26,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .rx_ws_sig = I2SI_WS_IN_IDX, .data_out_sig = I2SO_SD_OUT_IDX, .data_in_sig = I2SI_SD_IN_IDX, + .irq = -1, .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index d781839b6f..1557305eef 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -112,7 +112,6 @@ #define SOC_I2S_SUPPORTS_PCM (1) #define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_RX (0) -#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) #define SOC_I2S_SUPPORTS_TDM (1) #define SOC_I2S_APLL_MIN_FREQ (250000000) #define SOC_I2S_APLL_MAX_FREQ (500000000) diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 64fa8dd3b9..40a4ecb249 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -106,7 +106,10 @@ /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (1) - +#define SOC_I2S_SUPPORTS_PCM (1) +#define SOC_I2S_SUPPORTS_PDM_TX (1) +#define SOC_I2S_SUPPORTS_PDM_RX (0) +#define SOC_I2S_SUPPORTS_TDM (1) #define SOC_I2S_APLL_MIN_FREQ (250000000) #define SOC_I2S_APLL_MAX_FREQ (500000000) #define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware diff --git a/components/soc/esp32h2/ld/esp32h2.peripherals.ld b/components/soc/esp32h2/ld/esp32h2.peripherals.ld index 38e6b58258..ee3154ad43 100644 --- a/components/soc/esp32h2/ld/esp32h2.peripherals.ld +++ b/components/soc/esp32h2/ld/esp32h2.peripherals.ld @@ -7,7 +7,7 @@ PROVIDE ( SIGMADELTA = 0x60004f00 ); PROVIDE ( RTCCNTL = 0x60008000 ); PROVIDE ( RTCIO = 0x60008400 ); PROVIDE ( HINF = 0x6000B000 ); -PROVIDE ( I2S1 = 0x6002d000 ); +PROVIDE ( I2S0 = 0x6002d000 ); PROVIDE ( I2C0 = 0x60013000 ); PROVIDE ( UHCI0 = 0x60014000 ); PROVIDE ( UHCI1 = 0x6000c000 ); diff --git a/components/soc/esp32s3/i2s_periph.c b/components/soc/esp32s3/i2s_periph.c index f1b3b494d2..13960bd5f2 100644 --- a/components/soc/esp32s3/i2s_periph.c +++ b/components/soc/esp32s3/i2s_periph.c @@ -26,6 +26,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .rx_ws_sig = I2S0I_WS_IN_IDX, .data_out_sig = I2S0O_SD_OUT_IDX, .data_in_sig = I2S0I_SD_IN_IDX, + .irq = -1, .module = PERIPH_I2S0_MODULE, }, { @@ -35,6 +36,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .rx_ws_sig = I2S1I_WS_IN_IDX, .data_out_sig = I2S1O_SD_OUT_IDX, .data_in_sig = I2S1I_SD_IN_IDX, + .irq = -1, .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 5edff45ab4..f2fda6ab00 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -67,7 +67,6 @@ #define SOC_I2S_SUPPORTS_PCM (1) #define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_RX (1) -#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) #define SOC_I2S_SUPPORTS_TDM (1) /*-------------------------- LEDC CAPS ---------------------------------------*/ diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index 06c6d44fd5..55b9c883b3 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -1,24 +1,14 @@ I2S === -.. only:: esp32c3 - - .. warning:: - - This document is not updated for ESP32-C3 yet. +{IDF_TARGET_I2S_NUM:default="two", esp32s2="one", esp32c3="one"} Overview -------- I2S (Inter-IC Sound) is a serial, synchronous communication protocol that is usually used for transmitting audio data between two digital audio devices. -.. only:: esp32 - - {IDF_TARGET_NAME} contains two I2S peripherals. These peripherals can be configured to input and output sample data via the I2S driver. - -.. only:: esp32s2 - - {IDF_TARGET_NAME} contains one I2S peripheral. These peripherals can be configured to input and output sample data via the I2S driver. +{IDF_TARGET_NAME} contains {IDF_TARGET_I2S_NUM} I2S peripheral(s). These peripherals can be configured to input and output sample data via the I2S driver. An I2S bus consists of the following lines: @@ -30,20 +20,22 @@ Each I2S controller has the following features that can be configured using the - Operation as system master or slave - Capable of acting as transmitter or receiver -- Dedicated DMA controller that allows for streaming sample data without requiring the CPU to copy each data sample +- DMA controller that allows for streaming sample data without requiring the CPU to copy each data sample Each controller can operate in half-duplex communication mode. Thus, the two controllers can be combined to establish full-duplex communication. -I2S0 output can be routed directly to the digital-to-analog converter's (DAC) output channels (GPIO 25 & GPIO 26) to produce direct analog output without involving any external I2S codecs. I2S0 can also be used for transmitting PDM (Pulse-density modulation) signals. - -The I2S peripherals also support LCD mode for communicating data over a parallel bus, as used by some LCD displays and camera modules. LCD mode has the following operational modes: - -- LCD master transmitting mode -- Camera slave receiving mode -- ADC/DAC mode - .. only:: esp32 + I2S0 output can be routed directly to the digital-to-analog converter's (DAC) output channels (GPIO 25 & GPIO 26) to produce direct analog output without involving any external I2S codecs. I2S0 can also be used for transmitting PDM (Pulse-density modulation) signals. + +.. only:: esp32 or esp32s2 + + The I2S peripherals also support LCD mode for communicating data over a parallel bus, as used by some LCD displays and camera modules. LCD mode has the following operational modes: + + - LCD master transmitting mode + - Camera slave receiving mode + - ADC/DAC mode + For more information, see *{IDF_TARGET_NAME} Technical Reference Manual* > *I2S Controller (I2S)* > LCD Mode [`PDF <{IDF_TARGET_TRM_EN_URL}#camlcdctrl>`__]. .. note:: @@ -68,26 +60,50 @@ Install the I2S driver by calling the function :cpp:func`i2s_driver_install` and - The structure :cpp:type:`i2s_config_t` with defined communication parameters - Event queue size and handle +I2S will start automatically once :cpp:func`i2s_driver_install` returns ``ESP_OK``. + Configuration example: -.. code-block:: c +.. only:: not SOC_I2S_SUPPORTS_TDM - static const int i2s_num = 0; // i2s port number + .. code-block:: c - static const i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = 44100, - .bits_per_sample = 16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, - .intr_alloc_flags = 0, // default interrupt priority - .dma_buf_count = 8, - .dma_buf_len = 64, - .use_apll = false - }; + static const int i2s_num = 0; // i2s port number - i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); + i2s_config_t i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = 44100, + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S + .tx_desc_auto_clear = false, + .dma_buf_count = 8, + .dma_buf_len = 64, + .use_apll = false, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 // Interrupt level 1, default 0 + }; + i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); + +.. only:: SOC_I2S_SUPPORTS_TDM + + .. code-block:: c + + static const int i2s_num = 0; // i2s port number + + i2s_config_t i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = 44100, + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .tx_desc_auto_clear = false, + .dma_buf_count = 8, + .dma_buf_len = 64, + .bits_per_chan = I2S_BITS_PER_SAMPLE_16BIT + }; + + i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); Setting Communication Pins ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,15 +116,14 @@ Once the driver is installed, configure physical GPIO pins to which signals will .. code-block:: c static const i2s_pin_config_t pin_config = { - .bck_io_num = 26, - .ws_io_num = 25, - .data_out_num = 22, + .bck_io_num = 4, + .ws_io_num = 5, + .data_out_num = 18, .data_in_num = I2S_PIN_NO_CHANGE }; i2s_set_pin(i2s_num, &pin_config); - Running I2S Communication ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -117,14 +132,17 @@ To perform a transmission: - Prepare the data for sending - Call the function :cpp:func:`i2s_write` and pass the data buffer address and data length to it -The function will write the data to the I2S DMA Tx buffer, and then the data will be transmitted automatically. +The function will write the data to the DMA Tx buffer, and then the data will be transmitted automatically. .. code-block:: c i2s_write(I2S_NUM, samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100); +To retrieve received data, use the function :cpp:func:`i2s_read`. It will retrieve the data from the DMA Rx buffer, once the data is received by the I2S controller. -To retrieve received data, use the function :cpp:func:`i2s_read`. It will retrieve the data from the I2S DMA Rx buffer, once the data is received by the I2S controller. +.. code-block:: c + + i2s_read(I2S_NUM, data_recv, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_read, 100); You can temporarily stop the I2S driver by calling the function :cpp:func:`i2s_stop`, which will disable the I2S Tx/Rx units until the function :cpp:func:`i2s_start` is called. If the function :cpp:func`i2s_driver_install` is used, the driver will start up automatically eliminating the need to call :cpp:func:`i2s_start`. @@ -140,87 +158,184 @@ Application Example A code example for the I2S driver can be found in the directory :example:`peripherals/i2s`. -In addition, there are two short configuration examples for the I2S driver. +.. only:: SOC_I2S_SUPPORTS_ADC_DAC + In addition, there are two short configuration examples for the I2S driver. + +.. only:: not SOC_I2S_SUPPORTS_ADC_DAC + + In addition, there is a short configuration examples for the I2S driver. I2S configuration ^^^^^^^^^^^^^^^^^ -.. code-block:: c +Example for general usage. - #include "driver/i2s.h" - #include "freertos/queue.h" +.. only:: not SOC_I2S_SUPPORTS_TDM - static const int i2s_num = 0; // i2s port number + .. code-block:: c - static const i2s_config_t i2s_config = { - .param_cfg = { + #include "driver/i2s.h" + + static const int i2s_num = 0; // i2s port number + + i2s_config_t i2s_config = { .mode = I2S_MODE_MASTER | I2S_MODE_TX, .sample_rate = 44100, - .slot_bits_cfg = 16, + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, - }, - .intr_alloc_flags = 0, // default interrupt priority - .dma_buf_count = 8, - .dma_buf_len = 64, - .use_apll = false - }; + .communication_format = I2S_COMM_FORMAT_STAND_I2S + .tx_desc_auto_clear = false, + .dma_buf_count = 8, + .dma_buf_len = 64, + .use_apll = false, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 // Interrupt level 1, default 0 + }; - static const i2s_pin_config_t pin_config = { - .bck_io_num = 26, - .ws_io_num = 25, - .data_out_num = 22, - .data_in_num = I2S_PIN_NO_CHANGE - }; - - ... + static const i2s_pin_config_t pin_config = { + .bck_io_num = 4, + .ws_io_num = 5, + .data_out_num = 18, + .data_in_num = I2S_PIN_NO_CHANGE + }; i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver - i2s_set_pin(i2s_num, &pin_config); - i2s_set_sample_rates(i2s_num, 22050); //set sample rates + ... + /* You can reset parameters by calling 'i2s_set_clk' + * + * The low 16 bits are the valid data bits in one chan and the high 16 bits are + * the total bits in one chan. If high 16 bits is smaller than low 16 bits, it will + * be set to a same value as low 16 bits. + */ + uint32_t bits_cfg = (I2S_BITS_PER_CHAN_32BIT << 16) | I2S_BITS_PER_SAMPLE_16BIT; + i2s_set_clk(i2s_num, 22050, bits_cfg, I2S_CHANNEL_STEREO); + ... i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver +.. only:: SOC_I2S_SUPPORTS_TDM -Configuring I2S to use internal DAC for analog output -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + .. code-block:: c -.. code-block:: c + #include "driver/i2s.h" - #include "driver/i2s.h" - #include "freertos/queue.h" + static const int i2s_num = 0; // i2s port number - static const int i2s_num = 0; // i2s port number - - static const i2s_config_t i2s_config = { - .param_cfg = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, + i2s_config_t i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, .sample_rate = 44100, - .slot_bits_cfg = 16, /* the DAC module will only take the 8bits from MSB */ + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - }, - .intr_alloc_flags = 0, // default interrupt priority - .dma_buf_count = 8, - .dma_buf_len = 64, - .use_apll = false - }; + .communication_format = I2S_COMM_FORMAT_STAND_I2S + .tx_desc_auto_clear = false, + .dma_buf_count = 8, + .dma_buf_len = 64 + }; - ... + static const i2s_pin_config_t pin_config = { + .bck_io_num = 4, + .ws_io_num = 5, + .data_out_num = 18, + .data_in_num = I2S_PIN_NO_CHANGE + }; i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver + i2s_set_pin(i2s_num, &pin_config); - i2s_set_pin(i2s_num, NULL); //for internal DAC, this will enable both of the internal channels - - //You can call i2s_set_dac_mode to set built-in DAC output mode. - //i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); - - i2s_set_sample_rates(i2s_num, 22050); //set sample rates + ... + /* You can reset parameters by calling 'i2s_set_clk' + * + * The low 16 bits are the valid data bits in one chan and the high 16 bits are + * the total bits in one chan. If high 16 bits is smaller than low 16 bits, it will + * be set to a same value as low 16 bits. + */ + uint32_t bits_cfg = (I2S_BITS_PER_CHAN_32BIT << 16) | I2S_BITS_PER_SAMPLE_16BIT; + i2s_set_clk(i2s_num, 22050, bits_cfg, I2S_CHANNEL_STEREO); + ... i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver + I2S on {IDF_TARGET_NAME} support TDM mode, up to 16 channels are available in TDM mode. If you want to use TDM mode, set field ``channel_format`` of :cpp:type:`i2s_config_t` to ``I2S_CHANNEL_FMT_TDM``. Then enable the channels by setting ``tdm_chan_cfg.chan_mask`` using masks in :cpp:type:`i2s_channel_t`, the number of active channels and total channels will be calculate automatically. Also you can set a particular total channel number for it, but it shouldn't be smaller than the largest channel you use. + + .. code-block:: c + + #include "driver/i2s.h" + + static const int i2s_num = 0; // i2s port number + + i2s_config_t i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = 44100, + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, + .channel_format = I2S_CHANNEL_FMT_TDM, + .communication_format = I2S_COMM_FORMAT_STAND_I2S + .tx_desc_auto_clear = false, + .dma_buf_count = 8, + .dma_buf_len = 64, + .chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH2 + }; + + static const i2s_pin_config_t pin_config = { + .bck_io_num = 4, + .ws_io_num = 5, + .data_out_num = 18, + .data_in_num = I2S_PIN_NO_CHANGE + }; + + i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver + i2s_set_pin(i2s_num, &pin_config); + + ... + /* You can reset parameters by calling 'i2s_set_clk' + * + * The low 16 bits are the valid data bits in one chan and the high 16 bits are + * the total bits in one chan. If high 16 bits is smaller than low 16 bits, it will + * be set to a same value as low 16 bits. + */ + uint32_t bits_cfg = (I2S_BITS_PER_CHAN_32BIT << 16) | I2S_BITS_PER_SAMPLE_16BIT; + i2s_set_clk(i2s_port_t i2s_num, 22050, bits_cfg, I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1); // set clock + ... + + i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver + +.. only:: SOC_I2S_SUPPORTS_ADC_DAC + + Configuring I2S to use internal DAC for analog output + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + .. code-block:: c + + #include "driver/i2s.h" + #include "freertos/queue.h" + + static const int i2s_num = 0; // i2s port number + + static const i2s_config_t i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, + .sample_rate = 44100, + .bits_per_sample = 16, /* the DAC module will only take the 8bits from MSB */ + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .intr_alloc_flags = 0, // default interrupt priority + .dma_buf_count = 8, + .dma_buf_len = 64, + .use_apll = false + }; + + ... + + i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver + + i2s_set_pin(i2s_num, NULL); //for internal DAC, this will enable both of the internal channels + + //You can call i2s_set_dac_mode to set built-in DAC output mode. + //i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); + + i2s_set_sample_rates(i2s_num, 22050); //set sample rates + + i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver + API Reference ------------- From 3c57a6ac3641d8d558d42d21f590e0679dbb9482 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 20 Jul 2021 21:03:52 +0800 Subject: [PATCH 4/5] driver/i2s: refactor ll and hal --- components/driver/i2s.c | 1170 +++++++++-------- components/driver/include/driver/i2s.h | 43 +- components/driver/test/test_i2s.c | 170 +-- components/hal/esp32/include/hal/i2s_ll.h | 343 ++--- components/hal/esp32c3/include/hal/i2s_ll.h | 288 ++-- components/hal/esp32h2/include/hal/i2s_ll.h | 281 ++-- components/hal/esp32s2/include/hal/i2s_ll.h | 191 ++- components/hal/esp32s3/include/hal/i2s_ll.h | 278 ++-- components/hal/i2s_hal.c | 330 ++--- components/hal/include/hal/i2s_hal.h | 123 +- components/hal/include/hal/i2s_types.h | 42 +- components/soc/esp32c3/include/soc/soc_caps.h | 6 +- components/soc/esp32h2/include/soc/soc_caps.h | 6 +- .../soc/esp32s3/include/soc/i2s_struct.h | 2 +- components/soc/esp32s3/include/soc/soc_caps.h | 1 + docs/en/api-reference/peripherals/i2s.rst | 4 +- 16 files changed, 1871 insertions(+), 1407 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 5857e67bd6..36c4618d5b 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -43,10 +43,10 @@ static const char *TAG = "I2S"; -#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_ENTER_CRITICAL_ISR(i2s_num) portENTER_CRITICAL_ISR(&i2s_spinlock[i2s_num]) +#define I2S_EXIT_CRITICAL_ISR(i2s_num) portEXIT_CRITICAL_ISR(&i2s_spinlock[i2s_num]) +#define I2S_ENTER_CRITICAL(i2s_num) portENTER_CRITICAL(&i2s_spinlock[i2s_num]) +#define I2S_EXIT_CRITICAL(i2s_num) 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) @@ -119,6 +119,12 @@ static int _i2s_adc_channel = -1; static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, int dma_buf_len); static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma); +/************************************************************** + * I2S GPIO operation * + * - gpio_matrix_out_check_and_set * + * - gpio_matrix_in_check_and_set * + * - i2s_set_pin * + **************************************************************/ static void gpio_matrix_out_check_and_set(int gpio, uint32_t signal_idx, bool out_inv, bool oen_inv) { //if pin = -1, do not need to configure @@ -139,443 +145,68 @@ static void gpio_matrix_in_check_and_set(int gpio, uint32_t signal_idx, bool inv } } -float i2s_get_clk(i2s_port_t i2s_num) +esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) { ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); - return (float)p_i2s[i2s_num]->sample_rate; -} - -static void i2s_tx_reset(i2s_port_t i2s_num) -{ - p_i2s[i2s_num]->tx->curr_ptr = NULL; - p_i2s[i2s_num]->tx->rw_pos = 0; -#if SOC_GDMA_SUPPORTED - gdma_reset(p_i2s[i2s_num]->tx_dma_chan); -#else - //attach DMA - i2s_hal_attach_tx_dma(&(p_i2s[i2s_num]->hal)); - // Reset I2S TX module first, and then, reset DMA and FIFO. - i2s_hal_reset_tx(&(p_i2s[i2s_num]->hal)); - i2s_hal_reset_txdma(&(p_i2s[i2s_num]->hal)); - i2s_hal_reset_tx_fifo(&(p_i2s[i2s_num]->hal)); -#endif -} - -static void i2s_rx_reset(i2s_port_t i2s_num) -{ - p_i2s[i2s_num]->rx->curr_ptr = NULL; - p_i2s[i2s_num]->rx->rw_pos = 0; -#if SOC_GDMA_SUPPORTED - gdma_reset(p_i2s[i2s_num]->rx_dma_chan); -#else - //attach DMA - i2s_hal_attach_rx_dma(&(p_i2s[i2s_num]->hal)); - // Reset I2S RX module first, and then, reset DMA and FIFO. - i2s_hal_reset_rx(&(p_i2s[i2s_num]->hal)); - i2s_hal_reset_rxdma(&(p_i2s[i2s_num]->hal)); - i2s_hal_reset_rx_fifo(&(p_i2s[i2s_num]->hal)); -#endif -} - -static void i2s_tx_start(i2s_port_t i2s_num) -{ -#if SOC_GDMA_SUPPORTED - gdma_start(p_i2s[i2s_num]->tx_dma_chan, (uint32_t) p_i2s[i2s_num]->tx->desc[0]); -#else - i2s_hal_enable_tx_intr(&(p_i2s[i2s_num]->hal)); - i2s_hal_start_tx_link(&(p_i2s[i2s_num]->hal), (uint32_t) p_i2s[i2s_num]->tx->desc[0]); -#endif - i2s_hal_start_tx(&(p_i2s[i2s_num]->hal)); -} - -static void i2s_rx_start(i2s_port_t i2s_num) -{ -#if SOC_GDMA_SUPPORTED - gdma_start(p_i2s[i2s_num]->rx_dma_chan, (uint32_t) p_i2s[i2s_num]->rx->desc[0]); -#else - i2s_hal_enable_rx_intr(&(p_i2s[i2s_num]->hal)); - i2s_hal_start_rx_link(&(p_i2s[i2s_num]->hal), (uint32_t) p_i2s[i2s_num]->rx->desc[0]); -#endif - i2s_hal_start_rx(&(p_i2s[i2s_num]->hal)); -} - -static void i2s_tx_stop(i2s_port_t i2s_num) -{ -#if SOC_GDMA_SUPPORTED - gdma_stop(p_i2s[i2s_num]->tx_dma_chan); -#else - i2s_hal_stop_tx_link(&(p_i2s[i2s_num]->hal)); - i2s_hal_stop_tx(&(p_i2s[i2s_num]->hal)); - i2s_hal_disable_tx_intr(&(p_i2s[i2s_num]->hal)); -#endif -} - -static void i2s_rx_stop(i2s_port_t i2s_num) -{ -#if SOC_GDMA_SUPPORTED - gdma_stop(p_i2s[i2s_num]->rx_dma_chan); -#else - i2s_hal_stop_rx_link(&(p_i2s[i2s_num]->hal)); - i2s_hal_stop_rx(&(p_i2s[i2s_num]->hal)); - i2s_hal_disable_rx_intr(&(p_i2s[i2s_num]->hal)); -#endif -} - -#if SOC_I2S_SUPPORTS_APLL -static float i2s_apll_get_fi2s(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir) -{ - int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000; - -#if CONFIG_IDF_TARGET_ESP32 - /* ESP32 rev0 silicon issue for APLL range/accuracy, please see ESP32 ECO document for more information on this */ - if (esp_efuse_get_chip_ver() == 0) { - sdm0 = 0; - sdm1 = 0; - } -#endif - float fout = f_xtal * (sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4); - if (fout < SOC_I2S_APLL_MIN_FREQ || fout > SOC_I2S_APLL_MAX_FREQ) { - return SOC_I2S_APLL_MAX_FREQ; - } - float fpll = fout / (2 * (odir + 2)); //== fi2s (N=1, b=0, a=1) - return fpll / 2; -} - -/** - * @brief APLL calculate function, was described by following: - * APLL Output frequency is given by the formula: - * - * apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) - * apll_freq = fout / ((o_div + 2) * 2) - * - * The dividend in this expression should be in the range of 240 - 600 MHz. - * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. - * * sdm0 frequency adjustment parameter, 0..255 - * * sdm1 frequency adjustment parameter, 0..255 - * * sdm2 frequency adjustment parameter, 0..63 - * * o_div frequency divider, 0..31 - * - * The most accurate way to find the sdm0..2 and odir parameters is to loop through them all, - * then apply the above formula, finding the closest frequency to the desired one. - * But 256*256*64*32 = 134.217.728 loops are too slow with ESP32 - * 1. We will choose the parameters with the highest level of change, - * With 350MHzchannel_num != ch) { - p_i2s[i2s_num]->channel_num = (ch == 2) ? 2 : 1; - } - - i2s_dma_t *save_tx = NULL, *save_rx = NULL; - - if (data_bits != p_i2s[i2s_num]->bits_per_sample) { - p_i2s[i2s_num]->bits_per_sample = data_bits; - - // Round bytes_per_sample up to next multiple of 16 bits - int halfwords_per_sample = (data_bits + 15) / 16; - p_i2s[i2s_num]->bytes_per_sample = halfwords_per_sample * 2; - - // Because limited of DMA buffer is 4092 bytes - if (p_i2s[i2s_num]->dma_buf_len * p_i2s[i2s_num]->bytes_per_sample * p_i2s[i2s_num]->channel_num > 4092) { - p_i2s[i2s_num]->dma_buf_len = 4092 / p_i2s[i2s_num]->bytes_per_sample / p_i2s[i2s_num]->channel_num; - } - - // Re-create TX DMA buffer - if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { - save_tx = p_i2s[i2s_num]->tx; - //destroy old tx dma if exist - if (save_tx) { - i2s_destroy_dma_queue(i2s_num, save_tx); - } - p_i2s[i2s_num]->tx = i2s_create_dma_queue(i2s_num, p_i2s[i2s_num]->dma_buf_count, p_i2s[i2s_num]->dma_buf_len); - if (p_i2s[i2s_num]->tx == NULL) { - ESP_LOGE(TAG, "Failed to create tx dma buffer"); - i2s_driver_uninstall(i2s_num); - return ESP_ERR_NO_MEM; - } - } - // Re-create RX DMA buffer - if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { - save_rx = p_i2s[i2s_num]->rx; - //destroy old rx dma if exist - if (save_rx) { - i2s_destroy_dma_queue(i2s_num, save_rx); - } - p_i2s[i2s_num]->rx = i2s_create_dma_queue(i2s_num, p_i2s[i2s_num]->dma_buf_count, p_i2s[i2s_num]->dma_buf_len); - if (p_i2s[i2s_num]->rx == NULL) { - ESP_LOGE(TAG, "Failed to create rx dma buffer"); - i2s_driver_uninstall(i2s_num); - return ESP_ERR_NO_MEM; - } - i2s_hal_set_rx_eof_num(&(p_i2s[i2s_num]->hal), p_i2s[i2s_num]->dma_buf_len * p_i2s[i2s_num]->channel_num * p_i2s[i2s_num]->bytes_per_sample); - } - } - return ESP_OK; -} - -static esp_err_t i2s_fbclk_cal(int i2s_num, uint32_t rate, int channel, int channel_bit, uint32_t *sclk, uint32_t *fbck, uint32_t *bck_div) -{ - //Default select I2S_D2CLK (160M) - uint32_t _sclk = I2S_LL_BASE_CLK; - uint32_t _fbck = rate * channel * channel_bit; - uint32_t _bck_div = (256 % channel_bit) ? 12 : 8; - i2s_clock_src_t clk_src = I2S_CLK_D2CLK; - -//ADC mode only support on ESP32, + if (pin == NULL) { #if SOC_I2S_SUPPORTS_ADC_DAC - if ( p_i2s[i2s_num]->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { - _fbck = rate * I2S_LL_AD_BCK_FACTOR * 2; - _bck_div = I2S_LL_AD_BCK_FACTOR; - } -#endif // SOC_I2S_SUPPORTS_ADC_DAC - - if ( p_i2s[i2s_num]->mode & I2S_MODE_PDM) { -#if SOC_I2S_SUPPORTS_PDM_TX - if ( p_i2s[i2s_num]->mode & I2S_MODE_TX) { - int fp = 1; - int fs = 1; - i2s_hal_get_tx_pdm_fpfs(&(p_i2s[i2s_num]->hal), &fp, &fs); - _fbck = rate * I2S_LL_PDM_BCK_FACTOR * fp / fs; - } -#endif //SOC_I2S_SUPPORTS_PDM_TX -#if SOC_I2S_SUPPORTS_PDM_RX - if ( p_i2s[i2s_num]->mode & I2S_MODE_RX) { - i2s_pdm_dsr_t dsr; - i2s_hal_get_rx_pdm_dsr(&(p_i2s[i2s_num]->hal), &dsr); - _fbck = rate * I2S_LL_PDM_BCK_FACTOR * (dsr == I2S_PDM_DSR_16S ? 2 : 1); - } -#endif // SOC_I2S_SUPPORTS_PDM_RX - _bck_div = 8; - } - -#if SOC_I2S_SUPPORTS_APLL - int sdm0 = 0; - int sdm1 = 0; - int sdm2 = 0; - int odir = 0; - //If APLL is specified, try to calculate in APLL - if (p_i2s[i2s_num]->use_apll && i2s_apll_calculate_fi2s(p_i2s[i2s_num]->fixed_mclk, channel_bit, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) { - _sclk = p_i2s[i2s_num]->fixed_mclk; - clk_src = I2S_CLK_APLL; - ESP_LOGD(TAG, "sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); - rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, odir); - } -#endif // SOC_I2S_SUPPORTS_APLL - if ((_fbck * _bck_div) > _sclk) { - ESP_LOGE(TAG, "sample rate is too large\r\n"); - return ESP_ERR_INVALID_ARG; - } - i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), clk_src); - *sclk = _sclk; - *fbck = _fbck; - *bck_div = _bck_div; - return ESP_OK; -} - -static uint32_t i2s_get_active_chan_num(i2s_hal_config_t *hal_cfg) -{ - switch (hal_cfg->chan_fmt) { - case I2S_CHANNEL_FMT_RIGHT_LEFT: //fall through - case I2S_CHANNEL_FMT_ALL_RIGHT: //fall through - case I2S_CHANNEL_FMT_ALL_LEFT: - return 2; - case I2S_CHANNEL_FMT_ONLY_RIGHT: //fall through - case I2S_CHANNEL_FMT_ONLY_LEFT: - return 1; -#if SOC_I2S_SUPPORTS_TDM - case I2S_CHANNEL_FMT_TDM: { - uint32_t num = 0; - uint32_t max_chan = 0; - uint32_t chan_mask = hal_cfg->chan_mask; - - for (int i = 0; chan_mask && i < 16; i++, chan_mask >>= 1) { - if ((chan_mask & 0x01) == 1) { - num++; - max_chan = i + 1; - } - } - if (max_chan > hal_cfg->total_chan) { - hal_cfg->total_chan = max_chan; - } - return num; - } -#endif - default: - return 0; - } -} - -esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_channel_t ch) -{ - ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); - ESP_RETURN_ON_FALSE((p_i2s[i2s_num] != NULL), ESP_ERR_INVALID_ARG, TAG, "Not initialized yet"); - - i2s_hal_config_t *cfg = &p_i2s[i2s_num]->hal_cfg; - int data_bits = 0; - int chan_bits = 0; - int active_chan_num = 0; - int chan_num = 0; - - cfg->ch = ch; - cfg->sample_rate = rate; - cfg->bits_cfg.val = bits_cfg; - - cfg->bits_cfg.chan_bits = cfg->bits_cfg.chan_bits < cfg->bits_cfg.sample_bits ? - cfg->bits_cfg.sample_bits : cfg->bits_cfg.chan_bits; - chan_bits = cfg->bits_cfg.chan_bits; - data_bits = cfg->bits_cfg.sample_bits; - -#if SOC_I2S_SUPPORTS_TDM - cfg->chan_mask = ch & 0xFFFF; - active_chan_num = i2s_get_active_chan_num(cfg); - chan_num = cfg->total_chan; + return i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); #else - active_chan_num = i2s_get_active_chan_num(cfg); - chan_num = ch == I2S_CHANNEL_MONO ? 2 : active_chan_num; + return ESP_ERR_INVALID_ARG; #endif - ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); - - if ((data_bits % 8 != 0) || (data_bits > I2S_BITS_PER_SAMPLE_32BIT)) { - ESP_LOGE(TAG, "Invalid bits per sample"); + } + if (pin->bck_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->bck_io_num)) { + ESP_LOGE(TAG, "bck_io_num error"); return ESP_ERR_INVALID_ARG; } - //Stop I2S - i2s_stop(i2s_num); - // wait all on-going writing finish - if ((p_i2s[i2s_num]->mode & I2S_MODE_TX) && p_i2s[i2s_num]->tx) { - xSemaphoreTake(p_i2s[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); + if (pin->ws_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->ws_io_num)) { + ESP_LOGE(TAG, "ws_io_num error"); + return ESP_ERR_INVALID_ARG; } - if ((p_i2s[i2s_num]->mode & I2S_MODE_RX) && p_i2s[i2s_num]->rx) { - xSemaphoreTake(p_i2s[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); + if (pin->data_out_num != -1 && !GPIO_IS_VALID_OUTPUT_GPIO(pin->data_out_num)) { + ESP_LOGE(TAG, "data_out_num error"); + return ESP_ERR_INVALID_ARG; } - //malloc DMA buffer - if (i2s_alloc_dma_buffer(i2s_num, data_bits, active_chan_num) != ESP_OK ) { - return ESP_ERR_NO_MEM; + if (pin->data_in_num != -1 && !GPIO_IS_VALID_GPIO(pin->data_in_num)) { + ESP_LOGE(TAG, "data_in_num error"); + return ESP_ERR_INVALID_ARG; } - - uint32_t i2s_clk = 0; // I2S source clock - uint32_t i2s_bck = 0; // I2S back clock - uint32_t bck_div = 0; // I2S bck div - //calculate bck_div, f_bck and select source clock - if (i2s_fbclk_cal(i2s_num, rate, chan_num, chan_bits, &i2s_clk, &i2s_bck, &bck_div) != ESP_OK) { - return ESP_FAIL; - } - //configure i2s clock - if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { - i2s_hal_tx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); - i2s_hal_set_tx_sample_bit(&(p_i2s[i2s_num]->hal), chan_bits, data_bits); - // wait all writing on-going finish - if (p_i2s[i2s_num]->tx) { - xSemaphoreGive(p_i2s[i2s_num]->tx->mux); + if (p_i2s[i2s_num]->mode & I2S_MODE_SLAVE) { + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + gpio_matrix_in_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0); + gpio_matrix_in_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0); + } else { + gpio_matrix_in_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].rx_ws_sig, 0); + gpio_matrix_in_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0); + } + } else { + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + gpio_matrix_out_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0, 0); + gpio_matrix_out_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0, 0); + } else { + gpio_matrix_out_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].rx_ws_sig, 0, 0); + gpio_matrix_out_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0, 0); } } - if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { - i2s_hal_rx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); - i2s_hal_set_rx_sample_bit(&(p_i2s[i2s_num]->hal), chan_bits, data_bits); - // wait all writing on-going finish - if (p_i2s[i2s_num]->rx) { - xSemaphoreGive(p_i2s[i2s_num]->rx->mux); - } - } - i2s_hal_samples_config(&(p_i2s[i2s_num]->hal), &(p_i2s[i2s_num]->hal_cfg)); - // Reset message queue to avoid receiving unavailable values because the old dma queque has been destroyed - if (p_i2s[i2s_num]->tx) { - xQueueReset(p_i2s[i2s_num]->tx->queue); - } - if (p_i2s[i2s_num]->rx) { - xQueueReset(p_i2s[i2s_num]->rx->queue); - } - - //I2S start - i2s_start(i2s_num); - p_i2s[i2s_num]->sample_rate = rate; + gpio_matrix_out_check_and_set(pin->data_out_num, i2s_periph_signal[i2s_num].data_out_sig, 0, 0); + gpio_matrix_in_check_and_set(pin->data_in_num, i2s_periph_signal[i2s_num].data_in_sig, 0); return ESP_OK; } + +/************************************************************** + * I2S DMA operation * + * - i2s_dma_rx_callback * + * - i2s_dma_tx_callback * + * - i2s_intr_handler_default * + * - i2s_tx_reset * + * - i2s_rx_reset * + * - i2s_tx_start * + * - i2s_rx_start * + * - i2s_tx_stop * + * - i2s_rx_stop * + **************************************************************/ + #if SOC_GDMA_SUPPORTED static bool IRAM_ATTR i2s_dma_rx_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) { @@ -635,8 +266,7 @@ static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_e static void IRAM_ATTR i2s_intr_handler_default(void *arg) { i2s_obj_t *p_i2s = (i2s_obj_t *) arg; - uint32_t status; - i2s_hal_get_intr_status(&(p_i2s->hal), &status); + uint32_t status = i2s_hal_get_intr_status(&(p_i2s->hal)); if (status == 0) { //Avoid spurious interrupt return; @@ -702,6 +332,148 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) } #endif +static void i2s_tx_reset(i2s_port_t i2s_num) +{ + p_i2s[i2s_num]->tx->curr_ptr = NULL; + p_i2s[i2s_num]->tx->rw_pos = 0; +#if SOC_GDMA_SUPPORTED + // gdma_stop(p_i2s[i2s_num]->tx_dma_chan); + i2s_hal_reset_tx(&(p_i2s[i2s_num]->hal)); + gdma_reset(p_i2s[i2s_num]->tx_dma_chan); + i2s_hal_reset_tx_fifo(&(p_i2s[i2s_num]->hal)); +#else + // Reset I2S TX module first, and then, reset DMA and FIFO. + i2s_hal_reset_tx(&(p_i2s[i2s_num]->hal)); + i2s_hal_reset_txdma(&(p_i2s[i2s_num]->hal)); + i2s_hal_reset_tx_fifo(&(p_i2s[i2s_num]->hal)); +#endif +} + +static void i2s_rx_reset(i2s_port_t i2s_num) +{ + p_i2s[i2s_num]->rx->curr_ptr = NULL; + p_i2s[i2s_num]->rx->rw_pos = 0; +#if SOC_GDMA_SUPPORTED + i2s_hal_reset_rx(&(p_i2s[i2s_num]->hal)); + gdma_reset(p_i2s[i2s_num]->rx_dma_chan); + i2s_hal_reset_rx_fifo(&(p_i2s[i2s_num]->hal)); +#else + + // Reset I2S RX module first, and then, reset DMA and FIFO. + i2s_hal_reset_rx(&(p_i2s[i2s_num]->hal)); + i2s_hal_reset_rxdma(&(p_i2s[i2s_num]->hal)); + i2s_hal_reset_rx_fifo(&(p_i2s[i2s_num]->hal)); +#endif +} + +static void i2s_tx_start(i2s_port_t i2s_num) +{ +#if SOC_GDMA_SUPPORTED + gdma_start(p_i2s[i2s_num]->tx_dma_chan, (uint32_t) p_i2s[i2s_num]->tx->desc[0]); +#else + i2s_hal_enable_tx_dma(&(p_i2s[i2s_num]->hal)); + i2s_hal_enable_tx_intr(&(p_i2s[i2s_num]->hal)); + i2s_hal_start_tx_link(&(p_i2s[i2s_num]->hal), (uint32_t) p_i2s[i2s_num]->tx->desc[0]); +#endif + i2s_hal_start_tx(&(p_i2s[i2s_num]->hal)); +} + +static void i2s_rx_start(i2s_port_t i2s_num) +{ +#if SOC_GDMA_SUPPORTED + gdma_start(p_i2s[i2s_num]->rx_dma_chan, (uint32_t) p_i2s[i2s_num]->rx->desc[0]); +#else + i2s_hal_enable_rx_dma(&(p_i2s[i2s_num]->hal)); + i2s_hal_enable_rx_intr(&(p_i2s[i2s_num]->hal)); + i2s_hal_start_rx_link(&(p_i2s[i2s_num]->hal), (uint32_t) p_i2s[i2s_num]->rx->desc[0]); +#endif + i2s_hal_start_rx(&(p_i2s[i2s_num]->hal)); +} + +static void i2s_tx_stop(i2s_port_t i2s_num) +{ +#if SOC_GDMA_SUPPORTED + gdma_stop(p_i2s[i2s_num]->tx_dma_chan); +#else + i2s_hal_stop_tx_link(&(p_i2s[i2s_num]->hal)); + i2s_hal_stop_tx(&(p_i2s[i2s_num]->hal)); + i2s_hal_disable_tx_intr(&(p_i2s[i2s_num]->hal)); + i2s_hal_disable_tx_dma(&(p_i2s[i2s_num]->hal)); +#endif +} + +static void i2s_rx_stop(i2s_port_t i2s_num) +{ +#if SOC_GDMA_SUPPORTED + gdma_stop(p_i2s[i2s_num]->rx_dma_chan); +#else + i2s_hal_stop_rx_link(&(p_i2s[i2s_num]->hal)); + i2s_hal_stop_rx(&(p_i2s[i2s_num]->hal)); + i2s_hal_disable_rx_intr(&(p_i2s[i2s_num]->hal)); + i2s_hal_disable_rx_dma(&(p_i2s[i2s_num]->hal)); +#endif +} + +/************************************************************** + * I2S buffer operation * + * - i2s_alloc_dma_buffer * + * - i2s_destroy_dma_queue * + * - i2s_create_dma_queue * + * - i2s_zero_dma_buffer * + **************************************************************/ +static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, int data_bits, int ch) +{ + if (p_i2s[i2s_num]->channel_num != ch) { + p_i2s[i2s_num]->channel_num = (ch == 2) ? 2 : 1; + } + + i2s_dma_t *save_tx = NULL, *save_rx = NULL; + + if (data_bits != p_i2s[i2s_num]->bits_per_sample) { + p_i2s[i2s_num]->bits_per_sample = data_bits; + + // Round bytes_per_sample up to next multiple of 16 bits + int halfwords_per_sample = (data_bits + 15) / 16; + p_i2s[i2s_num]->bytes_per_sample = halfwords_per_sample * 2; + + // Because limited of DMA buffer is 4092 bytes + if (p_i2s[i2s_num]->dma_buf_len * p_i2s[i2s_num]->bytes_per_sample * p_i2s[i2s_num]->channel_num > 4092) { + p_i2s[i2s_num]->dma_buf_len = 4092 / p_i2s[i2s_num]->bytes_per_sample / p_i2s[i2s_num]->channel_num; + } + + // Re-create TX DMA buffer + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + save_tx = p_i2s[i2s_num]->tx; + //destroy old tx dma if exist + if (save_tx) { + i2s_destroy_dma_queue(i2s_num, save_tx); + } + p_i2s[i2s_num]->tx = i2s_create_dma_queue(i2s_num, p_i2s[i2s_num]->dma_buf_count, p_i2s[i2s_num]->dma_buf_len); + if (p_i2s[i2s_num]->tx == NULL) { + ESP_LOGE(TAG, "Failed to create tx dma buffer"); + i2s_driver_uninstall(i2s_num); + return ESP_ERR_NO_MEM; + } + } + // Re-create RX DMA buffer + if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { + save_rx = p_i2s[i2s_num]->rx; + //destroy old rx dma if exist + if (save_rx) { + i2s_destroy_dma_queue(i2s_num, save_rx); + } + p_i2s[i2s_num]->rx = i2s_create_dma_queue(i2s_num, p_i2s[i2s_num]->dma_buf_count, p_i2s[i2s_num]->dma_buf_len); + if (p_i2s[i2s_num]->rx == NULL) { + ESP_LOGE(TAG, "Failed to create rx dma buffer"); + i2s_driver_uninstall(i2s_num); + return ESP_ERR_NO_MEM; + } + i2s_hal_set_rx_eof_num(&(p_i2s[i2s_num]->hal), p_i2s[i2s_num]->dma_buf_len * p_i2s[i2s_num]->channel_num * p_i2s[i2s_num]->bytes_per_sample); + } + } + return ESP_OK; +} + static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma) { int bux_idx; @@ -794,50 +566,273 @@ static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, in return dma; } -esp_err_t i2s_start(i2s_port_t i2s_num) +esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num) { ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); - //start DMA link - I2S_ENTER_CRITICAL(); - -#if !SOC_GDMA_SUPPORTED - esp_intr_disable(p_i2s[i2s_num]->i2s_isr_handle); - i2s_hal_clear_intr_status(&(p_i2s[i2s_num]->hal), I2S_INTR_MAX); -#endif - if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { - i2s_tx_reset(i2s_num); - i2s_tx_start(i2s_num); + if (p_i2s[i2s_num]->rx && p_i2s[i2s_num]->rx->buf != NULL && p_i2s[i2s_num]->rx->buf_size != 0) { + for (int i = 0; i < p_i2s[i2s_num]->dma_buf_count; i++) { + memset(p_i2s[i2s_num]->rx->buf[i], 0, p_i2s[i2s_num]->rx->buf_size); + } } - if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { - i2s_rx_reset(i2s_num); - i2s_rx_start(i2s_num); + if (p_i2s[i2s_num]->tx && p_i2s[i2s_num]->tx->buf != NULL && p_i2s[i2s_num]->tx->buf_size != 0) { + int bytes_left = 0; + bytes_left = (p_i2s[i2s_num]->tx->buf_size - p_i2s[i2s_num]->tx->rw_pos) % 4; + if (bytes_left) { + size_t zero_bytes = 0, bytes_written; + i2s_write(i2s_num, (void *)&zero_bytes, bytes_left, &bytes_written, portMAX_DELAY); + } + for (int i = 0; i < p_i2s[i2s_num]->dma_buf_count; i++) { + memset(p_i2s[i2s_num]->tx->buf[i], 0, p_i2s[i2s_num]->tx->buf_size); + } } -#if !SOC_GDMA_SUPPORTED - esp_intr_enable(p_i2s[i2s_num]->i2s_isr_handle); -#endif - I2S_EXIT_CRITICAL(); return ESP_OK; } -esp_err_t i2s_stop(i2s_port_t i2s_num) +/************************************************************** + * I2S clock operation * + * - i2s_get_clk * + * - i2s_apll_get_fi2s * + * - i2s_apll_calculate_fi2s * + * - i2s_fbclk_cal * + **************************************************************/ + +float i2s_get_clk(i2s_port_t i2s_num) { ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); - I2S_ENTER_CRITICAL(); -#if !SOC_GDMA_SUPPORTED - esp_intr_disable(p_i2s[i2s_num]->i2s_isr_handle); -#endif - if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { - i2s_tx_stop(i2s_num); + return (float)p_i2s[i2s_num]->sample_rate; +} + + +#if SOC_I2S_SUPPORTS_APLL +static float i2s_apll_get_fi2s(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir) +{ + int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000; + +#if CONFIG_IDF_TARGET_ESP32 + /* ESP32 rev0 silicon issue for APLL range/accuracy, please see ESP32 ECO document for more information on this */ + if (esp_efuse_get_chip_ver() == 0) { + sdm0 = 0; + sdm1 = 0; } - if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { - i2s_rx_stop(i2s_num); - } -#if !SOC_GDMA_SUPPORTED - i2s_hal_clear_intr_status(&(p_i2s[i2s_num]->hal), I2S_INTR_MAX); #endif - I2S_EXIT_CRITICAL(); + float fout = f_xtal * (sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4); + if (fout < SOC_I2S_APLL_MIN_FREQ || fout > SOC_I2S_APLL_MAX_FREQ) { + return SOC_I2S_APLL_MAX_FREQ; + } + float fpll = fout / (2 * (odir + 2)); //== fi2s (N=1, b=0, a=1) + return fpll / 2; +} + +/** + * @brief APLL calculate function, was described by following: + * APLL Output frequency is given by the formula: + * + * apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) + * apll_freq = fout / ((o_div + 2) * 2) + * + * The dividend in this expression should be in the range of 240 - 600 MHz. + * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. + * * sdm0 frequency adjustment parameter, 0..255 + * * sdm1 frequency adjustment parameter, 0..255 + * * sdm2 frequency adjustment parameter, 0..63 + * * o_div frequency divider, 0..31 + * + * The most accurate way to find the sdm0..2 and odir parameters is to loop through them all, + * then apply the above formula, finding the closest frequency to the desired one. + * But 256*256*64*32 = 134.217.728 loops are too slow with ESP32 + * 1. We will choose the parameters with the highest level of change, + * With 350MHzmode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { + _fbck = rate * I2S_LL_AD_BCK_FACTOR * 2; + _bck_div = I2S_LL_AD_BCK_FACTOR; + } +#endif // SOC_I2S_SUPPORTS_ADC_DAC + + if ( p_i2s[i2s_num]->mode & I2S_MODE_PDM) { +#if SOC_I2S_SUPPORTS_PDM_TX + if ( p_i2s[i2s_num]->mode & I2S_MODE_TX) { + int fp = i2s_hal_get_tx_pdm_fp(&(p_i2s[i2s_num]->hal)); + int fs = i2s_hal_get_tx_pdm_fs(&(p_i2s[i2s_num]->hal)); + _fbck = rate * I2S_LL_PDM_BCK_FACTOR * fp / fs; + } +#endif //SOC_I2S_SUPPORTS_PDM_TX +#if SOC_I2S_SUPPORTS_PDM_RX + if ( p_i2s[i2s_num]->mode & I2S_MODE_RX) { + i2s_pdm_dsr_t dsr; + i2s_hal_get_rx_pdm_dsr(&(p_i2s[i2s_num]->hal), &dsr); + _fbck = rate * I2S_LL_PDM_BCK_FACTOR * (dsr == I2S_PDM_DSR_16S ? 2 : 1); + } +#endif // SOC_I2S_SUPPORTS_PDM_RX + _bck_div = 8; + } + +#if SOC_I2S_SUPPORTS_APLL + int sdm0 = 0; + int sdm1 = 0; + int sdm2 = 0; + int odir = 0; + //If APLL is specified, try to calculate in APLL + if (p_i2s[i2s_num]->use_apll && i2s_apll_calculate_fi2s(p_i2s[i2s_num]->fixed_mclk, channel_bit, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) { + _sclk = p_i2s[i2s_num]->fixed_mclk; + clk_src = I2S_CLK_APLL; + ESP_LOGD(TAG, "sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); + rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, odir); + } +#endif // SOC_I2S_SUPPORTS_APLL + if ((_fbck * _bck_div) > _sclk) { + ESP_LOGE(TAG, "sample rate is too large\r\n"); + return ESP_ERR_INVALID_ARG; + } + i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), clk_src); + *sclk = _sclk; + *fbck = _fbck; + *bck_div = _bck_div; + return ESP_OK; +} + +/************************************************************** + * I2S configuration * + * - i2s_get_active_chan_num * + * - i2s_set_dac_mode * + * - _i2s_adc_mode_recover * + * - i2s_set_adc_mode * + * - i2s_adc_enable * + * - i2s_adc_disable * + * - i2s_set_sample_rates * + * - i2s_pcm_config * + * - i2s_set_pdm_rx_down_sample * + * - i2s_set_pdm_tx_up_sample * + * - i2s_check_cfg_static * + * - i2s_param_config * + * - i2s_set_clk * + * - i2s_set_mode * + **************************************************************/ + +static uint32_t i2s_get_active_chan_num(i2s_hal_config_t *hal_cfg) +{ + switch (hal_cfg->chan_fmt) { + case I2S_CHANNEL_FMT_RIGHT_LEFT: //fall through + case I2S_CHANNEL_FMT_ALL_RIGHT: //fall through + case I2S_CHANNEL_FMT_ALL_LEFT: + return 2; + case I2S_CHANNEL_FMT_ONLY_RIGHT: //fall through + case I2S_CHANNEL_FMT_ONLY_LEFT: + return 1; +#if SOC_I2S_SUPPORTS_TDM + case I2S_CHANNEL_FMT_MULTIPLE: { + uint32_t num = 0; + uint32_t max_chan = 0; + uint32_t chan_mask = hal_cfg->chan_mask; + + for (int i = 0; chan_mask && i < 16; i++, chan_mask >>= 1) { + if ((chan_mask & 0x01) == 1) { + num++; + max_chan = i + 1; + } + } + if (max_chan > hal_cfg->total_chan) { + hal_cfg->total_chan = max_chan; + } + return num; + } +#endif + default: + return 0; + } +} #if SOC_I2S_SUPPORTS_ADC_DAC esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode) @@ -901,53 +896,6 @@ esp_err_t i2s_adc_disable(i2s_port_t i2s_num) } #endif -esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) -{ - ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); - if (pin == NULL) { -#if SOC_I2S_SUPPORTS_ADC_DAC - return i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); -#else - return ESP_ERR_INVALID_ARG; -#endif - } - if (pin->bck_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->bck_io_num)) { - ESP_LOGE(TAG, "bck_io_num error"); - return ESP_FAIL; - } - if (pin->ws_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->ws_io_num)) { - ESP_LOGE(TAG, "ws_io_num error"); - return ESP_FAIL; - } - if (pin->data_out_num != -1 && !GPIO_IS_VALID_OUTPUT_GPIO(pin->data_out_num)) { - ESP_LOGE(TAG, "data_out_num error"); - return ESP_FAIL; - } - if (pin->data_in_num != -1 && !GPIO_IS_VALID_GPIO(pin->data_in_num)) { - ESP_LOGE(TAG, "data_in_num error"); - return ESP_FAIL; - } - if (p_i2s[i2s_num]->mode & I2S_MODE_SLAVE) { - if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { - gpio_matrix_in_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0); - gpio_matrix_in_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0); - } else { - gpio_matrix_in_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].rx_ws_sig, 0); - gpio_matrix_in_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0); - } - } else { - if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { - gpio_matrix_out_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0, 0); - gpio_matrix_out_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0, 0); - } else { - gpio_matrix_out_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].rx_ws_sig, 0, 0); - gpio_matrix_out_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0, 0); - } - } - gpio_matrix_out_check_and_set(pin->data_out_num, i2s_periph_signal[i2s_num].data_out_sig, 0, 0); - gpio_matrix_in_check_and_set(pin->data_in_num, i2s_periph_signal[i2s_num].data_in_sig, 0); - return ESP_OK; -} esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate) { @@ -956,11 +904,31 @@ esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate) return i2s_set_clk(i2s_num, rate, p_i2s[i2s_num]->bits_per_sample, p_i2s[i2s_num]->channel_num); } +#if SOC_I2S_SUPPORTS_PCM +esp_err_t i2s_pcm_config(i2s_port_t i2s_num, const i2s_pcm_cfg_t *pcm_cfg) +{ + ESP_RETURN_ON_FALSE(!p_i2s[i2s_num], ESP_FAIL, TAG, "i2s has not installed yet"); + ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->communication_format & I2S_COMM_FORMAT_STAND_PCM_SHORT), + ESP_ERR_INVALID_ARG, TAG, "i2s communication mode is not PCM mode"); + i2s_stop(i2s_num); + if (pcm_cfg->mode & I2S_MODE_TX) { + i2s_hal_tx_pcm_cfg(&(p_i2s[i2s_num]->hal), pcm_cfg->pcm_type); + } else if(pcm_cfg->mode & I2S_MODE_RX) { + i2s_hal_rx_pcm_cfg(&(p_i2s[i2s_num]->hal), pcm_cfg->pcm_type); + } + i2s_start(i2s_num); + return ESP_OK; +} +#endif + #if SOC_I2S_SUPPORTS_PDM_RX esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr) { - ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + ESP_RETURN_ON_FALSE(!p_i2s[i2s_num], ESP_FAIL, TAG, "i2s has not installed yet"); + ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->mode & I2S_MODE_PDM), ESP_ERR_INVALID_ARG, TAG, "i2s mode is not PDM mode"); + i2s_stop(i2s_num); i2s_hal_set_rx_pdm_dsr(&(p_i2s[i2s_num]->hal), dsr); + // i2s will start in 'i2s_set_clk' return i2s_set_clk(i2s_num, p_i2s[i2s_num]->sample_rate, p_i2s[i2s_num]->bits_per_sample, p_i2s[i2s_num]->channel_num); } #endif @@ -968,9 +936,11 @@ esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr) #if SOC_I2S_SUPPORTS_PDM_TX esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, int sample_rate, int fp, int fs) { - I2S_ENTER_CRITICAL(); + ESP_RETURN_ON_FALSE(!p_i2s[i2s_num], ESP_FAIL, TAG, "i2s has not installed yet"); + ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->mode & I2S_MODE_PDM), ESP_ERR_INVALID_ARG, TAG, "i2s mode is not PDM mode"); + i2s_stop(i2s_num); i2s_hal_set_tx_pdm_fpfs(&(p_i2s[i2s_num]->hal), fp, fs); - I2S_EXIT_CRITICAL(); + // i2s will start in 'i2s_set_clk' return i2s_set_clk(i2s_num, sample_rate, p_i2s[i2s_num]->bits_per_sample, p_i2s[i2s_num]->channel_num); } #endif @@ -1022,25 +992,148 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num) return ESP_OK; } -esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num) +esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_channel_t ch) { ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); - if (p_i2s[i2s_num]->rx && p_i2s[i2s_num]->rx->buf != NULL && p_i2s[i2s_num]->rx->buf_size != 0) { - for (int i = 0; i < p_i2s[i2s_num]->dma_buf_count; i++) { - memset(p_i2s[i2s_num]->rx->buf[i], 0, p_i2s[i2s_num]->rx->buf_size); - } + ESP_RETURN_ON_FALSE((p_i2s[i2s_num] != NULL), ESP_ERR_INVALID_ARG, TAG, "Not initialized yet"); + + i2s_hal_config_t *cfg = &p_i2s[i2s_num]->hal_cfg; + int data_bits = 0; + int chan_bits = 0; + int active_chan_num = 0; + int chan_num = 0; + + cfg->ch = ch; + cfg->sample_rate = rate; + cfg->bits_cfg.val = bits_cfg; + + cfg->bits_cfg.chan_bits = cfg->bits_cfg.chan_bits < cfg->bits_cfg.sample_bits ? + cfg->bits_cfg.sample_bits : cfg->bits_cfg.chan_bits; + chan_bits = cfg->bits_cfg.chan_bits; + data_bits = cfg->bits_cfg.sample_bits; + +#if SOC_I2S_SUPPORTS_TDM + cfg->chan_mask = ch & 0xFFFF; + active_chan_num = i2s_get_active_chan_num(cfg); + chan_num = cfg->total_chan; +#else + active_chan_num = i2s_get_active_chan_num(cfg); + chan_num = ch == I2S_CHANNEL_MONO ? 2 : active_chan_num; +#endif + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + + if ((data_bits % 8 != 0) || (data_bits > I2S_BITS_PER_SAMPLE_32BIT)) { + ESP_LOGE(TAG, "Invalid bits per sample"); + return ESP_ERR_INVALID_ARG; } - if (p_i2s[i2s_num]->tx && p_i2s[i2s_num]->tx->buf != NULL && p_i2s[i2s_num]->tx->buf_size != 0) { - int bytes_left = 0; - bytes_left = (p_i2s[i2s_num]->tx->buf_size - p_i2s[i2s_num]->tx->rw_pos) % 4; - if (bytes_left) { - size_t zero_bytes = 0, bytes_written; - i2s_write(i2s_num, (void *)&zero_bytes, bytes_left, &bytes_written, portMAX_DELAY); - } - for (int i = 0; i < p_i2s[i2s_num]->dma_buf_count; i++) { - memset(p_i2s[i2s_num]->tx->buf[i], 0, p_i2s[i2s_num]->tx->buf_size); - } + //Stop I2S + i2s_stop(i2s_num); + // wait all on-going writing finish + if ((p_i2s[i2s_num]->mode & I2S_MODE_TX) && p_i2s[i2s_num]->tx) { + xSemaphoreTake(p_i2s[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); } + if ((p_i2s[i2s_num]->mode & I2S_MODE_RX) && p_i2s[i2s_num]->rx) { + xSemaphoreTake(p_i2s[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); + } + //malloc DMA buffer + if (i2s_alloc_dma_buffer(i2s_num, data_bits, active_chan_num) != ESP_OK ) { + return ESP_ERR_NO_MEM; + } + + uint32_t i2s_clk = 0; // I2S source clock + uint32_t i2s_bck = 0; // I2S back clock + uint32_t bck_div = 0; // I2S bck div + //calculate bck_div, f_bck and select source clock + if (i2s_fbclk_cal(i2s_num, rate, chan_num, chan_bits, &i2s_clk, &i2s_bck, &bck_div) != ESP_OK) { + return ESP_FAIL; + } + //configure i2s clock + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + i2s_hal_tx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); + i2s_hal_set_tx_sample_bit(&(p_i2s[i2s_num]->hal), chan_bits, data_bits); + // wait all writing on-going finish + if (p_i2s[i2s_num]->tx) { + xSemaphoreGive(p_i2s[i2s_num]->tx->mux); + } + i2s_hal_tx_set_channel_style(&(p_i2s[i2s_num]->hal), &(p_i2s[i2s_num]->hal_cfg)); + } + if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { + i2s_hal_rx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); + i2s_hal_set_rx_sample_bit(&(p_i2s[i2s_num]->hal), chan_bits, data_bits); + // wait all writing on-going finish + if (p_i2s[i2s_num]->rx) { + xSemaphoreGive(p_i2s[i2s_num]->rx->mux); + } + i2s_hal_rx_set_channel_style(&(p_i2s[i2s_num]->hal), &(p_i2s[i2s_num]->hal_cfg)); + } + // Reset message queue to avoid receiving unavailable values because the old dma queque has been destroyed + if (p_i2s[i2s_num]->tx) { + xQueueReset(p_i2s[i2s_num]->tx->queue); + } + if (p_i2s[i2s_num]->rx) { + xQueueReset(p_i2s[i2s_num]->rx->queue); + } + + //I2S start + i2s_start(i2s_num); + p_i2s[i2s_num]->sample_rate = rate; + return ESP_OK; +} + + + +/************************************************************** + * I2S driver operation * + * - i2s_start * + * - i2s_stop * + * - i2s_driver_install * + * - i2s_write * + * - i2s_write_expand * + * - i2s_read * + **************************************************************/ + +esp_err_t i2s_start(i2s_port_t i2s_num) +{ + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + //start DMA link + I2S_ENTER_CRITICAL(i2s_num); + +#if !SOC_GDMA_SUPPORTED + esp_intr_disable(p_i2s[i2s_num]->i2s_isr_handle); + i2s_hal_clear_intr_status(&(p_i2s[i2s_num]->hal), I2S_INTR_MAX); +#endif + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + i2s_tx_reset(i2s_num); + i2s_tx_start(i2s_num); + } + if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { + i2s_rx_reset(i2s_num); + i2s_rx_start(i2s_num); + } +#if !SOC_GDMA_SUPPORTED + esp_intr_enable(p_i2s[i2s_num]->i2s_isr_handle); +#endif + I2S_EXIT_CRITICAL(i2s_num); + return ESP_OK; +} + +esp_err_t i2s_stop(i2s_port_t i2s_num) +{ + ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); + I2S_ENTER_CRITICAL(i2s_num); +#if !SOC_GDMA_SUPPORTED + esp_intr_disable(p_i2s[i2s_num]->i2s_isr_handle); +#endif + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + i2s_tx_stop(i2s_num); + } + if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { + i2s_rx_stop(i2s_num); + } +#if !SOC_GDMA_SUPPORTED + i2s_hal_clear_intr_status(&(p_i2s[i2s_num]->hal), I2S_INTR_MAX); +#endif + I2S_EXIT_CRITICAL(i2s_num); return ESP_OK; } @@ -1088,16 +1181,16 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, active_chan = 2; break; case I2S_CHANNEL_FMT_ONLY_RIGHT: - p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0; + p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->left_align_en ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0; p_i2s[i2s_num]->hal_cfg.total_chan = 1; active_chan = 1; break; case I2S_CHANNEL_FMT_ONLY_LEFT: - p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1; + p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->left_align_en ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1; p_i2s[i2s_num]->hal_cfg.total_chan = 1; active_chan = 1; break; - case I2S_CHANNEL_FMT_TDM: + case I2S_CHANNEL_FMT_MULTIPLE: ESP_RETURN_ON_FALSE((i2s_config->chan_mask != 0), ESP_ERR_INVALID_ARG, TAG, "i2s all channel are disabled"); p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->chan_mask; i2s_get_active_chan_num(&p_i2s[i2s_num]->hal_cfg); @@ -1106,7 +1199,10 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, ESP_LOGE(TAG, "wrong i2s channel format, uninstalled i2s."); goto err; } - p_i2s[i2s_num]->hal_cfg.flags.val = i2s_config->tdm_flags.val; + p_i2s[i2s_num]->hal_cfg.left_align_en = i2s_config->left_align_en; + p_i2s[i2s_num]->hal_cfg.big_edin_en = i2s_config->big_edin_en; + p_i2s[i2s_num]->hal_cfg.bit_order_msb_en = i2s_config->bit_order_msb_en; + p_i2s[i2s_num]->hal_cfg.skip_msk_en = i2s_config->skip_msk_en; #endif // Set I2S driver configurations @@ -1119,18 +1215,6 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, p_i2s[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; p_i2s[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; -#if SOC_I2S_SUPPORTS_PCM - // Set PCM compress type for PCM communication mode - if (p_i2s[i2s_num]->communication_format & I2S_COMM_FORMAT_STAND_PCM_SHORT) { - if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { - i2s_hal_tx_pcm_cfg(&(p_i2s[i2s_num]->hal), i2s_config->pcm_compress_type); - } - if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { - i2s_hal_rx_pcm_cfg(&(p_i2s[i2s_num]->hal), i2s_config->pcm_compress_type); - } - } -#endif // SOC_I2S_SUPPORTS_PCM - #ifdef CONFIG_PM_ENABLE if (i2s_config->use_apll) { ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i2s_driver", &p_i2s[i2s_num]->pm_lock); @@ -1180,7 +1264,7 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, ESP_GOTO_ON_ERROR(ret, err, TAG, "I2S param configure error"); if (i2s_queue) { p_i2s[i2s_num]->i2s_queue = xQueueCreate(queue_size, sizeof(i2s_event_t)); - ESP_GOTO_ON_ERROR(ret, err, TAG, "I2S queue create failed"); + ESP_GOTO_ON_ERROR(p_i2s[i2s_num]->i2s_queue, err, TAG, "I2S queue create failed"); *((QueueHandle_t *) i2s_queue) = p_i2s[i2s_num]->i2s_queue; ESP_LOGI(TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_i2s[i2s_num]->i2s_queue)); } else { @@ -1375,6 +1459,7 @@ esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, siz esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_read, TickType_t ticks_to_wait) { + esp_err_t ret = ESP_OK; char *data_ptr, *dest_byte; int bytes_can_read; *bytes_read = 0; @@ -1389,6 +1474,7 @@ esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_re while (size > 0) { if (p_i2s[i2s_num]->rx->rw_pos == p_i2s[i2s_num]->rx->buf_size || p_i2s[i2s_num]->rx->curr_ptr == NULL) { if (xQueueReceive(p_i2s[i2s_num]->rx->queue, &p_i2s[i2s_num]->rx->curr_ptr, ticks_to_wait) == pdFALSE) { + ret = ESP_ERR_TIMEOUT; break; } p_i2s[i2s_num]->rx->rw_pos = 0; @@ -1409,5 +1495,5 @@ esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_re esp_pm_lock_release(p_i2s[i2s_num]->pm_lock); #endif xSemaphoreGive(p_i2s[i2s_num]->rx->mux); - return ESP_OK; + return ret; } diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index 5ec6f2841a..c7185bf52a 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -54,9 +54,9 @@ typedef struct { * */ typedef struct { - i2s_pcm_compress_t pcm_mode; /*!< I2S PCM a/u-law decompress or compress mode */ + i2s_mode_t mode; /*!< I2S mode. Usually only need to choose I2S_MODE_TX or I2S_MODE_RX */ + i2s_pcm_compress_t pcm_type; /*!< I2S PCM a/u-law decompress or compress type */ } i2s_pcm_cfg_t; - #endif /** @@ -76,24 +76,15 @@ typedef struct { bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */ bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */ int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/ - i2s_bits_per_chan_t bits_per_chan; /*!< I2S total bits in one channel, Should not be smaller than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */ - -#if SOC_I2S_SUPPORTS_PCM - i2s_pcm_compress_t pcm_compress_type; /*!< I2S PCM a/u-law decompress or compress mode. Set this field if `communication_format` is set to `I2S_COMM_FORMAT_STAND_PCM_SHORT` or `I2S_COMM_FORMAT_STAND_PCM_LONG` */ -#endif // SOC_I2S_SUPPORTS_PCM + i2s_bits_per_chan_t bits_per_chan; /*!< I2S total bits in one channel, only take effect when larger than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */ #if SOC_I2S_SUPPORTS_TDM i2s_channel_t chan_mask; /*!< I2S active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1< 1 - case I2S_TEST_MODE_SLAVE_TO_MAXTER: { - esp_rom_gpio_connect_out_signal(MASTER_BCK_IO, I2S0I_BCK_OUT_IDX, 0, 0); - esp_rom_gpio_connect_in_signal(MASTER_BCK_IO, I2S1O_BCK_IN_IDX, 0); + case I2S_TEST_MODE_SLAVE_TO_MAXTER: { + esp_rom_gpio_connect_out_signal(MASTER_BCK_IO, I2S0I_BCK_OUT_IDX, 0, 0); + esp_rom_gpio_connect_in_signal(MASTER_BCK_IO, I2S1O_BCK_IN_IDX, 0); - esp_rom_gpio_connect_out_signal(MASTER_WS_IO, I2S0I_WS_OUT_IDX, 0, 0); - esp_rom_gpio_connect_in_signal(MASTER_WS_IO, I2S1O_WS_IN_IDX, 0); + esp_rom_gpio_connect_out_signal(MASTER_WS_IO, I2S0I_WS_OUT_IDX, 0, 0); + esp_rom_gpio_connect_in_signal(MASTER_WS_IO, I2S1O_WS_IN_IDX, 0); - esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S1_DATA_OUT_IDX, 0, 0); - esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0_DATA_IN_IDX, 0); - } - break; + esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S1_DATA_OUT_IDX, 0, 0); + esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0_DATA_IN_IDX, 0); + } + break; - case I2S_TEST_MODE_MASTER_TO_SLAVE: { - esp_rom_gpio_connect_out_signal(MASTER_BCK_IO, I2S0O_BCK_OUT_IDX, 0, 0); - esp_rom_gpio_connect_in_signal(MASTER_BCK_IO, I2S1I_BCK_IN_IDX, 0); + case I2S_TEST_MODE_MASTER_TO_SLAVE: { + esp_rom_gpio_connect_out_signal(MASTER_BCK_IO, I2S0O_BCK_OUT_IDX, 0, 0); + esp_rom_gpio_connect_in_signal(MASTER_BCK_IO, I2S1I_BCK_IN_IDX, 0); - esp_rom_gpio_connect_out_signal(MASTER_WS_IO, I2S0O_WS_OUT_IDX, 0, 0); - esp_rom_gpio_connect_in_signal(MASTER_WS_IO, I2S1I_WS_IN_IDX, 0); + esp_rom_gpio_connect_out_signal(MASTER_WS_IO, I2S0O_WS_OUT_IDX, 0, 0); + esp_rom_gpio_connect_in_signal(MASTER_WS_IO, I2S1I_WS_IN_IDX, 0); - esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0_DATA_OUT_IDX, 0, 0); - esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S1_DATA_IN_IDX, 0); - } - break; + esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0_DATA_OUT_IDX, 0, 0); + esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S1_DATA_IN_IDX, 0); + } + break; #endif - case I2S_TEST_MODE_LOOPBACK: { - esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0_DATA_OUT_IDX, 0, 0); - esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0_DATA_IN_IDX, 0); - } - break; + case I2S_TEST_MODE_LOOPBACK: { + esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0_DATA_OUT_IDX, 0, 0); + esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0_DATA_IN_IDX, 0); + } + break; - default: { - TEST_FAIL_MESSAGE("error: mode not supported"); - } - break; + default: { + TEST_FAIL_MESSAGE("error: mode not supported"); + } + break; } } @@ -144,7 +144,7 @@ TEST_CASE("I2S basic driver install, uninstall, set pin test", "[i2s]") .dma_buf_count = 6, .dma_buf_len = 60, .use_apll = 0, - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 , + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, }; // normal i2s @@ -180,7 +180,7 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]") .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 , + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, }; i2s_pin_config_t master_pin_config = { .bck_io_num = MASTER_BCK_IO, @@ -193,29 +193,28 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]") i2s_test_io_config(I2S_TEST_MODE_LOOPBACK); printf("\r\nheap size: %d\n", esp_get_free_heap_size()); - uint8_t* data_wr = (uint8_t*)malloc(sizeof(uint8_t)*400); + uint8_t *data_wr = (uint8_t *)malloc(sizeof(uint8_t) * 400); size_t i2s_bytes_write = 0; size_t bytes_read = 0; int length = 0; - uint8_t *i2s_read_buff = (uint8_t*)malloc(sizeof(uint8_t)*10000); + uint8_t *i2s_read_buff = (uint8_t *)malloc(sizeof(uint8_t) * 10000); - for(int i=0; i<100; i++) { - data_wr[i] = i+1; + for (int i = 0; i < 100; i++) { + data_wr[i] = i + 1; } - int flag=0; // break loop flag + int flag = 0; // break loop flag int end_position = 0; // write data to slave - i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t)*400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS); - while(!flag){ + i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t) * 400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS); + while (!flag) { if (length >= 10000 - 500) { break; } - i2s_read(I2S_NUM_0, i2s_read_buff + length, sizeof(uint8_t)*500, &bytes_read, 1000/portMAX_DELAY); - if(bytes_read>0) { - printf("read data size: %d\n", bytes_read); - for(int i=length; i 0) { + for (int i = length; i < length + bytes_read; i++) { + if (i2s_read_buff[i] == 100) { + flag = 1; end_position = i; break; } @@ -224,8 +223,8 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]") length = length + bytes_read; } // test the read data right or not - for(int i=end_position-99; i<=end_position; i++) { - TEST_ASSERT_EQUAL_UINT8((i-end_position+100), *(i2s_read_buff + i)); + for (int i = end_position - 99; i <= end_position; i++) { + TEST_ASSERT_EQUAL_UINT8((i - end_position + 100), *(i2s_read_buff + i)); } free(data_wr); free(i2s_read_buff); @@ -246,7 +245,7 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 , + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, }; i2s_pin_config_t master_pin_config = { .bck_io_num = MASTER_BCK_IO, @@ -268,7 +267,7 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 , + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, }; i2s_pin_config_t slave_pin_config = { .bck_io_num = SLAVE_BCK_IO, @@ -282,27 +281,27 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") i2s_test_io_config(I2S_TEST_MODE_MASTER_TO_SLAVE); printf("\r\nheap size: %d\n", esp_get_free_heap_size()); - uint8_t* data_wr = (uint8_t*)malloc(sizeof(uint8_t)*400); + uint8_t *data_wr = (uint8_t *)malloc(sizeof(uint8_t) * 400); size_t i2s_bytes_write = 0; size_t bytes_read = 0; int length = 0; - uint8_t *i2s_read_buff = (uint8_t*)malloc(sizeof(uint8_t)*10000); + uint8_t *i2s_read_buff = (uint8_t *)malloc(sizeof(uint8_t) * 10000); - for(int i=0; i<100; i++) { - data_wr[i] = i+1; + for (int i = 0; i < 100; i++) { + data_wr[i] = i + 1; } - int flag=0; // break loop flag + int flag = 0; // break loop flag int end_position = 0; // write data to slave - i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t)*400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS); + i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t) * 400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS); printf("write data size: %d\n", i2s_bytes_write); - while(!flag){ - i2s_read(I2S_NUM_1, i2s_read_buff + length, sizeof(uint8_t)*500, &bytes_read, 1000/portMAX_DELAY); - if(bytes_read>0) { + while (!flag) { + i2s_read(I2S_NUM_1, i2s_read_buff + length, sizeof(uint8_t) * 500, &bytes_read, 1000 / portTICK_PERIOD_MS); + if (bytes_read > 0) { printf("read data size: %d\n", bytes_read); - for(int i=length; i 0) { - for(int i=length; i 0) { + for (int i = length; i < length + bytes_read; i++) { + if (i2s_read_buff[i] == 100) { + flag = 1; end_position = i; break; } @@ -396,8 +396,8 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") length = length + bytes_read; } // test the readed data right or not - for(int i=end_position-99; i<=end_position; i++) { - TEST_ASSERT_EQUAL_UINT8((i-end_position+100), *(i2s_read_buff + i)); + for (int i = end_position - 99; i <= end_position; i++) { + TEST_ASSERT_EQUAL_UINT8((i - end_position + 100), *(i2s_read_buff + i)); } free(data_wr); free(i2s_read_buff); @@ -417,7 +417,7 @@ TEST_CASE("I2S memory leaking test", "[i2s]") .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 , + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, }; i2s_pin_config_t master_pin_config = { .bck_io_num = MASTER_BCK_IO, @@ -431,7 +431,7 @@ TEST_CASE("I2S memory leaking test", "[i2s]") i2s_driver_uninstall(I2S_NUM_0); int initial_size = esp_get_free_heap_size(); - for(int i=0; i<100; i++) { + for (int i = 0; i < 100; i++) { TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &master_i2s_config, 0, NULL)); TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &master_pin_config)); i2s_driver_uninstall(I2S_NUM_0); @@ -475,14 +475,14 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]") uint32_t sample_rate_arr[8] = { 10675, 11025, 16000, 22050, 32000, 44100, 48000, 96000 }; int bits_per_sample_arr[3] = { 16, 24, 32 }; - for (int i = 0; i < (sizeof(sample_rate_arr)/sizeof(sample_rate_arr[0])); i++) { - for (int j = 0; j < (sizeof(bits_per_sample_arr)/sizeof(bits_per_sample_arr[0])); j++) { + for (int i = 0; i < (sizeof(sample_rate_arr) / sizeof(sample_rate_arr[0])); i++) { + for (int j = 0; j < (sizeof(bits_per_sample_arr) / sizeof(bits_per_sample_arr[0])); j++) { i2s_config.sample_rate = sample_rate_arr[i]; i2s_config.bits_per_sample = bits_per_sample_arr[j]; TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config)); - TEST_ASSERT((fabs((i2s_get_clk(I2S_NUM_0) - sample_rate_arr[i]))/(sample_rate_arr[i]))*100 < PERCENT_DIFF); + TEST_ASSERT((fabs((i2s_get_clk(I2S_NUM_0) - sample_rate_arr[i])) / (sample_rate_arr[i])) * 100 < PERCENT_DIFF); TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0)); TEST_ASSERT(initial_size == esp_get_free_heap_size()); } @@ -506,7 +506,7 @@ TEST_CASE("I2S adc test", "[i2s]") .dma_buf_count = 2, .dma_buf_len = 1024, .use_apll = 0, - }; + }; // install and start I2S driver i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); // init ADC pad @@ -514,7 +514,7 @@ TEST_CASE("I2S adc test", "[i2s]") // enable adc sampling, ADC_WIDTH_BIT_12, ADC_ATTEN_DB_11 hard-coded in adc_i2s_mode_init i2s_adc_enable(I2S_NUM_0); // init read buffer - uint16_t* i2sReadBuffer = (uint16_t*)calloc(1024, sizeof(uint16_t)); + uint16_t *i2sReadBuffer = (uint16_t *)calloc(1024, sizeof(uint16_t)); size_t bytesRead; for (int loop = 0; loop < 10; loop++) { @@ -526,7 +526,7 @@ TEST_CASE("I2S adc test", "[i2s]") } vTaskDelay(200 / portTICK_RATE_MS); // read data from adc, will block until buffer is full - i2s_read(I2S_NUM_0, (void*)i2sReadBuffer, 1024 * sizeof(uint16_t), &bytesRead, portMAX_DELAY); + i2s_read(I2S_NUM_0, (void *)i2sReadBuffer, 1024 * sizeof(uint16_t), &bytesRead, portMAX_DELAY); // calc average int64_t adcSumValue = 0; @@ -571,7 +571,7 @@ TEST_CASE("I2S dac test", "[i2s]") .dma_buf_count = 6, .dma_buf_len = 60, .use_apll = 0, - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 , + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, }; //install and start i2s driver diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index eaa74bec20..6b928721ec 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -67,7 +67,7 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param enable Set true to enable tx msb right */ -static inline void i2s_ll_tx_msb_right_en(i2s_dev_t *hw, bool enable) +static inline void i2s_ll_tx_enable_msb_right(i2s_dev_t *hw, bool enable) { hw->conf.tx_msb_right = enable; } @@ -78,7 +78,7 @@ static inline void i2s_ll_tx_msb_right_en(i2s_dev_t *hw, bool enable) * @param hw Peripheral I2S hardware instance address. * @param enable Set true to enable rx msb right */ -static inline void i2s_ll_rx_msb_right_en(i2s_dev_t *hw, bool enable) +static inline void i2s_ll_rx_enable_msb_right(i2s_dev_t *hw, bool enable) { hw->conf.rx_msb_right = enable; } @@ -89,7 +89,7 @@ static inline void i2s_ll_rx_msb_right_en(i2s_dev_t *hw, bool enable) * @param hw Peripheral I2S hardware instance address. * @param enable Set true to enable send right channel first */ -static inline void i2s_ll_tx_right_first_en(i2s_dev_t *hw, bool enable) +static inline void i2s_ll_tx_enable_right_first(i2s_dev_t *hw, bool enable) { hw->conf.tx_right_first = enable; } @@ -100,7 +100,7 @@ static inline void i2s_ll_tx_right_first_en(i2s_dev_t *hw, bool enable) * @param hw Peripheral I2S hardware instance address. * @param enable Set true to enable receive right channel first */ -static inline void i2s_ll_rx_right_first_en(i2s_dev_t *hw, bool enable) +static inline void i2s_ll_rx_enable_right_first(i2s_dev_t *hw, bool enable) { hw->conf.rx_right_first = enable; } @@ -111,7 +111,7 @@ static inline void i2s_ll_rx_right_first_en(i2s_dev_t *hw, bool enable) * @param hw Peripheral I2S hardware instance address. * @param enable Set true to enable tx fifo module */ -static inline void i2s_ll_tx_fifo_mod_force_en(i2s_dev_t *hw, bool enable) +static inline void i2s_ll_tx_force_enable_fifo_mod(i2s_dev_t *hw, bool enable) { hw->fifo_conf.tx_fifo_mod_force_en = enable; } @@ -122,7 +122,7 @@ static inline void i2s_ll_tx_fifo_mod_force_en(i2s_dev_t *hw, bool enable) * @param hw Peripheral I2S hardware instance address. * @param enable Set true to enable rx fifo module */ -static inline void i2s_ll_rx_fifo_mod_force_en(i2s_dev_t *hw, bool enable) +static inline void i2s_ll_rx_force_enable_fifo_mod(i2s_dev_t *hw, bool enable) { hw->fifo_conf.rx_fifo_mod_force_en = enable; } @@ -132,7 +132,7 @@ static inline void i2s_ll_rx_fifo_mod_force_en(i2s_dev_t *hw, bool enable) * @param hw Peripheral I2S hardware instance address. * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) +static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en) { hw->conf.tx_slave_mod = slave_en; } @@ -143,7 +143,7 @@ static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) * @param hw Peripheral I2S hardware instance address. * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) +static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en) { hw->conf.rx_slave_mod = slave_en; } @@ -153,7 +153,7 @@ static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_reset(i2s_dev_t *hw) { hw->conf.tx_reset = 1; hw->conf.tx_reset = 0; @@ -164,7 +164,7 @@ static inline void i2s_ll_reset_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_reset(i2s_dev_t *hw) { hw->conf.rx_reset = 1; hw->conf.rx_reset = 0; @@ -175,7 +175,7 @@ static inline void i2s_ll_reset_rx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw) { hw->conf.tx_fifo_reset = 1; hw->conf.tx_fifo_reset = 0; @@ -186,7 +186,7 @@ static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) { hw->conf.rx_fifo_reset = 1; hw->conf.rx_fifo_reset = 0; @@ -198,7 +198,7 @@ static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param src I2S source clock */ -static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { //0: disable APLL clock, I2S module will using PLL_D2_CLK(160M) as source clock //1: Enable APLL clock, I2S module will using APLL as source clock @@ -211,7 +211,7 @@ static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param src I2S source clock */ -static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { //0: disable APLL clock, I2S module will using PLL_D2_CLK(160M) as source clock //1: Enable APLL clock, I2S module will using APLL as source clock @@ -224,7 +224,7 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { hw->clkm_conf.clkm_div_num = set->mclk_div; hw->clkm_conf.clkm_div_b = set->b; @@ -238,7 +238,7 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { hw->clkm_conf.clkm_div_num = set->mclk_div; hw->clkm_conf.clkm_div_b = set->b; @@ -251,7 +251,7 @@ static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_tx_enable_intr(i2s_dev_t *hw) { hw->int_ena.out_eof = 1; hw->int_ena.out_dscr_err = 1; @@ -262,7 +262,7 @@ static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_tx_disable_intr(i2s_dev_t *hw) { hw->int_ena.out_eof = 0; hw->int_ena.out_dscr_err = 0; @@ -273,7 +273,7 @@ static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_rx_enable_intr(i2s_dev_t *hw) { hw->int_ena.in_suc_eof = 1; hw->int_ena.in_dscr_err = 1; @@ -284,7 +284,7 @@ static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_rx_disable_intr(i2s_dev_t *hw) { hw->int_ena.in_suc_eof = 0; hw->int_ena.in_dscr_err = 0; @@ -294,11 +294,12 @@ static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) * @brief Get I2S interrupt status * * @param hw Peripheral I2S hardware instance address. - * @param int_stat Pointer to module interrupt status + * @return + * - module interrupt status */ -static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *int_stat) +static inline uint32_t i2s_ll_get_intr_status(i2s_dev_t *hw) { - *int_stat = hw->int_st.val; + return hw->int_st.val; } /** @@ -317,7 +318,7 @@ static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t clr_mask) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) +static inline void i2s_ll_tx_reset_dma(i2s_dev_t *hw) { hw->lc_conf.out_rst = 1; hw->lc_conf.out_rst = 0; @@ -328,7 +329,7 @@ static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) +static inline void i2s_ll_rx_reset_dma(i2s_dev_t *hw) { hw->lc_conf.in_rst = 1; hw->lc_conf.in_rst = 0; @@ -339,7 +340,7 @@ static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_start(i2s_dev_t *hw) { hw->conf.tx_start = 1; } @@ -349,7 +350,7 @@ static inline void i2s_ll_start_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_start(i2s_dev_t *hw) { hw->conf.rx_start = 1; } @@ -360,7 +361,7 @@ static inline void i2s_ll_start_rx(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param link_addr DMA descriptor link address. */ -static inline void i2s_ll_start_tx_link(i2s_dev_t *hw, uint32_t link_addr) +static inline void i2s_ll_tx_start_link(i2s_dev_t *hw, uint32_t link_addr) { hw->out_link.addr = link_addr; hw->out_link.start = 1; @@ -372,7 +373,7 @@ static inline void i2s_ll_start_tx_link(i2s_dev_t *hw, uint32_t link_addr) * @param hw Peripheral I2S hardware instance address. * @param link_addr DMA descriptor link address. */ -static inline void i2s_ll_start_rx_link(i2s_dev_t *hw, uint32_t link_addr) +static inline void i2s_ll_rx_start_link(i2s_dev_t *hw, uint32_t link_addr) { hw->in_link.addr = link_addr; hw->in_link.start = 1; @@ -383,7 +384,7 @@ static inline void i2s_ll_start_rx_link(i2s_dev_t *hw, uint32_t link_addr) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_stop(i2s_dev_t *hw) { hw->conf.tx_start = 0; } @@ -393,7 +394,7 @@ static inline void i2s_ll_stop_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_stop(i2s_dev_t *hw) { hw->conf.rx_start = 0; } @@ -403,7 +404,7 @@ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) +static inline void i2s_ll_tx_stop_link(i2s_dev_t *hw) { hw->out_link.stop = 1; } @@ -413,7 +414,7 @@ static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) +static inline void i2s_ll_rx_stop_link(i2s_dev_t *hw) { hw->in_link.stop = 1; } @@ -424,7 +425,7 @@ static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param eof_addr Pointer to accept out eof des address */ -static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) +static inline void i2s_ll_tx_get_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) { *eof_addr = hw->out_eof_des_addr; } @@ -435,7 +436,7 @@ static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr * @param hw Peripheral I2S hardware instance address. * @param eof_addr Pointer to accept in eof des address */ -static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) +static inline void i2s_ll_rx_get_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) { *eof_addr = hw->in_eof_des_addr; } @@ -446,7 +447,7 @@ static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) * @param hw Peripheral I2S hardware instance address. * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) +static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num) { // On ESP32, the eof_num count in words. hw->rx_eof_num = eof_num / 4; @@ -456,12 +457,12 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) * @brief Congfigure TX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The chan bit width + * @param chan_bit The chan bit width * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) +static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) { - hw->fifo_conf.tx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); + hw->fifo_conf.tx_fifo_mod = (chan_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); hw->sample_rate_conf.tx_bits_mod = data_bit; } @@ -469,12 +470,12 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i * @brief Congfigure RX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The chan bit width + * @param chan_bit The chan bit width * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) +static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) { - hw->fifo_conf.rx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); + hw->fifo_conf.rx_fifo_mod = (chan_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); hw->sample_rate_conf.rx_bits_mod = data_bit; } @@ -484,97 +485,53 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable DMA */ -static inline void i2s_ll_dma_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_enable_dma(i2s_dev_t *hw, bool ena) { hw->fifo_conf.dscr_en = ena; } /** - * @brief Set I2S TX to philip standard + * @brief Configure TX WS signal width * * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle */ -static inline void i2s_ll_set_tx_format_philip(i2s_dev_t *hw) +static inline void i2s_ll_tx_set_ws_width(i2s_dev_t *hw, int width) { - hw->conf.tx_short_sync = 0; - hw->conf.tx_msb_shift = 1; + hw->conf.tx_short_sync = width == 1 ? 1 : 0; } /** - * @brief Set I2S RX to philip standard + * @brief Configure RX WS signal width * * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle */ -static inline void i2s_ll_set_rx_format_philip(i2s_dev_t *hw) +static inline void i2s_ll_rx_set_ws_width(i2s_dev_t *hw, int width) { - hw->conf.rx_short_sync = 0; - hw->conf.rx_msb_shift = 1; + hw->conf.rx_short_sync = width == 1 ? 1 : 0; } /** - * @brief Set I2S TX to MSB Alignment Standard + * @brief Enable TX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_set_tx_format_msb_align(i2s_dev_t *hw) +static inline void i2s_ll_tx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) { - hw->conf.tx_short_sync = 0; - hw->conf.tx_msb_shift = 0; + hw->conf.tx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S RX to MSB Alignment Standard + * @brief Enable RX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_set_rx_format_msb_align(i2s_dev_t *hw) +static inline void i2s_ll_rx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) { - hw->conf.rx_short_sync = 0; - hw->conf.rx_msb_shift = 0; -} - -/** - * @brief Set I2S TX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_short(i2s_dev_t *hw) -{ - hw->conf.tx_short_sync = 1; - hw->conf.tx_msb_shift = 0; -} - -/** - * @brief Set I2S RX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_short(i2s_dev_t *hw) -{ - hw->conf.rx_short_sync = 1; - hw->conf.rx_msb_shift = 0; -} - -/** - * @brief Set I2S TX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_long(i2s_dev_t *hw) -{ - hw->conf.tx_short_sync = 0; - hw->conf.tx_msb_shift = 0; -} - -/** - * @brief Set I2S RX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) -{ - hw->conf.rx_short_sync = 0; - hw->conf.rx_msb_shift = 0; + hw->conf.rx_msb_shift = msb_shift_enable; } /** @@ -583,14 +540,10 @@ static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param mono_ena Set true to enable mono mde. */ -static inline void i2s_ll_tx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) +static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) { int data_bit = hw->sample_rate_conf.tx_bits_mod; - if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) { - hw->fifo_conf.tx_fifo_mod = 0 + mono_ena; - } else { - hw->fifo_conf.tx_fifo_mod = 2 + mono_ena; - } + hw->fifo_conf.tx_fifo_mod = data_bit <= I2S_BITS_PER_SAMPLE_16BIT ? mono_ena : 2 + mono_ena; hw->conf_chan.tx_chan_mod = mono_ena; } @@ -600,14 +553,10 @@ static inline void i2s_ll_tx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) * @param hw Peripheral I2S hardware instance address. * @param mono_ena Set true to enable mono mde. */ -static inline void i2s_ll_rx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) +static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) { int data_bit = hw->sample_rate_conf.rx_bits_mod; - if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) { - hw->fifo_conf.rx_fifo_mod = 0 + mono_ena; - } else { - hw->fifo_conf.rx_fifo_mod = 2 + mono_ena; - } + hw->fifo_conf.rx_fifo_mod = data_bit <= I2S_BITS_PER_SAMPLE_16BIT ? mono_ena : 2 + mono_ena; hw->conf_chan.rx_chan_mod = mono_ena; } @@ -617,30 +566,21 @@ static inline void i2s_ll_rx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) * @param hw Peripheral I2S hardware instance address. * @param loopback_en Set true to enable loopback mode. */ -static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool loopback_en) +static inline void i2s_ll_enable_loop_back(i2s_dev_t *hw, bool loopback_en) { hw->conf.sig_loopback = loopback_en; } -/** - * @brief Set default RX PDM mode - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw) -{ - hw->pdm_conf.rx_sinc_dsr_16_en = 0; - hw->pdm_conf.pdm2pcm_conv_en = 1; - hw->pdm_conf.rx_pdm_en = 1; -} + +/******************************I2S PDM Configurations*************************************/ /** * @brief Configure RX PDM downsample * * @param hw Peripheral I2S hardware instance address. * @param dsr PDM downsample configuration paramater */ -static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) +static inline void i2s_ll_rx_set_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) { hw->pdm_conf.rx_sinc_dsr_16_en = dsr; } @@ -651,44 +591,88 @@ static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) * @param hw Peripheral I2S hardware instance address. * @param dsr Pointer to accept PDM downsample configuration */ -static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) +static inline void i2s_ll_rx_get_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) { *dsr = hw->pdm_conf.rx_sinc_dsr_16_en; } +/** + * @brief Enable I2S TX PDM mode + * + * @param hw Peripheral I2S hardware instance address. + * @param pdm_ena Set true to enable TX PDM mode + */ +static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pdm_ena) +{ + hw->pdm_conf.tx_pdm_en = pdm_ena; + hw->pdm_conf.pcm2pdm_conv_en = pdm_ena; +} + /** * @brief Enable I2S RX PDM mode * * @param hw Peripheral I2S hardware instance address. * @param pdm_ena Set true to enable RX PDM mode */ -static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_ena) +static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_ena) { hw->pdm_conf.rx_pdm_en = pdm_ena; + hw->pdm_conf.pdm2pcm_conv_en = pdm_ena; } /** - * @brief Configure I2S TX pdm + * @brief Set I2S TX PDM prescale * * @param hw Peripheral I2S hardware instance address. - * @param sample_rate The sample rate to be set. + * @param prescale I2S TX PDM prescale */ -static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) +static inline void i2s_ll_tx_set_pdm_prescale(i2s_dev_t *hw, bool prescale) { - uint32_t fp = 960; - uint32_t fs = sample_rate / 100; - typeof(hw->pdm_conf) pdm_conf_reg = hw->pdm_conf; - pdm_conf_reg.tx_sinc_osr2 = fp / fs; - pdm_conf_reg.tx_prescale = 0; - pdm_conf_reg.tx_hp_in_shift = 1; - pdm_conf_reg.tx_lp_in_shift = 1; - pdm_conf_reg.tx_sinc_in_shift = 1; - pdm_conf_reg.tx_sigmadelta_in_shift = 1; - pdm_conf_reg.pcm2pdm_conv_en = 1; - pdm_conf_reg.tx_pdm_en = 1; - hw->pdm_conf.val = pdm_conf_reg.val; - hw->pdm_freq_conf.tx_pdm_fp = fp; - hw->pdm_freq_conf.tx_pdm_fs = fs; + hw->pdm_conf.tx_prescale = prescale; +} + +/** + * @brief Set I2S TX PDM high pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_hp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->pdm_conf.tx_hp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM low pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_lp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->pdm_conf.tx_lp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sinc filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sinc_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->pdm_conf.tx_sinc_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sigma-delta filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sd_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->pdm_conf.tx_sigmadelta_in_shift = sig_scale; } /** @@ -699,7 +683,7 @@ static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) * @param fp The fp value of TX PDM filter module group0. * @param fs The fs value of TX PDM filter module group0. */ -static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) +static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) { hw->pdm_freq_conf.tx_pdm_fp = fp; hw->pdm_freq_conf.tx_pdm_fs = fs; @@ -707,56 +691,85 @@ static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f } /** - * @brief Get I2S TX PDM configuration + * @brief Get I2S TX PDM fp configuration paramater * * @param hw Peripheral I2S hardware instance address. - * @param fp Pointer to accept TX PDM fp configuration paramater - * @param fs Pointer to accept TX PDM fs configuration paramater + * @return + * - fp configuration paramater */ -static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) +static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) { - *fp = hw->pdm_freq_conf.tx_pdm_fp; - *fs = hw->pdm_freq_conf.tx_pdm_fs; + return hw->pdm_freq_conf.tx_pdm_fp; } /** - * @brief Enable I2S TX PDM mode + * @brief Get I2S TX PDM fs configuration paramater * * @param hw Peripheral I2S hardware instance address. - * @param pdm_ena Set true to enable TX PDM mode + * @return + * - fs configuration paramater */ -static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_ena) +static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) { - hw->pdm_conf.tx_pdm_en = pdm_ena; + return hw->pdm_freq_conf.tx_pdm_fs; +} + + + + +/****************************I2S ADC/DAC Configurations***********************************/ +/** + * @brief Enable I2S LCD mode + * @note Have to enable LCD mode to use build in ADC/DAC + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable LCD mode. + */ +static inline void i2s_ll_enable_lcd(i2s_dev_t *hw, bool enable) +{ + hw->conf2.lcd_en = enable; +} + +/** + * @brief Enable I2S camera mode + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable camera mode. + */ +static inline void i2s_ll_enable_camera(i2s_dev_t *hw, bool enable) +{ + hw->conf2.camera_en = enable; } /** * @brief Enable I2S build in ADC mode * * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable build in ADC */ -static inline void i2s_ll_build_in_adc_ena(i2s_dev_t *hw) +static inline void i2s_ll_enable_builtin_adc(i2s_dev_t *hw, bool enable) { - hw->conf2.lcd_en = 1; + hw->conf2.lcd_en = enable; hw->conf2.camera_en = 0; hw->conf.rx_right_first = 0; hw->conf.rx_msb_shift = 0; hw->conf.rx_mono = 0; hw->conf.rx_short_sync = 0; - hw->fifo_conf.rx_fifo_mod = 1; - hw->conf_chan.rx_chan_mod = 1; + hw->fifo_conf.rx_fifo_mod = enable; + hw->conf_chan.rx_chan_mod = enable; } /** * @brief Enable I2S build in DAC mode * * @param hw Peripheral I2S hardware instance address. + * * @param enable Set true to enable build in DAC */ -static inline void i2s_ll_build_in_dac_ena(i2s_dev_t *hw) +static inline void i2s_ll_enable_builtin_dac(i2s_dev_t *hw, bool enable) { - hw->conf2.lcd_en = 1; + hw->conf2.lcd_en = enable; hw->conf2.camera_en = 0; - hw->conf.tx_right_first = 1; + hw->conf.tx_right_first = enable; hw->conf.tx_msb_shift = 0; hw->conf.tx_short_sync = 0; } diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index 94eb7d9077..41a8c36d50 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -60,7 +60,7 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_tx_clock(i2s_dev_t *hw) +static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw) { hw->tx_clkm_conf.tx_clk_active = 1; } @@ -70,7 +70,7 @@ static inline void i2s_ll_enable_tx_clock(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_clock(i2s_dev_t *hw) +static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw) { hw->rx_clkm_conf.rx_clk_active = 1; } @@ -101,7 +101,7 @@ static inline void i2s_ll_mclk_use_rx_clk(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) +static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en) { hw->tx_conf.tx_slave_mod = slave_en; } @@ -112,7 +112,7 @@ static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) * @param hw Peripheral I2S hardware instance address. * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) +static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en) { hw->rx_conf.rx_slave_mod = slave_en; } @@ -122,7 +122,7 @@ static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_reset(i2s_dev_t *hw) { hw->tx_conf.tx_reset = 1; hw->tx_conf.tx_reset = 0; @@ -133,7 +133,7 @@ static inline void i2s_ll_reset_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_reset(i2s_dev_t *hw) { hw->rx_conf.rx_reset = 1; hw->rx_conf.rx_reset = 0; @@ -144,7 +144,7 @@ static inline void i2s_ll_reset_rx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw) { hw->tx_conf.tx_fifo_reset = 1; hw->tx_conf.tx_fifo_reset = 0; @@ -155,7 +155,7 @@ static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) { hw->rx_conf.rx_fifo_reset = 1; hw->rx_conf.rx_fifo_reset = 0; @@ -167,7 +167,7 @@ static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param src I2S source clock. */ -static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { hw->tx_clkm_conf.tx_clk_sel = 2; } @@ -178,7 +178,7 @@ static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` */ -static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { hw->rx_clkm_conf.rx_clk_sel = 2; } @@ -189,7 +189,7 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { if (set->a == 0 || set->b == 0) { hw->tx_clkm_div_conf.tx_clkm_div_x = 0; @@ -218,7 +218,7 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { if (set->a == 0 || set->b == 0) { hw->rx_clkm_div_conf.rx_clkm_div_x = 0; @@ -246,7 +246,7 @@ static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_start(i2s_dev_t *hw) { hw->tx_conf.tx_update = 0; hw->tx_conf.tx_update = 1; @@ -258,7 +258,7 @@ static inline void i2s_ll_start_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_start(i2s_dev_t *hw) { hw->rx_conf.rx_update = 0; hw->rx_conf.rx_update = 1; @@ -270,7 +270,7 @@ static inline void i2s_ll_start_rx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_stop(i2s_dev_t *hw) { hw->tx_conf.tx_start = 0; } @@ -280,7 +280,7 @@ static inline void i2s_ll_stop_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_stop(i2s_dev_t *hw) { hw->rx_conf.rx_start = 0; } @@ -291,7 +291,7 @@ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param width WS width in BCK cycle */ -static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) +static inline void i2s_ll_tx_set_ws_width(i2s_dev_t *hw, int width) { hw->tx_conf1.tx_tdm_ws_width = width - 1; } @@ -302,7 +302,7 @@ static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) * @param hw Peripheral I2S hardware instance address. * @param width WS width in BCK cycle */ -static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) +static inline void i2s_ll_rx_set_ws_width(i2s_dev_t *hw, int width) { hw->rx_conf1.rx_tdm_ws_width = width - 1; } @@ -313,7 +313,7 @@ static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) * @param hw Peripheral I2S hardware instance address. * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) +static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num) { hw->rx_eof_num.rx_eof_num = eof_num; } @@ -322,26 +322,26 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) * @brief Congfigure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The chan bit width + * @param chan_bit The chan bit width * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) +static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) { hw->tx_conf1.tx_bits_mod = data_bit - 1; - hw->tx_conf1.tx_tdm_chan_bits = sample_bit - 1; + hw->tx_conf1.tx_tdm_chan_bits = chan_bit - 1; } /** * @brief Congfigure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The chan bit width + * @param chan_bit The chan bit width * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) +static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) { hw->rx_conf1.rx_bits_mod = data_bit - 1; - hw->rx_conf1.rx_tdm_chan_bits = sample_bit - 1; + hw->rx_conf1.rx_tdm_chan_bits = chan_bit - 1; } /** @@ -350,7 +350,7 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i * @param hw Peripheral I2S hardware instance address. * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) +static inline void i2s_ll_tx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { hw->tx_conf1.tx_half_sample_bits = half_sample_bits - 1; } @@ -361,7 +361,7 @@ static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_ * @param hw Peripheral I2S hardware instance address. * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) +static inline void i2s_ll_rx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { hw->rx_conf1.rx_half_sample_bits = half_sample_bits - 1; } @@ -372,7 +372,7 @@ static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_ * @param hw Peripheral I2S hardware instance address. * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_tx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) +static inline void i2s_ll_tx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) { hw->tx_conf1.tx_msb_shift = msb_shift_enable; } @@ -383,7 +383,7 @@ static inline void i2s_ll_tx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab * @param hw Peripheral I2S hardware instance address. * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) +static inline void i2s_ll_rx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) { hw->rx_conf1.rx_msb_shift = msb_shift_enable; } @@ -394,7 +394,7 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab * @param hw Peripheral I2S hardware instance address. * @param total_num Total chan number */ -static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_tx_set_chan_num(i2s_dev_t *hw, int total_num) { hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; } @@ -405,7 +405,7 @@ static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num) * @param hw Peripheral I2S hardware instance address. * @param total_num Total chan number */ -static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_rx_set_chan_num(i2s_dev_t *hw, int total_num) { hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; } @@ -416,7 +416,7 @@ static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num) * @param hw Peripheral I2S hardware instance address. * @param chan_mask mask of tx active chan */ -static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) +static inline void i2s_ll_tx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; @@ -430,7 +430,7 @@ static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_m * @param hw Peripheral I2S hardware instance address. * @param chan_mask mask of rx active chan */ -static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) +static inline void i2s_ll_rx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; @@ -444,7 +444,7 @@ static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_m * @param hw Peripheral I2S hardware instance address. * @param ws_pol_level pin level of WS(output) when receiving left channel data */ -static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) +static inline void i2s_tx_set_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { hw->tx_conf.tx_ws_idle_pol = ws_pol_level; } @@ -455,7 +455,7 @@ static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) * @param hw Peripheral I2S hardware instance address. * @param ws_pol_level pin level of WS(input) when receiving left channel data */ -static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) +static inline void i2s_rx_set_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { hw->rx_conf.rx_ws_idle_pol = ws_pol_level; } @@ -466,47 +466,133 @@ static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) * @param hw Peripheral I2S hardware instance address. * @param pdm_enable Set true to TX enable PDM mode */ -static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable) +static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) { - if (pdm_enable) { - hw->tx_conf.tx_tdm_en = 0; - hw->tx_conf.tx_pdm_en = 1; - } else { - hw->tx_conf.tx_pdm_en = 0; - hw->tx_conf.tx_tdm_en = 1; - } + hw->tx_conf.tx_pdm_en = pdm_enable; + hw->tx_conf.tx_tdm_en = !pdm_enable; + hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pdm_enable; } /** - * @brief Configure I2S TX pdm + * @brief Set I2S TX PDM prescale * * @param hw Peripheral I2S hardware instance address. - * @param sample_rate The sample rate to be set. + * @param prescale I2S TX PDM prescale */ -static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) +static inline void i2s_ll_tx_set_pdm_prescale(i2s_dev_t *hw, bool prescale) { - uint32_t fp = 960; - uint32_t fs = sample_rate / 100; - typeof(hw->tx_pcm2pdm_conf) pdm_conf_reg = hw->tx_pcm2pdm_conf; - typeof(hw->tx_pcm2pdm_conf1) pdm_conf1_reg = hw->tx_pcm2pdm_conf1; - pdm_conf_reg.pcm2pdm_conv_en = 1; - pdm_conf_reg.tx_pdm_prescale = 0; - pdm_conf_reg.tx_pdm_hp_in_shift = 1; - pdm_conf_reg.tx_pdm_lp_in_shift = 1; - pdm_conf_reg.tx_pdm_sinc_in_shift = 1; - pdm_conf_reg.tx_pdm_sigmadelta_in_shift = 1; - pdm_conf_reg.tx_pdm_sinc_osr2 = fp / fs; - pdm_conf_reg.tx_pdm_dac_mode_en = 1; - pdm_conf_reg.tx_pdm_sigmadelta_dither = 0; - pdm_conf_reg.tx_pdm_sigmadelta_dither2 = 0; - pdm_conf_reg.tx_pdm_dac_2out_en = 1; - pdm_conf1_reg.tx_pdm_fp = fp; - pdm_conf1_reg.tx_pdm_fs = fs; - pdm_conf1_reg.tx_iir_hp_mult12_5 = 7; - pdm_conf1_reg.tx_iir_hp_mult12_0 = 6; - pdm_conf_reg.tx_pdm_hp_bypass = 0; - hw->tx_pcm2pdm_conf = pdm_conf_reg; - hw->tx_pcm2pdm_conf1 = pdm_conf1_reg; + hw->tx_pcm2pdm_conf.tx_pdm_prescale = prescale; +} + +/** + * @brief Set I2S TX PDM high pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_hp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_hp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM low pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_lp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_lp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sinc filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sinc_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sinc_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sigma-delta filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sd_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM high pass filter param0 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 + I2S_TX_IIR_HP_MULT12_0[2:0]) + */ +static inline void i2s_ll_tx_set_pdm_hp_filter_param0(i2s_dev_t *hw, uint32_t param) +{ + hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_0 = param; +} + +/** + * @brief Set I2S TX PDM high pass filter param5 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 + I2S_TX_IIR_HP_MULT12_5[2:0]) + */ +static inline void i2s_ll_tx_set_pdm_hp_filter_param5(i2s_dev_t *hw, uint32_t param) +{ + hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_5 = param; +} + +/** + * @brief Enable I2S TX PDM high pass filter + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable I2S TX PDM high pass filter, set false to bypass it + */ +static inline void i2s_ll_tx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) +{ + hw->tx_pcm2pdm_conf.tx_pdm_hp_bypass = !enable; +} + +/** + * @brief Enable I2S TX PDM sigma-delta codec + * + * @param hw Peripheral I2S hardware instance address. + * @param dither I2S TX PDM sigmadelta dither value + */ +static inline void i2s_ll_tx_enable_pdm_sd_codec(i2s_dev_t *hw, bool enable) +{ + hw->tx_pcm2pdm_conf.tx_pdm_dac_2out_en = enable; + hw->tx_pcm2pdm_conf.tx_pdm_dac_mode_en = enable; +} + +/** + * @brief Set I2S TX PDM sigma-delta codec dither + * + * @param hw Peripheral I2S hardware instance address. + * @param dither I2S TX PDM sigmadelta dither value + */ +static inline void i2s_ll_tx_set_pdm_sd_dither(i2s_dev_t *hw, uint32_t dither) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither = dither; +} + +/** + * @brief Set I2S TX PDM sigma-delta codec dither + * + * @param hw Peripheral I2S hardware instance address. + * @param dither2 I2S TX PDM sigmadelta dither2 value + */ +static inline void i2s_ll_tx_set_pdm_sd_dither2(i2s_dev_t *hw, uint32_t dither2) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither2 = dither2; } /** @@ -517,7 +603,7 @@ static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) * @param fp The fp value of TX PDM filter module group0. * @param fs The fs value of TX PDM filter module group0. */ -static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) +static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) { hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp; hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs; @@ -525,28 +611,40 @@ static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f } /** - * @brief Get I2S TX PDM configuration + * @brief Get I2S TX PDM fp configuration paramater * * @param hw Peripheral I2S hardware instance address. - * @param fp Pointer to accept TX PDM fp configuration paramater - * @param fs Pointer to accept TX PDM fs configuration paramater + * @return + * - fp configuration paramater */ -static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) +static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) { - *fp = hw->tx_pcm2pdm_conf1.tx_pdm_fp; - *fs = hw->tx_pcm2pdm_conf1.tx_pdm_fs; + return hw->tx_pcm2pdm_conf1.tx_pdm_fp; +} + +/** + * @brief Get I2S TX PDM fs configuration paramater + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - fs configuration paramater + */ +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 + * @param pdm_enable Set true to RX enable PDM mode (ignored) */ -static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) +static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) { - hw->rx_conf.rx_pdm_en = pdm_enable; - hw->rx_conf.rx_tdm_en = !pdm_enable; + hw->rx_conf.rx_pdm_en = 0; + hw->rx_conf.rx_tdm_en = 1; } /** @@ -555,14 +653,10 @@ static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) +static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { - if (pcm_cfg == I2S_PCM_DISABLE) { - hw->tx_conf.tx_pcm_bypass = 1; - } else { - hw->tx_conf.tx_pcm_conf = pcm_cfg; - hw->tx_conf.tx_pcm_bypass = 0; - } + hw->tx_conf.tx_pcm_conf = pcm_cfg; + hw->tx_conf.tx_pcm_bypass = !pcm_cfg; } /** @@ -571,14 +665,10 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) +static inline void i2s_ll_rx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { - if (pcm_cfg == I2S_PCM_DISABLE) { - hw->rx_conf.rx_pcm_bypass = 1; - } else { - hw->rx_conf.rx_pcm_conf = pcm_cfg; - hw->rx_conf.rx_pcm_bypass = 0; - } + hw->rx_conf.rx_pcm_conf = pcm_cfg; + hw->rx_conf.rx_pcm_bypass = !pcm_cfg; } /** @@ -587,7 +677,7 @@ static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable left alignment */ -static inline void i2s_ll_tx_left_align_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_tx_enable_left_align(i2s_dev_t *hw, bool ena) { hw->tx_conf.tx_left_align = ena; } @@ -598,7 +688,7 @@ static inline void i2s_ll_tx_left_align_enable(i2s_dev_t *hw, bool ena) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable left alignment */ -static inline void i2s_ll_rx_left_align_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_rx_enable_left_align(i2s_dev_t *hw, bool ena) { hw->rx_conf.rx_left_align = ena; } @@ -609,7 +699,7 @@ static inline void i2s_ll_rx_left_align_enable(i2s_dev_t *hw, bool ena) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_rx_big_endian_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_rx_enable_big_endian(i2s_dev_t *hw, bool ena) { hw->rx_conf.rx_big_endian = ena; } @@ -620,7 +710,7 @@ static inline void i2s_ll_rx_big_endian_enable(i2s_dev_t *hw, bool ena) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_tx_big_endian_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_tx_enable_big_endian(i2s_dev_t *hw, bool ena) { hw->tx_conf.tx_big_endian = ena; } @@ -665,7 +755,7 @@ static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena) * @param hw Peripheral I2S hardware instance address. * @param data Single data to be set */ -static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) +static inline void i2s_ll_set_single_data(i2s_dev_t *hw, uint32_t data) { hw->conf_single_data = data; } @@ -676,7 +766,7 @@ static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable loopback mode. */ -static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_enable_loop_back(i2s_dev_t *hw, bool ena) { hw->tx_conf.sig_loopback = ena; } diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index 056cb5ce55..4f933c78bd 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -61,7 +61,7 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_tx_clock(i2s_dev_t *hw) +static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw) { hw->tx_clkm_conf.tx_clk_active = 1; } @@ -71,7 +71,7 @@ static inline void i2s_ll_enable_tx_clock(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_clock(i2s_dev_t *hw) +static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw) { hw->rx_clkm_conf.rx_clk_active = 1; } @@ -102,7 +102,7 @@ static inline void i2s_ll_mclk_use_rx_clk(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) +static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en) { hw->tx_conf.tx_slave_mod = slave_en; } @@ -113,7 +113,7 @@ static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) * @param hw Peripheral I2S hardware instance address. * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) +static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en) { hw->rx_conf.rx_slave_mod = slave_en; } @@ -123,7 +123,7 @@ static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_reset(i2s_dev_t *hw) { hw->tx_conf.tx_reset = 1; hw->tx_conf.tx_reset = 0; @@ -134,7 +134,7 @@ static inline void i2s_ll_reset_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_reset(i2s_dev_t *hw) { hw->rx_conf.rx_reset = 1; hw->rx_conf.rx_reset = 0; @@ -145,7 +145,7 @@ static inline void i2s_ll_reset_rx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw) { hw->tx_conf.tx_fifo_reset = 1; hw->tx_conf.tx_fifo_reset = 0; @@ -156,7 +156,7 @@ static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) { hw->rx_conf.rx_fifo_reset = 1; hw->rx_conf.rx_fifo_reset = 0; @@ -168,7 +168,7 @@ static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param src I2S source clock. */ -static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { hw->tx_clkm_conf.tx_clk_sel = 2; } @@ -179,7 +179,7 @@ static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` */ -static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { hw->rx_clkm_conf.rx_clk_sel = 2; } @@ -190,7 +190,7 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { if (set->a == 0 || set->b == 0) { hw->tx_clkm_div_conf.tx_clkm_div_x = 0; @@ -219,7 +219,7 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { if (set->a == 0 || set->b == 0) { hw->rx_clkm_div_conf.rx_clkm_div_x = 0; @@ -247,7 +247,7 @@ static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_start(i2s_dev_t *hw) { hw->tx_conf.tx_update = 0; hw->tx_conf.tx_update = 1; @@ -259,7 +259,7 @@ static inline void i2s_ll_start_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_start(i2s_dev_t *hw) { hw->rx_conf.rx_update = 0; hw->rx_conf.rx_update = 1; @@ -271,7 +271,7 @@ static inline void i2s_ll_start_rx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_stop(i2s_dev_t *hw) { hw->tx_conf.tx_start = 0; } @@ -281,7 +281,7 @@ static inline void i2s_ll_stop_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_stop(i2s_dev_t *hw) { hw->rx_conf.rx_start = 0; } @@ -292,7 +292,7 @@ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param width WS width in BCK cycle */ -static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) +static inline void i2s_ll_tx_set_ws_width(i2s_dev_t *hw, int width) { hw->tx_conf1.tx_tdm_ws_width = width - 1; } @@ -303,7 +303,7 @@ static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) * @param hw Peripheral I2S hardware instance address. * @param width WS width in BCK cycle */ -static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) +static inline void i2s_ll_rx_set_ws_width(i2s_dev_t *hw, int width) { hw->rx_conf1.rx_tdm_ws_width = width - 1; } @@ -314,7 +314,7 @@ static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) * @param hw Peripheral I2S hardware instance address. * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) +static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num) { hw->rx_eof_num.rx_eof_num = eof_num; } @@ -323,26 +323,26 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) * @brief Congfigure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The chan bit width + * @param chan_bit The chan bit width * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) +static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) { hw->tx_conf1.tx_bits_mod = data_bit - 1; - hw->tx_conf1.tx_tdm_chan_bits = sample_bit - 1; + hw->tx_conf1.tx_tdm_chan_bits = chan_bit - 1; } /** * @brief Congfigure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The chan bit width + * @param chan_bit The chan bit width * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) +static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) { hw->rx_conf1.rx_bits_mod = data_bit - 1; - hw->rx_conf1.rx_tdm_chan_bits = sample_bit - 1; + hw->rx_conf1.rx_tdm_chan_bits = chan_bit - 1; } /** @@ -351,7 +351,7 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i * @param hw Peripheral I2S hardware instance address. * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) +static inline void i2s_ll_tx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { hw->tx_conf1.tx_half_sample_bits = half_sample_bits - 1; } @@ -362,7 +362,7 @@ static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_ * @param hw Peripheral I2S hardware instance address. * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) +static inline void i2s_ll_rx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { hw->rx_conf1.rx_half_sample_bits = half_sample_bits - 1; } @@ -373,7 +373,7 @@ static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_ * @param hw Peripheral I2S hardware instance address. * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_tx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) +static inline void i2s_ll_tx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) { hw->tx_conf1.tx_msb_shift = msb_shift_enable; } @@ -384,7 +384,7 @@ static inline void i2s_ll_tx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab * @param hw Peripheral I2S hardware instance address. * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) +static inline void i2s_ll_rx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) { hw->rx_conf1.rx_msb_shift = msb_shift_enable; } @@ -395,7 +395,7 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab * @param hw Peripheral I2S hardware instance address. * @param total_num Total chan number */ -static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_tx_set_chan_num(i2s_dev_t *hw, int total_num) { hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; } @@ -406,7 +406,7 @@ static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num) * @param hw Peripheral I2S hardware instance address. * @param total_num Total chan number */ -static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_rx_set_chan_num(i2s_dev_t *hw, int total_num) { hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; } @@ -417,7 +417,7 @@ static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num) * @param hw Peripheral I2S hardware instance address. * @param chan_mask mask of tx active chan */ -static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) +static inline void i2s_ll_tx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; @@ -431,7 +431,7 @@ static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_m * @param hw Peripheral I2S hardware instance address. * @param chan_mask mask of rx active chan */ -static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) +static inline void i2s_ll_rx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; @@ -445,7 +445,7 @@ static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_m * @param hw Peripheral I2S hardware instance address. * @param ws_pol_level pin level of WS(output) when receiving left channel data */ -static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) +static inline void i2s_tx_set_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { hw->tx_conf.tx_ws_idle_pol = ws_pol_level; } @@ -456,7 +456,7 @@ static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) * @param hw Peripheral I2S hardware instance address. * @param ws_pol_level pin level of WS(input) when receiving left channel data */ -static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) +static inline void i2s_rx_set_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { hw->rx_conf.rx_ws_idle_pol = ws_pol_level; } @@ -467,47 +467,133 @@ static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) * @param hw Peripheral I2S hardware instance address. * @param pdm_enable Set true to TX enable PDM mode */ -static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable) +static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) { - if (pdm_enable) { - hw->tx_conf.tx_tdm_en = 0; - hw->tx_conf.tx_pdm_en = 1; - } else { - hw->tx_conf.tx_pdm_en = 0; - hw->tx_conf.tx_tdm_en = 1; - } + hw->tx_conf.tx_pdm_en = pdm_enable; + hw->tx_conf.tx_tdm_en = !pdm_enable; + hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pdm_enable; } /** - * @brief Configure I2S TX pdm + * @brief Set I2S TX PDM prescale * * @param hw Peripheral I2S hardware instance address. - * @param sample_rate The sample rate to be set. + * @param prescale I2S TX PDM prescale */ -static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) +static inline void i2s_ll_tx_set_pdm_prescale(i2s_dev_t *hw, bool prescale) { - uint32_t fp = 960; - uint32_t fs = sample_rate / 100; - typeof(hw->tx_pcm2pdm_conf) pdm_conf_reg = hw->tx_pcm2pdm_conf; - typeof(hw->tx_pcm2pdm_conf1) pdm_conf1_reg = hw->tx_pcm2pdm_conf1; - pdm_conf_reg.pcm2pdm_conv_en = 1; - pdm_conf_reg.tx_pdm_prescale = 0; - pdm_conf_reg.tx_pdm_hp_in_shift = 1; - pdm_conf_reg.tx_pdm_lp_in_shift = 1; - pdm_conf_reg.tx_pdm_sinc_in_shift = 1; - pdm_conf_reg.tx_pdm_sigmadelta_in_shift = 1; - pdm_conf_reg.tx_pdm_sinc_osr2 = fp / fs; - pdm_conf_reg.tx_pdm_dac_mode_en = 1; - pdm_conf_reg.tx_pdm_sigmadelta_dither = 0; - pdm_conf_reg.tx_pdm_sigmadelta_dither2 = 0; - pdm_conf_reg.tx_pdm_dac_2out_en = 1; - pdm_conf1_reg.tx_pdm_fp = fp; - pdm_conf1_reg.tx_pdm_fs = fs; - pdm_conf1_reg.tx_iir_hp_mult12_5 = 7; - pdm_conf1_reg.tx_iir_hp_mult12_0 = 6; - pdm_conf_reg.tx_pdm_hp_bypass = 0; - hw->tx_pcm2pdm_conf = pdm_conf_reg; - hw->tx_pcm2pdm_conf1 = pdm_conf1_reg; + hw->tx_pcm2pdm_conf.tx_pdm_prescale = prescale; +} + +/** + * @brief Set I2S TX PDM high pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_hp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_hp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM low pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_lp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_lp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sinc filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sinc_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sinc_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sigma-delta filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sd_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM high pass filter param0 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 + I2S_TX_IIR_HP_MULT12_0[2:0]) + */ +static inline void i2s_ll_tx_set_pdm_hp_filter_param0(i2s_dev_t *hw, uint32_t param) +{ + hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_0 = param; +} + +/** + * @brief Set I2S TX PDM high pass filter param5 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 + I2S_TX_IIR_HP_MULT12_5[2:0]) + */ +static inline void i2s_ll_tx_set_pdm_hp_filter_param5(i2s_dev_t *hw, uint32_t param) +{ + hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_5 = param; +} + +/** + * @brief Enable I2S TX PDM high pass filter + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable I2S TX PDM high pass filter, set false to bypass it + */ +static inline void i2s_ll_tx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) +{ + hw->tx_pcm2pdm_conf.tx_pdm_hp_bypass = !enable; +} + +/** + * @brief Enable I2S TX PDM sigma-delta codec + * + * @param hw Peripheral I2S hardware instance address. + * @param dither I2S TX PDM sigmadelta dither value + */ +static inline void i2s_ll_tx_enable_pdm_sd_codec(i2s_dev_t *hw, bool enable) +{ + hw->tx_pcm2pdm_conf.tx_pdm_dac_2out_en = enable; + hw->tx_pcm2pdm_conf.tx_pdm_dac_mode_en = enable; +} + +/** + * @brief Set I2S TX PDM sigma-delta codec dither + * + * @param hw Peripheral I2S hardware instance address. + * @param dither I2S TX PDM sigmadelta dither value + */ +static inline void i2s_ll_tx_set_pdm_sd_dither(i2s_dev_t *hw, uint32_t dither) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither = dither; +} + +/** + * @brief Set I2S TX PDM sigma-delta codec dither + * + * @param hw Peripheral I2S hardware instance address. + * @param dither2 I2S TX PDM sigmadelta dither2 value + */ +static inline void i2s_ll_tx_set_pdm_sd_dither2(i2s_dev_t *hw, uint32_t dither2) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither2 = dither2; } /** @@ -518,7 +604,7 @@ static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) * @param fp The fp value of TX PDM filter module group0. * @param fs The fs value of TX PDM filter module group0. */ -static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) +static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) { hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp; hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs; @@ -526,16 +612,27 @@ static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f } /** - * @brief Get I2S TX PDM configuration + * @brief Get I2S TX PDM fp configuration paramater * * @param hw Peripheral I2S hardware instance address. - * @param fp Pointer to accept TX PDM fp configuration paramater - * @param fs Pointer to accept TX PDM fs configuration paramater + * @return + * - fp configuration paramater */ -static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) +static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) { - *fp = hw->tx_pcm2pdm_conf1.tx_pdm_fp; - *fs = hw->tx_pcm2pdm_conf1.tx_pdm_fs; + return hw->tx_pcm2pdm_conf1.tx_pdm_fp; +} + +/** + * @brief Get I2S TX PDM fs configuration paramater + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - fs configuration paramater + */ +static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) +{ + return hw->tx_pcm2pdm_conf1.tx_pdm_fs; } /** @@ -544,7 +641,7 @@ static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t * @param hw Peripheral I2S hardware instance address. * @param pdm_enable Set true to RX enable PDM mode */ -static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) +static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) { hw->rx_conf.rx_pdm_en = pdm_enable; hw->rx_conf.rx_tdm_en = !pdm_enable; @@ -556,14 +653,10 @@ static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) +static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { - if (pcm_cfg == I2S_PCM_DISABLE) { - hw->tx_conf.tx_pcm_bypass = 1; - } else { - hw->tx_conf.tx_pcm_conf = pcm_cfg; - hw->tx_conf.tx_pcm_bypass = 0; - } + hw->tx_conf.tx_pcm_conf = pcm_cfg; + hw->tx_conf.tx_pcm_bypass = !pcm_cfg; } /** @@ -572,14 +665,10 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) +static inline void i2s_ll_rx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { - if (pcm_cfg == I2S_PCM_DISABLE) { - hw->rx_conf.rx_pcm_bypass = 1; - } else { - hw->rx_conf.rx_pcm_conf = pcm_cfg; - hw->rx_conf.rx_pcm_bypass = 0; - } + hw->rx_conf.rx_pcm_conf = pcm_cfg; + hw->rx_conf.rx_pcm_bypass = !pcm_cfg; } /** @@ -588,7 +677,7 @@ static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable left alignment */ -static inline void i2s_ll_tx_left_align_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_tx_enable_left_align(i2s_dev_t *hw, bool ena) { hw->tx_conf.tx_left_align = ena; } @@ -599,7 +688,7 @@ static inline void i2s_ll_tx_left_align_enable(i2s_dev_t *hw, bool ena) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable left alignment */ -static inline void i2s_ll_rx_left_align_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_rx_enable_left_align(i2s_dev_t *hw, bool ena) { hw->rx_conf.rx_left_align = ena; } @@ -610,7 +699,7 @@ static inline void i2s_ll_rx_left_align_enable(i2s_dev_t *hw, bool ena) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_rx_big_endian_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_rx_enable_big_endian(i2s_dev_t *hw, bool ena) { hw->rx_conf.rx_big_endian = ena; } @@ -621,7 +710,7 @@ static inline void i2s_ll_rx_big_endian_enable(i2s_dev_t *hw, bool ena) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_tx_big_endian_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_tx_enable_big_endian(i2s_dev_t *hw, bool ena) { hw->tx_conf.tx_big_endian = ena; } @@ -666,7 +755,7 @@ static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena) * @param hw Peripheral I2S hardware instance address. * @param data Single data to be set */ -static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) +static inline void i2s_ll_set_single_data(i2s_dev_t *hw, uint32_t data) { hw->conf_single_data = data; } @@ -677,7 +766,7 @@ static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable loopback mode. */ -static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_enable_loop_back(i2s_dev_t *hw, bool ena) { hw->tx_conf.sig_loopback = ena; } diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index 5ca3262018..91ba45e3f3 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -66,7 +66,7 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param enable Set true to enable tx msb right */ -static inline void i2s_ll_tx_msb_right_en(i2s_dev_t *hw, bool enable) +static inline void i2s_ll_tx_enable_msb_right(i2s_dev_t *hw, bool enable) { hw->conf.tx_msb_right = enable; } @@ -77,7 +77,7 @@ static inline void i2s_ll_tx_msb_right_en(i2s_dev_t *hw, bool enable) * @param hw Peripheral I2S hardware instance address. * @param enable Set true to enable rx msb right */ -static inline void i2s_ll_rx_msb_right_en(i2s_dev_t *hw, bool enable) +static inline void i2s_ll_rx_enable_msb_right(i2s_dev_t *hw, bool enable) { hw->conf.rx_msb_right = enable; } @@ -88,7 +88,7 @@ static inline void i2s_ll_rx_msb_right_en(i2s_dev_t *hw, bool enable) * @param hw Peripheral I2S hardware instance address. * @param enable Set true to enable send right channel first */ -static inline void i2s_ll_tx_right_first_en(i2s_dev_t *hw, bool enable) +static inline void i2s_ll_tx_enable_right_first(i2s_dev_t *hw, bool enable) { hw->conf.tx_right_first = enable; } @@ -99,7 +99,7 @@ static inline void i2s_ll_tx_right_first_en(i2s_dev_t *hw, bool enable) * @param hw Peripheral I2S hardware instance address. * @param enable Set true to enable receive right channel first */ -static inline void i2s_ll_rx_right_first_en(i2s_dev_t *hw, bool enable) +static inline void i2s_ll_rx_enable_right_first(i2s_dev_t *hw, bool enable) { hw->conf.rx_right_first = enable; } @@ -110,7 +110,7 @@ static inline void i2s_ll_rx_right_first_en(i2s_dev_t *hw, bool enable) * @param hw Peripheral I2S hardware instance address. * @param enable Set true to enable tx fifo module */ -static inline void i2s_ll_tx_fifo_mod_force_en(i2s_dev_t *hw, bool enable) +static inline void i2s_ll_tx_force_enable_fifo_mod(i2s_dev_t *hw, bool enable) { hw->fifo_conf.tx_fifo_mod_force_en = enable; } @@ -121,7 +121,7 @@ static inline void i2s_ll_tx_fifo_mod_force_en(i2s_dev_t *hw, bool enable) * @param hw Peripheral I2S hardware instance address. * @param enable Set true to enable rx fifo module */ -static inline void i2s_ll_rx_fifo_mod_force_en(i2s_dev_t *hw, bool enable) +static inline void i2s_ll_rx_force_enable_fifo_mod(i2s_dev_t *hw, bool enable) { hw->fifo_conf.rx_fifo_mod_force_en = enable; } @@ -132,7 +132,7 @@ static inline void i2s_ll_rx_fifo_mod_force_en(i2s_dev_t *hw, bool enable) * @param hw Peripheral I2S hardware instance address. * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) +static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en) { hw->conf.tx_slave_mod = slave_en; } @@ -143,7 +143,7 @@ static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) * @param hw Peripheral I2S hardware instance address. * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) +static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en) { hw->conf.rx_slave_mod = slave_en; } @@ -153,7 +153,7 @@ static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_reset(i2s_dev_t *hw) { hw->conf.tx_reset = 1; hw->conf.tx_reset = 0; @@ -164,7 +164,7 @@ static inline void i2s_ll_reset_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_reset(i2s_dev_t *hw) { hw->conf.rx_reset = 1; hw->conf.rx_reset = 0; @@ -175,7 +175,7 @@ static inline void i2s_ll_reset_rx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw) { hw->conf.tx_fifo_reset = 1; hw->conf.tx_fifo_reset = 0; @@ -186,7 +186,7 @@ static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) { hw->conf.rx_fifo_reset = 1; hw->conf.rx_fifo_reset = 0; @@ -198,7 +198,7 @@ static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param src I2S source clock */ -static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { hw->clkm_conf.clk_sel = (src == 1) ? 1 : 2; } @@ -209,7 +209,7 @@ static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param src I2S source clock */ -static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { hw->clkm_conf.clk_sel = (src == 1) ? 1 : 2; } @@ -220,7 +220,7 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { hw->clkm_conf.clkm_div_num = set->mclk_div; hw->clkm_conf.clkm_div_b = set->b; @@ -234,7 +234,7 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { hw->clkm_conf.clkm_div_num = set->mclk_div; hw->clkm_conf.clkm_div_b = set->b; @@ -247,7 +247,7 @@ static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_tx_enable_intr(i2s_dev_t *hw) { hw->int_ena.out_eof = 1; hw->int_ena.out_dscr_err = 1; @@ -258,7 +258,7 @@ static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_tx_disable_intr(i2s_dev_t *hw) { hw->int_ena.out_eof = 0; hw->int_ena.out_dscr_err = 0; @@ -269,7 +269,7 @@ static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_rx_enable_intr(i2s_dev_t *hw) { hw->int_ena.in_suc_eof = 1; hw->int_ena.in_dscr_err = 1; @@ -280,7 +280,7 @@ static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_rx_disable_intr(i2s_dev_t *hw) { hw->int_ena.in_suc_eof = 0; hw->int_ena.in_dscr_err = 0; @@ -290,11 +290,12 @@ static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) * @brief Get I2S interrupt status * * @param hw Peripheral I2S hardware instance address. - * @param intr_mask Pointer to accept interrupt status + * @return + * - module interrupt status */ -static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *intr_mask) +static inline uint32_t i2s_ll_get_intr_status(i2s_dev_t *hw) { - *intr_mask = hw->int_st.val; + return hw->int_st.val; } /** @@ -313,7 +314,7 @@ static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t clr_mask) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) +static inline void i2s_ll_tx_reset_dma(i2s_dev_t *hw) { hw->lc_conf.out_rst = 1; hw->lc_conf.out_rst = 0; @@ -324,18 +325,44 @@ static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) +static inline void i2s_ll_rx_reset_dma(i2s_dev_t *hw) { hw->lc_conf.in_rst = 1; hw->lc_conf.in_rst = 0; } +/** + * @brief Enable 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 pdm_enable Set true to TX enable PDM mode (ignored) + */ +static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) +{ + // Remain empty +} + +/** + * @brief Enable 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 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) +{ + // Remain empty +} + /** * @brief Start TX module * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_start(i2s_dev_t *hw) { hw->conf.tx_start = 1; } @@ -345,7 +372,7 @@ static inline void i2s_ll_start_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_start(i2s_dev_t *hw) { hw->conf.rx_start = 1; } @@ -356,7 +383,7 @@ static inline void i2s_ll_start_rx(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param link_addr DMA descriptor link address. */ -static inline void i2s_ll_start_tx_link(i2s_dev_t *hw, uint32_t link_addr) +static inline void i2s_ll_tx_start_link(i2s_dev_t *hw, uint32_t link_addr) { hw->out_link.addr = link_addr; hw->out_link.start = 1; @@ -368,7 +395,7 @@ static inline void i2s_ll_start_tx_link(i2s_dev_t *hw, uint32_t link_addr) * @param hw Peripheral I2S hardware instance address. * @param link_addr DMA descriptor link address. */ -static inline void i2s_ll_start_rx_link(i2s_dev_t *hw, uint32_t link_addr) +static inline void i2s_ll_rx_start_link(i2s_dev_t *hw, uint32_t link_addr) { hw->in_link.addr = link_addr; hw->in_link.start = 1; @@ -379,7 +406,7 @@ static inline void i2s_ll_start_rx_link(i2s_dev_t *hw, uint32_t link_addr) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_stop(i2s_dev_t *hw) { hw->conf.tx_start = 0; } @@ -389,7 +416,7 @@ static inline void i2s_ll_stop_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_stop(i2s_dev_t *hw) { hw->conf.rx_start = 0; } @@ -399,7 +426,7 @@ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) +static inline void i2s_ll_tx_stop_link(i2s_dev_t *hw) { hw->out_link.stop = 1; } @@ -409,7 +436,7 @@ static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) +static inline void i2s_ll_rx_stop_link(i2s_dev_t *hw) { hw->in_link.stop = 1; } @@ -420,7 +447,7 @@ static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param eof_addr Pointer to accept out eof des address */ -static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) +static inline void i2s_ll_tx_get_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) { *eof_addr = hw->out_eof_des_addr; } @@ -431,7 +458,7 @@ static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr * @param hw Peripheral I2S hardware instance address. * @param eof_addr Pointer to accept in eof des address */ -static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) +static inline void i2s_ll_rx_get_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) { *eof_addr = hw->in_eof_des_addr; } @@ -442,7 +469,7 @@ static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) * @param hw Peripheral I2S hardware instance address. * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t eof_num) +static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, uint32_t eof_num) { hw->rx_eof_num = eof_num; } @@ -451,12 +478,12 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t eof_num) * @brief Congfigure TX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The chan bit width + * @param chan_bit The chan bit width * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) +static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) { - hw->fifo_conf.tx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); + hw->fifo_conf.tx_fifo_mod = (chan_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); hw->sample_rate_conf.tx_bits_mod = data_bit; } @@ -464,12 +491,12 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i * @brief Congfigure RX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The chan bit width + * @param chan_bit The chan bit width * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) +static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) { - hw->fifo_conf.rx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); + hw->fifo_conf.rx_fifo_mod = (chan_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); hw->sample_rate_conf.rx_bits_mod = data_bit; } @@ -479,7 +506,7 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable DMA */ -static inline void i2s_ll_dma_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_enable_dma(i2s_dev_t *hw, bool ena) { hw->fifo_conf.dscr_en = ena; } @@ -489,7 +516,7 @@ static inline void i2s_ll_dma_enable(i2s_dev_t *hw, bool ena) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_set_tx_format_philip(i2s_dev_t *hw) +static inline void i2s_ll_tx_set_format_philip(i2s_dev_t *hw) { hw->conf.tx_short_sync = 0; hw->conf.tx_msb_shift = 1; @@ -500,7 +527,7 @@ static inline void i2s_ll_set_tx_format_philip(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_set_rx_format_philip(i2s_dev_t *hw) +static inline void i2s_ll_rx_set_format_philip(i2s_dev_t *hw) { hw->conf.rx_short_sync = 0; hw->conf.rx_msb_shift = 1; @@ -511,7 +538,7 @@ static inline void i2s_ll_set_rx_format_philip(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_set_tx_format_msb_align(i2s_dev_t *hw) +static inline void i2s_ll_tx_set_format_msb_align(i2s_dev_t *hw) { hw->conf.tx_short_sync = 0; hw->conf.tx_msb_shift = 0; @@ -522,7 +549,7 @@ static inline void i2s_ll_set_tx_format_msb_align(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_set_rx_format_msb_align(i2s_dev_t *hw) +static inline void i2s_ll_rx_set_format_msb_align(i2s_dev_t *hw) { hw->conf.rx_short_sync = 0; hw->conf.rx_msb_shift = 0; @@ -533,7 +560,7 @@ static inline void i2s_ll_set_rx_format_msb_align(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_set_tx_pcm_short(i2s_dev_t *hw) +static inline void i2s_ll_tx_set_pcm_short(i2s_dev_t *hw) { hw->conf.tx_short_sync = 1; hw->conf.tx_msb_shift = 0; @@ -544,7 +571,7 @@ static inline void i2s_ll_set_tx_pcm_short(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_set_rx_pcm_short(i2s_dev_t *hw) +static inline void i2s_ll_rx_set_pcm_short(i2s_dev_t *hw) { hw->conf.rx_short_sync = 1; hw->conf.rx_msb_shift = 0; @@ -555,7 +582,7 @@ static inline void i2s_ll_set_rx_pcm_short(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_set_tx_pcm_long(i2s_dev_t *hw) +static inline void i2s_ll_tx_set_pcm_long(i2s_dev_t *hw) { hw->conf.tx_short_sync = 0; hw->conf.tx_msb_shift = 0; @@ -566,26 +593,66 @@ static inline void i2s_ll_set_tx_pcm_long(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) +static inline void i2s_ll_rx_set_pcm_long(i2s_dev_t *hw) { hw->conf.rx_short_sync = 0; hw->conf.rx_msb_shift = 0; } +/** + * @brief Configure TX WS signal width + * + * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle + */ +static inline void i2s_ll_tx_set_ws_width(i2s_dev_t *hw, int width) +{ + hw->conf.tx_short_sync = width == 1 ? 1 : 0; +} + +/** + * @brief Configure RX WS signal width + * + * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle + */ +static inline void i2s_ll_rx_set_ws_width(i2s_dev_t *hw, int width) +{ + hw->conf.rx_short_sync = width == 1 ? 1 : 0; +} + +/** + * @brief Enable TX MSB shift, the data will be launch at the first BCK clock + * + * @param hw Peripheral I2S hardware instance address. + * @param msb_shift_enable Set true to enable MSB shift + */ +static inline void i2s_ll_tx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) +{ + hw->conf.tx_msb_shift = msb_shift_enable; +} + +/** + * @brief Enable RX MSB shift, the data will be launch at the first BCK clock + * + * @param hw Peripheral I2S hardware instance address. + * @param msb_shift_enable Set true to enable MSB shift + */ +static inline void i2s_ll_rx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) +{ + hw->conf.rx_msb_shift = msb_shift_enable; +} + /** * @brief Enable TX mono mode * * @param hw Peripheral I2S hardware instance address. * @param mono_ena Set true to enable mono mde. */ -static inline void i2s_ll_tx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) +static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) { int data_bit = hw->sample_rate_conf.tx_bits_mod; - if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) { - hw->fifo_conf.tx_fifo_mod = 0 + mono_ena; - } else { - hw->fifo_conf.tx_fifo_mod = 2 + mono_ena; - } + hw->fifo_conf.tx_fifo_mod = data_bit <= I2S_BITS_PER_SAMPLE_16BIT ? mono_ena : 2 + mono_ena; hw->conf.tx_dma_equal = mono_ena; hw->conf_chan.tx_chan_mod = mono_ena; } @@ -596,14 +663,10 @@ static inline void i2s_ll_tx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) * @param hw Peripheral I2S hardware instance address. * @param mono_ena Set true to enable mono mde. */ -static inline void i2s_ll_rx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) +static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) { int data_bit = hw->sample_rate_conf.rx_bits_mod; - if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) { - hw->fifo_conf.rx_fifo_mod = 0 + mono_ena; - } else { - hw->fifo_conf.rx_fifo_mod = 2 + mono_ena; - } + hw->fifo_conf.rx_fifo_mod = data_bit <= I2S_BITS_PER_SAMPLE_16BIT ? mono_ena : 2 + mono_ena; hw->conf.rx_dma_equal = mono_ena; hw->conf_chan.rx_chan_mod = mono_ena; } @@ -614,7 +677,7 @@ static inline void i2s_ll_rx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) * @param hw Peripheral I2S hardware instance address. * @param loopback_en Set true to enable loopback mode. */ -static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool loopback_en) +static inline void i2s_ll_enable_loop_back(i2s_dev_t *hw, bool loopback_en) { hw->conf.sig_loopback = loopback_en; } diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 3b2766fe5c..76ef727b88 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -61,7 +61,7 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_tx_clock(i2s_dev_t *hw) +static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw) { hw->tx_clkm_conf.tx_clk_active = 1; } @@ -71,7 +71,7 @@ static inline void i2s_ll_enable_tx_clock(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_clock(i2s_dev_t *hw) +static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw) { hw->rx_clkm_conf.rx_clk_active = 1; } @@ -102,7 +102,7 @@ static inline void i2s_ll_mclk_use_rx_clk(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) +static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en) { hw->tx_conf.tx_slave_mod = slave_en; } @@ -113,7 +113,7 @@ static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) * @param hw Peripheral I2S hardware instance address. * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) +static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en) { hw->rx_conf.rx_slave_mod = slave_en; } @@ -123,7 +123,7 @@ static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_reset(i2s_dev_t *hw) { hw->tx_conf.tx_reset = 1; hw->tx_conf.tx_reset = 0; @@ -134,7 +134,7 @@ static inline void i2s_ll_reset_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_reset(i2s_dev_t *hw) { hw->rx_conf.rx_reset = 1; hw->rx_conf.rx_reset = 0; @@ -145,7 +145,7 @@ static inline void i2s_ll_reset_rx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw) { hw->tx_conf.tx_fifo_reset = 1; hw->tx_conf.tx_fifo_reset = 0; @@ -156,7 +156,7 @@ static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) { hw->rx_conf.rx_fifo_reset = 1; hw->rx_conf.rx_fifo_reset = 0; @@ -169,7 +169,7 @@ static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` * TX and RX share the same clock setting */ -static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { hw->tx_clkm_conf.tx_clk_sel = 2; } @@ -181,7 +181,7 @@ static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` * TX and RX share the same clock setting */ -static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { hw->rx_clkm_conf.rx_clk_sel = 2; } @@ -192,7 +192,7 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { if (set->a == 0 || set->b == 0) { hw->tx_clkm_div_conf.tx_clkm_div_x = 0; @@ -221,7 +221,7 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) { if (set->a == 0 || set->b == 0) { hw->rx_clkm_div_conf.rx_clkm_div_x = 0; @@ -249,7 +249,7 @@ static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_start(i2s_dev_t *hw) { hw->tx_conf.tx_update = 0; hw->tx_conf.tx_update = 1; @@ -261,7 +261,7 @@ static inline void i2s_ll_start_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_start(i2s_dev_t *hw) { hw->rx_conf.rx_update = 0; hw->rx_conf.rx_update = 1; @@ -273,7 +273,7 @@ static inline void i2s_ll_start_rx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_tx(i2s_dev_t *hw) +static inline void i2s_ll_tx_stop(i2s_dev_t *hw) { hw->tx_conf.tx_start = 0; } @@ -283,7 +283,7 @@ static inline void i2s_ll_stop_tx(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +static inline void i2s_ll_rx_stop(i2s_dev_t *hw) { hw->rx_conf.rx_start = 0; } @@ -294,7 +294,7 @@ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param width WS width in BCK cycle */ -static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) +static inline void i2s_ll_tx_set_ws_width(i2s_dev_t *hw, int width) { hw->tx_conf1.tx_tdm_ws_width = width - 1; } @@ -305,7 +305,7 @@ static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) * @param hw Peripheral I2S hardware instance address. * @param width WS width in BCK cycle */ -static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) +static inline void i2s_ll_rx_set_ws_width(i2s_dev_t *hw, int width) { hw->rx_conf1.rx_tdm_ws_width = width - 1; } @@ -316,7 +316,7 @@ static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) * @param hw Peripheral I2S hardware instance address. * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) +static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num) { hw->rx_eof_num.rx_eof_num = eof_num; } @@ -325,26 +325,26 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) * @brief Congfigure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The chan bit width + * @param chan_bit The chan bit width * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) +static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) { hw->tx_conf1.tx_bits_mod = data_bit - 1; - hw->tx_conf1.tx_tdm_chan_bits = sample_bit - 1; + hw->tx_conf1.tx_tdm_chan_bits = chan_bit - 1; } /** * @brief Congfigure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The chan bit width + * @param chan_bit The chan bit width * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) +static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) { hw->rx_conf1.rx_bits_mod = data_bit - 1; - hw->rx_conf1.rx_tdm_chan_bits = sample_bit - 1; + hw->rx_conf1.rx_tdm_chan_bits = chan_bit - 1; } /** @@ -353,7 +353,7 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i * @param hw Peripheral I2S hardware instance address. * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) +static inline void i2s_ll_tx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { hw->tx_conf1.tx_half_sample_bits = half_sample_bits - 1; } @@ -364,7 +364,7 @@ static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_ * @param hw Peripheral I2S hardware instance address. * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) +static inline void i2s_ll_rx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { hw->rx_conf1.rx_half_sample_bits = half_sample_bits - 1; } @@ -375,7 +375,7 @@ static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_ * @param hw Peripheral I2S hardware instance address. * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_tx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) +static inline void i2s_ll_tx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) { hw->tx_conf1.tx_msb_shift = msb_shift_enable; } @@ -386,7 +386,7 @@ static inline void i2s_ll_tx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab * @param hw Peripheral I2S hardware instance address. * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) +static inline void i2s_ll_rx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) { hw->rx_conf1.rx_msb_shift = msb_shift_enable; } @@ -397,7 +397,7 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab * @param hw Peripheral I2S hardware instance address. * @param total_num Total chan number */ -static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_tx_set_chan_num(i2s_dev_t *hw, int total_num) { hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; } @@ -408,7 +408,7 @@ static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num) * @param hw Peripheral I2S hardware instance address. * @param total_num Total chan number */ -static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_rx_set_chan_num(i2s_dev_t *hw, int total_num) { hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; } @@ -419,7 +419,7 @@ static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num) * @param hw Peripheral I2S hardware instance address. * @param chan_mask mask of tx active chan */ -static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) +static inline void i2s_ll_tx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; @@ -433,7 +433,7 @@ static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_m * @param hw Peripheral I2S hardware instance address. * @param chan_mask mask of rx active chan */ -static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) +static inline void i2s_ll_rx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; @@ -447,7 +447,7 @@ static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_m * @param hw Peripheral I2S hardware instance address. * @param ws_pol_level pin level of WS(output) when receiving left channel data */ -static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) +static inline void i2s_tx_set_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { hw->tx_conf.tx_ws_idle_pol = ws_pol_level; } @@ -458,7 +458,7 @@ static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) * @param hw Peripheral I2S hardware instance address. * @param ws_pol_level pin level of WS(input) when receiving left channel data */ -static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) +static inline void i2s_rx_set_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { hw->rx_conf.rx_ws_idle_pol = ws_pol_level; } @@ -469,10 +469,11 @@ static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) * @param hw Peripheral I2S hardware instance address. * @param pdm_enable Set true to TX enable PDM mode */ -static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable) +static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) { hw->tx_conf.tx_pdm_en = pdm_enable; hw->tx_conf.tx_tdm_en = !pdm_enable; + hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = pdm_enable; } /** @@ -481,10 +482,11 @@ static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable) * @param hw Peripheral I2S hardware instance address. * @param pdm_enable Set true to RX enable PDM mode */ -static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) +static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) { hw->rx_conf.rx_pdm_en = pdm_enable; hw->rx_conf.rx_tdm_en = !pdm_enable; + hw->rx_conf.rx_pdm2pcm_en = pdm_enable; } /** @@ -495,7 +497,7 @@ static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) * @param fp The fp value of TX PDM filter module group0. * @param fs The fs value of TX PDM filter module group0. */ -static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) +static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) { hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp; hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs; @@ -503,61 +505,149 @@ static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f } /** - * @brief Get I2S TX PDM configuration + * @brief Get I2S TX PDM fp configuration paramater * * @param hw Peripheral I2S hardware instance address. - * @param fp Pointer to accept TX PDM fp configuration paramater - * @param fs Pointer to accept TX PDM fs configuration paramater + * @return + * - fp configuration paramater */ -static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) +static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) { - *fp = hw->tx_pcm2pdm_conf1.tx_pdm_fp; - *fs = hw->tx_pcm2pdm_conf1.tx_pdm_fs; + return hw->tx_pcm2pdm_conf1.tx_pdm_fp; } /** - * @brief Configure I2S TX pdm + * @brief Get I2S TX PDM fs configuration paramater * * @param hw Peripheral I2S hardware instance address. - * @param sample_rate The sample rate to be set. + * @return + * - fs configuration paramater */ -static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) +static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) { - uint32_t fp = 960; - uint32_t fs = sample_rate / 100; - typeof(hw->tx_pcm2pdm_conf) pdm_conf_reg = hw->tx_pcm2pdm_conf; - typeof(hw->tx_pcm2pdm_conf1) pdm_conf1_reg = hw->tx_pcm2pdm_conf1; - pdm_conf_reg.pcm2pdm_conv_en = 1; - pdm_conf_reg.tx_prescale = 0; - pdm_conf_reg.tx_hp_in_shift = 1; - pdm_conf_reg.tx_lp_in_shift = 1; - pdm_conf_reg.tx_sinc_in_shift = 1; - pdm_conf_reg.tx_sigmadelta_in_shift = 1; - pdm_conf_reg.tx_sinc_osr2 = fp / fs; - pdm_conf_reg.tx_dac_mode_en = 1; - pdm_conf_reg.tx_sigmadelta_dither = 0; - pdm_conf_reg.tx_sigmadelta_dither2 = 0; - pdm_conf_reg.tx_dac_2out_en = 1; - pdm_conf1_reg.tx_pdm_fp = fp; - pdm_conf1_reg.tx_pdm_fs = fs; - pdm_conf1_reg.tx_iir_hp_mult12_5 = 7; - pdm_conf1_reg.tx_iir_hp_mult12_0 = 6; - pdm_conf_reg.tx_hp_bypass = 0; - hw->tx_pcm2pdm_conf = pdm_conf_reg; - hw->tx_pcm2pdm_conf1 = pdm_conf1_reg; + return hw->tx_pcm2pdm_conf1.tx_pdm_fs; } /** - * @brief Set default RX PDM mode + * @brief Set I2S TX PDM prescale * * @param hw Peripheral I2S hardware instance address. + * @param prescale I2S TX PDM prescale */ -static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw) +static inline void i2s_ll_tx_set_pdm_prescale(i2s_dev_t *hw, bool prescale) { - hw->rx_conf.rx_tdm_en = 0; - hw->rx_conf.rx_pdm2pcm_en = 1; - hw->rx_conf.rx_pdm_sinc_dsr_16_en = 0; - hw->rx_conf.rx_pdm_en = 1; + hw->tx_pcm2pdm_conf.tx_prescale = prescale; +} + +/** + * @brief Set I2S TX PDM high pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_hp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_hp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM low pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_lp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_lp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sinc filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sinc_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_sinc_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sigma-delta filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sd_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_sigmadelta_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM high pass filter param0 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 + I2S_TX_IIR_HP_MULT12_0[2:0]) + */ +static inline void i2s_ll_tx_set_pdm_hp_filter_param0(i2s_dev_t *hw, uint32_t param) +{ + hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_0 = param; +} + +/** + * @brief Set I2S TX PDM high pass filter param5 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 + I2S_TX_IIR_HP_MULT12_5[2:0]) + */ +static inline void i2s_ll_tx_set_pdm_hp_filter_param5(i2s_dev_t *hw, uint32_t param) +{ + hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_5 = param; +} + +/** + * @brief Enable I2S TX PDM high pass filter + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable I2S TX PDM high pass filter, set false to bypass it + */ +static inline void i2s_ll_tx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) +{ + hw->tx_pcm2pdm_conf.tx_hp_bypass = !enable; +} + +/** + * @brief Enable I2S TX PDM sigma-delta codec + * + * @param hw Peripheral I2S hardware instance address. + * @param dither I2S TX PDM sigmadelta dither value + */ +static inline void i2s_ll_tx_enable_pdm_sd_codec(i2s_dev_t *hw, bool enable) +{ + hw->tx_pcm2pdm_conf.tx_dac_2out_en = enable; + hw->tx_pcm2pdm_conf.tx_dac_mode_en = enable; +} + +/** + * @brief Set I2S TX PDM sigma-delta codec dither + * + * @param hw Peripheral I2S hardware instance address. + * @param dither I2S TX PDM sigmadelta dither value + */ +static inline void i2s_ll_tx_set_pdm_sd_dither(i2s_dev_t *hw, uint32_t dither) +{ + hw->tx_pcm2pdm_conf.tx_sigmadelta_dither = dither; +} + +/** + * @brief Set I2S TX PDM sigma-delta codec dither + * + * @param hw Peripheral I2S hardware instance address. + * @param dither2 I2S TX PDM sigmadelta dither2 value + */ +static inline void i2s_ll_tx_set_pdm_sd_dither2(i2s_dev_t *hw, uint32_t dither2) +{ + hw->tx_pcm2pdm_conf.tx_sigmadelta_dither2 = dither2; } /** @@ -566,7 +656,7 @@ static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw) * @param hw Peripheral I2S hardware instance address. * @param dsr PDM downsample configuration paramater */ -static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) +static inline void i2s_ll_rx_set_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) { hw->rx_conf.rx_pdm_sinc_dsr_16_en = dsr; } @@ -577,7 +667,7 @@ static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) * @param hw Peripheral I2S hardware instance address. * @param dsr Pointer to accept PDM downsample configuration */ -static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) +static inline void i2s_ll_rx_get_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) { *dsr = hw->rx_conf.rx_pdm_sinc_dsr_16_en; } @@ -588,14 +678,10 @@ static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) +static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { - if (pcm_cfg == I2S_PCM_DISABLE) { - hw->tx_conf.tx_pcm_bypass = 1; - } else { - hw->tx_conf.tx_pcm_conf = pcm_cfg; - hw->tx_conf.tx_pcm_bypass = 0; - } + hw->tx_conf.tx_pcm_conf = pcm_cfg; + hw->tx_conf.tx_pcm_bypass = !pcm_cfg; } /** @@ -604,14 +690,10 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) +static inline void i2s_ll_rx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { - if (pcm_cfg == I2S_PCM_DISABLE) { - hw->rx_conf.rx_pcm_bypass = 1; - } else { - hw->rx_conf.rx_pcm_conf = pcm_cfg; - hw->rx_conf.rx_pcm_bypass = 0; - } + hw->rx_conf.rx_pcm_conf = pcm_cfg; + hw->rx_conf.rx_pcm_bypass = !pcm_cfg; } /** @@ -620,7 +702,7 @@ static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable left alignment */ -static inline void i2s_ll_tx_left_align_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_tx_enable_left_align(i2s_dev_t *hw, bool ena) { hw->tx_conf.tx_left_align = ena; } @@ -631,7 +713,7 @@ static inline void i2s_ll_tx_left_align_enable(i2s_dev_t *hw, bool ena) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable left alignment */ -static inline void i2s_ll_rx_left_align_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_rx_enable_left_align(i2s_dev_t *hw, bool ena) { hw->rx_conf.rx_left_align = ena; } @@ -642,7 +724,7 @@ static inline void i2s_ll_rx_left_align_enable(i2s_dev_t *hw, bool ena) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_rx_big_endian_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_rx_enable_big_endian(i2s_dev_t *hw, bool ena) { hw->rx_conf.rx_big_endian = ena; } @@ -653,7 +735,7 @@ static inline void i2s_ll_rx_big_endian_enable(i2s_dev_t *hw, bool ena) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_tx_big_endian_enable(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_tx_enable_big_endian(i2s_dev_t *hw, bool ena) { hw->tx_conf.tx_big_endian = ena; } @@ -698,9 +780,9 @@ static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena) * @param hw Peripheral I2S hardware instance address. * @param data Single data to be set */ -static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) +static inline void i2s_ll_set_single_data(i2s_dev_t *hw, uint32_t data) { - hw->conf_signal_data = data; + hw->conf_single_data = data; } /** @@ -709,7 +791,7 @@ static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) * @param hw Peripheral I2S hardware instance address. * @param ena Set true to enable loopback mode. */ -static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_enable_loop_back(i2s_dev_t *hw, bool ena) { hw->tx_conf.sig_loopback = ena; } diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index bbabba6ba7..b7cbe45994 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -65,34 +65,34 @@ static void i2s_hal_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_ll_c void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel) { - i2s_ll_set_tx_clk_src(hal->dev, sel); - i2s_ll_set_rx_clk_src(hal->dev, sel); + i2s_ll_tx_clk_set_src(hal->dev, sel); + i2s_ll_rx_clk_set_src(hal->dev, sel); } void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor) { i2s_ll_clk_cal_t clk_set = {0}; i2s_hal_clk_cal(sclk, fbck, factor, &clk_set); - i2s_ll_set_tx_clk(hal->dev, &clk_set); + i2s_ll_tx_set_clk(hal->dev, &clk_set); } void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor) { i2s_ll_clk_cal_t clk_set = {0}; i2s_hal_clk_cal(sclk, fbck, factor, &clk_set); - i2s_ll_set_rx_clk(hal->dev, &clk_set); + i2s_ll_rx_set_clk(hal->dev, &clk_set); } void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal) { - i2s_ll_set_tx_slave_mod(hal->dev, 0); //TX master - i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave + i2s_ll_tx_set_slave_mod(hal->dev, 0); //TX master + i2s_ll_rx_set_slave_mod(hal->dev, 1); //RX Slave } void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal) { - i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave - i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave + i2s_ll_tx_set_slave_mod(hal->dev, 1); //TX Slave + i2s_ll_rx_set_slave_mod(hal->dev, 1); //RX Slave } void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num) @@ -102,193 +102,195 @@ void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num) i2s_ll_enable_clock(hal->dev); } -static void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) +static void i2s_hal_tx_set_pdm_mode(i2s_hal_context_t *hal, uint32_t sample_rate) { -#if !SOC_I2S_SUPPORTS_TDM - switch (hal_cfg->comm_fmt) { - case I2S_COMM_FORMAT_STAND_MSB: - if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_set_tx_format_msb_align(hal->dev); - } - if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_set_rx_format_msb_align(hal->dev); - } - break; - case I2S_COMM_FORMAT_STAND_PCM_SHORT: - if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_set_tx_pcm_short(hal->dev); - } - if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_set_rx_pcm_short(hal->dev); - } - break; - case I2S_COMM_FORMAT_STAND_PCM_LONG: - if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_set_tx_pcm_long(hal->dev); - } - if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_set_rx_pcm_long(hal->dev); - } - break; - default: //I2S_COMM_FORMAT_STAND_I2S - if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_set_tx_format_philip(hal->dev); - } - if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_set_rx_format_philip(hal->dev); - } - break; - } - if (hal_cfg->ch == I2S_CHANNEL_MONO) { - if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_tx_mono_mode_ena(hal->dev, true); - } - if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_rx_mono_mode_ena(hal->dev, true); - } - } +#if SOC_I2S_SUPPORTS_PDM_TX + /* enable pdm tx mode */ + i2s_ll_tx_enable_pdm(hal->dev, true); + /* set pdm tx default presacle */ + i2s_ll_tx_set_pdm_prescale(hal->dev, 0); + /* set pdm tx default sacle of high pass filter */ + i2s_ll_tx_set_pdm_hp_scale(hal->dev, I2S_PDM_SIG_SCALING_MUL_1); + /* set pdm tx default sacle of low pass filter */ + i2s_ll_tx_set_pdm_lp_scale(hal->dev, I2S_PDM_SIG_SCALING_MUL_1); + /* set pdm tx default sacle of sinc filter */ + i2s_ll_tx_set_pdm_sinc_scale(hal->dev, I2S_PDM_SIG_SCALING_MUL_1); + /* set pdm tx default sacle of sigma-delta filter */ + i2s_ll_tx_set_pdm_sd_scale(hal->dev, I2S_PDM_SIG_SCALING_MUL_1); + /* set pdm tx sample rate */ + i2s_ll_tx_set_pdm_fpfs(hal->dev, 960, sample_rate / 100); + +#if SOC_I2S_SUPPORTS_PDM_CODEC + /* enable pdm high pass filter */ + i2s_ll_tx_enable_pdm_hp_filter(hal->dev, true); + /* set pdm tx high pass filter parameters */ + i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, 6); + i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, 7); + /* enable pdm sigma-delta codec */ + i2s_ll_tx_enable_pdm_sd_codec(hal->dev, true); + /* set pdm tx sigma-delta codec dither */ + i2s_ll_tx_set_pdm_sd_dither(hal->dev, 0); + i2s_ll_tx_set_pdm_sd_dither2(hal->dev, 0); + +#endif // SOC_I2S_SUPPORTS_PDM_CODEC +#endif // SOC_I2S_SUPPORTS_PDM_TX +} + +static void i2s_hal_rx_set_pdm_mode(i2s_hal_context_t *hal) +{ +#if SOC_I2S_SUPPORTS_PDM_RX + /* enable pdm rx mode */ + i2s_ll_rx_enable_pdm(hal->dev, true); + /* set pdm rx downsample number */ + i2s_ll_rx_set_pdm_dsr(hal->dev, I2S_PDM_DSR_8S); +#endif // SOC_I2S_SUPPORTS_PDM_RX +} + + +static void i2s_hal_tx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) +{ + /* disable pdm tx mode */ + i2s_ll_tx_enable_pdm(hal->dev, false); + +#if SOC_I2S_SUPPORTS_TDM + i2s_ll_tx_enable_clock(hal->dev); + i2s_ll_tx_clk_set_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default + i2s_ll_mclk_use_tx_clk(hal->dev); + + i2s_ll_tx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask); + i2s_ll_tx_enable_left_align(hal->dev, hal_cfg->left_align_en); + i2s_ll_tx_enable_big_endian(hal->dev, hal_cfg->big_edin_en); + i2s_ll_tx_set_bit_order(hal->dev, hal_cfg->bit_order_msb_en); + i2s_ll_tx_set_skip_mask(hal->dev, hal_cfg->skip_msk_en); #else - int chan_bits = hal_cfg->bits_cfg.chan_bits; - int chan_num = hal_cfg->total_chan; - bool msb_shift_en = false; - int tdm_ws_width = 0; - switch (hal_cfg->comm_fmt) { - case I2S_COMM_FORMAT_STAND_MSB: - msb_shift_en = false; - tdm_ws_width = chan_num * chan_bits / 2; - break; - case I2S_COMM_FORMAT_STAND_PCM_SHORT: - msb_shift_en = false; - tdm_ws_width = 1; - break; - case I2S_COMM_FORMAT_STAND_PCM_LONG: - msb_shift_en = false; - tdm_ws_width = chan_bits; - break; - default: //I2S_COMM_FORMAT_STAND_I2S - msb_shift_en = true; - tdm_ws_width = chan_num * chan_bits / 2; - break; - } - if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_tx_msb_shift_enable(hal->dev, msb_shift_en); - i2s_ll_set_tx_tdm_ws_width(hal->dev, tdm_ws_width); - i2s_ll_set_tx_half_sample_bit(hal->dev, chan_num * chan_bits / 2); - } - if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_rx_msb_shift_enable(hal->dev, msb_shift_en); - i2s_ll_set_rx_tdm_ws_width(hal->dev, tdm_ws_width); - i2s_ll_set_rx_half_sample_bit(hal->dev, chan_num * chan_bits / 2); - } + i2s_ll_tx_enable_msb_right(hal->dev, false); + i2s_ll_tx_enable_right_first(hal->dev, false); + i2s_ll_tx_force_enable_fifo_mod(hal->dev, true); #endif } -void i2s_hal_samples_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) +static void i2s_hal_rx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) { - int data_bits = hal_cfg->bits_cfg.sample_bits; - int chan_bits = hal_cfg->bits_cfg.chan_bits; + /* disable pdm rx mode */ + i2s_ll_rx_enable_pdm(hal->dev, false); + #if SOC_I2S_SUPPORTS_TDM - int chan_num = hal_cfg->total_chan; - if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_set_tx_chan_num(hal->dev, chan_num); - i2s_ll_set_tx_sample_bit(hal->dev, chan_bits, data_bits); - } - if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_set_rx_chan_num(hal->dev, chan_num); - i2s_ll_set_rx_sample_bit(hal->dev, chan_bits, data_bits); - } + i2s_ll_rx_enable_clock(hal->dev); + i2s_ll_rx_clk_set_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default + i2s_ll_mclk_use_rx_clk(hal->dev); + + i2s_ll_rx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask); + i2s_ll_rx_enable_left_align(hal->dev, hal_cfg->left_align_en); + i2s_ll_rx_enable_big_endian(hal->dev, hal_cfg->big_edin_en); + i2s_ll_rx_set_bit_order(hal->dev, hal_cfg->bit_order_msb_en); #else - if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_set_tx_sample_bit(hal->dev, chan_bits, data_bits); - } - if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_set_rx_sample_bit(hal->dev, chan_bits, data_bits); - } + i2s_ll_rx_enable_msb_right(hal->dev, false); + i2s_ll_rx_enable_right_first(hal->dev, false); + i2s_ll_rx_force_enable_fifo_mod(hal->dev, true); #endif - //I2S standards config: Philip, MSB or PCM, Only I2S mode should do this configuration. - if ((hal_cfg->mode & (~(I2S_MODE_I2S))) == 0) { - i2s_hal_format_config(hal, hal_cfg); +} + +static uint32_t i2s_hal_get_ws_bit(i2s_comm_format_t fmt, uint32_t chan_num, uint32_t chan_bits) +{ + switch (fmt) { + case I2S_COMM_FORMAT_STAND_MSB: + return chan_num * chan_bits / 2; + case I2S_COMM_FORMAT_STAND_PCM_SHORT: + return 1; + case I2S_COMM_FORMAT_STAND_PCM_LONG: + return chan_bits; + default: //I2S_COMM_FORMAT_STAND_I2S + return chan_num * chan_bits / 2; } } +void i2s_hal_tx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) +{ + uint32_t chan_num = 2; + uint32_t chan_bits = hal_cfg->bits_cfg.chan_bits; + uint32_t data_bits = hal_cfg->bits_cfg.sample_bits; + + /* Set channel number and valid data bits */ +#if SOC_I2S_SUPPORTS_TDM + chan_num = hal_cfg->total_chan; + i2s_ll_tx_set_chan_num(hal->dev, chan_num); +#endif + i2s_ll_tx_set_sample_bit(hal->dev, chan_bits, data_bits); + + /* Set communication format */ + bool shift_en = hal_cfg->comm_fmt == I2S_COMM_FORMAT_STAND_I2S ? true : false; + uint32_t ws_width = i2s_hal_get_ws_bit(hal_cfg->comm_fmt, chan_num, chan_bits); + i2s_ll_tx_enable_msb_shift(hal->dev, shift_en); + i2s_ll_tx_set_ws_width(hal->dev, ws_width); +#if SOC_I2S_SUPPORTS_TDM + i2s_ll_tx_set_half_sample_bit(hal->dev, chan_num * chan_bits / 2); +#endif +} + +void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) +{ + uint32_t chan_num = 2; + uint32_t chan_bits = hal_cfg->bits_cfg.chan_bits; + uint32_t data_bits = hal_cfg->bits_cfg.sample_bits; + +#if SOC_I2S_SUPPORTS_TDM + chan_num = hal_cfg->total_chan; + i2s_ll_rx_set_chan_num(hal->dev, chan_num); +#endif + i2s_ll_rx_set_sample_bit(hal->dev, chan_bits, data_bits); + + /* Set communication format */ + bool shift_en = hal_cfg->comm_fmt == I2S_COMM_FORMAT_STAND_I2S ? true : false; + uint32_t ws_width = i2s_hal_get_ws_bit(hal_cfg->comm_fmt, chan_num, chan_bits); + i2s_ll_rx_enable_msb_shift(hal->dev, shift_en); + i2s_ll_rx_set_ws_width(hal->dev, ws_width); +#if SOC_I2S_SUPPORTS_TDM + i2s_ll_rx_set_half_sample_bit(hal->dev, chan_num * chan_bits / 2); +#endif +} + void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) { - bool is_slave = ((hal_cfg->mode & I2S_MODE_SLAVE) > 0); - - if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_stop_tx(hal->dev); - i2s_ll_reset_tx(hal->dev); -#if SOC_I2S_SUPPORTS_TDM - i2s_ll_set_tx_pdm_en(hal->dev, false); - i2s_ll_enable_tx_clock(hal->dev); - i2s_ll_set_tx_clk_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default - i2s_ll_mclk_use_tx_clk(hal->dev); - - i2s_ll_set_tx_active_chan_mask(hal->dev, hal_cfg->chan_mask); - i2s_ll_tx_left_align_enable(hal->dev, hal_cfg->flags.left_align_en); - i2s_ll_tx_big_endian_enable(hal->dev, hal_cfg->flags.big_edin_en); - i2s_ll_tx_set_bit_order(hal->dev, hal_cfg->flags.bit_order_msb_en); - i2s_ll_tx_set_skip_mask(hal->dev, hal_cfg->flags.skip_msk_en); -#else - i2s_ll_tx_msb_right_en(hal->dev, false); - i2s_ll_tx_right_first_en(hal->dev, false); - i2s_ll_tx_fifo_mod_force_en(hal->dev, true); -#endif - i2s_ll_set_tx_slave_mod(hal->dev, is_slave); //TX Slave - } - - - if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_stop_rx(hal->dev); - i2s_ll_reset_rx(hal->dev); -#if SOC_I2S_SUPPORTS_TDM - i2s_ll_set_rx_pdm_en(hal->dev, false); - i2s_ll_enable_rx_clock(hal->dev); - i2s_ll_set_rx_clk_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default - i2s_ll_mclk_use_rx_clk(hal->dev); - - i2s_ll_set_rx_active_chan_mask(hal->dev, hal_cfg->chan_mask); - i2s_ll_rx_left_align_enable(hal->dev, hal_cfg->flags.left_align_en); - i2s_ll_rx_big_endian_enable(hal->dev, hal_cfg->flags.big_edin_en); - i2s_ll_rx_set_bit_order(hal->dev, hal_cfg->flags.bit_order_msb_en); -#else - i2s_ll_rx_msb_right_en(hal->dev, false); - i2s_ll_rx_right_first_en(hal->dev, false); - i2s_ll_rx_fifo_mod_force_en(hal->dev, true); -#endif - i2s_ll_set_rx_slave_mod(hal->dev, is_slave); //RX Slave - } #if SOC_I2S_SUPPORTS_ADC_DAC - if (hal_cfg->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { + if ((hal_cfg->mode & I2S_MODE_DAC_BUILT_IN) || (hal_cfg->mode & I2S_MODE_ADC_BUILT_IN)) { if (hal_cfg->mode & I2S_MODE_DAC_BUILT_IN) { - i2s_ll_build_in_dac_ena(hal->dev); + i2s_ll_enable_builtin_dac(hal->dev, true); } if (hal_cfg->mode & I2S_MODE_ADC_BUILT_IN) { - i2s_ll_build_in_adc_ena(hal->dev); + i2s_ll_enable_builtin_adc(hal->dev, true); } - // Buildin ADC and DAC have nothing to do with communication format configuration. + /* Use builtin ADC/DAC, return directly. */ return; + } else { + i2s_ll_enable_builtin_dac(hal->dev, false); + i2s_ll_enable_builtin_adc(hal->dev, false); } #endif -#if SOC_I2S_SUPPORTS_PDM_TX if (hal_cfg->mode & I2S_MODE_TX) { + i2s_ll_tx_stop(hal->dev); + i2s_ll_tx_reset(hal->dev); + i2s_ll_tx_set_slave_mod(hal->dev, (hal_cfg->mode & I2S_MODE_SLAVE) != 0); //TX Slave if (hal_cfg->mode & I2S_MODE_PDM) { - i2s_ll_tx_pdm_cfg(hal->dev, hal_cfg->sample_rate); + /* Set tx pdm mode */ + i2s_hal_tx_set_pdm_mode(hal, hal_cfg->sample_rate); } else { - i2s_ll_set_tx_pdm_en(hal->dev, false); + /* Set tx common mode */ + i2s_hal_tx_set_common_mode(hal, hal_cfg); + i2s_hal_tx_set_channel_style(hal, hal_cfg); } } -#endif // SOC_I2S_SUPPORTS_PDM_TX -#if SOC_I2S_SUPPORTS_PDM_RX if (hal_cfg->mode & I2S_MODE_RX) { + i2s_ll_rx_stop(hal->dev); + i2s_ll_rx_reset(hal->dev); + i2s_ll_rx_set_slave_mod(hal->dev, (hal_cfg->mode & I2S_MODE_SLAVE) != 0); //RX Slave if (hal_cfg->mode & I2S_MODE_PDM) { - i2s_ll_rx_pdm_cfg(hal->dev); + /* Set rx pdm mode */ + i2s_hal_rx_set_pdm_mode(hal); } else { - i2s_ll_set_rx_pdm_en(hal->dev, false); + /* Set rx common mode */ + i2s_hal_rx_set_common_mode(hal, hal_cfg); + i2s_hal_rx_set_channel_style(hal, hal_cfg); } } -#endif // SOC_I2S_SUPPORTS_PDM_RX - //Configure I2S chan number,sample bit. - i2s_hal_samples_config(hal, hal_cfg); } diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index be07a92e41..ee5c32abc3 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -57,15 +57,10 @@ typedef struct { #if SOC_I2S_SUPPORTS_TDM uint32_t total_chan; /*!< Total number of I2S channels */ uint32_t chan_mask; /*!< Active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<dev) +#define i2s_hal_reset_tx(hal) i2s_ll_tx_reset((hal)->dev) /** * @brief Reset I2S TX fifo * * @param hal Context of the HAL layer */ -#define i2s_hal_reset_tx_fifo(hal) i2s_ll_reset_tx_fifo((hal)->dev) +#define i2s_hal_reset_tx_fifo(hal) i2s_ll_tx_reset_fifo((hal)->dev) /** * @brief Reset I2S RX channel * * @param hal Context of the HAL layer */ -#define i2s_hal_reset_rx(hal) i2s_ll_reset_rx((hal)->dev) +#define i2s_hal_reset_rx(hal) i2s_ll_rx_reset((hal)->dev) /** * @brief Reset I2S RX fifo * * @param hal Context of the HAL layer */ -#define i2s_hal_reset_rx_fifo(hal) i2s_ll_reset_rx_fifo((hal)->dev) +#define i2s_hal_reset_rx_fifo(hal) i2s_ll_rx_reset_fifo((hal)->dev) /** * @brief Init the I2S hal. This function should be called first before other hal layer function is called @@ -122,12 +117,20 @@ void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num); void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel); /** - * @brief Configure communication format + * @brief Set Tx channel style * * @param hal Context of the HAL layer * @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t` */ -void i2s_hal_samples_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg); +void i2s_hal_tx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg); + +/** + * @brief Set Rx channel style + * + * @param hal Context of the HAL layer + * @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t` + */ +void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg); /** * @brief Config I2S param @@ -156,28 +159,28 @@ void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal); * * @param hal Context of the HAL layer */ -#define i2s_hal_start_tx(hal) i2s_ll_start_tx((hal)->dev) +#define i2s_hal_start_tx(hal) i2s_ll_tx_start((hal)->dev) /** * @brief Start I2S rx * * @param hal Context of the HAL layer */ -#define i2s_hal_start_rx(hal) i2s_ll_start_rx((hal)->dev) +#define i2s_hal_start_rx(hal) i2s_ll_rx_start((hal)->dev) /** * @brief Stop I2S tx * * @param hal Context of the HAL layer */ -#define i2s_hal_stop_tx(hal) i2s_ll_stop_tx((hal)->dev) +#define i2s_hal_stop_tx(hal) i2s_ll_tx_stop((hal)->dev) /** * @brief Stop I2S rx * * @param hal Context of the HAL layer */ -#define i2s_hal_stop_rx(hal) i2s_ll_stop_rx((hal)->dev) +#define i2s_hal_stop_rx(hal) i2s_ll_rx_stop((hal)->dev) /** * @brief Set the received data length to trigger `in_suc_eof` interrupt. @@ -185,7 +188,7 @@ void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal); * @param hal Context of the HAL layer * @param eof_byte The byte length that trigger in_suc_eof interrupt. */ -#define i2s_hal_set_rx_eof_num(hal, eof_byte) i2s_ll_set_rx_eof_num((hal)->dev, eof_byte) +#define i2s_hal_set_rx_eof_num(hal, eof_byte) i2s_ll_rx_set_eof_num((hal)->dev, eof_byte) /** * @brief Set I2S TX sample bit @@ -194,7 +197,7 @@ void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal); * @param chan_bit I2S TX chan bit * @param data_bit The sample data bit length. */ -#define i2s_hal_set_tx_sample_bit(hal, chan_bit, data_bit) i2s_ll_set_tx_sample_bit((hal)->dev, chan_bit, data_bit) +#define i2s_hal_set_tx_sample_bit(hal, chan_bit, data_bit) i2s_ll_tx_set_sample_bit((hal)->dev, chan_bit, data_bit) /** * @brief Set I2S RX sample bit @@ -203,7 +206,7 @@ void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal); * @param chan_bit I2S RX chan bit * @param data_bit The sample data bit length. */ -#define i2s_hal_set_rx_sample_bit(hal, chan_bit, data_bit) i2s_ll_set_rx_sample_bit((hal)->dev, chan_bit, data_bit) +#define i2s_hal_set_rx_sample_bit(hal, chan_bit, data_bit) i2s_ll_rx_set_sample_bit((hal)->dev, chan_bit, data_bit) /** * @brief Configure I2S TX module clock devider @@ -232,7 +235,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @param hal Context of the HAL layer * @param cfg PCM configure paramater, refer to `i2s_pcm_compress_t` */ -#define i2s_hal_tx_pcm_cfg(hal, cfg) i2s_ll_tx_pcm_cfg((hal)->dev, cfg) +#define i2s_hal_tx_pcm_cfg(hal, cfg) i2s_ll_tx_set_pcm_type((hal)->dev, cfg) /** * @brief Configure I2S RX PCM encoder or decoder. @@ -240,7 +243,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @param hal Context of the HAL layer * @param cfg PCM configure paramater, refer to `i2s_pcm_compress_t` */ -#define i2s_hal_rx_pcm_cfg(hal, cfg) i2s_ll_rx_pcm_cfg((hal)->dev, cfg) +#define i2s_hal_rx_pcm_cfg(hal, cfg) i2s_ll_rx_set_pcm_type((hal)->dev, cfg) #endif /** @@ -248,7 +251,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * * @param hal Context of the HAL layer */ -#define i2s_hal_enable_sig_loopback(hal) i2s_ll_loop_back_ena((hal)->dev, true) +#define i2s_hal_enable_sig_loopback(hal) i2s_ll_enable_loop_back((hal)->dev, true) #if SOC_I2S_SUPPORTS_PDM_TX /** @@ -259,16 +262,25 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @param fp TX PDM fp paramater configuration * @param fs TX PDM fs paramater configuration */ -#define i2s_hal_set_tx_pdm_fpfs(hal, fp, fs) i2s_ll_set_tx_pdm_fpfs((hal)->dev, fp, fs) +#define i2s_hal_set_tx_pdm_fpfs(hal, fp, fs) i2s_ll_tx_set_pdm_fpfs((hal)->dev, fp, fs) /** - * @brief Get I2S TX PDM configuration + * @brief Get I2S TX PDM fp * * @param hal Context of the HAL layer - * @param fp Pointer to accept TX PDM fp paramater configuration - * @param fs Pointer to accept TX PDM fs paramater configuration + * @return + * - fp configuration paramater */ -#define i2s_hal_get_tx_pdm_fpfs(hal, fp, fs) i2s_ll_get_tx_pdm_fpfs((hal)->dev, (uint32_t *)fp, (uint32_t *)fs) +#define i2s_hal_get_tx_pdm_fp(hal) i2s_ll_tx_get_pdm_fp((hal)->dev) + +/** + * @brief Get I2S TX PDM fs + * + * @param hal Context of the HAL layer + * @return + * - fs configuration paramater + */ +#define i2s_hal_get_tx_pdm_fs(hal) i2s_ll_tx_get_pdm_fs((hal)->dev) #endif #if SOC_I2S_SUPPORTS_PDM_RX @@ -279,7 +291,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @param hal Context of the HAL layer * @param dsr PDM downsample configuration paramater */ -#define i2s_hal_set_rx_pdm_dsr(hal, dsr) i2s_ll_set_pdm_rx_dsr((hal)->dev, dsr) +#define i2s_hal_set_rx_pdm_dsr(hal, dsr) i2s_ll_rx_set_pdm_dsr((hal)->dev, dsr) /** * @brief Get RX PDM downsample configuration @@ -287,7 +299,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @param hal Context of the HAL layer * @param dsr Pointer to accept PDM downsample configuration */ -#define i2s_hal_get_rx_pdm_dsr(hal, dsr) i2s_ll_get_pdm_rx_dsr((hal)->dev, dsr) +#define i2s_hal_get_rx_pdm_dsr(hal, dsr) i2s_ll_rx_get_pdm_dsr((hal)->dev, dsr) #endif #if !SOC_GDMA_SUPPORTED @@ -296,22 +308,37 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * * @param hal Context of the HAL layer */ -#define i2s_hal_attach_tx_dma(hal) i2s_ll_dma_enable((hal)->dev,true) +#define i2s_hal_enable_tx_dma(hal) i2s_ll_enable_dma((hal)->dev,true) /** * @brief Enable I2S RX DMA * * @param hal Context of the HAL layer */ -#define i2s_hal_attach_rx_dma(hal) i2s_ll_dma_enable((hal)->dev,true) +#define i2s_hal_enable_rx_dma(hal) i2s_ll_enable_dma((hal)->dev,true) + +/** + * @brief Disable I2S TX DMA + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_disable_tx_dma(hal) i2s_ll_enable_dma((hal)->dev,false) + +/** + * @brief Disable I2S RX DMA + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_disable_rx_dma(hal) i2s_ll_enable_dma((hal)->dev,false) /** * @brief Get I2S interrupt status * * @param hal Context of the HAL layer - * @param status Pointer to accept I2S interrupt status + * @return + * - module interrupt status */ -#define i2s_hal_get_intr_status(hal, status) i2s_ll_get_intr_status((hal)->dev, status) +#define i2s_hal_get_intr_status(hal) i2s_ll_get_intr_status((hal)->dev) /** * @brief Get I2S interrupt status @@ -326,28 +353,28 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * * @param hal Context of the HAL layer */ -#define i2s_hal_enable_rx_intr(hal) i2s_ll_enable_rx_intr((hal)->dev) +#define i2s_hal_enable_rx_intr(hal) i2s_ll_rx_enable_intr((hal)->dev) /** * @brief Disable I2S RX interrupt * * @param hal Context of the HAL layer */ -#define i2s_hal_disable_rx_intr(hal) i2s_ll_disable_rx_intr((hal)->dev) +#define i2s_hal_disable_rx_intr(hal) i2s_ll_rx_disable_intr((hal)->dev) /** * @brief Disable I2S TX interrupt * * @param hal Context of the HAL layer */ -#define i2s_hal_disable_tx_intr(hal) i2s_ll_disable_tx_intr((hal)->dev) +#define i2s_hal_disable_tx_intr(hal) i2s_ll_tx_disable_intr((hal)->dev) /** * @brief Enable I2S TX interrupt * * @param hal Context of the HAL layer */ -#define i2s_hal_enable_tx_intr(hal) i2s_ll_enable_tx_intr((hal)->dev) +#define i2s_hal_enable_tx_intr(hal) i2s_ll_tx_enable_intr((hal)->dev) /** * @brief Configure TX DMA descriptor address and start TX DMA @@ -355,7 +382,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @param hal Context of the HAL layer * @param link_addr DMA descriptor link address. */ -#define i2s_hal_start_tx_link(hal, link_addr) i2s_ll_start_tx_link((hal)->dev, link_addr) +#define i2s_hal_start_tx_link(hal, link_addr) i2s_ll_tx_start_link((hal)->dev, link_addr) /** * @brief Configure RX DMA descriptor address and start RX DMA @@ -363,35 +390,35 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @param hal Context of the HAL layer * @param link_addr DMA descriptor link address. */ -#define i2s_hal_start_rx_link(hal, link_addr) i2s_ll_start_rx_link((hal)->dev, link_addr) +#define i2s_hal_start_rx_link(hal, link_addr) i2s_ll_rx_start_link((hal)->dev, link_addr) /** * @brief Stop TX DMA link * * @param hal Context of the HAL layer */ -#define i2s_hal_stop_tx_link(hal) i2s_ll_stop_out_link((hal)->dev) +#define i2s_hal_stop_tx_link(hal) i2s_ll_tx_stop_link((hal)->dev) /** * @brief Stop RX DMA link * * @param hal Context of the HAL layer */ -#define i2s_hal_stop_rx_link(hal) i2s_ll_stop_in_link((hal)->dev) +#define i2s_hal_stop_rx_link(hal) i2s_ll_rx_stop_link((hal)->dev) /** * @brief Reset RX DMA * * @param hal Context of the HAL layer */ -#define i2s_hal_reset_rxdma(hal) i2s_ll_reset_dma_in((hal)->dev) +#define i2s_hal_reset_rxdma(hal) i2s_ll_rx_reset_dma((hal)->dev) /** * @brief Reset TX DMA * * @param hal Context of the HAL layer */ -#define i2s_hal_reset_txdma(hal) i2s_ll_reset_dma_out((hal)->dev) +#define i2s_hal_reset_txdma(hal) i2s_ll_tx_reset_dma((hal)->dev) /** * @brief Get I2S out eof descriptor address @@ -399,7 +426,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @param hal Context of the HAL layer * @param addr Pointer to accept out eof des address */ -#define i2s_hal_get_out_eof_des_addr(hal, addr) i2s_ll_get_out_eof_des_addr((hal)->dev, addr) +#define i2s_hal_get_out_eof_des_addr(hal, addr) i2s_ll_tx_get_eof_des_addr((hal)->dev, addr) /** * @brief Get I2S in suc eof descriptor address @@ -407,7 +434,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @param hal Context of the HAL layer * @param addr Pointer to accept in suc eof des address */ -#define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_get_in_eof_des_addr((hal)->dev, addr) +#define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_rx_get_eof_des_addr((hal)->dev, addr) #endif #ifdef __cplusplus diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index 6b12b4812d..a42ad40d05 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -29,10 +29,10 @@ extern "C" { * */ typedef enum { - I2S_BITS_PER_SAMPLE_8BIT = 8, - I2S_BITS_PER_SAMPLE_16BIT = 16, - I2S_BITS_PER_SAMPLE_24BIT = 24, - I2S_BITS_PER_SAMPLE_32BIT = 32, + I2S_BITS_PER_SAMPLE_8BIT = 8, /*!< data bit-width: 8 */ + I2S_BITS_PER_SAMPLE_16BIT = 16, /*!< data bit-width: 16 */ + I2S_BITS_PER_SAMPLE_24BIT = 24, /*!< data bit-width: 24 */ + I2S_BITS_PER_SAMPLE_32BIT = 32, /*!< data bit-width: 32 */ } i2s_bits_per_sample_t; /** @@ -40,11 +40,11 @@ typedef enum { * */ typedef enum { - I2S_BITS_PER_CHAN_DEFAULT = (0), /*!< chan bit equals to data bit*/ - I2S_BITS_PER_CHAN_8BIT = (8), /*!< chan bit 8*/ - I2S_BITS_PER_CHAN_16BIT = (16), /*!< chan bit 16*/ - I2S_BITS_PER_CHAN_24BIT = (24), /*!< chan bit 24*/ - I2S_BITS_PER_CHAN_32BIT = (32), /*!< chan bit 32*/ + I2S_BITS_PER_CHAN_DEFAULT = (0), /*!< channel bit-width equals to data bit-width */ + I2S_BITS_PER_CHAN_8BIT = (8), /*!< channel bit-width: 8 */ + I2S_BITS_PER_CHAN_16BIT = (16), /*!< channel bit-width: 16 */ + I2S_BITS_PER_CHAN_24BIT = (24), /*!< channel bit-width: 24 */ + I2S_BITS_PER_CHAN_32BIT = (32), /*!< channel bit-width: 32 */ } i2s_bits_per_chan_t; /** @@ -93,7 +93,7 @@ typedef enum { I2S_COMM_FORMAT_STAND_MSB = 0X02, /*!< I2S communication MSB alignment standard, data launch at first BCK*/ I2S_COMM_FORMAT_STAND_PCM_SHORT = 0x04, /*!< PCM Short standard, also known as DSP mode. The period of synchronization signal (WS) is 1 bck cycle.*/ I2S_COMM_FORMAT_STAND_PCM_LONG = 0x0C, /*!< PCM Long standard. The period of synchronization signal (WS) is channel_bit*bck cycles.*/ - I2S_COMM_FORMAT_STAND_MAX, /*!< standard max*/ + I2S_COMM_FORMAT_STAND_MAX, /*!< standard max*/ //old definition will be removed in the future. I2S_COMM_FORMAT_I2S __attribute__((deprecated)) = 0x01, /*!< I2S communication format I2S, correspond to `I2S_COMM_FORMAT_STAND_I2S`*/ @@ -108,13 +108,14 @@ typedef enum { * @brief I2S channel format type */ typedef enum { - I2S_CHANNEL_FMT_RIGHT_LEFT = 0x00, - I2S_CHANNEL_FMT_ALL_RIGHT, - I2S_CHANNEL_FMT_ALL_LEFT, - I2S_CHANNEL_FMT_ONLY_RIGHT, - I2S_CHANNEL_FMT_ONLY_LEFT, + I2S_CHANNEL_FMT_RIGHT_LEFT, /*!< Separated left and right channel */ + I2S_CHANNEL_FMT_ALL_RIGHT, /*!< Load right channel data in both two channels */ + I2S_CHANNEL_FMT_ALL_LEFT, /*!< Load left channel data in both two channels */ + I2S_CHANNEL_FMT_ONLY_RIGHT, /*!< Only load data in right channel */ + I2S_CHANNEL_FMT_ONLY_LEFT, /*!< Only load data in left channel */ #if SOC_I2S_SUPPORTS_TDM - I2S_CHANNEL_FMT_TDM, // Up to 16 channels + // Multiple channels are available with TDM feature + I2S_CHANNEL_FMT_MULTIPLE, /*!< More than two channels are used */ #endif } i2s_channel_fmt_t; @@ -183,6 +184,15 @@ typedef enum { } i2s_pdm_dsr_t; #endif +#if SOC_I2S_SUPPORTS_PDM_TX +typedef enum { + I2S_PDM_SIG_SCALING_DIV_2 = 0, /*!< I2S TX PDM sigmadelta signal scaling: /2 */ + I2S_PDM_SIG_SCALING_MUL_1 = 1, /*!< I2S TX PDM sigmadelta signal scaling: x1 */ + I2S_PDM_SIG_SCALING_MUL_2 = 2, /*!< I2S TX PDM sigmadelta signal scaling: x2 */ + I2S_PDM_SIG_SCALING_MUL_4 = 3, /*!< I2S TX PDM sigmadelta signal scaling: x4 */ +} i2s_pdm_sig_scale_t; +#endif + /** * @brief PDM PCM convter enable/disable. * diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 1557305eef..cb25945ed5 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -111,12 +111,8 @@ #define SOC_I2S_NUM (1) #define SOC_I2S_SUPPORTS_PCM (1) #define SOC_I2S_SUPPORTS_PDM_TX (1) -#define SOC_I2S_SUPPORTS_PDM_RX (0) +#define SOC_I2S_SUPPORTS_PDM_CODEC (1) #define SOC_I2S_SUPPORTS_TDM (1) -#define SOC_I2S_APLL_MIN_FREQ (250000000) -#define SOC_I2S_APLL_MAX_FREQ (500000000) -#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware -#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated /*-------------------------- LEDC CAPS ---------------------------------------*/ #define SOC_LEDC_SUPPORT_XTAL_CLOCK (1) diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 40a4ecb249..9b7f87eebc 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -108,12 +108,8 @@ #define SOC_I2S_NUM (1) #define SOC_I2S_SUPPORTS_PCM (1) #define SOC_I2S_SUPPORTS_PDM_TX (1) -#define SOC_I2S_SUPPORTS_PDM_RX (0) +#define SOC_I2S_SUPPORTS_PDM_CODEC (1) #define SOC_I2S_SUPPORTS_TDM (1) -#define SOC_I2S_APLL_MIN_FREQ (250000000) -#define SOC_I2S_APLL_MAX_FREQ (500000000) -#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware -#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated /*-------------------------- LEDC CAPS ---------------------------------------*/ #define SOC_LEDC_SUPPORT_XTAL_CLOCK (1) diff --git a/components/soc/esp32s3/include/soc/i2s_struct.h b/components/soc/esp32s3/include/soc/i2s_struct.h index 1699ab9128..fc02adc0b8 100644 --- a/components/soc/esp32s3/include/soc/i2s_struct.h +++ b/components/soc/esp32s3/include/soc/i2s_struct.h @@ -319,7 +319,7 @@ typedef volatile struct { }; uint32_t val; } rx_eof_num; - uint32_t conf_signal_data; /*I2S signal data register*/ + uint32_t conf_single_data; /*the right channel or left channel put out constant value stored in this register according to tx_chan_mod and reg_tx_msb_right*/ union { struct { uint32_t tx_idle : 1; /*1: i2s_tx is idle state. 0: i2s_tx is working.*/ diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index f2fda6ab00..b3680c6bd8 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -67,6 +67,7 @@ #define SOC_I2S_SUPPORTS_PCM (1) #define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_RX (1) +#define SOC_I2S_SUPPORTS_PDM_CODEC (1) #define SOC_I2S_SUPPORTS_TDM (1) /*-------------------------- LEDC CAPS ---------------------------------------*/ diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index 55b9c883b3..73498c6d59 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -257,7 +257,7 @@ Example for general usage. i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver - I2S on {IDF_TARGET_NAME} support TDM mode, up to 16 channels are available in TDM mode. If you want to use TDM mode, set field ``channel_format`` of :cpp:type:`i2s_config_t` to ``I2S_CHANNEL_FMT_TDM``. Then enable the channels by setting ``tdm_chan_cfg.chan_mask`` using masks in :cpp:type:`i2s_channel_t`, the number of active channels and total channels will be calculate automatically. Also you can set a particular total channel number for it, but it shouldn't be smaller than the largest channel you use. + I2S on {IDF_TARGET_NAME} support TDM mode, up to 16 channels are available in TDM mode. If you want to use TDM mode, set field ``channel_format`` of :cpp:type:`i2s_config_t` to ``I2S_CHANNEL_FMT_MULTIPLE``. Then enable the channels by setting ``tdm_chan_cfg.chan_mask`` using masks in :cpp:type:`i2s_channel_t`, the number of active channels and total channels will be calculate automatically. Also you can set a particular total channel number for it, but it shouldn't be smaller than the largest channel you use. .. code-block:: c @@ -269,7 +269,7 @@ Example for general usage. .mode = I2S_MODE_MASTER | I2S_MODE_TX, .sample_rate = 44100, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, - .channel_format = I2S_CHANNEL_FMT_TDM, + .channel_format = I2S_CHANNEL_FMT_MULTIPLE, .communication_format = I2S_COMM_FORMAT_STAND_I2S .tx_desc_auto_clear = false, .dma_buf_count = 8, From f863998e90bc8636d374c101fd4a2dfac6894668 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 27 Jul 2021 15:54:31 +0800 Subject: [PATCH 5/5] driver/i2s: support mclk --- components/driver/i2s.c | 143 ++++++++++++-------- components/driver/include/driver/i2s.h | 87 +++++++----- components/driver/test/test_i2s.c | 2 + components/hal/CMakeLists.txt | 2 +- components/hal/esp32/include/hal/i2s_ll.h | 4 +- components/hal/esp32c3/include/hal/i2s_ll.h | 2 +- components/hal/esp32h2/include/hal/i2s_ll.h | 4 +- components/hal/esp32s2/include/hal/i2s_ll.h | 4 +- components/hal/i2s_hal.c | 42 ++---- components/hal/include/hal/i2s_hal.h | 71 +++++++++- components/hal/include/hal/i2s_types.h | 32 ++--- components/soc/esp32/i2s_periph.c | 14 +- components/soc/esp32c3/i2s_periph.c | 9 +- components/soc/esp32s2/i2s_periph.c | 5 +- components/soc/esp32s3/i2s_periph.c | 22 +-- components/soc/include/soc/i2s_periph.h | 1 + docs/en/api-reference/peripherals/i2s.rst | 24 +++- 17 files changed, 295 insertions(+), 173 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 36c4618d5b..f0dc634ac3 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -14,7 +14,6 @@ #include "freertos/semphr.h" #include "soc/lldesc.h" -#include "driver/periph_ctrl.h" #include "driver/gpio.h" #include "driver/i2s.h" #include "hal/gpio_hal.h" @@ -50,8 +49,6 @@ static const char *TAG = "I2S"; #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 I2S_MAX_BUFFER_SIZE (4*1024*1024) //the maximum RAM can be allocated - #if !SOC_GDMA_SUPPORTED #define I2S_INTR_IN_SUC_EOF BIT(9) #define I2S_INTR_OUT_EOF BIT(12) @@ -101,6 +98,8 @@ typedef struct { bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor on underflow */ bool use_apll; /*!< I2S use APLL clock */ int fixed_mclk; /*!< I2S fixed MLCK clock */ + i2s_mclk_multiple_t mclk_multiple; /*!< The multiple of I2S master clock(MCLK) to sample rate */ + #ifdef CONFIG_PM_ENABLE esp_pm_lock_handle_t pm_lock; #endif @@ -123,6 +122,7 @@ static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma); * I2S GPIO operation * * - gpio_matrix_out_check_and_set * * - gpio_matrix_in_check_and_set * + * - i2s_check_set_mclk * * - i2s_set_pin * **************************************************************/ static void gpio_matrix_out_check_and_set(int gpio, uint32_t signal_idx, bool out_inv, bool oen_inv) @@ -145,6 +145,34 @@ static void gpio_matrix_in_check_and_set(int gpio, uint32_t signal_idx, bool inv } } +static esp_err_t i2s_check_set_mclk(i2s_port_t i2s_num, gpio_num_t gpio_num) +{ + if (gpio_num == -1) { + return ESP_OK; + } +#if CONFIG_IDF_TARGET_ESP32 + ESP_RETURN_ON_FALSE((gpio_num == GPIO_NUM_0 || gpio_num == GPIO_NUM_1 || gpio_num == GPIO_NUM_3), + ESP_ERR_INVALID_ARG, TAG, + "ESP32 only support to set GPIO0/GPIO1/GPIO3 as mclk signal, error GPIO number:%d", gpio_num); + bool is_i2s0 = i2s_num == I2S_NUM_0; + if (gpio_num == GPIO_NUM_0) { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); + WRITE_PERI_REG(PIN_CTRL, is_i2s0 ? 0xFFF0 : 0xFFFF); + } else if (gpio_num == GPIO_NUM_1) { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_CLK_OUT3); + WRITE_PERI_REG(PIN_CTRL, is_i2s0 ? 0xF0F0 : 0xF0FF); + } else { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_CLK_OUT2); + WRITE_PERI_REG(PIN_CTRL, is_i2s0 ? 0xFF00 : 0xFF0F); + } +#else + ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "mck_io_num invalid"); + gpio_matrix_out_check_and_set(gpio_num, i2s_periph_signal[i2s_num].mck_out_sig, 0, 0); +#endif + ESP_LOGI(TAG, "I2S%d, MCLK output by GPIO%d", i2s_num, gpio_num); + return ESP_OK; +} + esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) { ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); @@ -155,22 +183,16 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) return ESP_ERR_INVALID_ARG; #endif } - if (pin->bck_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->bck_io_num)) { - ESP_LOGE(TAG, "bck_io_num error"); - return ESP_ERR_INVALID_ARG; - } - if (pin->ws_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->ws_io_num)) { - ESP_LOGE(TAG, "ws_io_num error"); - return ESP_ERR_INVALID_ARG; - } - if (pin->data_out_num != -1 && !GPIO_IS_VALID_OUTPUT_GPIO(pin->data_out_num)) { - ESP_LOGE(TAG, "data_out_num error"); - return ESP_ERR_INVALID_ARG; - } - if (pin->data_in_num != -1 && !GPIO_IS_VALID_GPIO(pin->data_in_num)) { - ESP_LOGE(TAG, "data_in_num error"); - return ESP_ERR_INVALID_ARG; - } + + ESP_RETURN_ON_FALSE((pin->bck_io_num == -1 || GPIO_IS_VALID_GPIO(pin->bck_io_num)), + ESP_ERR_INVALID_ARG, TAG, "bck_io_num invalid"); + ESP_RETURN_ON_FALSE((pin->ws_io_num == -1 || GPIO_IS_VALID_GPIO(pin->ws_io_num)), + ESP_ERR_INVALID_ARG, TAG, "ws_io_num invalid"); + ESP_RETURN_ON_FALSE((pin->data_out_num == -1 || GPIO_IS_VALID_GPIO(pin->data_out_num)), + ESP_ERR_INVALID_ARG, TAG, "data_out_num invalid"); + ESP_RETURN_ON_FALSE((pin->data_in_num == -1 || GPIO_IS_VALID_GPIO(pin->data_in_num)), + ESP_ERR_INVALID_ARG, TAG, "data_in_num invalid"); + if (p_i2s[i2s_num]->mode & I2S_MODE_SLAVE) { if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { gpio_matrix_in_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0); @@ -180,6 +202,7 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) gpio_matrix_in_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0); } } else { + ESP_RETURN_ON_ERROR(i2s_check_set_mclk(i2s_num, pin->mck_io_num), TAG, "mclk config failed"); if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { gpio_matrix_out_check_and_set(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0, 0); gpio_matrix_out_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0, 0); @@ -188,6 +211,7 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) gpio_matrix_out_check_and_set(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0, 0); } } + gpio_matrix_out_check_and_set(pin->data_out_num, i2s_periph_signal[i2s_num].data_out_sig, 0, 0); gpio_matrix_in_check_and_set(pin->data_in_num, i2s_periph_signal[i2s_num].data_in_sig, 0); return ESP_OK; @@ -730,7 +754,8 @@ static esp_err_t i2s_fbclk_cal(int i2s_num, uint32_t rate, int channel, int chan //Default select I2S_D2CLK (160M) uint32_t _sclk = I2S_LL_BASE_CLK; uint32_t _fbck = rate * channel * channel_bit; - uint32_t _bck_div = (256 % channel_bit) ? 12 : 8; + i2s_mclk_multiple_t multi = p_i2s[i2s_num]->mclk_multiple ? p_i2s[i2s_num]->mclk_multiple : I2S_MCLK_MULTIPLE_256; + uint32_t _bck_div = rate * multi / _fbck; i2s_clock_src_t clk_src = I2S_CLK_D2CLK; //ADC mode only support on ESP32, @@ -907,41 +932,43 @@ esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate) #if SOC_I2S_SUPPORTS_PCM esp_err_t i2s_pcm_config(i2s_port_t i2s_num, const i2s_pcm_cfg_t *pcm_cfg) { - ESP_RETURN_ON_FALSE(!p_i2s[i2s_num], ESP_FAIL, TAG, "i2s has not installed yet"); + ESP_RETURN_ON_FALSE(p_i2s[i2s_num], ESP_FAIL, TAG, "i2s has not installed yet"); ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->communication_format & I2S_COMM_FORMAT_STAND_PCM_SHORT), ESP_ERR_INVALID_ARG, TAG, "i2s communication mode is not PCM mode"); i2s_stop(i2s_num); - if (pcm_cfg->mode & I2S_MODE_TX) { + I2S_ENTER_CRITICAL(i2s_num); + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { i2s_hal_tx_pcm_cfg(&(p_i2s[i2s_num]->hal), pcm_cfg->pcm_type); - } else if(pcm_cfg->mode & I2S_MODE_RX) { + } else if(p_i2s[i2s_num]->mode & I2S_MODE_RX) { i2s_hal_rx_pcm_cfg(&(p_i2s[i2s_num]->hal), pcm_cfg->pcm_type); } + I2S_EXIT_CRITICAL(i2s_num); i2s_start(i2s_num); return ESP_OK; } #endif #if SOC_I2S_SUPPORTS_PDM_RX -esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr) +esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t downsample) { - ESP_RETURN_ON_FALSE(!p_i2s[i2s_num], ESP_FAIL, TAG, "i2s has not installed yet"); + ESP_RETURN_ON_FALSE(p_i2s[i2s_num], ESP_FAIL, TAG, "i2s has not installed yet"); ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->mode & I2S_MODE_PDM), ESP_ERR_INVALID_ARG, TAG, "i2s mode is not PDM mode"); i2s_stop(i2s_num); - i2s_hal_set_rx_pdm_dsr(&(p_i2s[i2s_num]->hal), dsr); + i2s_hal_set_rx_pdm_dsr(&(p_i2s[i2s_num]->hal), downsample); // i2s will start in 'i2s_set_clk' return i2s_set_clk(i2s_num, p_i2s[i2s_num]->sample_rate, p_i2s[i2s_num]->bits_per_sample, p_i2s[i2s_num]->channel_num); } #endif #if SOC_I2S_SUPPORTS_PDM_TX -esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, int sample_rate, int fp, int fs) +esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, const i2s_pdm_tx_upsample_cfg_t *upsample_cfg) { - ESP_RETURN_ON_FALSE(!p_i2s[i2s_num], ESP_FAIL, TAG, "i2s has not installed yet"); + ESP_RETURN_ON_FALSE(p_i2s[i2s_num], ESP_FAIL, TAG, "i2s has not installed yet"); ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->mode & I2S_MODE_PDM), ESP_ERR_INVALID_ARG, TAG, "i2s mode is not PDM mode"); i2s_stop(i2s_num); - i2s_hal_set_tx_pdm_fpfs(&(p_i2s[i2s_num]->hal), fp, fs); + i2s_hal_set_tx_pdm_fpfs(&(p_i2s[i2s_num]->hal), upsample_cfg->fp, upsample_cfg->fs); // i2s will start in 'i2s_set_clk' - return i2s_set_clk(i2s_num, sample_rate, p_i2s[i2s_num]->bits_per_sample, p_i2s[i2s_num]->channel_num); + return i2s_set_clk(i2s_num, upsample_cfg->sample_rate, p_i2s[i2s_num]->bits_per_sample, p_i2s[i2s_num]->channel_num); } #endif @@ -969,18 +996,29 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num) ESP_RETURN_ON_FALSE((i2s_check_cfg_static(i2s_num) == ESP_OK), ESP_ERR_INVALID_ARG, TAG, "param check error"); i2s_hal_config_t *cfg = &p_i2s[i2s_num]->hal_cfg; + p_i2s[i2s_num]->communication_format = cfg->comm_fmt; +#if SOC_I2S_SUPPORTS_ADC_DAC + if ((cfg->mode & I2S_MODE_DAC_BUILT_IN) || (cfg->mode & I2S_MODE_ADC_BUILT_IN)) { + if (cfg->mode & I2S_MODE_DAC_BUILT_IN) { + i2s_hal_enable_builtin_dac(&(p_i2s[i2s_num]->hal)); + } + if (cfg->mode & I2S_MODE_ADC_BUILT_IN) { + //in ADC built-in mode, we need to call i2s_set_adc_mode to + //initialize the specific ADC channel. + //in the current stage, we only support ADC1 and single channel mode. + //In default data mode, the ADC data is in 12-bit resolution mode. + adc_power_acquire(); + i2s_hal_enable_builtin_adc(&(p_i2s[i2s_num]->hal)); + } + } else { + i2s_hal_disable_builtin_dac(&(p_i2s[i2s_num]->hal)); + i2s_hal_disable_builtin_adc(&(p_i2s[i2s_num]->hal)); +#endif + // configure I2S data port interface. + i2s_hal_config_param(&(p_i2s[i2s_num]->hal), cfg); #if SOC_I2S_SUPPORTS_ADC_DAC - if (cfg->mode & I2S_MODE_ADC_BUILT_IN) { - //in ADC built-in mode, we need to call i2s_set_adc_mode to - //initialize the specific ADC channel. - //in the current stage, we only support ADC1 and single channel mode. - //In default data mode, the ADC data is in 12-bit resolution mode. - adc_power_acquire(); } #endif - p_i2s[i2s_num]->communication_format = cfg->comm_fmt; - // configure I2S data port interface. - i2s_hal_config_param(&(p_i2s[i2s_num]->hal), cfg); if ((p_i2s[i2s_num]->mode & I2S_MODE_RX) && (p_i2s[i2s_num]->mode & I2S_MODE_TX)) { i2s_hal_enable_sig_loopback(&(p_i2s[i2s_num]->hal)); if (p_i2s[i2s_num]->mode & I2S_MODE_MASTER) { @@ -1098,10 +1136,6 @@ esp_err_t i2s_start(i2s_port_t i2s_num) //start DMA link I2S_ENTER_CRITICAL(i2s_num); -#if !SOC_GDMA_SUPPORTED - esp_intr_disable(p_i2s[i2s_num]->i2s_isr_handle); - i2s_hal_clear_intr_status(&(p_i2s[i2s_num]->hal), I2S_INTR_MAX); -#endif if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { i2s_tx_reset(i2s_num); i2s_tx_start(i2s_num); @@ -1181,12 +1215,12 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, active_chan = 2; break; case I2S_CHANNEL_FMT_ONLY_RIGHT: - p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->left_align_en ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0; + p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->left_align ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0; p_i2s[i2s_num]->hal_cfg.total_chan = 1; active_chan = 1; break; case I2S_CHANNEL_FMT_ONLY_LEFT: - p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->left_align_en ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1; + p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->left_align ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1; p_i2s[i2s_num]->hal_cfg.total_chan = 1; active_chan = 1; break; @@ -1199,10 +1233,10 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, ESP_LOGE(TAG, "wrong i2s channel format, uninstalled i2s."); goto err; } - p_i2s[i2s_num]->hal_cfg.left_align_en = i2s_config->left_align_en; - p_i2s[i2s_num]->hal_cfg.big_edin_en = i2s_config->big_edin_en; - p_i2s[i2s_num]->hal_cfg.bit_order_msb_en = i2s_config->bit_order_msb_en; - p_i2s[i2s_num]->hal_cfg.skip_msk_en = i2s_config->skip_msk_en; + p_i2s[i2s_num]->hal_cfg.left_align = i2s_config->left_align; + p_i2s[i2s_num]->hal_cfg.big_edin = i2s_config->big_edin; + p_i2s[i2s_num]->hal_cfg.bit_order_msb = i2s_config->bit_order_msb; + p_i2s[i2s_num]->hal_cfg.skip_msk = i2s_config->skip_msk; #endif // Set I2S driver configurations @@ -1214,11 +1248,15 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, p_i2s[i2s_num]->bytes_per_sample = 0; // Not initialized yet p_i2s[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; p_i2s[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; + p_i2s[i2s_num]->mclk_multiple = i2s_config->mclk_multiple; #ifdef CONFIG_PM_ENABLE +#if SOC_I2S_SUPPORTS_APLL if (i2s_config->use_apll) { ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i2s_driver", &p_i2s[i2s_num]->pm_lock); - } else { + } else +#endif // SOC_I2S_SUPPORTS_APLL + { ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "i2s_driver", &p_i2s[i2s_num]->pm_lock); } if (ret != ESP_OK) { @@ -1264,7 +1302,7 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, ESP_GOTO_ON_ERROR(ret, err, TAG, "I2S param configure error"); if (i2s_queue) { p_i2s[i2s_num]->i2s_queue = xQueueCreate(queue_size, sizeof(i2s_event_t)); - ESP_GOTO_ON_ERROR(p_i2s[i2s_num]->i2s_queue, err, TAG, "I2S queue create failed"); + ESP_GOTO_ON_ERROR((p_i2s[i2s_num]->i2s_queue != NULL), err, TAG, "I2S queue create failed"); *((QueueHandle_t *) i2s_queue) = p_i2s[i2s_num]->i2s_queue; ESP_LOGI(TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_i2s[i2s_num]->i2s_queue)); } else { @@ -1359,7 +1397,6 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by size_t bytes_can_write; *bytes_written = 0; ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); - ESP_RETURN_ON_FALSE((size < I2S_MAX_BUFFER_SIZE), ESP_ERR_INVALID_ARG, TAG, "size is too large"); ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->tx), ESP_ERR_INVALID_ARG, TAG, "tx NULL"); xSemaphoreTake(p_i2s[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); #ifdef CONFIG_PM_ENABLE @@ -1402,7 +1439,6 @@ esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, siz *bytes_written = 0; ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); ESP_RETURN_ON_FALSE((size > 0), ESP_ERR_INVALID_ARG, TAG, "size must greater than zero"); - ESP_RETURN_ON_FALSE((aim_bits * size < I2S_MAX_BUFFER_SIZE), ESP_ERR_INVALID_ARG, TAG, "size is too large"); ESP_RETURN_ON_FALSE((aim_bits >= src_bits), ESP_ERR_INVALID_ARG, TAG, "aim_bits mustn't be less than src_bits"); ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->tx), ESP_ERR_INVALID_ARG, TAG, "tx NULL"); if (src_bits < I2S_BITS_PER_SAMPLE_8BIT || aim_bits < I2S_BITS_PER_SAMPLE_8BIT) { @@ -1465,7 +1501,6 @@ esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_re *bytes_read = 0; dest_byte = (char *)dest; ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); - ESP_RETURN_ON_FALSE((size < I2S_MAX_BUFFER_SIZE), ESP_ERR_INVALID_ARG, TAG, "size is too large"); ESP_RETURN_ON_FALSE((p_i2s[i2s_num]->rx), ESP_ERR_INVALID_ARG, TAG, "rx NULL"); xSemaphoreTake(p_i2s[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); #ifdef CONFIG_PM_ENABLE diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index c7185bf52a..3f6031ed26 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -14,6 +14,7 @@ #include "soc/rtc_periph.h" #include "soc/soc_caps.h" #include "hal/i2s_types.h" +#include "driver/periph_ctrl.h" #include "esp_intr_alloc.h" #if SOC_I2S_SUPPORTS_ADC_DAC @@ -37,28 +38,53 @@ typedef enum { I2S_NUM_MAX, /*!< I2S port max */ } i2s_port_t; -/** - * @brief I2S pin number for i2s_set_pin - * - */ -typedef struct { - int bck_io_num; /*!< BCK in out pin*/ - int ws_io_num; /*!< WS in out pin*/ - int data_out_num; /*!< DATA out pin*/ - int data_in_num; /*!< DATA in pin*/ -} i2s_pin_config_t; - #if SOC_I2S_SUPPORTS_PCM /** * @brief I2S PCM configuration * */ typedef struct { - i2s_mode_t mode; /*!< I2S mode. Usually only need to choose I2S_MODE_TX or I2S_MODE_RX */ i2s_pcm_compress_t pcm_type; /*!< I2S PCM a/u-law decompress or compress type */ } i2s_pcm_cfg_t; #endif +#if SOC_I2S_SUPPORTS_PDM_TX +/** + * @brief Default I2S PDM Up-Sampling Rate configuration + */ +#define I2S_PDM_DEFAULT_UPSAMPLE_CONFIG(rate) { \ + .sample_rate = rate, \ + .fp = 960, \ + .fs = (rate) / 100, \ + } + +/** + * @brief I2S PDM up-sample rate configuration + * @note TX PDM can only be set to the following two upsampling rate configurations: + * 1: fp = 960, fs = sample_rate / 100, in this case, Fpdm = 128*48000 + * 2: fp = 960, fs = 480, in this case, Fpdm = 128*Fpcm = 128*sample_rate + * If the pdm receiver do not care the pdm serial clock, it's recommended set Fpdm = 128*48000. + * Otherwise, the second configuration should be applied. + */ +typedef struct { + int sample_rate; /*!< I2S PDM sample rate */ + int fp; /*!< I2S PDM TX upsampling paramater. Normally it should be set to 960 */ + int fs; /*!< I2S PDM TX upsampling paramater. When it is set to 480, the pdm clock frequency Fpdm = 128 * sample_rate, when it is set to sample_rate / 100, Fpdm will be fixed to 128*48000 */ +} i2s_pdm_tx_upsample_cfg_t; +#endif + +/** + * @brief I2S pin number for i2s_set_pin + * + */ +typedef struct { + int mck_io_num; /*!< MCK in out pin*/ + int bck_io_num; /*!< BCK in out pin*/ + int ws_io_num; /*!< WS in out pin*/ + int data_out_num; /*!< DATA out pin*/ + int data_in_num; /*!< DATA in pin*/ +} i2s_pin_config_t; + /** * @brief I2S driver configuration parameters * @@ -75,16 +101,17 @@ typedef struct { int dma_buf_len; /*!< I2S DMA Buffer Length */ bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */ bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */ - int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/ + int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value. If fixed_mclk set, mclk_multiple won't take effect */ + i2s_mclk_multiple_t mclk_multiple; /*!< The multiple of I2S master clock(MCLK) to sample rate */ i2s_bits_per_chan_t bits_per_chan; /*!< I2S total bits in one channel, only take effect when larger than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */ #if SOC_I2S_SUPPORTS_TDM i2s_channel_t chan_mask; /*!< I2S active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<clkm_conf.clka_en = (src == 1) ? 1 : 0; + hw->clkm_conf.clka_en = (src == I2S_CLK_APLL) ? 1 : 0; } /** @@ -215,7 +215,7 @@ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { //0: disable APLL clock, I2S module will using PLL_D2_CLK(160M) as source clock //1: Enable APLL clock, I2S module will using APLL as source clock - hw->clkm_conf.clka_en = (src == 1) ? 1 : 0; + hw->clkm_conf.clka_en = (src == I2S_CLK_APLL) ? 1 : 0; } /** diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index 41a8c36d50..c67586aaf0 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -176,7 +176,7 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) * @brief Set RX source clock * * @param hw Peripheral I2S hardware instance address. - * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` + * @param src I2S source clock, ESP32-C3 only support `I2S_CLK_D2CLK` */ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index 4f933c78bd..a96c03c7c2 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -18,7 +18,7 @@ * See readme.md in soc/include/hal/readme.md ******************************************************************************/ -// The LL layer for ESP32-S3 I2S register operations +// The LL layer for ESP32-H2 I2S register operations #pragma once #include @@ -177,7 +177,7 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) * @brief Set RX source clock * * @param hw Peripheral I2S hardware instance address. - * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` + * @param src I2S source clock, ESP32-H2 only support `I2S_CLK_D2CLK` */ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index 91ba45e3f3..b0c4085ed8 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -200,7 +200,7 @@ static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) */ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { - hw->clkm_conf.clk_sel = (src == 1) ? 1 : 2; + hw->clkm_conf.clk_sel = (src == I2S_CLK_APLL) ? 1 : 2; } /** @@ -211,7 +211,7 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) */ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { - hw->clkm_conf.clk_sel = (src == 1) ? 1 : 2; + hw->clkm_conf.clk_sel = (src == I2S_CLK_APLL) ? 1 : 2; } /** diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index b7cbe45994..df0a24bf0e 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -102,7 +102,7 @@ void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num) i2s_ll_enable_clock(hal->dev); } -static void i2s_hal_tx_set_pdm_mode(i2s_hal_context_t *hal, uint32_t sample_rate) +void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rate) { #if SOC_I2S_SUPPORTS_PDM_TX /* enable pdm tx mode */ @@ -136,7 +136,7 @@ static void i2s_hal_tx_set_pdm_mode(i2s_hal_context_t *hal, uint32_t sample_rate #endif // SOC_I2S_SUPPORTS_PDM_TX } -static void i2s_hal_rx_set_pdm_mode(i2s_hal_context_t *hal) +void i2s_hal_rx_set_pdm_mode_default(i2s_hal_context_t *hal) { #if SOC_I2S_SUPPORTS_PDM_RX /* enable pdm rx mode */ @@ -147,7 +147,7 @@ static void i2s_hal_rx_set_pdm_mode(i2s_hal_context_t *hal) } -static void i2s_hal_tx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) +void i2s_hal_tx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) { /* disable pdm tx mode */ i2s_ll_tx_enable_pdm(hal->dev, false); @@ -158,10 +158,10 @@ static void i2s_hal_tx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_con i2s_ll_mclk_use_tx_clk(hal->dev); i2s_ll_tx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask); - i2s_ll_tx_enable_left_align(hal->dev, hal_cfg->left_align_en); - i2s_ll_tx_enable_big_endian(hal->dev, hal_cfg->big_edin_en); - i2s_ll_tx_set_bit_order(hal->dev, hal_cfg->bit_order_msb_en); - i2s_ll_tx_set_skip_mask(hal->dev, hal_cfg->skip_msk_en); + i2s_ll_tx_enable_left_align(hal->dev, hal_cfg->left_align); + i2s_ll_tx_enable_big_endian(hal->dev, hal_cfg->big_edin); + i2s_ll_tx_set_bit_order(hal->dev, hal_cfg->bit_order_msb); + i2s_ll_tx_set_skip_mask(hal->dev, hal_cfg->skip_msk); #else i2s_ll_tx_enable_msb_right(hal->dev, false); i2s_ll_tx_enable_right_first(hal->dev, false); @@ -169,7 +169,7 @@ static void i2s_hal_tx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_con #endif } -static void i2s_hal_rx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) +void i2s_hal_rx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) { /* disable pdm rx mode */ i2s_ll_rx_enable_pdm(hal->dev, false); @@ -180,9 +180,9 @@ static void i2s_hal_rx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_con i2s_ll_mclk_use_rx_clk(hal->dev); i2s_ll_rx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask); - i2s_ll_rx_enable_left_align(hal->dev, hal_cfg->left_align_en); - i2s_ll_rx_enable_big_endian(hal->dev, hal_cfg->big_edin_en); - i2s_ll_rx_set_bit_order(hal->dev, hal_cfg->bit_order_msb_en); + i2s_ll_rx_enable_left_align(hal->dev, hal_cfg->left_align); + i2s_ll_rx_enable_big_endian(hal->dev, hal_cfg->big_edin); + i2s_ll_rx_set_bit_order(hal->dev, hal_cfg->bit_order_msb); #else i2s_ll_rx_enable_msb_right(hal->dev, false); i2s_ll_rx_enable_right_first(hal->dev, false); @@ -251,29 +251,13 @@ void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) { -#if SOC_I2S_SUPPORTS_ADC_DAC - if ((hal_cfg->mode & I2S_MODE_DAC_BUILT_IN) || (hal_cfg->mode & I2S_MODE_ADC_BUILT_IN)) { - if (hal_cfg->mode & I2S_MODE_DAC_BUILT_IN) { - i2s_ll_enable_builtin_dac(hal->dev, true); - } - if (hal_cfg->mode & I2S_MODE_ADC_BUILT_IN) { - i2s_ll_enable_builtin_adc(hal->dev, true); - } - /* Use builtin ADC/DAC, return directly. */ - return; - } else { - i2s_ll_enable_builtin_dac(hal->dev, false); - i2s_ll_enable_builtin_adc(hal->dev, false); - } -#endif - if (hal_cfg->mode & I2S_MODE_TX) { i2s_ll_tx_stop(hal->dev); i2s_ll_tx_reset(hal->dev); i2s_ll_tx_set_slave_mod(hal->dev, (hal_cfg->mode & I2S_MODE_SLAVE) != 0); //TX Slave if (hal_cfg->mode & I2S_MODE_PDM) { /* Set tx pdm mode */ - i2s_hal_tx_set_pdm_mode(hal, hal_cfg->sample_rate); + i2s_hal_tx_set_pdm_mode_default(hal, hal_cfg->sample_rate); } else { /* Set tx common mode */ i2s_hal_tx_set_common_mode(hal, hal_cfg); @@ -286,7 +270,7 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf i2s_ll_rx_set_slave_mod(hal->dev, (hal_cfg->mode & I2S_MODE_SLAVE) != 0); //RX Slave if (hal_cfg->mode & I2S_MODE_PDM) { /* Set rx pdm mode */ - i2s_hal_rx_set_pdm_mode(hal); + i2s_hal_rx_set_pdm_mode_default(hal); } else { /* Set rx common mode */ i2s_hal_rx_set_common_mode(hal, hal_cfg); diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index ee5c32abc3..d0446f7a47 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -57,10 +57,10 @@ typedef struct { #if SOC_I2S_SUPPORTS_TDM uint32_t total_chan; /*!< Total number of I2S channels */ uint32_t chan_mask; /*!< Active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<dev, true) +/** + * @brief Set I2S configuration for common TX mode + * @note Common mode is for non-PDM mode like philip/MSB/PCM + * + * @param hal Context of the HAL layer + * @param hal_cfg hal configuration structure + */ +void i2s_hal_tx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg); + +/** + * @brief Set I2S configuration for common RX mode + * @note Common mode is for non-PDM mode like philip/MSB/PCM + * + * @param hal Context of the HAL layer + * @param hal_cfg hal configuration structure + */ +void i2s_hal_rx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg); + #if SOC_I2S_SUPPORTS_PDM_TX /** * @brief Configure I2S TX PDM sample rate @@ -281,6 +299,14 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * - fs configuration paramater */ #define i2s_hal_get_tx_pdm_fs(hal) i2s_ll_tx_get_pdm_fs((hal)->dev) + +/** + * @brief Set I2S default configuration for PDM TX mode + * + * @param hal Context of the HAL layer + * @param sample_rate PDM sample rate + */ +void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rate); #endif #if SOC_I2S_SUPPORTS_PDM_RX @@ -300,6 +326,13 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @param dsr Pointer to accept PDM downsample configuration */ #define i2s_hal_get_rx_pdm_dsr(hal, dsr) i2s_ll_rx_get_pdm_dsr((hal)->dev, dsr) + +/** + * @brief Set I2S default configuration for PDM R mode + * + * @param hal Context of the HAL layer + */ +void i2s_hal_rx_set_pdm_mode_default(i2s_hal_context_t *hal); #endif #if !SOC_GDMA_SUPPORTED @@ -437,6 +470,36 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc #define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_rx_get_eof_des_addr((hal)->dev, addr) #endif +#if SOC_I2S_SUPPORTS_ADC_DAC +/** + * @brief Enable Builtin DAC + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_enable_builtin_dac(hal) i2s_ll_enable_builtin_dac((hal)->dev, true); + +/** + * @brief Enable Builtin ADC + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_enable_builtin_adc(hal) i2s_ll_enable_builtin_adc((hal)->dev, true); + +/** + * @brief Disable Builtin DAC + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_disable_builtin_dac(hal) i2s_ll_enable_builtin_dac((hal)->dev, false); + +/** + * @brief Disable Builtin ADC + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_disable_builtin_adc(hal) i2s_ll_enable_builtin_adc((hal)->dev, false); +#endif + #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index a42ad40d05..630aedb149 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -52,16 +52,12 @@ typedef enum { * */ typedef enum { - // I2S_CHANNEL_MONO and I2S_CHANNEL_STEREO values are changed to be compatible with TDM mode - // The lower 16 bits is for enabling specific channels - // The highest bit in I2S_CHANNEL_MONO is for differentiating I2S_CHANNEL_MONO and I2S_CHANNEL_STEREO because they both use two channels - // Two channels will transmit same data in I2S_CHANNEL_MONO mode, and different data in I2S_CHANNEL_STEREO mode - I2S_CHANNEL_MONO = (0x01 << 31) | 0x03, /*!< I2S channel (mono), two channel enabled */ - I2S_CHANNEL_STEREO = 0x03, /*!< I2S channel (stereo), two channel enabled */ + I2S_CHANNEL_MONO = (0x01 << 31) | 0x03, /*!< I2S channel (mono), two channel enabled. In this mode, you only need to send one channel data but the fifo will copy same data for another channel automatically, then both channels will transmit same data. The highest bit is for differentiating I2S_CHANNEL_STEREO since they both use two channels */ + I2S_CHANNEL_STEREO = 0x03, /*!< I2S channel (stereo), two channel enabled. In this mode, two channels will transmit different data. */ #if SOC_I2S_SUPPORTS_TDM // Bit map of active chan. // There are 16 channels in TDM mode. - // For TX module, only the active channel send the audio data, the inactive channel send a constant(configurable) or will be skiped if 'skip_msk_en' in 'i2s_hal_tdm_flags_t' is set. + // For TX module, only the active channel send the audio data, the inactive channel send a constant(configurable) or will be skiped if 'skip_msk' is set. // For RX module, only receive the audio data in active channels, the data in inactive channels will be ignored. // the bit map of active channel can not exceed (0x1< *I2S Controller (I2S)* > LCD Mode [`PDF <{IDF_TARGET_TRM_EN_URL}#camlcdctrl>`__]. -.. note:: +.. only:: SOC_I2S_SUPPORTS_APLL - For high accuracy clock applications, use the APLL_CLK clock source, which has the frequency range of 16 ~ 128 MHz. You can enable the APLL_CLK clock source by setting :cpp:member:`i2s_config_t::use_apll` to ``TRUE``. + .. note:: - If :cpp:member:`i2s_config_t::use_apll` = ``TRUE`` and :cpp:member:`i2s_config_t::fixed_mclk` > ``0``, then the master clock output frequency for I2S will be equal to the value of :cpp:member:`i2s_config_t::fixed_mclk`, which means that the mclk frequency is provided by the user, instead of being calculated by the driver. + For high accuracy clock applications, use the APLL_CLK clock source, which has the frequency range of 16 ~ 128 MHz. You can enable the APLL_CLK clock source by setting :cpp:member:`i2s_config_t::use_apll` to ``TRUE``. - The clock rate of the word select line, which is called audio left-right clock rate (LRCK) here, is always the divisor of the master clock output frequency and for which the following is always true: 0 < MCLK/LRCK/channels/bits_per_sample < 64. + If :cpp:member:`i2s_config_t::use_apll` = ``TRUE`` and :cpp:member:`i2s_config_t::fixed_mclk` > ``0``, then the master clock output frequency for I2S will be equal to the value of :cpp:member:`i2s_config_t::fixed_mclk`, which means that the mclk frequency is provided by the user, instead of being calculated by the driver. + + The clock rate of the word select line, which is called audio left-right clock rate (LRCK) here, is always the divisor of the master clock output frequency and for which the following is always true: 0 < MCLK/LRCK/channels/bits_per_sample < 64. Functional Overview @@ -60,7 +63,7 @@ Install the I2S driver by calling the function :cpp:func`i2s_driver_install` and - The structure :cpp:type:`i2s_config_t` with defined communication parameters - Event queue size and handle -I2S will start automatically once :cpp:func`i2s_driver_install` returns ``ESP_OK``. +Once :cpp:func`i2s_driver_install` returns ``ESP_OK``, it means I2S has started. Configuration example: @@ -111,11 +114,16 @@ Setting Communication Pins Once the driver is installed, configure physical GPIO pins to which signals will be routed. For this, call the function :cpp:func`i2s_set_pin` and pass the following arguments to it: - Port number -- The structure :cpp:type:`i2s_pin_config_t` defining the GPIO pin numbers to which the driver should route the BCK, WS, DATA out, and DATA in signals. If you want to keep a currently allocated pin number for a specific signal, or if this signal is unused, then pass the macro :c:macro:`I2S_PIN_NO_CHANGE`. See the example below. +- The structure :cpp:type:`i2s_pin_config_t` defining the GPIO pin numbers to which the driver should route the MCK, BCK, WS, DATA out, and DATA in signals. If you want to keep a currently allocated pin number for a specific signal, or if this signal is unused, then pass the macro :c:macro:`I2S_PIN_NO_CHANGE`. See the example below. + +.. note:: + + MCK only takes effect in `I2S_MODE_MASTER` mode. .. code-block:: c static const i2s_pin_config_t pin_config = { + .mck_io_num = 0, .bck_io_num = 4, .ws_io_num = 5, .data_out_num = 18, @@ -257,7 +265,9 @@ Example for general usage. i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver - I2S on {IDF_TARGET_NAME} support TDM mode, up to 16 channels are available in TDM mode. If you want to use TDM mode, set field ``channel_format`` of :cpp:type:`i2s_config_t` to ``I2S_CHANNEL_FMT_MULTIPLE``. Then enable the channels by setting ``tdm_chan_cfg.chan_mask`` using masks in :cpp:type:`i2s_channel_t`, the number of active channels and total channels will be calculate automatically. Also you can set a particular total channel number for it, but it shouldn't be smaller than the largest channel you use. + I2S on {IDF_TARGET_NAME} support TDM mode, up to 16 channels are available in TDM mode. If you want to use TDM mode, set field ``channel_format`` of :cpp:type:`i2s_config_t` to ``I2S_CHANNEL_FMT_MULTIPLE``. Then enable the channels by setting ``chan_mask`` using masks in :cpp:type:`i2s_channel_t`, the number of active channels and total channels will be calculate automatically. Also you can set a particular total channel number for it, but it shouldn't be smaller than the largest channel you use. + + If active channels are discrete, the inactive channels within total channels will be filled by a constant automatically. But if ``skip_msk`` is enabled, these inactive channels will be skiped. .. code-block:: c