From f7f8c9c11fa7caeb51b3d728897f69b81fde79cc Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 15 Jun 2021 15:43:03 +0800 Subject: [PATCH] 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,