diff --git a/components/driver/i2s.c b/components/driver/i2s.c index be3e90b3b7..48fbb5740f 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -53,6 +53,7 @@ static const char* I2S_TAG = "I2S"; #define I2S_AD_BCK_FACTOR (2) #define I2S_PDM_BCK_FACTOR (64) #define I2S_BASE_CLK (2*APB_CLK_FREQ) +#define I2S_MAX_BUFFER_SIZE (4*1024*1024) //the maximum RAM can be allocated /** * @brief DMA buffer object @@ -84,12 +85,12 @@ typedef struct { int channel_num; /*!< Number of channels*/ int bytes_per_sample; /*!< Bytes per sample*/ int bits_per_sample; /*!< Bits per sample*/ + i2s_comm_format_t communication_format; /*!hal)); + i2s_hal_reset_txdma(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_reset_tx_fifo(&(p_i2s_obj[i2s_num]->hal)); +} + +static void i2s_rx_reset(i2s_port_t i2s_num) +{ + // Reset I2S RX module first, and then, reset DMA and FIFO. + i2s_hal_reset_rx(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_reset_rxdma(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_reset_rx_fifo(&(p_i2s_obj[i2s_num]->hal)); +} + +#if SOC_I2S_SUPPORTS_PCM +esp_err_t i2s_pcm_config(i2s_port_t i2s_num, int mode, i2s_pcm_cfg_t pcm_cfg) +{ + if (mode & I2S_MODE_TX) { + i2s_hal_tx_pcm_cfg(&(p_i2s_obj[i2s_num]->hal), pcm_cfg); + } else if(mode & I2S_MODE_RX) { + i2s_hal_rx_pcm_cfg(&(p_i2s_obj[i2s_num]->hal), pcm_cfg); + } + return ESP_OK; +} +#endif + +uint32_t i2s_get_clk(i2s_port_t i2s_num) { I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - i2s_hal_clear_intr_status(&(p_i2s_obj[i2s_num]->hal), clr_mask); - return ESP_OK; -} - -esp_err_t i2s_enable_rx_intr(i2s_port_t i2s_num) -{ - - I2S_ENTER_CRITICAL(); - i2s_hal_enable_rx_intr(&(p_i2s_obj[i2s_num]->hal)); - I2S_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t i2s_disable_rx_intr(i2s_port_t i2s_num) -{ - I2S_ENTER_CRITICAL(); - i2s_hal_disable_rx_intr(&(p_i2s_obj[i2s_num]->hal)); - I2S_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t i2s_disable_tx_intr(i2s_port_t i2s_num) -{ - I2S_ENTER_CRITICAL(); - i2s_hal_disable_tx_intr(&(p_i2s_obj[i2s_num]->hal)); - I2S_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num) -{ - I2S_ENTER_CRITICAL(); - i2s_hal_enable_tx_intr(&(p_i2s_obj[i2s_num]->hal)); - I2S_EXIT_CRITICAL(); - return ESP_OK; -} - -float i2s_get_clk(i2s_port_t i2s_num) -{ - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - return p_i2s_obj[i2s_num]->real_rate; + return p_i2s_obj[i2s_num]->sample_rate; } static esp_err_t i2s_isr_register(i2s_port_t i2s_num, int intr_alloc_flags, void (*fn)(void*), void * arg, i2s_isr_handle_t *handle) @@ -178,6 +167,7 @@ static esp_err_t i2s_isr_register(i2s_port_t i2s_num, int intr_alloc_flags, void return esp_intr_alloc(i2s_periph_signal[i2s_num].irq, intr_alloc_flags, fn, arg, handle); } +#if SOC_I2S_SUPPORTS_APLL static float i2s_apll_get_fi2s(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir) { int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000; @@ -298,34 +288,146 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm return ESP_OK; } +#endif -esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch) +static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, int data_bits, int ch) { - int factor = (256%bits)? 384 : 256; // According to hardware codec requirement(supported 256fs or 384fs) - int clkmInteger, clkmDecimals, bck = 0; - double denom = (double)1 / 64; - int channel = 2; + if (p_i2s_obj[i2s_num]->channel_num != ch) { + p_i2s_obj[i2s_num]->channel_num = (ch == 2) ? 2 : 1; + } + i2s_dma_t *save_tx = NULL, *save_rx = NULL; - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + if (data_bits != p_i2s_obj[i2s_num]->bits_per_sample) { + p_i2s_obj[i2s_num]->bits_per_sample = data_bits; - if (bits % 8 != 0 || bits > I2S_BITS_PER_SAMPLE_32BIT || bits < I2S_BITS_PER_SAMPLE_16BIT) { + // Round bytes_per_sample up to next multiple of 16 bits + int halfwords_per_sample = (data_bits + 15) / 16; + p_i2s_obj[i2s_num]->bytes_per_sample = halfwords_per_sample * 2; + + // Because limited of DMA buffer is 4092 bytes + if (p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num > 4092) { + p_i2s_obj[i2s_num]->dma_buf_len = 4092 / p_i2s_obj[i2s_num]->bytes_per_sample / p_i2s_obj[i2s_num]->channel_num; + } + + // Re-create TX DMA buffer + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + save_tx = p_i2s_obj[i2s_num]->tx; + p_i2s_obj[i2s_num]->tx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); + if (p_i2s_obj[i2s_num]->tx == NULL) { + ESP_LOGE(I2S_TAG, "Failed to create tx dma buffer"); + i2s_driver_uninstall(i2s_num); + return ESP_ERR_NO_MEM; + } + + //destroy old tx dma if exist + if (save_tx) { + i2s_destroy_dma_queue(i2s_num, save_tx); + } + } + + // Re-create RX DMA buffer + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + save_rx = p_i2s_obj[i2s_num]->rx; + p_i2s_obj[i2s_num]->rx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); + if (p_i2s_obj[i2s_num]->rx == NULL){ + ESP_LOGE(I2S_TAG, "Failed to create rx dma buffer"); + i2s_driver_uninstall(i2s_num); + return ESP_ERR_NO_MEM; + } + i2s_hal_set_rx_eof_num(&(p_i2s_obj[i2s_num]->hal), p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample); + //destroy old rx dma if exist + if (save_rx) { + i2s_destroy_dma_queue(i2s_num, save_rx); + } + } + } + return ESP_OK; +} + +static esp_err_t i2s_fbclk_cal(int i2s_num, uint32_t rate, int channel, int channel_bit, uint32_t *sclk, uint32_t *fbck, uint32_t *bck_div) +{ + //Default select I2S_D2CLK (160M) + uint32_t _sclk = I2S_BASE_CLK; + uint32_t _fbck = rate * channel * channel_bit; + uint32_t _bck_div = (256%channel_bit)? 12 : 8; + i2s_clock_src_t clk_src = I2S_CLK_D2CLK; + +//ADC mode only support on ESP32, +#if SOC_I2S_SUPPORTS_ADC_DAC + if ( p_i2s_obj[i2s_num]->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { + _fbck = rate * I2S_AD_BCK_FACTOR * 2; + _bck_div = I2S_AD_BCK_FACTOR; + } +#endif + +#if SOC_I2S_SUPPORTS_PDM + if ( p_i2s_obj[i2s_num]->mode & I2S_MODE_PDM) { +#if SOC_I2S_SUPPORTS_PDM_TX + if ( p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + int fp = 1; + int fs = 1; + i2s_hal_get_tx_pdm_fpfs(&(p_i2s_obj[i2s_num]->hal), &fp, &fs); + _fbck = rate * I2S_PDM_BCK_FACTOR * fp / fs; + } +#endif +#if SOC_I2S_SUPPORTS_PDM_RX + if ( p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + i2s_pdm_dsr_t dsr; + i2s_hal_get_rx_pdm_dsr(&(p_i2s_obj[i2s_num]->hal), &dsr); + _fbck = rate * I2S_PDM_BCK_FACTOR * (dsr == I2S_PDM_DSR_16S ? 2 : 1); + } +#endif + _bck_div = 8; + } +#endif + +#if SOC_I2S_SUPPORTS_APLL + int sdm0 = 0; + int sdm1 = 0; + int sdm2 = 0; + int odir = 0; + //If APLL is specified, try to calculate in APLL + if (p_i2s_obj[i2s_num]->use_apll && i2s_apll_calculate_fi2s(p_i2s_obj[i2s_num]->fixed_mclk, channel_bit, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) { + _sclk = p_i2s_obj[i2s_num]->fixed_mclk; + clk_src = I2S_CLK_APLL; + ESP_LOGD(I2S_TAG, "sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); + rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, odir); + } +#endif + if ((_fbck * _bck_div) > _sclk) { + ESP_LOGE(I2S_TAG, "sample rate is too large\r\n"); + return ESP_ERR_INVALID_ARG; + } + i2s_hal_set_clock_src(&(p_i2s_obj[i2s_num]->hal), clk_src); + *sclk = _sclk; + *fbck = _fbck; + *bck_div = _bck_div; + return ESP_OK; +} + +/* + 1. stop i2s; + 2. calculate mclk, bck, bck_factor + 3. malloc dma buffer; + 4. start i2s +*/ +esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_slot_bits_cfg_t slot_bit_cfg, i2s_slot_channel_cfg_t slot_ch_cfg) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_ARG); + + int data_bits = slot_bit_cfg & 0xffff; + int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT; + int active_slot_num = slot_ch_cfg & 0xffff; + int slot_num = (slot_ch_cfg >> SLOT_CH_SHIFT) == 0 ? ((active_slot_num == I2S_CHANNEL_MONO)) ? 2 : active_slot_num : (slot_ch_cfg >> SLOT_CH_SHIFT); + + if ((data_bits % 8 != 0) || (data_bits > I2S_BITS_PER_SAMPLE_32BIT)) { ESP_LOGE(I2S_TAG, "Invalid bits per sample"); return ESP_ERR_INVALID_ARG; } - - if (p_i2s_obj[i2s_num] == NULL) { - ESP_LOGE(I2S_TAG, "Not initialized yet"); - return ESP_ERR_INVALID_ARG; - } - p_i2s_obj[i2s_num]->sample_rate = rate; - double clkmdiv = (double)I2S_BASE_CLK / (rate * factor); - - if (clkmdiv > 256) { - ESP_LOGE(I2S_TAG, "clkmdiv is too large\r\n"); - return ESP_ERR_INVALID_ARG; - } - + //Stop I2S + i2s_stop(i2s_num); // wait all on-going writing finish if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) && p_i2s_obj[i2s_num]->tx) { xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); @@ -333,162 +435,41 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && p_i2s_obj[i2s_num]->rx) { xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); } - - i2s_stop(i2s_num); -#if SOC_I2S_SUPPORTS_ADC_DAC - /* I2S-ADC only support single channel format. */ - if (!(p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN)) { - i2s_hal_set_rx_mode(&(p_i2s_obj[i2s_num]->hal), ch, bits); - } -#else - i2s_hal_set_rx_mode(&(p_i2s_obj[i2s_num]->hal), ch, bits); -#endif - i2s_hal_set_tx_mode(&(p_i2s_obj[i2s_num]->hal), ch, bits); - - if (p_i2s_obj[i2s_num]->channel_num != (int)ch) { - p_i2s_obj[i2s_num]->channel_num = (ch == 2) ? 2 : 1; + //malloc DMA buffer + if (i2s_alloc_dma_buffer(i2s_num, data_bits, active_slot_num) != ESP_OK ) { + return ESP_ERR_NO_MEM; } - if ((int)bits != p_i2s_obj[i2s_num]->bits_per_sample) { - p_i2s_obj[i2s_num]->bits_per_sample = bits; - - // Round bytes_per_sample up to next multiple of 16 bits - int halfwords_per_sample = (bits + 15) / 16; - p_i2s_obj[i2s_num]->bytes_per_sample = halfwords_per_sample * 2; - - // Because limited of DMA buffer is 4092 bytes - if (p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num > 4092) { - p_i2s_obj[i2s_num]->dma_buf_len = 4092 / p_i2s_obj[i2s_num]->bytes_per_sample / p_i2s_obj[i2s_num]->channel_num; - } - // Re-create TX DMA buffer - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - - save_tx = p_i2s_obj[i2s_num]->tx; - - p_i2s_obj[i2s_num]->tx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); - if (p_i2s_obj[i2s_num]->tx == NULL) { - ESP_LOGE(I2S_TAG, "Failed to create tx dma buffer"); - i2s_driver_uninstall(i2s_num); - return ESP_ERR_NO_MEM; - } - i2s_hal_set_out_link_addr(&(p_i2s_obj[i2s_num]->hal), (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0]); - - //destroy old tx dma if exist - if (save_tx) { - i2s_destroy_dma_queue(i2s_num, save_tx); - } - } - // Re-create RX DMA buffer - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - - save_rx = p_i2s_obj[i2s_num]->rx; - - p_i2s_obj[i2s_num]->rx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); - if (p_i2s_obj[i2s_num]->rx == NULL){ - ESP_LOGE(I2S_TAG, "Failed to create rx dma buffer"); - i2s_driver_uninstall(i2s_num); - return ESP_ERR_NO_MEM; - } - i2s_hal_set_in_link(&(p_i2s_obj[i2s_num]->hal), p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample, (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0]); - //destroy old rx dma if exist - if (save_rx) { - i2s_destroy_dma_queue(i2s_num, save_rx); - } - } - - } - - double mclk; - int sdm0, sdm1, sdm2, odir, m_scale = 8; - int fi2s_clk = rate*channel*bits*m_scale; -#if SOC_I2S_SUPPORTS_ADC_DAC - if (p_i2s_obj[i2s_num]->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { - - //DAC uses bclk as sample clock, not WS. WS can be something arbitrary. - //Rate as given to this function is the intended sample rate; - //According to the TRM, WS clk equals to the sample rate, and bclk is double the speed of WS - uint32_t b_clk = rate * I2S_AD_BCK_FACTOR; - fi2s_clk /= I2S_AD_BCK_FACTOR; - int factor2 = 60; - mclk = b_clk * factor2; - clkmdiv = ((double) I2S_BASE_CLK) / mclk; - clkmInteger = clkmdiv; - clkmDecimals = (clkmdiv - clkmInteger) / denom; - bck = mclk / b_clk; -#endif -#if SOC_I2S_SUPPORTS_PDM - } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_PDM) { - uint32_t b_clk = 0; - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - uint32_t fp, fs; - i2s_hal_get_tx_pdm(&(p_i2s_obj[i2s_num]->hal), &fp, &fs); - // Recommended set `fp = 960, fs = sample_rate / 100` - fs = rate / 100; - i2s_hal_tx_pdm_cfg(&(p_i2s_obj[i2s_num]->hal), fp, fs); - b_clk = rate * I2S_PDM_BCK_FACTOR * fp / fs; - - } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - uint32_t dsr; - i2s_hal_get_rx_pdm(&(p_i2s_obj[i2s_num]->hal), &dsr); - b_clk = rate * I2S_PDM_BCK_FACTOR * (dsr ? 2 : 1); - } - fi2s_clk = b_clk * m_scale; - int factor2 = 5 ; - mclk = b_clk * factor2; - clkmdiv = ((double) I2S_BASE_CLK) / mclk; - clkmInteger = clkmdiv; - clkmDecimals = (clkmdiv - clkmInteger) / denom; - bck = mclk / b_clk; - } else -#endif - { - clkmInteger = clkmdiv; - clkmDecimals = (clkmdiv - clkmInteger) / denom; - mclk = clkmInteger + denom * clkmDecimals; - bck = factor/(bits * channel); - } - - if(p_i2s_obj[i2s_num]->use_apll && p_i2s_obj[i2s_num]->fixed_mclk) { - fi2s_clk = p_i2s_obj[i2s_num]->fixed_mclk; - m_scale = fi2s_clk/bits/rate/channel; - } - if(p_i2s_obj[i2s_num]->use_apll && i2s_apll_calculate_fi2s(fi2s_clk, bits, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) { - ESP_LOGD(I2S_TAG, "sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); - rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, odir); - i2s_hal_set_clk_div(&(p_i2s_obj[i2s_num]->hal), 1, 1, 0, m_scale, m_scale); - i2s_hal_set_clock_sel(&(p_i2s_obj[i2s_num]->hal), I2S_CLK_APLL); - double fi2s_rate = i2s_apll_get_fi2s(bits, sdm0, sdm1, sdm2, odir); - p_i2s_obj[i2s_num]->real_rate = fi2s_rate/bits/channel/m_scale; - ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK_M: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", - rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/8, 1, 0); - } else { - i2s_hal_set_clock_sel(&(p_i2s_obj[i2s_num]->hal), I2S_CLK_D2CLK); - i2s_hal_set_clk_div(&(p_i2s_obj[i2s_num]->hal), clkmInteger, 63, clkmDecimals, bck, bck); - double real_rate = (double) (I2S_BASE_CLK / (bck * bits * clkmInteger) / 2); - p_i2s_obj[i2s_num]->real_rate = real_rate; - ESP_LOGI(I2S_TAG, "PLL_D2: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", - rate, real_rate, bits, clkmInteger, bck, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 64, clkmDecimals); + uint32_t i2s_clk = 0; // I2S source clock + uint32_t i2s_bck = 0; // I2S back clock + uint32_t bck_div = 0; // I2S bck div + //calculate bck_div, f_bck and select source clock + if (i2s_fbclk_cal(i2s_num, rate, slot_num, slot_bits, &i2s_clk, &i2s_bck, &bck_div) != ESP_OK) { + return ESP_FAIL; } + //configure i2s clock if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - p_i2s_obj[i2s_num]->tx->curr_ptr = NULL; - p_i2s_obj[i2s_num]->tx->rw_pos = 0; + i2s_hal_tx_clock_config(&(p_i2s_obj[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); + i2s_hal_set_tx_sample_bit(&(p_i2s_obj[i2s_num]->hal), slot_bits, data_bits); + // wait all writing on-going finish + if (p_i2s_obj[i2s_num]->tx) { + xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux); + } } if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - p_i2s_obj[i2s_num]->rx->curr_ptr = NULL; - p_i2s_obj[i2s_num]->rx->rw_pos = 0; - } - - i2s_hal_set_tx_bits_mod(&(p_i2s_obj[i2s_num]->hal), bits); - i2s_hal_set_rx_bits_mod(&(p_i2s_obj[i2s_num]->hal), bits); - - // wait all writing on-going finish - if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) && p_i2s_obj[i2s_num]->tx) { - xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux); - } - if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && p_i2s_obj[i2s_num]->rx) { - xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux); + i2s_hal_rx_clock_config(&(p_i2s_obj[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); + i2s_hal_set_rx_sample_bit(&(p_i2s_obj[i2s_num]->hal), slot_bits, data_bits); + // wait all writing on-going finish + if (p_i2s_obj[i2s_num]->rx) { + xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux); + } } + i2s_slot_bits_cfg_t i2s_slot_bits_cfg = (slot_bits << SLOT_BIT_SHIFT) | data_bits; + i2s_slot_channel_cfg_t i2s_slot_channel_cfg = (slot_num << SLOT_CH_SHIFT) | active_slot_num; + i2s_hal_samples_config(&(p_i2s_obj[i2s_num]->hal), p_i2s_obj[i2s_num]->mode, p_i2s_obj[i2s_num]->communication_format, i2s_slot_bits_cfg, i2s_slot_channel_cfg); + //I2S start i2s_start(i2s_num); + p_i2s_obj[i2s_num]->sample_rate = rate; return ESP_OK; } @@ -504,11 +485,8 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) i2s_event_t i2s_event; int dummy; - portBASE_TYPE high_priority_task_awoken = 0; - - lldesc_t *finish_desc = NULL; - + uint32_t finish_desc = 0; if ((status & I2S_INTR_OUT_DSCR_ERR) || (status & I2S_INTR_IN_DSCR_ERR)) { ESP_EARLY_LOGE(I2S_TAG, "dma error, interrupt status: 0x%08x", status); if (p_i2s->i2s_queue) { @@ -521,7 +499,7 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) } if ((status & I2S_INTR_OUT_EOF) && p_i2s->tx) { - i2s_hal_get_out_eof_des_addr(&(p_i2s->hal), (uint32_t *)&finish_desc); + i2s_hal_get_out_eof_des_addr(&(p_i2s->hal), &finish_desc); // All buffers are empty. This means we have an underflow on our hands. if (xQueueIsQueueFullFromISR(p_i2s->tx->queue)) { xQueueReceiveFromISR(p_i2s->tx->queue, &dummy, &high_priority_task_awoken); @@ -532,7 +510,7 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) memset((void *) dummy, 0, p_i2s->tx->buf_size); } } - xQueueSendFromISR(p_i2s->tx->queue, (void*)(&finish_desc->buf), &high_priority_task_awoken); + xQueueSendFromISR(p_i2s->tx->queue, &(((lldesc_t *)finish_desc)->buf), &high_priority_task_awoken); if (p_i2s->i2s_queue) { i2s_event.type = I2S_EVENT_TX_DONE; if (xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) { @@ -544,11 +522,11 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) if ((status & I2S_INTR_IN_SUC_EOF) && p_i2s->rx) { // All buffers are full. This means we have an overflow. - i2s_hal_get_in_eof_des_addr(&(p_i2s->hal), (uint32_t *)&finish_desc); + i2s_hal_get_in_eof_des_addr(&(p_i2s->hal), &finish_desc); if (xQueueIsQueueFullFromISR(p_i2s->rx->queue)) { xQueueReceiveFromISR(p_i2s->rx->queue, &dummy, &high_priority_task_awoken); } - xQueueSendFromISR(p_i2s->rx->queue, (void*)(&finish_desc->buf), &high_priority_task_awoken); + xQueueSendFromISR(p_i2s->rx->queue, &(((lldesc_t *)finish_desc)->buf), &high_priority_task_awoken); if (p_i2s->i2s_queue) { i2s_event.type = I2S_EVENT_RX_DONE; if (p_i2s->i2s_queue && xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) { @@ -638,7 +616,6 @@ static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, in return NULL; } } - for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) { dma->desc[bux_idx]->owner = 1; dma->desc[bux_idx]->eof = 1; @@ -661,16 +638,27 @@ esp_err_t i2s_start(i2s_port_t i2s_num) I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); //start DMA link I2S_ENTER_CRITICAL(); - i2s_hal_reset(&(p_i2s_obj[i2s_num]->hal)); esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle); i2s_hal_clear_intr_status(&(p_i2s_obj[i2s_num]->hal), I2S_INTR_MAX); if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - i2s_enable_tx_intr(i2s_num); + p_i2s_obj[i2s_num]->tx->curr_ptr = NULL; + p_i2s_obj[i2s_num]->tx->rw_pos = 0; + //attach DMA + i2s_hal_attach_tx_dma(&(p_i2s_obj[i2s_num]->hal)); + i2s_tx_reset(i2s_num); + i2s_hal_enable_tx_intr(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_start_tx_link(&(p_i2s_obj[i2s_num]->hal), (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0]); i2s_hal_start_tx(&(p_i2s_obj[i2s_num]->hal)); } if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - i2s_enable_rx_intr(i2s_num); + p_i2s_obj[i2s_num]->rx->curr_ptr = NULL; + p_i2s_obj[i2s_num]->rx->rw_pos = 0; + //attach DMA + i2s_hal_attach_rx_dma(&(p_i2s_obj[i2s_num]->hal)); + i2s_rx_reset(i2s_num); + i2s_hal_enable_rx_intr(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_start_rx_link(&(p_i2s_obj[i2s_num]->hal), (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0]); i2s_hal_start_rx(&(p_i2s_obj[i2s_num]->hal)); } esp_intr_enable(p_i2s_obj[i2s_num]->i2s_isr_handle); @@ -684,12 +672,14 @@ esp_err_t i2s_stop(i2s_port_t i2s_num) I2S_ENTER_CRITICAL(); esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle); if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + i2s_hal_stop_tx_link(&(p_i2s_obj[i2s_num]->hal)); i2s_hal_stop_tx(&(p_i2s_obj[i2s_num]->hal)); - i2s_disable_tx_intr(i2s_num); + i2s_hal_disable_tx_intr(&(p_i2s_obj[i2s_num]->hal)); } if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + i2s_hal_stop_rx_link(&(p_i2s_obj[i2s_num]->hal)); i2s_hal_stop_rx(&(p_i2s_obj[i2s_num]->hal)); - i2s_disable_rx_intr(i2s_num); + i2s_hal_disable_rx_intr(&(p_i2s_obj[i2s_num]->hal)); } uint32_t mask; i2s_hal_get_intr_status(&(p_i2s_obj[i2s_num]->hal), &mask); @@ -735,6 +725,29 @@ esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel) _i2s_adc_channel = adc_channel; return adc_i2s_mode_init(adc_unit, adc_channel); } + +esp_err_t i2s_adc_enable(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); + I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); + + adc1_dma_mode_acquire(); + _i2s_adc_mode_recover(); + i2s_rx_reset(i2s_num); + return i2s_set_clk(i2s_num, p_i2s_obj[i2s_num]->sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); +} + +esp_err_t i2s_adc_disable(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); + I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); + + i2s_hal_stop_rx(&(p_i2s_obj[i2s_num]->hal)); + adc1_lock_release(); + return ESP_OK; +} #endif esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) @@ -747,7 +760,6 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) return ESP_ERR_INVALID_ARG; #endif } - if (pin->bck_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->bck_io_num)) { ESP_LOGE(I2S_TAG, "bck_io_num error"); return ESP_FAIL; @@ -764,55 +776,25 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) ESP_LOGE(I2S_TAG, "data_in_num error"); return ESP_FAIL; } - - int bck_sig = -1, ws_sig = -1, data_out_sig = -1, data_in_sig = -1; - //Each IIS hw module has a RX and TX unit. - //For TX unit, the output signal index should be I2SnO_xxx_OUT_IDX - //For TX unit, the input signal index should be I2SnO_xxx_IN_IDX - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { - bck_sig = i2s_periph_signal[i2s_num].o_bck_out_sig; - ws_sig = i2s_periph_signal[i2s_num].o_ws_out_sig; - data_out_sig = i2s_periph_signal[i2s_num].o_data_out_sig; - } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { - bck_sig = i2s_periph_signal[i2s_num].o_bck_in_sig; - ws_sig = i2s_periph_signal[i2s_num].o_ws_in_sig; - data_out_sig = i2s_periph_signal[i2s_num].o_data_out_sig; + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + gpio_matrix_in_check(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0); + gpio_matrix_in_check(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0); + } else { + gpio_matrix_in_check(pin->ws_io_num, i2s_periph_signal[i2s_num].rx_ws_sig, 0); + gpio_matrix_in_check(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0); + } + } else { + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + gpio_matrix_out_check(pin->ws_io_num, i2s_periph_signal[i2s_num].tx_ws_sig, 0, 0); + gpio_matrix_out_check(pin->bck_io_num, i2s_periph_signal[i2s_num].tx_bck_sig, 0, 0); + } else { + gpio_matrix_out_check(pin->ws_io_num, i2s_periph_signal[i2s_num].rx_ws_sig, 0, 0); + gpio_matrix_out_check(pin->bck_io_num, i2s_periph_signal[i2s_num].rx_bck_sig, 0, 0); } } - //For RX unit, the output signal index should be I2SnI_xxx_OUT_IDX - //For RX unit, the input signal index shuld be I2SnI_xxx_IN_IDX - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { - bck_sig = i2s_periph_signal[i2s_num].i_bck_out_sig; - ws_sig = i2s_periph_signal[i2s_num].i_ws_out_sig; - data_in_sig = i2s_periph_signal[i2s_num].i_data_in_sig; - } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { - bck_sig = i2s_periph_signal[i2s_num].i_bck_in_sig; - ws_sig = i2s_periph_signal[i2s_num].i_ws_in_sig; - data_in_sig = i2s_periph_signal[i2s_num].i_data_in_sig; - } - } - //For "full-duplex + slave" mode, we should select RX signal index for ws and bck. - //For "full-duplex + master" mode, we should select TX signal index for ws and bck. - if ((p_i2s_obj[i2s_num]->mode & I2S_FULL_DUPLEX_SLAVE_MODE_MASK) == I2S_FULL_DUPLEX_SLAVE_MODE_MASK) { - bck_sig = i2s_periph_signal[i2s_num].i_bck_in_sig; - ws_sig = i2s_periph_signal[i2s_num].i_ws_in_sig; - } else if ((p_i2s_obj[i2s_num]->mode & I2S_FULL_DUPLEX_MASTER_MODE_MASK) == I2S_FULL_DUPLEX_MASTER_MODE_MASK) { - bck_sig = i2s_periph_signal[i2s_num].o_bck_out_sig; - ws_sig = i2s_periph_signal[i2s_num].o_ws_out_sig; - } - gpio_matrix_out_check(pin->data_out_num, data_out_sig, 0, 0); - gpio_matrix_in_check(pin->data_in_num, data_in_sig, 0); - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { - gpio_matrix_out_check(pin->ws_io_num, ws_sig, 0, 0); - gpio_matrix_out_check(pin->bck_io_num, bck_sig, 0, 0); - } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { - gpio_matrix_in_check(pin->ws_io_num, ws_sig, 0); - gpio_matrix_in_check(pin->bck_io_num, bck_sig, 0); - } - ESP_LOGD(I2S_TAG, "data: out %d, in: %d, ws: %d, bck: %d", data_out_sig, data_in_sig, ws_sig, bck_sig); - + gpio_matrix_out_check(pin->data_out_num, i2s_periph_signal[i2s_num].data_out_sig, 0, 0); + gpio_matrix_in_check(pin->data_in_num, i2s_periph_signal[i2s_num].data_in_sig, 0); return ESP_OK; } @@ -823,16 +805,26 @@ esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate) return i2s_set_clk(i2s_num, rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); } -#if SOC_I2S_SUPPORTS_PDM +#if SOC_I2S_SUPPORTS_PDM_RX esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr) { I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - i2s_hal_rx_pdm_cfg(&(p_i2s_obj[i2s_num]->hal), dsr); + i2s_hal_set_rx_pdm_dsr(&(p_i2s_obj[i2s_num]->hal), dsr); return i2s_set_clk(i2s_num, p_i2s_obj[i2s_num]->sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); } #endif -static esp_err_t i2s_check_cfg_static(i2s_port_t i2s_num, const i2s_config_t *cfg) +#if SOC_I2S_SUPPORTS_PDM_TX +esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, int sample_rate, int fp, int fs) +{ + I2S_ENTER_CRITICAL(); + i2s_hal_set_tx_pdm_fpfs(&(p_i2s_obj[i2s_num]->hal), fp, fs); + I2S_EXIT_CRITICAL(); + return i2s_set_clk(i2s_num, sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); +} +#endif + +static esp_err_t i2s_check_cfg_static(i2s_port_t i2s_num, const i2s_config_param_t *cfg) { #if SOC_I2S_SUPPORTS_ADC_DAC //We only check if the I2S number is invalid when set to build in ADC and DAC mode. @@ -851,7 +843,7 @@ static esp_err_t i2s_check_cfg_static(i2s_port_t i2s_num, const i2s_config_t *cf return ESP_OK; } -static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_config) +static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_param_t *i2s_config) { I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); I2S_CHECK((i2s_config), "param null", ESP_ERR_INVALID_ARG); @@ -866,20 +858,17 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co adc_power_acquire(); } #endif + p_i2s_obj[i2s_num]->communication_format = i2s_config->communication_format; // configure I2S data port interface. i2s_hal_config_param(&(p_i2s_obj[i2s_num]->hal), i2s_config); if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX)) { i2s_hal_enable_sig_loopback(&(p_i2s_obj[i2s_num]->hal)); if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { - i2s_hal_enable_master_mode(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_enable_master_fd_mode(&(p_i2s_obj[i2s_num]->hal)); } else { - i2s_hal_enable_slave_mode(&(p_i2s_obj[i2s_num]->hal)); + i2s_hal_enable_slave_fd_mode(&(p_i2s_obj[i2s_num]->hal)); } } - - p_i2s_obj[i2s_num]->use_apll = i2s_config->use_apll; - p_i2s_obj[i2s_num]->tx_desc_auto_clear = i2s_config->tx_desc_auto_clear; - p_i2s_obj[i2s_num]->fixed_mclk = i2s_config->fixed_mclk; return ESP_OK; } @@ -925,19 +914,23 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, i2s_spinlock[x] = i2s_spinlock_unlocked[0]; } //To make sure hardware is enabled before any hardware register operations. +#if SOC_GDMA_SUPPORTED + periph_module_enable(PERIPH_GDMA_MODULE); +#endif periph_module_enable(i2s_periph_signal[i2s_num].module); + i2s_hal_init(&(p_i2s_obj[i2s_num]->hal), i2s_num); p_i2s_obj[i2s_num]->i2s_num = i2s_num; - p_i2s_obj[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; - p_i2s_obj[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; - p_i2s_obj[i2s_num]->i2s_queue = i2s_queue; - p_i2s_obj[i2s_num]->mode = i2s_config->mode; + p_i2s_obj[i2s_num]->mode = i2s_config->param_cfg.mode; + p_i2s_obj[i2s_num]->channel_num = i2s_config->param_cfg.channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1; + + p_i2s_obj[i2s_num]->i2s_queue = i2s_queue; p_i2s_obj[i2s_num]->bits_per_sample = 0; p_i2s_obj[i2s_num]->bytes_per_sample = 0; // Not initialized yet - p_i2s_obj[i2s_num]->channel_num = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1; - + p_i2s_obj[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; + p_i2s_obj[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; #ifdef CONFIG_PM_ENABLE if (i2s_config->use_apll) { err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i2s_driver", &p_i2s_obj[i2s_num]->pm_lock); @@ -966,13 +959,15 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, return err; } i2s_stop(i2s_num); - err = i2s_param_config(i2s_num, i2s_config); + p_i2s_obj[i2s_num]->use_apll = i2s_config->use_apll; + p_i2s_obj[i2s_num]->fixed_mclk = i2s_config->fixed_mclk; + p_i2s_obj[i2s_num]->tx_desc_auto_clear = i2s_config->tx_desc_auto_clear; + err = i2s_param_config(i2s_num, &(i2s_config->param_cfg)); if (err != ESP_OK) { i2s_driver_uninstall(i2s_num); ESP_LOGE(I2S_TAG, "I2S param configure error"); return err; } - if (i2s_queue) { p_i2s_obj[i2s_num]->i2s_queue = xQueueCreate(queue_size, sizeof(i2s_event_t)); *((QueueHandle_t*) i2s_queue) = p_i2s_obj[i2s_num]->i2s_queue; @@ -980,8 +975,13 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, } else { p_i2s_obj[i2s_num]->i2s_queue = NULL; } + i2s_slot_bits_cfg_t slot_bits_cfg = i2s_config->param_cfg.slot_bits_cfg; + i2s_slot_channel_cfg_t slot_channel_cfg = p_i2s_obj[i2s_num]->channel_num; +#if SOC_I2S_SUPPORTS_TDM + slot_channel_cfg = i2s_config->param_cfg.slot_channel_cfg; +#endif //set clock and start - return i2s_set_clk(i2s_num, i2s_config->sample_rate, i2s_config->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); + return i2s_set_clk(i2s_num, i2s_config->sample_rate, slot_bits_cfg, slot_channel_cfg); } ESP_LOGW(I2S_TAG, "I2S driver already installed"); @@ -1012,11 +1012,14 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) p_i2s_obj[i2s_num]->i2s_queue = NULL; } +#if SOC_I2S_SUPPORTS_APLL if(p_i2s_obj[i2s_num]->use_apll) { // switch back to PLL clock source i2s_hal_set_clock_sel(&(p_i2s_obj[i2s_num]->hal), I2S_CLK_D2CLK); rtc_clk_apll_enable(0, 0, 0, 0, 0); } +#endif + #ifdef CONFIG_PM_ENABLE if (p_i2s_obj[i2s_num]->pm_lock) { esp_pm_lock_delete(p_i2s_obj[i2s_num]->pm_lock); @@ -1026,7 +1029,6 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) free(p_i2s_obj[i2s_num]); p_i2s_obj[i2s_num] = NULL; periph_module_disable(i2s_periph_signal[i2s_num].module); - return ESP_OK; } @@ -1036,7 +1038,7 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by size_t bytes_can_write; *bytes_written = 0; I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((size < SOC_I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); + I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_ERR_INVALID_ARG); xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); #ifdef CONFIG_PM_ENABLE @@ -1071,32 +1073,6 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by return ESP_OK; } -#if SOC_I2S_SUPPORTS_ADC_DAC -esp_err_t i2s_adc_enable(i2s_port_t i2s_num) -{ - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); - I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); - - adc1_dma_mode_acquire(); - _i2s_adc_mode_recover(); - i2s_hal_start_rx(&(p_i2s_obj[i2s_num]->hal)); - i2s_hal_reset(&(p_i2s_obj[i2s_num]->hal)); - return i2s_set_clk(i2s_num, p_i2s_obj[i2s_num]->sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); -} - -esp_err_t i2s_adc_disable(i2s_port_t i2s_num) -{ - I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); - I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); - - i2s_hal_stop_rx(&(p_i2s_obj[i2s_num]->hal)); - adc1_lock_release(); - return ESP_OK; -} -#endif - esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, size_t src_bits, size_t aim_bits, size_t *bytes_written, TickType_t ticks_to_wait) { char *data_ptr; @@ -1105,7 +1081,7 @@ esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, siz *bytes_written = 0; I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); I2S_CHECK((size > 0), "size must greater than zero", ESP_ERR_INVALID_ARG); - I2S_CHECK((aim_bits * size < SOC_I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); + I2S_CHECK((aim_bits * size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); I2S_CHECK((aim_bits >= src_bits), "aim_bits mustn't be less than src_bits", ESP_ERR_INVALID_ARG); I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_ERR_INVALID_ARG); if (src_bits < I2S_BITS_PER_SAMPLE_8BIT || aim_bits < I2S_BITS_PER_SAMPLE_8BIT) { @@ -1167,7 +1143,7 @@ esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_re *bytes_read = 0; dest_byte = (char *)dest; I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); - I2S_CHECK((size < SOC_I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); + I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); I2S_CHECK((p_i2s_obj[i2s_num]->rx), "rx NULL", ESP_ERR_INVALID_ARG); xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); #ifdef CONFIG_PM_ENABLE diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index 4ee73b594d..0c5b1c288d 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -28,8 +28,53 @@ extern "C" { #define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */ + +/** + * @brief I2S driver configuration parameters + * + */ +typedef struct { + union { + // Compatible with previous versions. For ESP32-S3, ESP32-C3 and the later chip, you should use `param_cfg` fields to initialize I2S. + struct { + i2s_mode_t mode; /*!< I2S work mode*/ + uint32_t sample_rate; /*!< I2S sample rate*/ + uint32_t bits_per_sample; /*!< I2S bits per sample*/ + i2s_channel_fmt_t channel_format; /*!< I2S channel format */ + i2s_comm_format_t communication_format; /*!< I2S communication format */ + }; + i2s_config_param_t param_cfg; /*!< I2S config paramater */ + }; + int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */ + int dma_buf_count; /*!< I2S DMA Buffer Count */ + int dma_buf_len; /*!< I2S DMA Buffer Length */ + bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */ + bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */ + int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/ +} i2s_driver_config_t; + +typedef i2s_driver_config_t i2s_config_t; typedef intr_handle_t i2s_isr_handle_t; +/** + * @brief I2S event types + * + */ +typedef enum { + I2S_EVENT_DMA_ERROR, + I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/ + I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/ + I2S_EVENT_MAX, /*!< I2S event max index*/ +} i2s_event_type_t; +/** + * @brief Event structure used in I2S event queue + * + */ +typedef struct { + i2s_event_type_t type; /*!< I2S event type */ + size_t size; /*!< I2S data size for I2S_DATA event*/ +} i2s_event_t; + /** * @brief Set I2S pin number * @@ -54,7 +99,7 @@ typedef intr_handle_t i2s_isr_handle_t; */ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin); -#if SOC_I2S_SUPPORTS_PDM +#if SOC_I2S_SUPPORTS_PDM_RX /** * @brief Set PDM mode down-sample rate * In PDM RX mode, there would be 2 rounds of downsample process in hardware. @@ -75,6 +120,30 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin); esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr); #endif +#if SOC_I2S_SUPPORTS_PDM_TX +/** + * @brief Set TX PDM mode up-sample rate + * TX PDM have two type upsampling rate configurations: + * 1: fp = 960, fs = sample_rate / 100, in this case, Fpdm = 128*48000 + * 2: fp = 960, fs = 480, in this case, Fpdm = 128*Fpcm = 128*sample_rate + * If the pdm receiver do not care the pdm serial clock, it's recommended set Fpdm = 128*48000 + * + * @param i2s_num I2S_NUM_0 + * @param sample_rate The sample rate to be set + * @param fp PDM TX upsampling configuration paramater + * @param fs PDM TX upsampling configuration paramater + * + * @note After calling this function, it would call i2s_set_clk inside to update the clock frequency. + * Please call this function after I2S driver has been initialized. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NO_MEM Out of memory + */ +esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, int sample_rate, int fp, int fs); +#endif + /** * @brief Install and start I2S driver. * @@ -243,6 +312,23 @@ esp_err_t i2s_start(i2s_port_t i2s_num); */ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num); +#if SOC_I2S_SUPPORTS_PCM +/** + * @brief Configure I2S a/u-law decompress or compress + * + * @param i2s_num I2S_NUM_0 + * + * @param mode I2S mode. I2S_MODE_TX, I2S_MODE_RX + * + * @param pcm_cfg a/u-law decompress or compress configuration paramater + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t i2s_pcm_config(i2s_port_t i2s_num, int mode, i2s_pcm_cfg_t pcm_cfg); +#endif + /** * @brief Set clock & bit width used for I2S RX and TX. * @@ -252,16 +338,16 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num); * * @param rate I2S sample rate (ex: 8000, 44100...) * - * @param bits I2S bit width (I2S_BITS_PER_SAMPLE_16BIT, I2S_BITS_PER_SAMPLE_24BIT, I2S_BITS_PER_SAMPLE_32BIT) + * @param slot_bits i2s slot bit configuration * - * @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO) + * @param sloct_ch I2S slot number configuration * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_NO_MEM Out of memory */ -esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch); +esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_slot_bits_cfg_t slot_bits, i2s_slot_channel_cfg_t sloct_ch); /** * @brief get clock set on particular port number. @@ -271,7 +357,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b * @return * - actual clock set by i2s driver */ -float i2s_get_clk(i2s_port_t i2s_num); +uint32_t i2s_get_clk(i2s_port_t i2s_num); #if SOC_I2S_SUPPORTS_ADC_DAC /** diff --git a/components/driver/test/adc_dma_test/test_esp32.c b/components/driver/test/adc_dma_test/test_esp32.c index 104f88375a..36375596a0 100644 --- a/components/driver/test/adc_dma_test/test_esp32.c +++ b/components/driver/test/adc_dma_test/test_esp32.c @@ -54,10 +54,12 @@ static void example_i2s_init(void) { int i2s_num = EXAMPLE_I2S_NUM; i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, - .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, - .bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS, - .channel_format = EXAMPLE_I2S_FORMAT, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, + .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, + .slot_bits_cfg = EXAMPLE_I2S_SAMPLE_BITS, + .channel_format = EXAMPLE_I2S_FORMAT, + }, .intr_alloc_flags = 0, .dma_buf_count = 2, .dma_buf_len = 1024, diff --git a/components/driver/test/dac_dma_test/test_esp32.c b/components/driver/test/dac_dma_test/test_esp32.c index eba5dfd565..c69843e81c 100644 --- a/components/driver/test/dac_dma_test/test_esp32.c +++ b/components/driver/test/dac_dma_test/test_esp32.c @@ -56,10 +56,12 @@ static void example_i2s_init(void) { int i2s_num = EXAMPLE_I2S_NUM; i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, - .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, - .bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS, - .channel_format = EXAMPLE_I2S_FORMAT, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, + .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, + .slot_bits_cfg = EXAMPLE_I2S_SAMPLE_BITS, + .channel_format = EXAMPLE_I2S_FORMAT, + }, .intr_alloc_flags = 0, .dma_buf_count = 2, .dma_buf_len = 1024, diff --git a/components/driver/test/test_i2s.c b/components/driver/test/test_i2s.c index 41e29cf2dc..025ba78270 100644 --- a/components/driver/test/test_i2s.c +++ b/components/driver/test/test_i2s.c @@ -107,11 +107,20 @@ TEST_CASE("I2S basic driver install, uninstall, set pin test", "[i2s]") { // dac, adc i2s i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 60, .use_apll = 0, @@ -152,11 +161,20 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]") { // master driver installed and send data i2s_config_t master_i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, @@ -218,10 +236,19 @@ TEST_CASE("I2S adc test", "[i2s]") { // init I2S ADC i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .intr_alloc_flags = 0, .dma_buf_count = 2, .dma_buf_len = 1024, @@ -272,11 +299,20 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") { // master driver installed and send data i2s_config_t master_i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, @@ -294,11 +330,20 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") printf("\r\nheap size: %d\n", esp_get_free_heap_size()); i2s_config_t slave_i2s_config = { - .mode = I2S_MODE_SLAVE | I2S_MODE_RX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_SLAVE | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, @@ -357,11 +402,20 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") { // master driver installed and send data i2s_config_t master_i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 1, @@ -379,11 +433,20 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") printf("\r\nheap size: %d\n", esp_get_free_heap_size()); i2s_config_t slave_i2s_config = { - .mode = I2S_MODE_SLAVE | I2S_MODE_TX, // Only RX - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_SLAVE | I2S_MODE_TX, // Only RX + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 1, @@ -442,11 +505,20 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") TEST_CASE("I2S memory leaking test", "[i2s]") { i2s_config_t master_i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_RX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 100, .use_apll = 0, @@ -489,11 +561,20 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]") }; i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = SAMPLE_RATE, - .bits_per_sample = SAMPLE_BITS, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 60, .use_apll = true, @@ -510,8 +591,8 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]") for (int i = 0; i < (sizeof(sample_rate_arr)/sizeof(sample_rate_arr[0])); i++) { for (int j = 0; j < (sizeof(bits_per_sample_arr)/sizeof(bits_per_sample_arr[0])); j++) { - i2s_config.sample_rate = sample_rate_arr[i]; - i2s_config.bits_per_sample = bits_per_sample_arr[j]; + i2s_config.param_cfg.sample_rate = sample_rate_arr[i]; + i2s_config.param_cfg.slot_bits_cfg = bits_per_sample_arr[j]; TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config)); diff --git a/components/efuse/esp32c3/private_include/esp_efuse_utility.h b/components/efuse/esp32c3/private_include/esp_efuse_utility.h index 37573eea8f..d2256ab312 100644 --- a/components/efuse/esp32c3/private_include/esp_efuse_utility.h +++ b/components/efuse/esp32c3/private_include/esp_efuse_utility.h @@ -16,6 +16,16 @@ extern "C" { #define ESP_EFUSE_FIELD_CORRESPONDS_CODING_SCHEME(scheme, max_num_bit) +/*-------------------------- I2S CAPS ----------------------------------------*/ +#define SOC_I2S_NUM (1) +#define SOC_I2S_SUPPORTS_PCM (1) +#define SOC_I2S_SUPPORTS_PDM_TX (1) +#define SOC_I2S_SUPPORTS_PDM_RX (0) +#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) +#define SOC_I2S_SUPPORTS_TDM (1) +#define SOC_GDMA_I2S0_DMA_CHANNEL (0) + #ifdef __cplusplus } #endif + diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index 96d4a3f8ec..981a441705 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -1,4 +1,4 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,9 +23,6 @@ #pragma once #include -#include "soc/rtc_periph.h" -#include "soc/rtc.h" -#include "soc/efuse_periph.h" #include "soc/i2s_periph.h" #include "hal/i2s_types.h" @@ -42,19 +39,148 @@ extern "C" { #define I2S_INTR_OUT_DSCR_ERR BIT(14) #define I2S_INTR_MAX (0xFFFFFFFF) + +/* I2S clock configuration structure */ +typedef struct { + uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a) + uint16_t a; + uint16_t b; // The decimal part of module clock devider, the decimal is: b/a + uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div +} i2s_clk_cal_t; + /** - * @brief Reset rx fifo + * @brief Calculate the closest sample rate clock configuration. + * clock relationship: + * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) * - * @param hw Peripheral I2S hardware instance address. + * @param fsclk I2S source clock freq. + * @param fbck BCK freuency. + * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. + * @param cal Point to `i2s_clk_cal_t` structure. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal) { - hw->conf.rx_fifo_reset = 1; - hw->conf.rx_fifo_reset = 0; + int ma = 0; + int mb = 0; + uint32_t mclk = fbck*bck_div; + cal->mclk_div = fsclk / mclk; + cal->bck_div = bck_div; + cal->a = 1; + cal->b = 0; + uint32_t freq_diff = fsclk - mclk * cal->mclk_div; + uint32_t min = ~0; + if (freq_diff == 0) { + return; + } + for (int a = 2; a <= 63; a++) { + for (int b = 1; b < a; b++) { + ma = freq_diff*a; + mb = mclk*b; + if (ma == mb) { + cal->a = a; + cal->b = b; + return; + } + if (abs((mb - ma)) < min) { + cal->a = a; + cal->b = b; + min = abs(mb - ma); + } + } + } } /** - * @brief Reset tx fifo + * @brief I2S module general init, enable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_general_init(i2s_dev_t *hw) +{ + if (hw->clkm_conf.clk_en == 0) { + hw->clkm_conf.clk_en = 1; + hw->conf2.val = 0; + } +} + +/** + * @brief I2S TX module general init. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw) +{ + hw->conf.tx_start = 0; + hw->conf.tx_reset = 1; + hw->conf.tx_reset = 0; + hw->conf.tx_msb_right = 0; + hw->conf.tx_right_first = 0; + hw->conf.tx_slave_mod = 0; + hw->fifo_conf.tx_fifo_mod_force_en = 1; +} + +/** + * @brief I2S RX module general init. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw) +{ + hw->conf.rx_start = 0; + hw->conf.rx_reset = 1; + hw->conf.rx_reset = 0; + hw->conf.rx_msb_right = 0; + hw->conf.rx_right_first = 0; + hw->conf.rx_slave_mod = 0; + hw->fifo_conf.rx_fifo_mod_force_en = 1; +} + +/** + * @brief Enable I2S TX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->conf.tx_slave_mod = slave_en; +} + +/** + * @brief Enable I2S RX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->conf.rx_slave_mod = slave_en; +} + +/** + * @brief Reset I2S TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +{ + hw->conf.tx_reset = 1; + hw->conf.tx_reset = 0; +} + +/** + * @brief Reset I2S RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_rx(i2s_dev_t *hw) +{ + hw->conf.rx_reset = 1; + hw->conf.rx_reset = 0; +} + +/** + * @brief Reset I2S TX FIFO * * @param hw Peripheral I2S hardware instance address. */ @@ -65,40 +191,72 @@ static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) } /** - * @brief Enable rx interrupt + * @brief Reset I2S RX FIFO * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) { - hw->int_ena.in_suc_eof = 1; - hw->int_ena.in_dscr_err = 1; + hw->conf.rx_fifo_reset = 1; + hw->conf.rx_fifo_reset = 0; } /** - * @brief Disable rx interrupt + * @brief Set TX source clock * * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock */ -static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { - hw->int_ena.in_suc_eof = 0; - hw->int_ena.in_dscr_err = 0; + //0: disable APLL clock, I2S module will using PLL_D2_CLK(160M) as source clock + //1: Enable APLL clock, I2S module will using APLL as source clock + hw->clkm_conf.clka_en = (src == 1) ? 1 : 0; } /** - * @brief Disable tx interrupt + * @brief Set RX source clock * * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock */ -static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { - hw->int_ena.out_eof = 0; - hw->int_ena.out_dscr_err = 0; + //0: disable APLL clock, I2S module will using PLL_D2_CLK(160M) as source clock + //1: Enable APLL clock, I2S module will using APLL as source clock + hw->clkm_conf.clka_en = (src == 1) ? 1 : 0; } /** - * @brief Enable tx interrupt + * @brief Configure I2S TX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +{ + hw->clkm_conf.clkm_div_num = set->mclk_div; + hw->clkm_conf.clkm_div_b = set->b; + hw->clkm_conf.clkm_div_a = set->a; + hw->sample_rate_conf.tx_bck_div_num = set->bck_div; +} + +/** + * @brief Configure I2S RX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +{ + hw->clkm_conf.clkm_div_num = set->mclk_div; + hw->clkm_conf.clkm_div_b = set->b; + hw->clkm_conf.clkm_div_a = set->a; + hw->sample_rate_conf.rx_bck_div_num = set->bck_div; +} + +/** + * @brief Enable TX interrupt * * @param hw Peripheral I2S hardware instance address. */ @@ -109,14 +267,58 @@ static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) } /** - * @brief Reset dma in + * @brief Disable TX interrupt * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) +static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) { - hw->lc_conf.in_rst = 1; - hw->lc_conf.in_rst = 0; + hw->int_ena.out_eof = 0; + hw->int_ena.out_dscr_err = 0; +} + +/** + * @brief Enable RX interrupt + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +{ + hw->int_ena.in_suc_eof = 1; + hw->int_ena.in_dscr_err = 1; +} + +/** + * @brief Disable RX interrupt + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +{ + hw->int_ena.in_suc_eof = 0; + hw->int_ena.in_dscr_err = 0; +} + +/** + * @brief Get I2S interrupt status + * + * @param hw Peripheral I2S hardware instance address. + * @param int_stat Pointer to module interrupt status + */ +static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *int_stat) +{ + *int_stat = hw->int_st.val; +} + +/** + * @brief Clear I2S interrupt status + * + * @param hw Peripheral I2S hardware instance address. + * @param clr_mask Interrupt mask to clear interrupt status + */ +static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t clr_mask) +{ + hw->int_clr.val = clr_mask; } /** @@ -131,39 +333,18 @@ static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) } /** - * @brief Reset tx + * @brief Reset dma in * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) { - hw->conf.tx_reset = 1; - hw->conf.tx_reset = 0; + hw->lc_conf.in_rst = 1; + hw->lc_conf.in_rst = 0; } /** - * @brief Reset rx - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_rx(i2s_dev_t *hw) -{ - hw->conf.rx_reset = 1; - hw->conf.rx_reset = 0; -} - -/** - * @brief Start out link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_out_link(i2s_dev_t *hw) -{ - hw->out_link.start = 1; -} - -/** - * @brief Start tx + * @brief Start TX module * * @param hw Peripheral I2S hardware instance address. */ @@ -173,17 +354,7 @@ static inline void i2s_ll_start_tx(i2s_dev_t *hw) } /** - * @brief Start in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_in_link(i2s_dev_t *hw) -{ - hw->in_link.start = 1; -} - -/** - * @brief Start rx + * @brief Start RX module * * @param hw Peripheral I2S hardware instance address. */ @@ -192,6 +363,50 @@ static inline void i2s_ll_start_rx(i2s_dev_t *hw) hw->conf.rx_start = 1; } +/** + * @brief Configure TX DMA descriptor address and start TX DMA + * + * @param hw Peripheral I2S hardware instance address. + * @param link_addr DMA descriptor link address. + */ +static inline void i2s_ll_start_tx_link(i2s_dev_t *hw, uint32_t link_addr) +{ + hw->out_link.addr = link_addr; + hw->out_link.start = 1; +} + +/** + * @brief Configure RX DMA descriptor address and start RX DMA + * + * @param hw Peripheral I2S hardware instance address. + * @param link_addr DMA descriptor link address. + */ +static inline void i2s_ll_start_rx_link(i2s_dev_t *hw, uint32_t link_addr) +{ + hw->in_link.addr = link_addr; + hw->in_link.start = 1; +} + +/** + * @brief Stop TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_stop_tx(i2s_dev_t *hw) +{ + hw->conf.tx_start = 0; +} + +/** + * @brief Stop RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +{ + hw->conf.rx_start = 0; +} + /** * @brief Stop out link * @@ -202,16 +417,6 @@ static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) hw->out_link.stop = 1; } -/** - * @brief Stop tx - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_tx(i2s_dev_t *hw) -{ - hw->conf.tx_start = 0; -} - /** * @brief Stop in link * @@ -223,435 +428,78 @@ static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) } /** - * @brief Stop rx + * @brief Get I2S out eof descriptor address * * @param hw Peripheral I2S hardware instance address. + * @param eof_addr Pointer to accept out eof des address */ -static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) { - hw->conf.rx_start = 0; + *eof_addr = hw->out_eof_des_addr; } /** - * @brief Enable dma + * @brief Get I2S in eof descriptor address * * @param hw Peripheral I2S hardware instance address. + * @param eof_addr Pointer to accept in eof des address */ -static inline void i2s_ll_enable_dma(i2s_dev_t *hw) +static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) { - //Enable and configure DMA - typeof(hw->lc_conf) lc_conf; - lc_conf.val = 0; - lc_conf.out_eof_mode = 1; - hw->lc_conf.val = lc_conf.val; + *eof_addr = hw->in_eof_des_addr; } /** - * @brief Get I2S interrupt status + * @brief Configure the received length to trigger in_suc_eof interrupt * * @param hw Peripheral I2S hardware instance address. - * @param val value to get interrupt status + * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->int_st.val; -} - -/** - * @brief Clear I2S interrupt status - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to clear interrupt status - */ -static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val) -{ - hw->int_clr.val = val; -} - -/** - * @brief Get I2S out eof des address - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get out eof des address - */ -static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->out_eof_des_addr; -} - -/** - * @brief Get I2S in eof des address - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get in eof des address - */ -static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->in_eof_des_addr; -} - -/** - * @brief Get I2S tx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx fifo mode - */ -static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->fifo_conf.tx_fifo_mod; -} - -/** - * @brief Set I2S tx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mode - */ -static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->fifo_conf.tx_fifo_mod = val; -} - -/** - * @brief Get I2S rx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx fifo mode - */ -static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->fifo_conf.rx_fifo_mod; -} - -/** - * @brief Set I2S rx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mode - */ -static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->fifo_conf.rx_fifo_mod = val; -} - -/** - * @brief Set I2S tx chan mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx chan mode - */ -static inline void i2s_ll_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf_chan.tx_chan_mod = val; -} - -/** - * @brief Set I2S rx chan mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx chan mode - */ -static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf_chan.rx_chan_mod = val; -} - -/** - * @brief Set I2S out link address - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set out link address - */ -static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val) -{ - hw->out_link.addr = val; -} - -/** - * @brief Set I2S in link address - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set in link address - */ -static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val) -{ - hw->in_link.addr = val; -} - -/** - * @brief Set I2S rx eof num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx eof num - */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) { // On ESP32, the eof_num count in words. - hw->rx_eof_num = val / 4; + hw->rx_eof_num = eof_num / 4; } /** - * @brief Set I2S clkm div num + * @brief Congfigure TX slot bit and audio data bit, on ESP32, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div num + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - hw->clkm_conf.clkm_div_num = val; + hw->fifo_conf.tx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); + hw->sample_rate_conf.tx_bits_mod = data_bit; } /** - * @brief Set I2S clkm div b + * @brief Congfigure RX slot bit and audio data bit, on ESP32, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div b + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - hw->clkm_conf.clkm_div_b = val; + hw->fifo_conf.rx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); + hw->sample_rate_conf.rx_bits_mod = data_bit; } /** - * @brief Set I2S clkm div a + * @brief Enable I2S DMA * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div a + * @param ena Set true to enable DMA */ -static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_dma_enable(i2s_dev_t *hw, bool ena) { - hw->clkm_conf.clkm_div_a = val; -} - -/** - * @brief Set I2S tx bck div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bck div num - */ -static inline void i2s_ll_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.tx_bck_div_num = val; -} - -/** - * @brief Set I2S rx bck div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bck div num - */ -static inline void i2s_ll_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.rx_bck_div_num = val; -} - -/** - * @brief Set I2S clk sel - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clk sel - */ -static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val) -{ - hw->clkm_conf.clka_en = (val == 1) ? 1 : 0; -} - -/** - * @brief Set I2S tx bits mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bits mod - */ -static inline void i2s_ll_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.tx_bits_mod = val; -} - -/** - * @brief Set I2S rx bits mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bits mod - */ -static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.rx_bits_mod = val; -} - -/** - * @brief Set I2S dscr en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set dscr en - */ -static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val) -{ - hw->fifo_conf.dscr_en = val; -} - -/** - * @brief Set I2S lcd en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set lcd en - */ -static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val) -{ - hw->conf2.lcd_en = val; -} - -/** - * @brief Set I2S camera en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set camera en - */ -static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val) -{ - hw->conf2.camera_en = val; -} - -/** - * @brief Set I2S tx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mod force en - */ -static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - hw->fifo_conf.tx_fifo_mod_force_en = val; -} - -/** - * @brief Set I2S rx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mod force en - */ -static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - hw->fifo_conf.rx_fifo_mod_force_en = val; -} - -/** - * @brief Set I2S tx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx right first - */ -static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_right_first = val; -} - -/** - * @brief Set I2S rx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx right first - */ -static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_right_first = val; -} - -/** - * @brief Set I2S tx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx slave mod - */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_slave_mod = val; -} - -/** - * @brief Set I2S rx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx slave mod - */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_slave_mod = val; -} - -/** - * @brief Get I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx msb right - */ -static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->conf.tx_msb_right; -} - -/** - * @brief Get I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx msb right - */ -static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->conf.rx_msb_right; -} - -/** - * @brief Set I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx msb right - */ -static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_msb_right = val; -} - -/** - * @brief Set I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx msb right - */ -static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_msb_right = val; -} - -/** - * @brief Set I2S tx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx mono - */ -static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_mono = val; -} - -/** - * @brief Set I2S rx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx mono - */ -static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_mono = val; -} - -/** - * @brief Set I2S sig loopback - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set sig loopback - */ -static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.sig_loopback = val; + if (ena && !hw->fifo_conf.dscr_en) { + hw->fifo_conf.dscr_en = 1; + } else if (!ena && hw->fifo_conf.dscr_en) { + hw->fifo_conf.dscr_en = 0; + } } /** @@ -742,6 +590,159 @@ static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) hw->conf.rx_msb_shift = 0; } +/** + * @brief Enable TX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_tx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) +{ + int data_bit = hw->sample_rate_conf.tx_bits_mod; + if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) { + hw->fifo_conf.tx_fifo_mod = 0 + mono_ena; + } else { + hw->fifo_conf.tx_fifo_mod = 2 + mono_ena; + } + hw->conf_chan.tx_chan_mod = mono_ena; +} + +/** + * @brief Enable RX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_rx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) +{ + int data_bit = hw->sample_rate_conf.rx_bits_mod; + if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) { + hw->fifo_conf.rx_fifo_mod = 0 + mono_ena; + } else { + hw->fifo_conf.rx_fifo_mod = 2 + mono_ena; + } + hw->conf_chan.rx_chan_mod = mono_ena; +} + +/** + * @brief Enable I2S loopback mode + * + * @param hw Peripheral I2S hardware instance address. + * @param loopback_en Set true to enable loopback mode. + */ +static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool loopback_en) +{ + hw->conf.sig_loopback = loopback_en; +} + +/** + * @brief Set default RX PDM mode + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw) +{ + hw->pdm_conf.rx_sinc_dsr_16_en = 0; + hw->pdm_conf.pdm2pcm_conv_en = 1; + hw->pdm_conf.rx_pdm_en = 1; +} + +/** + * @brief Configure RX PDM downsample + * + * @param hw Peripheral I2S hardware instance address. + * @param dsr PDM downsample configuration paramater + */ +static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) +{ + hw->pdm_conf.rx_sinc_dsr_16_en = dsr; +} + +/** + * @brief Get RX PDM downsample configuration + * + * @param hw Peripheral I2S hardware instance address. + * @param dsr Pointer to accept PDM downsample configuration + */ +static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) +{ + *dsr = hw->pdm_conf.rx_sinc_dsr_16_en; +} + +/** + * @brief Enable I2S RX PDM mode + * + * @param hw Peripheral I2S hardware instance address. + * @param pdm_ena Set true to enable RX PDM mode + */ +static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_ena) +{ + hw->pdm_conf.rx_pdm_en = pdm_ena; +} + +/** + * @brief Configure I2S TX pdm + * + * @param hw Peripheral I2S hardware instance address. + * @param sample_rate The sample rate to be set. + */ +static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) +{ + uint32_t fp = 960; + uint32_t fs = sample_rate / 100; + typeof(hw->pdm_conf) pdm_conf_reg = hw->pdm_conf; + pdm_conf_reg.tx_sinc_osr2 = fp/fs; + pdm_conf_reg.tx_prescale = 0; + pdm_conf_reg.tx_hp_in_shift = 1; + pdm_conf_reg.tx_lp_in_shift = 1; + pdm_conf_reg.tx_sinc_in_shift = 1; + pdm_conf_reg.tx_sigmadelta_in_shift = 1; + pdm_conf_reg.pcm2pdm_conv_en = 1; + pdm_conf_reg.tx_pdm_en = 1; + hw->pdm_conf.val = pdm_conf_reg.val; + hw->pdm_freq_conf.tx_pdm_fp = fp; + hw->pdm_freq_conf.tx_pdm_fs = fs; +} + +/** + * @brief Configure I2S TX PDM sample rate + * Fpdm = 64*Fpcm*fp/fs + * + * @param hw Peripheral I2S hardware instance address. + * @param fp The fp value of TX PDM filter module group0. + * @param fs The fs value of TX PDM filter module group0. + */ +static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) +{ + hw->pdm_freq_conf.tx_pdm_fp = fp; + hw->pdm_freq_conf.tx_pdm_fs = fs; + hw->pdm_conf.tx_sinc_osr2 = fp / fs; +} + +/** + * @brief Get I2S TX PDM configuration + * + * @param hw Peripheral I2S hardware instance address. + * @param fp Pointer to accept TX PDM fp configuration paramater + * @param fs Pointer to accept TX PDM fs configuration paramater + */ +static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) +{ + *fp = hw->pdm_freq_conf.tx_pdm_fp; + *fs = hw->pdm_freq_conf.tx_pdm_fs; +} + +/** + * @brief Enable I2S TX PDM mode + * + * @param hw Peripheral I2S hardware instance address. + * @param pdm_ena Set true to enable TX PDM mode + */ +static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_ena) +{ + hw->pdm_conf.tx_pdm_en = pdm_ena; +} + /** * @brief Enable I2S build in ADC mode * @@ -751,8 +752,12 @@ static inline void i2s_ll_build_in_adc_ena(i2s_dev_t *hw) { hw->conf2.lcd_en = 1; hw->conf2.camera_en = 0; + hw->conf.rx_right_first = 0; hw->conf.rx_msb_shift = 0; + hw->conf.rx_mono = 0; hw->conf.rx_short_sync = 0; + hw->fifo_conf.rx_fifo_mod = 1; + hw->conf_chan.rx_chan_mod = 1; } /** @@ -769,82 +774,6 @@ static inline void i2s_ll_build_in_dac_ena(i2s_dev_t *hw) hw->conf.tx_short_sync = 0; } - -/** - * @brief Enable I2S RX PDM mode - * - * @param hw Peripheral I2S hardware instance address. - * @param pdm_en Set true to enable rx PDM mode - */ -static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_en) -{ - hw->pdm_conf.rx_pdm_en = pdm_en; -} - -/** - * @brief Enable I2S tx pdm mode - * - * @param hw Peripheral I2S hardware instance address. - * @param pdm_en Set true to enable tx PDM mode - */ -static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_en) -{ - hw->pdm_conf.tx_pdm_en = pdm_en; -} - -/** - * @brief Configure I2S tx PDM filter module group0 - * - * @param hw Peripheral I2S hardware instance address. - * @param fp The fp value of TX PDM filter module group0. - * @param fs The fs value of TX PDM filter module group0. - */ -static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t fp, uint32_t fs) -{ - hw->pdm_freq_conf.tx_pdm_fp = fp; - hw->pdm_freq_conf.tx_pdm_fs = fs; - hw->pdm_conf.tx_sinc_osr2 = fp/fs; - hw->pdm_conf.pcm2pdm_conv_en = 1; - hw->pdm_conf.tx_pdm_en = 1; -} - -/** - * @brief Configure I2S rx PDM - * - * @param hw Peripheral I2S hardware instance address. - * @param dsr Down-sampling rate value of rx PDM - */ -static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw, uint32_t dsr) -{ - hw->pdm_conf.rx_sinc_dsr_16_en = dsr; - hw->pdm_conf.pdm2pcm_conv_en = 1; - hw->pdm_conf.rx_pdm_en = 1; -} - -/** - * @brief Get I2S tx PDM configuration - * - * @param hw Peripheral I2S hardware instance address. - * @param fp Pointer to store tx PDM fp configuration - * @param fs Pointer to store tx PDM fs configuration - */ -static inline void i2s_ll_get_tx_pdm(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) -{ - *fp = hw->pdm_freq_conf.tx_pdm_fp; - *fs = hw->pdm_freq_conf.tx_pdm_fs; -} - -/** - * @brief Get I2S rx PDM configuration - * - * @param hw Peripheral I2S hardware instance address. - * @param dsr Pointer to stoe the rx PDM down-sample rate configuration - */ -static inline void i2s_ll_get_rx_pdm(i2s_dev_t *hw, uint32_t *dsr) -{ - *dsr = hw->pdm_conf.rx_sinc_dsr_16_en; -} - #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index 4a6042cf12..f9d7331a87 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,18 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +// The LL layer for I2C register operations /******************************************************************************* * NOTICE * The hal is not public api, don't use in application code. - * See readme.md in soc/include/hal/readme.md + * See readme.md in hal/include/hal/readme.md ******************************************************************************/ -// The LL layer for ESP32-S3 I2S register operations - #pragma once - #include -#include #include "soc/i2s_periph.h" #include "hal/i2s_types.h" @@ -31,880 +28,688 @@ extern "C" { #endif -// Get I2S hardware instance with giving i2s num -#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL) -#define I2S_INTR_IN_SUC_EOF BIT(9) -#define I2S_INTR_OUT_EOF BIT(12) -#define I2S_INTR_IN_DSCR_ERR BIT(13) -#define I2S_INTR_OUT_DSCR_ERR BIT(14) -#define I2S_INTR_MAX (0xFFFFFFFF) +#define I2S_LL_GET_HW(num) (&I2S0) +#define I2S_INTR_OUT_DSCR_ERR (0x1 << 6) +#define I2S_INTR_OUT_EOF (0x1 << 4) +#define I2S_INTR_IN_DSCR_ERR (0x1 << 5) +#define I2S_INTR_IN_SUC_EOF (0x1 << 1) +#define I2S_INTR_MAX (~0) + +#define I2S_TDM_CH_MASK (0xffff) + +/* I2S clock configuration structure */ +typedef struct { + uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a) + uint16_t a; + uint16_t b; // The decimal part of module clock devider, the decimal is: b/a + uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div +} i2s_clk_cal_t; /** - * @brief Reset rx fifo + * @brief Calculate the closest sample rate clock configuration. + * clock relationship: + * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) * - * @param hw Peripheral I2S hardware instance address. + * @param fsclk I2S source clock freq. + * @param fbck BCK freuency. + * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. + * @param cal Point to `i2s_clk_cal_t` structure. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal) { - abort(); // TODO ESP32-C3 IDF-2098 - - + int ma = 0; + int mb = 0; + uint32_t mclk = fbck*bck_div; + cal->mclk_div = fsclk / mclk; + cal->bck_div = bck_div; + cal->a = 1; + cal->b = 0; + uint32_t freq_diff = fsclk - mclk * cal->mclk_div; + uint32_t min = freq_diff * 512; + if (freq_diff == 0) { + return; + } + for (int a = 2; a <= 512; a++) { + for (int b = 1; b < a; b++) { + ma = freq_diff*a; + mb = mclk*b; + if (ma == mb) { + cal->a = a; + cal->b = b; + return; + } + if (abs((mb - ma)) < min) { + cal->a = a; + cal->b = b; + min = abs(mb - ma); + } + } + } } /** - * @brief Reset tx fifo + * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_general_init(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->tx_clkm_conf.clk_en = 1; } /** - * @brief Enable rx interrupt + * @brief Reset I2S TX module, enable default source clock and set to TDM mode. * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->tx_conf.tx_start = 0; + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; + hw->tx_conf.tx_slave_mod = 0; + hw->tx_conf.tx_tdm_en = 1; + hw->tx_conf.tx_pdm_en = 0; + hw->tx_clkm_conf.tx_clk_active = 1; + hw->tx_clkm_conf.tx_clk_sel = 2; } /** - * @brief Disable rx interrupt + * @brief Reset I2S RX module, enable default source clock and set to TDM mode. * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->rx_conf.rx_start = 0; + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; + hw->rx_conf.rx_slave_mod = 0; + hw->rx_conf.rx_tdm_en = 1; + hw->rx_conf.rx_pdm_en = 0; + hw->rx_clkm_conf.rx_clk_active = 1; + hw->rx_clkm_conf.rx_clk_sel = 2; + hw->rx_clkm_conf.mclk_sel = 0; } /** - * @brief Disable tx interrupt + * @brief Enable I2S TX slave mode * * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->tx_conf.tx_slave_mod = slave_en; } /** - * @brief Enable tx interrupt + * @brief Enable I2S RX slave mode * * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->rx_conf.rx_slave_mod = slave_en; } /** - * @brief Reset dma in - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-C3 IDF-2098 - - -} - -/** - * @brief Reset dma out - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-C3 IDF-2098 - - -} - -/** - * @brief Reset tx + * @brief Reset I2S TX module * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_reset_tx(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; } /** - * @brief Reset rx + * @brief Reset I2S RX module * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_reset_rx(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - - + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; } /** - * @brief Start out link + * @brief Reset I2S TX FIFO * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_out_link(i2s_dev_t *hw) +static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_fifo_reset = 1; + hw->tx_conf.tx_fifo_reset = 0; } /** - * @brief Start tx + * @brief Reset I2S RX FIFO + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +{ + hw->rx_conf.rx_fifo_reset = 1; + hw->rx_conf.rx_fifo_reset = 0; +} + +/** + * @brief Set TX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` + */ +static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + hw->tx_clkm_conf.tx_clk_sel = 2; +} + +/** + * @brief Set RX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` + */ +static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + hw->rx_clkm_conf.rx_clk_sel = 2; +} + +/** + * @brief Configure I2S TX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +{ + if (set->a == 0 || set->b == 0) { + hw->tx_clkm_div_conf.tx_clkm_div_x = 0; + hw->tx_clkm_div_conf.tx_clkm_div_y = 0; + hw->tx_clkm_div_conf.tx_clkm_div_z = 0; + } else { + if(set->b > set->a/2) { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/(set->a-set->b) -1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%(set->a-set->b); + hw->tx_clkm_div_conf.tx_clkm_div_z = set->a-set->b; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 1; + } else { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/set->b-1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%set->b+1; + hw->tx_clkm_div_conf.tx_clkm_div_z = set->b; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0; + } + } + hw->tx_clkm_conf.tx_clkm_div_num = set->mclk_div; + hw->tx_conf1.tx_bck_div_num = set->bck_div-1; +} + +/** + * @brief Configure I2S RX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +{ + if (set->a == 0 || set->b == 0) { + hw->rx_clkm_div_conf.rx_clkm_div_x = 0; + hw->rx_clkm_div_conf.rx_clkm_div_y = 0; + hw->rx_clkm_div_conf.rx_clkm_div_z = 0; + } else { + if(set->b > set->a/2) { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/(set->a-set->b)-1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%(set->a-set->b); + hw->rx_clkm_div_conf.rx_clkm_div_z = set->a-set->b; + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 1; + } else { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/set->b-1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%set->b+1; + hw->rx_clkm_div_conf.rx_clkm_div_z = set->b; + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0; + } + } + hw->rx_clkm_conf.rx_clkm_div_num = set->mclk_div; + hw->rx_conf1.rx_bck_div_num = set->bck_div-1; +} + +/** + * @brief Start I2S TX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_start_tx(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_update = 0; + hw->tx_conf.tx_update = 1; + hw->tx_conf.tx_start = 1; } /** - * @brief Start in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_in_link(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Start rx + * @brief Start I2S RX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_start_rx(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf.rx_update = 0; + hw->rx_conf.rx_update = 1; + hw->rx_conf.rx_start = 1; } /** - * @brief Stop out link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Stop tx + * @brief Stop I2S TX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_stop_tx(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_start = 0; } /** - * @brief Stop in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Stop rx + * @brief Stop I2S RX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf.rx_start = 0; } /** - * @brief Enable dma + * @brief Configure TX WS signal width * * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle */ -static inline void i2s_ll_enable_dma(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) { - abort(); // TODO ESP32-C3 IDF-2098 - // //Enable and configure DMA - // typeof(hw->lc_conf) lc_conf; - // lc_conf.val = 0; - // lc_conf.out_eof_mode = 1; - + hw->tx_conf1.tx_tdm_ws_width = width-1; } /** - * @brief Get I2S interrupt status + * @brief Configure RX WS signal width * * @param hw Peripheral I2S hardware instance address. - * @param val value to get interrupt status + * @param width WS width in BCK cycle */ -static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->int_st.val; + hw->rx_conf1.rx_tdm_ws_width = width-1; } /** - * @brief Clear I2S interrupt status + * @brief Configure the received length to trigger in_suc_eof interrupt * * @param hw Peripheral I2S hardware instance address. - * @param val value to clear interrupt status + * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_eof_num.rx_eof_num = eof_num; } /** - * @brief Get I2S out eof des address + * @brief Congfigure TX slot bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get out eof des address + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->out_eof_des_addr; + hw->tx_conf1.tx_bits_mod = data_bit - 1; + hw->tx_conf1.tx_tdm_chan_bits = sample_bit-1; } /** - * @brief Get I2S in eof des address + * @brief Congfigure RX slot bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get in eof des address + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->in_eof_des_addr; + hw->rx_conf1.rx_bits_mod = data_bit - 1; + hw->rx_conf1.rx_tdm_chan_bits = sample_bit-1; } /** - * @brief Get I2S tx fifo mode + * @brief Configure RX half_sample_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx fifo mode + * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->fifo_conf.tx_fifo_mod; + hw->tx_conf1.tx_half_sample_bits = half_sample_bits-1; } /** - * @brief Set I2S tx fifo mode + * @brief Configure RX half_sample_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mode + * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf1.rx_half_sample_bits = half_sample_bits-1; } /** - * @brief Get I2S rx fifo mode + * @brief Enable TX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx fifo mode + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_tx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->fifo_conf.rx_fifo_mod; + hw->tx_conf1.tx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S rx fifo mode + * @brief Enable RX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mode + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf1.rx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S tx chan mode + * @brief Configure TX total slot number * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx chan mode + * @param total_num Total slot number */ -static inline void i2s_ll_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_slot_mun(i2s_dev_t *hw, int total_num) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num-1; } /** - * @brief Set I2S rx chan mode + * @brief Configure RX total slot number * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx chan mode + * @param total_num Total slot number */ -static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_slot_mun(i2s_dev_t *hw, int total_num) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num-1; } /** - * @brief Set I2S out link address + * @brief Set the bimap of the active TX slot, only the active slot can launch audio data. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set out link address + * @param */ -static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) { - abort(); // TODO ESP32-C3 IDF-2098 - + typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK; + tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK; + hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set I2S in link address + * @brief Set the bimap of the active RX slot, only the active slot can receive audio data. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set in link address + * @param */ -static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) { - abort(); // TODO ESP32-C3 IDF-2098 - + typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK; + tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK; + hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set I2S rx eof num + * @brief Set TX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx eof num + * @param */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_ws_idle_pol = ws_pol_level; } /** - * @brief Get I2S tx pdm fp + * @brief Set RX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx pdm fp + * @param */ -static inline void i2s_ll_get_tx_pdm_fp(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->pdm_freq_conf.tx_pdm_fp; + hw->rx_conf.rx_ws_idle_pol = ws_pol_level; } /** - * @brief Get I2S tx pdm fs + * @brief Enable TX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx pdm fs + * @param pdm_enable Set true to TX enable PDM mode */ -static inline void i2s_ll_get_tx_pdm_fs(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->pdm_freq_conf.tx_pdm_fs; + if (pdm_enable) { + hw->tx_conf.tx_tdm_en = 0; + hw->tx_conf.tx_pdm_en = 1; + } else { + hw->tx_conf.tx_pdm_en = 0; + hw->tx_conf.tx_tdm_en = 1; + } } /** - * @brief Set I2S tx pdm fp + * @brief Configure I2S TX pdm * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm fp + * @param sample_rate The sample rate to be set. */ -static inline void i2s_ll_set_tx_pdm_fp(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) { - abort(); // TODO ESP32-C3 IDF-2098 - + uint32_t fp = 960; + uint32_t fs = sample_rate / 100; + typeof(hw->tx_pcm2pdm_conf) pdm_conf_reg = hw->tx_pcm2pdm_conf; + typeof(hw->tx_pcm2pdm_conf1) pdm_conf1_reg = hw->tx_pcm2pdm_conf1; + pdm_conf_reg.pcm2pdm_conv_en = 1; + pdm_conf_reg.tx_pdm_prescale = 0; + pdm_conf_reg.tx_pdm_hp_in_shift = 1; + pdm_conf_reg.tx_pdm_lp_in_shift = 1; + pdm_conf_reg.tx_pdm_sinc_in_shift = 1; + pdm_conf_reg.tx_pdm_sigmadelta_in_shift = 1; + pdm_conf_reg.tx_pdm_sinc_osr2 = fp/fs; + pdm_conf_reg.tx_pdm_dac_mode_en = 1; + pdm_conf_reg.tx_pdm_sigmadelta_dither = 0; + pdm_conf_reg.tx_pdm_sigmadelta_dither2 = 0; + pdm_conf_reg.tx_pdm_dac_2out_en = 1; + pdm_conf1_reg.tx_pdm_fp = fp; + pdm_conf1_reg.tx_pdm_fs = fs; + pdm_conf1_reg.tx_iir_hp_mult12_5 = 7; + pdm_conf1_reg.tx_iir_hp_mult12_0 =6; + pdm_conf_reg.tx_pdm_hp_bypass = 0; + hw->tx_pcm2pdm_conf = pdm_conf_reg; + hw->tx_pcm2pdm_conf1 = pdm_conf1_reg; } /** - * @brief Set I2S tx pdm fs + * @brief Configure I2S TX PDM sample rate + * Fpdm = 64*Fpcm*fp/fs * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm fs + * @param fp The fp value of TX PDM filter module group0. + * @param fs The fs value of TX PDM filter module group0. */ -static inline void i2s_ll_set_tx_pdm_fs(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp; + hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs; + hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = fp / fs; } /** - * @brief Get I2S rx sinc dsr 16 en + * @brief Get I2S TX PDM configuration * * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx sinc dsr 16 en + * @param fp Pointer to accept TX PDM fp configuration paramater + * @param fs Pointer to accept TX PDM fs configuration paramater */ -static inline void i2s_ll_get_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool *val) +static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) { - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->pdm_conf.rx_sinc_dsr_16_en; + *fp = hw->tx_pcm2pdm_conf1.tx_pdm_fp; + *fs = hw->tx_pcm2pdm_conf1.tx_pdm_fs; } /** - * @brief Set I2S clkm div num + * @brief Enable RX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div num + * @param pdm_enable Set true to RX enable PDM mode */ -static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { - abort(); // TODO ESP32-C3 IDF-2098 - + if (pdm_enable) { + hw->rx_conf.rx_tdm_en = 0; + hw->rx_conf.rx_pdm_en = 1; + } else { + hw->rx_conf.rx_pdm_en = 0; + hw->rx_conf.rx_tdm_en = 1; + } } /** - * @brief Set I2S clkm div b + * @brief Configura TX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div b + * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) { - abort(); // TODO ESP32-C3 IDF-2098 - + if (pcm_cfg == I2S_PCM_DISABLE) { + hw->tx_conf.tx_pcm_bypass = 1; + } else { + hw->tx_conf.tx_pcm_conf = pcm_cfg; + hw->tx_conf.tx_pcm_bypass = 0; + } } /** - * @brief Set I2S clkm div a + * @brief Configure RX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div a + * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) { - abort(); // TODO ESP32-C3 IDF-2098 - + if (pcm_cfg == I2S_PCM_DISABLE) { + hw->rx_conf.rx_pcm_bypass = 1; + } else { + hw->rx_conf.rx_pcm_conf = pcm_cfg; + hw->rx_conf.rx_pcm_bypass = 0; + } } /** - * @brief Set I2S tx bck div num + * @brief Enable TX audio data left alignment * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bck div num + * @param ena Set true to enable left alignment */ -static inline void i2s_ll_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_left_align_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_left_align = ena; } /** - * @brief Set I2S rx bck div num + * @brief Enable RX audio data left alignment * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bck div num + * @param ena Set true to enable left alignment */ -static inline void i2s_ll_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_left_align_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf.rx_left_align = ena; } /** - * @brief Set I2S clk sel + * @brief Enable TX big endian mode * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clk sel + * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_big_endian_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf.rx_big_endian = ena; } /** - * @brief Set I2S tx bits mod + * @brief Enable RX big endian mode * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bits mod + * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_big_endian_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_big_endian = ena; } /** - * @brief Set I2S rx bits mod + * @brief Configure TX bit order * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bits mod + * @param lsb_order_ena Set true to enable LSB bit order */ -static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.tx_bit_order = lsb_order_ena; } /** - * @brief Set I2S rx sinc dsr 16 en + * @brief Configure RX bit order * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx sinc dsr 16 en + * @param lsb_order_ena Set true to enable LSB bit order */ -static inline void i2s_ll_set_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool val) +static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->rx_conf.rx_bit_order = lsb_order_ena; } /** - * @brief Set I2S dscr en + * @brief Configure single data * * @param hw Peripheral I2S hardware instance address. - * @param val value to set dscr en + * @param data Single data to be set */ -static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val) +static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) { - abort(); // TODO ESP32-C3 IDF-2098 - + hw->conf_single_data = data; } /** - * @brief Set I2S lcd en + * @brief Enable loopback mode * * @param hw Peripheral I2S hardware instance address. - * @param val value to set lcd en + * @param ena Set true to enable loopback mode. */ -static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val) +static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S camera en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set camera en - */ -static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S pcm2pdm conv en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set pcm2pdm conv en - */ -static inline void i2s_ll_set_pcm2pdm_conv_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S TX to MSB Alignment Standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_format_msb_align(i2s_dev_t *hw) -{ -} - - -static inline void i2s_ll_set_rx_format_msb_align(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_long(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_short(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to philip standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_format_philip(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_short(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to philip standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_format_philip(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S pdm2pcm conv en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set pdm2pcm conv en - */ -static inline void i2s_ll_set_pdm2pcm_conv_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S rx pdm en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx pdm en - */ -static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S tx pdm en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm en - */ -static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S tx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mod force en - */ -static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S rx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mod force en - */ -static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S tx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx right first - */ -static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S rx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx right first - */ -static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S tx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx slave mod - */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S rx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx slave mod - */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Get I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx msb right - */ -static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->conf.tx_msb_right; -} - -/** - * @brief Get I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx msb right - */ -static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - // *val = hw->conf.rx_msb_right; -} - -/** - * @brief Set I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx msb right - */ -static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx msb right - */ -static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S tx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx mono - */ -static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S rx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx mono - */ -static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S tx sinc osr2 - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx sinc osr2 - */ -static inline void i2s_ll_set_tx_sinc_osr2(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - -} - -/** - * @brief Set I2S sig loopback - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set sig loopback - */ -static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-C3 IDF-2098 - + hw->tx_conf.sig_loopback = ena; } #ifdef __cplusplus diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index 3e0a7eeb20..fc683436e2 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -1,4 +1,4 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -39,19 +39,148 @@ extern "C" { #define I2S_INTR_OUT_DSCR_ERR BIT(14) #define I2S_INTR_MAX (0xFFFFFFFF) +/* I2S clock configuration structure */ +typedef struct { + uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a) + uint16_t a; + uint16_t b; // The decimal part of module clock devider, the decimal is: b/a + uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div +} i2s_clk_cal_t; + /** - * @brief Reset rx fifo + * @brief Calculate the closest sample rate clock configuration. + * clock relationship: + * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) * - * @param hw Peripheral I2S hardware instance address. + * @param fsclk I2S source clock freq. + * @param fbck BCK freuency. + * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. + * @param cal Point to `i2s_clk_cal_t` structure. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal) { - hw->conf.rx_fifo_reset = 1; - hw->conf.rx_fifo_reset = 0; + int ma = 0; + int mb = 0; + uint32_t mclk = fbck*bck_div; + cal->mclk_div = fsclk / mclk; + cal->bck_div = bck_div; + cal->a = 1; + cal->b = 0; + uint32_t freq_diff = fsclk - mclk * cal->mclk_div; + uint32_t min = ~0; + if (freq_diff == 0) { + return; + } + for (int a = 2; a <= 63; a++) { + for (int b = 1; b < a; b++) { + ma = freq_diff*a; + mb = mclk*b; + if (ma == mb) { + cal->a = a; + cal->b = b; + return; + } + if (abs((mb - ma)) < min) { + cal->a = a; + cal->b = b; + min = abs(mb - ma); + } + } + } } /** - * @brief Reset tx fifo + * @brief I2S module general init, enable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_general_init(i2s_dev_t *hw) +{ + if (hw->clkm_conf.clk_en == 0) { + hw->clkm_conf.clk_sel = 2; + hw->clkm_conf.clk_en = 1; + hw->conf2.val = 0; + } +} + +/** + * @brief I2S TX module general init. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw) +{ + hw->conf.tx_start = 0; + hw->conf.tx_reset = 1; + hw->conf.tx_reset = 0; + hw->conf.tx_msb_right = 0; + hw->conf.tx_right_first = 0; + hw->conf.tx_slave_mod = 0; + hw->fifo_conf.tx_fifo_mod_force_en = 1; +} + +/** + * @brief I2S RX module general init. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw) +{ + hw->conf.rx_start = 0; + hw->conf.rx_reset = 1; + hw->conf.rx_reset = 0; + hw->conf.rx_msb_right = 0; + hw->conf.rx_right_first = 0; + hw->conf.rx_slave_mod = 0; + hw->fifo_conf.rx_fifo_mod_force_en = 1; +} + +/** + * @brief Enable I2S TX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->conf.tx_slave_mod = slave_en; +} + +/** + * @brief Enable I2S RX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->conf.rx_slave_mod = slave_en; +} + +/** + * @brief Reset TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +{ + hw->conf.tx_reset = 1; + hw->conf.tx_reset = 0; +} + +/** + * @brief Reset RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_rx(i2s_dev_t *hw) +{ + hw->conf.rx_reset = 1; + hw->conf.rx_reset = 0; +} + +/** + * @brief Reset TX FIFO * * @param hw Peripheral I2S hardware instance address. */ @@ -62,40 +191,68 @@ static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) } /** - * @brief Enable rx interrupt + * @brief Reset RX FIFO * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) { - hw->int_ena.in_suc_eof = 1; - hw->int_ena.in_dscr_err = 1; + hw->conf.rx_fifo_reset = 1; + hw->conf.rx_fifo_reset = 0; } /** - * @brief Disable rx interrupt + * @brief Set TX source clock * * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock */ -static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { - hw->int_ena.in_suc_eof = 0; - hw->int_ena.in_dscr_err = 0; + hw->clkm_conf.clk_sel = (src == 1) ? 1 : 2; } /** - * @brief Disable tx interrupt + * @brief Set RX source clock * * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock */ -static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { - hw->int_ena.out_eof = 0; - hw->int_ena.out_dscr_err = 0; + hw->clkm_conf.clk_sel = (src == 1) ? 1 : 2; } /** - * @brief Enable tx interrupt + * @brief Configure I2S TX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +{ + hw->clkm_conf.clkm_div_num = set->mclk_div; + hw->clkm_conf.clkm_div_b = set->b; + hw->clkm_conf.clkm_div_a = set->a; + hw->sample_rate_conf.tx_bck_div_num = set->bck_div; +} + +/** + * @brief Configure I2S RX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) +{ + hw->clkm_conf.clkm_div_num = set->mclk_div; + hw->clkm_conf.clkm_div_b = set->b; + hw->clkm_conf.clkm_div_a = set->a; + hw->sample_rate_conf.rx_bck_div_num = set->bck_div; +} + +/** + * @brief Enable TX interrupt * * @param hw Peripheral I2S hardware instance address. */ @@ -106,14 +263,58 @@ static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) } /** - * @brief Reset dma in + * @brief Disable TX interrupt * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) +static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) { - hw->lc_conf.in_rst = 1; - hw->lc_conf.in_rst = 0; + hw->int_ena.out_eof = 0; + hw->int_ena.out_dscr_err = 0; +} + +/** + * @brief Enable RX interrupt + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +{ + hw->int_ena.in_suc_eof = 1; + hw->int_ena.in_dscr_err = 1; +} + +/** + * @brief Disable RX interrupt + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +{ + hw->int_ena.in_suc_eof = 0; + hw->int_ena.in_dscr_err = 0; +} + +/** + * @brief Get I2S interrupt status + * + * @param hw Peripheral I2S hardware instance address. + * @param intr_mask Pointer to accept interrupt status + */ +static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *intr_mask) +{ + *intr_mask = hw->int_st.val; +} + +/** + * @brief Clear I2S interrupt status + * + * @param hw Peripheral I2S hardware instance address. + * @param clr_mask Interrupt mask to be cleared. + */ +static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t clr_mask) +{ + hw->int_clr.val = clr_mask; } /** @@ -128,39 +329,18 @@ static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) } /** - * @brief Reset tx + * @brief Reset dma in * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) { - hw->conf.tx_reset = 1; - hw->conf.tx_reset = 0; + hw->lc_conf.in_rst = 1; + hw->lc_conf.in_rst = 0; } /** - * @brief Reset rx - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_rx(i2s_dev_t *hw) -{ - hw->conf.rx_reset = 1; - hw->conf.rx_reset = 0; -} - -/** - * @brief Start out link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_out_link(i2s_dev_t *hw) -{ - hw->out_link.start = 1; -} - -/** - * @brief Start tx + * @brief Start TX module * * @param hw Peripheral I2S hardware instance address. */ @@ -170,17 +350,7 @@ static inline void i2s_ll_start_tx(i2s_dev_t *hw) } /** - * @brief Start in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_in_link(i2s_dev_t *hw) -{ - hw->in_link.start = 1; -} - -/** - * @brief Start rx + * @brief Start RX module * * @param hw Peripheral I2S hardware instance address. */ @@ -189,6 +359,50 @@ static inline void i2s_ll_start_rx(i2s_dev_t *hw) hw->conf.rx_start = 1; } +/** + * @brief Configure TX DMA descriptor address and start TX DMA + * + * @param hw Peripheral I2S hardware instance address. + * @param link_addr DMA descriptor link address. + */ +static inline void i2s_ll_start_tx_link(i2s_dev_t *hw, uint32_t link_addr) +{ + hw->out_link.addr = link_addr; + hw->out_link.start = 1; +} + +/** + * @brief Configure RX DMA descriptor address and start TX DMA + * + * @param hw Peripheral I2S hardware instance address. + * @param link_addr DMA descriptor link address. + */ +static inline void i2s_ll_start_rx_link(i2s_dev_t *hw, uint32_t link_addr) +{ + hw->in_link.addr = link_addr; + hw->in_link.start = 1; +} + +/** + * @brief Stop TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_stop_tx(i2s_dev_t *hw) +{ + hw->conf.tx_start = 0; +} + +/** + * @brief Stop RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +{ + hw->conf.rx_start = 0; +} + /** * @brief Stop out link * @@ -199,16 +413,6 @@ static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) hw->out_link.stop = 1; } -/** - * @brief Stop tx - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_tx(i2s_dev_t *hw) -{ - hw->conf.tx_start = 0; -} - /** * @brief Stop in link * @@ -220,456 +424,77 @@ static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) } /** - * @brief Stop rx + * @brief Get I2S out eof descriptor address * * @param hw Peripheral I2S hardware instance address. + * @param eof_addr Pointer to accept out eof des address */ -static inline void i2s_ll_stop_rx(i2s_dev_t *hw) +static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) { - hw->conf.rx_start = 0; + *eof_addr = hw->out_eof_des_addr; } /** - * @brief Enable dma + * @brief Get I2S in eof descriptor address * * @param hw Peripheral I2S hardware instance address. + * @param eof_addr Pointer to accept in eof des address */ -static inline void i2s_ll_enable_dma(i2s_dev_t *hw) +static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr) { - //Enable and configure DMA - typeof(hw->lc_conf) lc_conf; - lc_conf.val = 0; - lc_conf.out_eof_mode = 1; - hw->lc_conf.val = lc_conf.val; + *eof_addr = hw->in_eof_des_addr; } /** - * @brief Get I2S interrupt status + * @brief Configure the received length to trigger in_suc_eof interrupt * * @param hw Peripheral I2S hardware instance address. - * @param val value to get interrupt status + * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t eof_num) { - *val = hw->int_st.val; + hw->rx_eof_num = eof_num; } /** - * @brief Clear I2S interrupt status + * @brief Congfigure TX slot bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to clear interrupt status + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - hw->int_clr.val = val; + hw->fifo_conf.tx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); + hw->sample_rate_conf.tx_bits_mod = data_bit; } /** - * @brief Get I2S out eof des address + * @brief Congfigure RX slot bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get out eof des address + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - *val = hw->out_eof_des_addr; + hw->fifo_conf.rx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2); + hw->sample_rate_conf.rx_bits_mod = data_bit; } /** - * @brief Get I2S in eof des address + * @brief Enable I2S DMA * * @param hw Peripheral I2S hardware instance address. - * @param val value to get in eof des address + * @param ena Set true to enable DMA */ -static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_dma_enable(i2s_dev_t *hw, bool ena) { - *val = hw->in_eof_des_addr; -} - -/** - * @brief Get I2S tx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx fifo mode - */ -static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->fifo_conf.tx_fifo_mod; -} - -/** - * @brief Set I2S tx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mode - */ -static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->fifo_conf.tx_fifo_mod = val; -} - -/** - * @brief Get I2S rx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx fifo mode - */ -static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->fifo_conf.rx_fifo_mod; -} - -/** - * @brief Set I2S rx fifo mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mode - */ -static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->fifo_conf.rx_fifo_mod = val; -} - -/** - * @brief Set I2S tx chan mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx chan mode - */ -static inline void i2s_ll_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf_chan.tx_chan_mod = val; -} - -/** - * @brief Set I2S rx chan mode - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx chan mode - */ -static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf_chan.rx_chan_mod = val; -} - -/** - * @brief Set I2S tx dma equal - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx dma equal - */ -static inline void i2s_ll_set_tx_dma_equal(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_dma_equal = val; -} - -/** - * @brief Set I2S rx dma equal - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx dma equal - */ -static inline void i2s_ll_set_rx_dma_equal(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_dma_equal = val; -} - -/** - * @brief Set I2S out link address - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set out link address - */ -static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val) -{ - hw->out_link.addr = val; -} - -/** - * @brief Set I2S in link address - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set in link address - */ -static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val) -{ - hw->in_link.addr = val; -} - -/** - * @brief Set I2S rx eof num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx eof num - */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val) -{ - hw->rx_eof_num = val; -} - -/** - * @brief Set I2S clkm div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div num - */ -static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val) -{ - hw->clkm_conf.clkm_div_num = val; -} - -/** - * @brief Set I2S clkm div b - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div b - */ -static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val) -{ - hw->clkm_conf.clkm_div_b = val; -} - -/** - * @brief Set I2S clkm div a - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div a - */ -static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val) -{ - hw->clkm_conf.clkm_div_a = val; -} - -/** - * @brief Set I2S tx bck div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bck div num - */ -static inline void i2s_ll_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.tx_bck_div_num = val; -} - -/** - * @brief Set I2S rx bck div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bck div num - */ -static inline void i2s_ll_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.rx_bck_div_num = val; -} - -/** - * @brief Set I2S clk sel - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clk sel - */ -static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val) -{ - hw->clkm_conf.clk_sel = (val == 1) ? 1 : 2; -} - -/** - * @brief Set I2S tx bits mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bits mod - */ -static inline void i2s_ll_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.tx_bits_mod = val; -} - -/** - * @brief Set I2S rx bits mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bits mod - */ -static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->sample_rate_conf.rx_bits_mod = val; -} - -/** - * @brief Set I2S dscr en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set dscr en - */ -static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val) -{ - hw->fifo_conf.dscr_en = val; -} - -/** - * @brief Set I2S lcd en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set lcd en - */ -static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val) -{ - hw->conf2.lcd_en = val; -} - -/** - * @brief Set I2S camera en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set camera en - */ -static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val) -{ - hw->conf2.camera_en = val; -} - -/** - * @brief Set I2S tx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mod force en - */ -static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - hw->fifo_conf.tx_fifo_mod_force_en = val; -} - -/** - * @brief Set I2S rx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mod force en - */ -static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - hw->fifo_conf.rx_fifo_mod_force_en = val; -} - -/** - * @brief Set I2S tx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx right first - */ -static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_right_first = val; -} - -/** - * @brief Set I2S rx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx right first - */ -static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_right_first = val; -} - -/** - * @brief Set I2S tx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx slave mod - */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_slave_mod = val; -} - -/** - * @brief Set I2S rx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx slave mod - */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_slave_mod = val; -} - -/** - * @brief Get I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx msb right - */ -static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->conf.tx_msb_right; -} - -/** - * @brief Get I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx msb right - */ -static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - *val = hw->conf.rx_msb_right; -} - -/** - * @brief Set I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx msb right - */ -static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_msb_right = val; -} - -/** - * @brief Set I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx msb right - */ -static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_msb_right = val; -} - -/** - * @brief Set I2S tx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx mono - */ -static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.tx_mono = val; -} - -/** - * @brief Set I2S rx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx mono - */ -static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.rx_mono = val; -} - -/** - * @brief Set I2S sig loopback - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set sig loopback - */ -static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val) -{ - hw->conf.sig_loopback = val; + if (ena && !hw->fifo_conf.dscr_en) { + hw->fifo_conf.dscr_en = 1; + } else if (!ena && hw->fifo_conf.dscr_en) { + hw->fifo_conf.dscr_en = 0; + } } /** @@ -760,6 +585,53 @@ static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) hw->conf.rx_msb_shift = 0; } +/** + * @brief Enable TX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_tx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) +{ + int data_bit = hw->sample_rate_conf.tx_bits_mod; + if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) { + hw->fifo_conf.tx_fifo_mod = 0 + mono_ena; + } else { + hw->fifo_conf.tx_fifo_mod = 2 + mono_ena; + } + hw->conf.tx_dma_equal = mono_ena; + hw->conf_chan.tx_chan_mod = mono_ena; +} + +/** + * @brief Enable RX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_rx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena) +{ + int data_bit = hw->sample_rate_conf.rx_bits_mod; + if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) { + hw->fifo_conf.rx_fifo_mod = 0 + mono_ena; + } else { + hw->fifo_conf.rx_fifo_mod = 2 + mono_ena; + } + hw->conf.rx_dma_equal = mono_ena; + hw->conf_chan.rx_chan_mod = mono_ena; +} + +/** + * @brief Enable I2S loopback mode + * + * @param hw Peripheral I2S hardware instance address. + * @param loopback_en Set true to enable loopback mode. + */ +static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool loopback_en) +{ + hw->conf.sig_loopback = loopback_en; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 645e84793e..618b204d2d 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,16 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +// The LL layer for I2C register operations /******************************************************************************* * NOTICE * The hal is not public api, don't use in application code. * See readme.md in hal/include/hal/readme.md ******************************************************************************/ -// The LL layer for ESP32-S3 I2S register operations - #pragma once - #include #include "soc/i2s_periph.h" #include "hal/i2s_types.h" @@ -30,28 +28,157 @@ extern "C" { #endif -// Get I2S hardware instance with giving i2s num -#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL) -#define I2S_INTR_IN_SUC_EOF BIT(9) -#define I2S_INTR_OUT_EOF BIT(12) -#define I2S_INTR_IN_DSCR_ERR BIT(13) -#define I2S_INTR_OUT_DSCR_ERR BIT(14) -#define I2S_INTR_MAX (0xFFFFFFFF) +#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : &I2S1) +#define I2S_INTR_OUT_DSCR_ERR (0x1 << 6) +#define I2S_INTR_OUT_EOF (0x1 << 4) +#define I2S_INTR_IN_DSCR_ERR (0x1 << 5) +#define I2S_INTR_IN_SUC_EOF (0x1 << 1) +#define I2S_INTR_MAX (~0) + +#define I2S_TDM_CH_MASK (0xffff) + +/* I2S clock configuration structure */ +typedef struct { + uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a) + uint16_t a; + uint16_t b; // The decimal part of module clock devider, the decimal is: b/a + uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div +} i2s_clk_cal_t; /** - * @brief Reset rx fifo + * @brief Calculate the closest sample rate clock configuration. + * clock relationship: + * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) * - * @param hw Peripheral I2S hardware instance address. + * @param fsclk I2S source clock freq. + * @param fbck BCK freuency. + * @param bck_div The BCK devider of bck. Generally, set bck_div to 8. + * @param cal Point to `i2s_clk_cal_t` structure. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal) { - hw->rx_conf.rx_fifo_reset = 1; - hw->rx_conf.rx_fifo_reset = 0; + int ma = 0; + int mb = 0; + uint32_t mclk = fbck*bck_div; + cal->mclk_div = fsclk / mclk; + cal->bck_div = bck_div; + cal->a = 1; + cal->b = 0; + uint32_t freq_diff = fsclk - mclk * cal->mclk_div; + uint32_t min = freq_diff * 512; + if (freq_diff == 0) { + return; + } + for (int a = 2; a <= 512; a++) { + for (int b = 1; b < a; b++) { + ma = freq_diff*a; + mb = mclk*b; + if (ma == mb) { + cal->a = a; + cal->b = b; + return; + } + if (abs((mb - ma)) < min) { + cal->a = a; + cal->b = b; + min = abs(mb - ma); + } + } + } } /** - * @brief Reset tx fifo + * @brief I2S module general init, enable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_general_init(i2s_dev_t *hw) +{ + hw->tx_clkm_conf.clk_en = 1; +} + +/** + * @brief Reset I2S TX module, enable default source clock and set to TDM mode. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw) +{ + hw->tx_conf.tx_start = 0; + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; + hw->tx_conf.tx_slave_mod = 0; + hw->tx_conf.tx_tdm_en = 1; + hw->tx_conf.tx_pdm_en = 0; + hw->tx_clkm_conf.tx_clk_active = 1; + hw->tx_clkm_conf.tx_clk_sel = 2; +} + +/** + * @brief Reset I2S RX module, enable default source clock and set to TDM mode. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw) +{ + hw->rx_conf.rx_start = 0; + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; + hw->rx_conf.rx_slave_mod = 0; + hw->rx_conf.rx_tdm_en = 1; + hw->rx_conf.rx_pdm_en = 0; + hw->rx_clkm_conf.rx_clk_active = 1; + hw->rx_clkm_conf.rx_clk_sel = 2; + hw->rx_clkm_conf.mclk_sel = 0; +} + +/** + * @brief Enable I2S TX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->tx_conf.tx_slave_mod = slave_en; +} + +/** + * @brief Enable I2S RX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->rx_conf.rx_slave_mod = slave_en; +} + +/** + * @brief Reset I2S TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_tx(i2s_dev_t *hw) +{ + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; +} + +/** + * @brief Reset I2S RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_rx(i2s_dev_t *hw) +{ + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; +} + +/** + * @brief Reset I2S TX FIFO * * @param hw Peripheral I2S hardware instance address. */ @@ -62,787 +189,502 @@ static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) } /** - * @brief Enable rx interrupt + * @brief Reset I2S RX FIFO * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) { + hw->rx_conf.rx_fifo_reset = 1; + hw->rx_conf.rx_fifo_reset = 0; } /** - * @brief Disable rx interrupt + * @brief Set TX source clock * * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` */ -static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { + hw->tx_clkm_conf.tx_clk_sel = 2; } /** - * @brief Disable tx interrupt + * @brief Set RX source clock * * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` */ -static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) { + hw->rx_clkm_conf.rx_clk_sel = 2; } /** - * @brief Enable tx interrupt + * @brief Configure I2S TX clock devider * * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) { + if (set->a == 0 || set->b == 0) { + hw->tx_clkm_div_conf.tx_clkm_div_x = 0; + hw->tx_clkm_div_conf.tx_clkm_div_y = 0; + hw->tx_clkm_div_conf.tx_clkm_div_z = 0; + } else { + if(set->b > set->a/2) { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/(set->a-set->b) -1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%(set->a-set->b); + hw->tx_clkm_div_conf.tx_clkm_div_z = set->a-set->b; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 1; + } else { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/set->b-1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%set->b+1; + hw->tx_clkm_div_conf.tx_clkm_div_z = set->b; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0; + } + } + hw->tx_clkm_conf.tx_clkm_div_num = set->mclk_div; + hw->tx_conf1.tx_bck_div_num = set->bck_div-1; } /** - * @brief Reset dma in + * @brief Configure I2S RX clock devider * * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set) { + if (set->a == 0 || set->b == 0) { + hw->rx_clkm_div_conf.rx_clkm_div_x = 0; + hw->rx_clkm_div_conf.rx_clkm_div_y = 0; + hw->rx_clkm_div_conf.rx_clkm_div_z = 0; + } else { + if(set->b > set->a/2) { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/(set->a-set->b)-1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%(set->a-set->b); + hw->rx_clkm_div_conf.rx_clkm_div_z = set->a-set->b; + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 1; + } else { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/set->b-1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%set->b+1; + hw->rx_clkm_div_conf.rx_clkm_div_z = set->b; + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0; + } + } + hw->rx_clkm_conf.rx_clkm_div_num = set->mclk_div; + hw->rx_conf1.rx_bck_div_num = set->bck_div-1; } /** - * @brief Reset dma out - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) -{ -} - -/** - * @brief Reset tx - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_tx(i2s_dev_t *hw) -{ -} - -/** - * @brief Reset rx - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_rx(i2s_dev_t *hw) -{ -} - -/** - * @brief Start out link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_out_link(i2s_dev_t *hw) -{ -} - -/** - * @brief Start tx + * @brief Start I2S TX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_start_tx(i2s_dev_t *hw) { + hw->tx_conf.tx_update = 0; + hw->tx_conf.tx_update = 1; + hw->tx_conf.tx_start = 1; } /** - * @brief Start in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_in_link(i2s_dev_t *hw) -{ -} - -/** - * @brief Start rx + * @brief Start I2S RX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_start_rx(i2s_dev_t *hw) { + hw->rx_conf.rx_update = 0; + hw->rx_conf.rx_update = 1; + hw->rx_conf.rx_start = 1; } /** - * @brief Stop out link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) -{ -} - -/** - * @brief Stop tx + * @brief Stop I2S TX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_stop_tx(i2s_dev_t *hw) { + hw->tx_conf.tx_start = 0; } /** - * @brief Stop in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) -{ -} - -/** - * @brief Stop rx + * @brief Stop I2S RX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) { + hw->rx_conf.rx_start = 0; } /** - * @brief Enable dma + * @brief Configure TX WS signal width * * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle */ -static inline void i2s_ll_enable_dma(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) { + hw->tx_conf1.tx_tdm_ws_width = width-1; } /** - * @brief Get I2S interrupt status + * @brief Configure RX WS signal width * * @param hw Peripheral I2S hardware instance address. - * @param val value to get interrupt status + * @param width WS width in BCK cycle */ -static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) { - *val = hw->int_st.val; + hw->rx_conf1.rx_tdm_ws_width = width-1; } /** - * @brief Clear I2S interrupt status + * @brief Configure the received length to trigger in_suc_eof interrupt * * @param hw Peripheral I2S hardware instance address. - * @param val value to clear interrupt status + * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) { - hw->int_clr.val = val; + hw->rx_eof_num.rx_eof_num = eof_num; } /** - * @brief Get I2S out eof des address + * @brief Congfigure TX slot bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get out eof des address + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { + hw->tx_conf1.tx_bits_mod = data_bit - 1; + hw->tx_conf1.tx_tdm_chan_bits = sample_bit-1; } /** - * @brief Get I2S in eof des address + * @brief Congfigure RX slot bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get in eof des address + * @param sample_bit The slot bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { + hw->rx_conf1.rx_bits_mod = data_bit - 1; + hw->rx_conf1.rx_tdm_chan_bits = sample_bit-1; } /** - * @brief Get I2S tx fifo mode + * @brief Configure RX half_sample_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx fifo mode + * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { + hw->tx_conf1.tx_half_sample_bits = half_sample_bits-1; } /** - * @brief Set I2S tx fifo mode + * @brief Configure RX half_sample_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mode + * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { + hw->rx_conf1.rx_half_sample_bits = half_sample_bits-1; } /** - * @brief Get I2S rx fifo mode + * @brief Enable TX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx fifo mode + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_tx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) { + hw->tx_conf1.tx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S rx fifo mode + * @brief Enable RX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mode + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) { + hw->rx_conf1.rx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S tx chan mode + * @brief Configure TX total slot number * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx chan mode + * @param total_num Total slot number */ -static inline void i2s_ll_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_slot_mun(i2s_dev_t *hw, int total_num) { + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num-1; } /** - * @brief Set I2S rx chan mode + * @brief Configure RX total slot number * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx chan mode + * @param total_num Total slot number */ -static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_slot_mun(i2s_dev_t *hw, int total_num) { + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num-1; } /** - * @brief Set I2S out link address + * @brief Set the bimap of the active TX slot, only the active slot can launch audio data. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set out link address + * @param */ -static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) { + typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK; + tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK; + hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set I2S in link address + * @brief Set the bimap of the active RX slot, only the active slot can receive audio data. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set in link address + * @param */ -static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) { + typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK; + tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK; + hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set I2S rx eof num + * @brief Set TX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx eof num + * @param */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { + hw->tx_conf.tx_ws_idle_pol = ws_pol_level; } /** - * @brief Get I2S tx pdm fp + * @brief Set RX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx pdm fp + * @param */ -static inline void i2s_ll_get_tx_pdm_fp(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { + hw->rx_conf.rx_ws_idle_pol = ws_pol_level; } /** - * @brief Get I2S tx pdm fs + * @brief Enable TX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx pdm fs + * @param pdm_enable Set true to TX enable PDM mode */ -static inline void i2s_ll_get_tx_pdm_fs(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { + if (pdm_enable) { + hw->tx_conf.tx_tdm_en = 0; + hw->tx_conf.tx_pdm_en = 1; + } else { + hw->tx_conf.tx_pdm_en = 0; + hw->tx_conf.tx_tdm_en = 1; + } } /** - * @brief Set I2S tx pdm fp + * @brief Enable RX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm fp + * @param pdm_enable Set true to RX enable PDM mode */ -static inline void i2s_ll_set_tx_pdm_fp(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { + if (pdm_enable) { + hw->rx_conf.rx_tdm_en = 0; + hw->rx_conf.rx_pdm_en = 1; + } else { + hw->rx_conf.rx_pdm_en = 0; + hw->rx_conf.rx_tdm_en = 1; + } } /** - * @brief Set I2S tx pdm fs - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm fs - */ -static inline void i2s_ll_set_tx_pdm_fs(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Get I2S rx sinc dsr 16 en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx sinc dsr 16 en - */ -static inline void i2s_ll_get_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool *val) -{ -} - -/** - * @brief Set I2S clkm div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div num - */ -static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S clkm div b - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div b - */ -static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S clkm div a - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div a - */ -static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx bck div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bck div num - */ -static inline void i2s_ll_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx bck div num - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bck div num - */ -static inline void i2s_ll_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S clk sel - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set clk sel - */ -static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx bits mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bits mod - */ -static inline void i2s_ll_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx bits mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bits mod - */ -static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx sinc dsr 16 en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx sinc dsr 16 en - */ -static inline void i2s_ll_set_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S dscr en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set dscr en - */ -static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S lcd en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set lcd en - */ -static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S camera en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set camera en - */ -static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S pcm2pdm conv en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set pcm2pdm conv en - */ -static inline void i2s_ll_set_pcm2pdm_conv_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S pdm2pcm conv en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set pdm2pcm conv en - */ -static inline void i2s_ll_set_pdm2pcm_conv_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S rx pdm en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx pdm en - */ -static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S tx pdm en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm en - */ -static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S tx msb shift - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx msb shift - */ -static inline void i2s_ll_set_tx_msb_shift(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx msb shift - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx msb shift - */ -static inline void i2s_ll_set_rx_msb_shift(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx short sync - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx short sync - */ -static inline void i2s_ll_set_tx_short_sync(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx short sync - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx short sync - */ -static inline void i2s_ll_set_rx_short_sync(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mod force en - */ -static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S rx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mod force en - */ -static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ -} - -/** - * @brief Set I2S tx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx right first - */ -static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx right first - */ -static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx slave mod - */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx slave mod - */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Get I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx msb right - */ -static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ -} - -/** - * @brief Get I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx msb right - */ -static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ -} - -/** - * @brief Set I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx msb right - */ -static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx msb right - */ -static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx mono - */ -static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S rx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx mono - */ -static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S tx sinc osr2 - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx sinc osr2 - */ -static inline void i2s_ll_set_tx_sinc_osr2(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S sig loopback - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set sig loopback - */ -static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val) -{ -} - -/** - * @brief Set I2S TX to philip standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_format_philip(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to philip standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_format_philip(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to MSB Alignment Standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_format_msb_align(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to MSB Alignment Standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_format_msb_align(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_short(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_short(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_long(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) -{ -} - -/** - * @brief Configure I2S TX pdm - * - * @param sample_rate The sample rate to be set. - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) -{ -} - -/** - * @brief Configure I2S TX pdm + * @brief Set default RX PDM mode * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw) { + hw->rx_conf.rx_tdm_en = 0; + hw->rx_conf.rx_pdm2pcm_en = 1; + hw->rx_conf.rx_sinc_dsr_16_en = 0; + hw->rx_conf.rx_pdm_en = 1; } /** - * @brief Enable I2S build in ADC mode + * @brief Configure RX PDM downsample * * @param hw Peripheral I2S hardware instance address. + * @param dsr PDM downsample configuration paramater */ -static inline void i2s_ll_build_in_adc_ena(i2s_dev_t *hw) +static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) { + hw->rx_conf.rx_sinc_dsr_16_en = dsr; } /** - * @brief Enable I2S build in DAC mode + * @brief Get RX PDM downsample configuration * * @param hw Peripheral I2S hardware instance address. + * @param dsr Pointer to accept PDM downsample configuration */ -static inline void i2s_ll_build_in_dac_ena(i2s_dev_t *hw) +static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) { + *dsr = hw->rx_conf.rx_sinc_dsr_16_en; +} + +/** + * @brief Configura TX a/u-law decompress or compress + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm_cfg PCM configuration paramater + */ +static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) +{ + if (pcm_cfg == I2S_PCM_DISABLE) { + hw->tx_conf.tx_pcm_bypass = 1; + } else { + hw->tx_conf.tx_pcm_conf = pcm_cfg; + hw->tx_conf.tx_pcm_bypass = 0; + } +} + +/** + * @brief Configure RX a/u-law decompress or compress + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm_cfg PCM configuration paramater + */ +static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_t pcm_cfg) +{ + if (pcm_cfg == I2S_PCM_DISABLE) { + hw->rx_conf.rx_pcm_bypass = 1; + } else { + hw->rx_conf.rx_pcm_conf = pcm_cfg; + hw->rx_conf.rx_pcm_bypass = 0; + } +} + +/** + * @brief Enable TX audio data left alignment + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable left alignment + */ +static inline void i2s_ll_tx_left_align_enable(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.tx_left_align = ena; +} + +/** + * @brief Enable RX audio data left alignment + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable left alignment + */ +static inline void i2s_ll_rx_left_align_enable(i2s_dev_t *hw, bool ena) +{ + hw->rx_conf.rx_left_align = ena; +} + +/** + * @brief Enable TX big endian mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable big endian mode + */ +static inline void i2s_ll_rx_big_endian_enable(i2s_dev_t *hw, bool ena) +{ + hw->rx_conf.rx_big_endian = ena; +} + +/** + * @brief Enable RX big endian mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable big endian mode + */ +static inline void i2s_ll_tx_big_endian_enable(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.tx_big_endian = ena; +} + +/** + * @brief Configure TX bit order + * + * @param hw Peripheral I2S hardware instance address. + * @param lsb_order_ena Set true to enable LSB bit order + */ +static inline void i2s_ll_tx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) +{ + hw->tx_conf.tx_bit_order = lsb_order_ena; +} + +/** + * @brief Configure RX bit order + * + * @param hw Peripheral I2S hardware instance address. + * @param lsb_order_ena Set true to enable LSB bit order + */ +static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) +{ + hw->rx_conf.rx_bit_order = lsb_order_ena; +} + +/** + * @brief Configure single data + * + * @param hw Peripheral I2S hardware instance address. + * @param data Single data to be set + */ +static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) +{ + hw->conf_single_data = data; +} + +/** + * @brief Enable loopback mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable loopback mode. + */ +static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.sig_loopback = ena; } #ifdef __cplusplus diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index f994add41b..c3c008ce5e 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -1,4 +1,4 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,230 +12,291 @@ // See the License for the specific language governing permissions and // limitations under the License. + // The HAL layer for I2S (common part) #include "soc/soc.h" #include "soc/soc_caps.h" +#include "soc/gdma_channel.h" #include "hal/i2s_hal.h" -#define I2S_TX_PDM_FP_DEF 960 // Set to the recommended value(960) in TRM -#define I2S_RX_PDM_DSR_DEF 0 +#define I2S_MODE_I2S (I2S_MODE_MASTER|I2S_MODE_SLAVE|I2S_MODE_TX|I2S_MODE_RX) /*!< I2S normal mode*/ -void i2s_hal_set_tx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits) +void i2s_hal_reset_tx(i2s_hal_context_t *hal) { - if (bits <= I2S_BITS_PER_SAMPLE_16BIT) { - i2s_ll_set_tx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1); - } else { - i2s_ll_set_tx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 2 : 3); - } - i2s_ll_set_tx_chan_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1); -#if SOC_I2S_SUPPORTS_DMA_EQUAL - i2s_ll_set_tx_dma_equal(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1); -#endif -} - -void i2s_hal_set_rx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits) -{ - if (bits <= I2S_BITS_PER_SAMPLE_16BIT) { - i2s_ll_set_rx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1); - } else { - i2s_ll_set_rx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 2 : 3); - } - i2s_ll_set_rx_chan_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1); -#if SOC_I2S_SUPPORTS_DMA_EQUAL - i2s_ll_set_rx_dma_equal(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1); -#endif -} - -void i2s_hal_set_in_link(i2s_hal_context_t *hal, uint32_t bytes_num, uint32_t addr) -{ - i2s_ll_set_in_link_addr(hal->dev, addr); - i2s_ll_set_rx_eof_num(hal->dev, bytes_num); -} - -#if SOC_I2S_SUPPORTS_PDM -void i2s_hal_tx_pdm_cfg(i2s_hal_context_t *hal, uint32_t fp, uint32_t fs) -{ - i2s_ll_tx_pdm_cfg(hal->dev, fp, fs); -} - -void i2s_hal_get_tx_pdm(i2s_hal_context_t *hal, uint32_t *fp, uint32_t *fs) -{ - i2s_ll_get_tx_pdm(hal->dev, fp, fs); -} - -void i2s_hal_rx_pdm_cfg(i2s_hal_context_t *hal, uint32_t dsr) -{ - i2s_ll_rx_pdm_cfg(hal->dev, dsr); -} - -void i2s_hal_get_rx_pdm(i2s_hal_context_t *hal, uint32_t *dsr) -{ - i2s_ll_get_rx_pdm(hal->dev, dsr); -} -#endif - -void i2s_hal_set_clk_div(i2s_hal_context_t *hal, int div_num, int div_a, int div_b, int tx_bck_div, int rx_bck_div) -{ - i2s_ll_set_clkm_div_num(hal->dev, div_num); - i2s_ll_set_clkm_div_a(hal->dev, div_a); - i2s_ll_set_clkm_div_b(hal->dev, div_b); - i2s_ll_set_tx_bck_div_num(hal->dev, tx_bck_div); - i2s_ll_set_rx_bck_div_num(hal->dev, rx_bck_div); -} - -void i2s_hal_set_tx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits) -{ - i2s_ll_set_tx_bits_mod(hal->dev, bits); -} - -void i2s_hal_set_rx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits) -{ - i2s_ll_set_rx_bits_mod(hal->dev, bits); -} - -void i2s_hal_reset(i2s_hal_context_t *hal) -{ - // Reset I2S TX/RX module first, and then, reset DMA and FIFO. i2s_ll_reset_tx(hal->dev); +} + +void i2s_hal_reset_rx(i2s_hal_context_t *hal) +{ i2s_ll_reset_rx(hal->dev); - i2s_ll_reset_dma_in(hal->dev); - i2s_ll_reset_dma_out(hal->dev); - i2s_ll_reset_rx_fifo(hal->dev); +} + +void i2s_hal_reset_tx_fifo(i2s_hal_context_t *hal) +{ i2s_ll_reset_tx_fifo(hal->dev); } +void i2s_hal_reset_rx_fifo(i2s_hal_context_t *hal) +{ + i2s_ll_reset_rx_fifo(hal->dev); +} + void i2s_hal_start_tx(i2s_hal_context_t *hal) { - i2s_ll_start_out_link(hal->dev); i2s_ll_start_tx(hal->dev); } void i2s_hal_start_rx(i2s_hal_context_t *hal) { - i2s_ll_start_in_link(hal->dev); i2s_ll_start_rx(hal->dev); } void i2s_hal_stop_tx(i2s_hal_context_t *hal) { - i2s_ll_stop_out_link(hal->dev); i2s_ll_stop_tx(hal->dev); } void i2s_hal_stop_rx(i2s_hal_context_t *hal) { - i2s_ll_stop_in_link(hal->dev); i2s_ll_stop_rx(hal->dev); } -void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_config_t *i2s_config) +void i2s_hal_set_tx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit) { - switch (i2s_config->communication_format) { + i2s_ll_set_tx_sample_bit(hal->dev, slot_bit, data_bit); +} + +void i2s_hal_set_rx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit) +{ + i2s_ll_set_rx_sample_bit(hal->dev, slot_bit, data_bit); +} + +void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel) +{ + i2s_ll_set_tx_clk_src(hal->dev, sel); + i2s_ll_set_rx_clk_src(hal->dev, sel); +} + +void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor) +{ + i2s_clk_cal_t clk_set = {0}; + i2s_ll_clk_cal(sclk, fbck, factor, &clk_set); + i2s_ll_set_tx_clk(hal->dev, &clk_set); +} + +void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor) +{ + i2s_clk_cal_t clk_set = {0}; + i2s_ll_clk_cal(sclk, fbck, factor, &clk_set); + i2s_ll_set_rx_clk(hal->dev, &clk_set); +} + +void i2s_hal_set_rx_eof_num(i2s_hal_context_t *hal, uint32_t eof_byte) +{ + i2s_ll_set_rx_eof_num(hal->dev, eof_byte); +} + +void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal) +{ + i2s_ll_set_tx_slave_mod(hal->dev, 0); //TX master + i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave +} + +void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal) +{ + i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave + i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave +} + +#if SOC_I2S_SUPPORTS_PCM +void i2s_hal_tx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg) +{ + i2s_ll_tx_pcm_cfg(hal->dev, cfg); +} + +void i2s_hal_rx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg) +{ + i2s_ll_rx_pcm_cfg(hal->dev, cfg); +} +#endif + +void i2s_hal_enable_sig_loopback(i2s_hal_context_t *hal) +{ + i2s_ll_loop_back_ena(hal->dev, 1); +} + +#if SOC_I2S_SUPPORTS_PDM_TX +void i2s_hal_set_tx_pdm_fpfs(i2s_hal_context_t *hal, int fp, int fs) +{ + i2s_ll_set_tx_pdm_fpfs(hal->dev, fp, fs); +} + +void i2s_hal_get_tx_pdm_fpfs(i2s_hal_context_t *hal, int *fp, int *fs) +{ + i2s_ll_get_tx_pdm_fpfs(hal->dev, (uint32_t *)fp, (uint32_t *)fs); +} +#endif + +#if SOC_I2S_SUPPORTS_PDM_RX +void i2s_hal_set_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t dsr) +{ + i2s_ll_set_pdm_rx_dsr(hal->dev, dsr); +} + +void i2s_hal_get_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t *dsr) +{ + i2s_ll_get_pdm_rx_dsr(hal->dev, dsr); +} +#endif + +void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num) +{ + //Get hardware instance. + hal->dev = I2S_LL_GET_HW(i2s_num); +#if SOC_GDMA_SUPPORTED + hal->dma = &GDMA; + if (i2s_num == 0) { + hal->dma_ch = SOC_GDMA_I2S0_DMA_CHANNEL; + hal->dma_peri_sel = SOC_GDMA_TRIG_PERIPH_I2S0; + } +#if SOC_I2S_NUM > 1 + if (i2s_num == 1) { + hal->dma_ch = SOC_GDMA_I2S1_DMA_CHANNEL; + hal->dma_peri_sel = SOC_GDMA_TRIG_PERIPH_I2S1; + } +#endif + gdma_ll_enable_m2m_mode(hal->dma, hal->dma_ch, false); +#endif + i2s_ll_general_init(hal->dev); +} + +static void i2s_hal_format_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg) +{ + int active_slot_num = slot_ch_cfg & 0xffff; +#if !SOC_I2S_SUPPORTS_TDM + switch (format) { case I2S_COMM_FORMAT_STAND_MSB: - if (i2s_config->mode & I2S_MODE_TX) { + if (i2s_mode & I2S_MODE_TX) { i2s_ll_set_tx_format_msb_align(hal->dev); } - if (i2s_config->mode & I2S_MODE_RX) { + if (i2s_mode & I2S_MODE_RX) { i2s_ll_set_rx_format_msb_align(hal->dev); } break; case I2S_COMM_FORMAT_STAND_PCM_SHORT: - if (i2s_config->mode & I2S_MODE_TX) { - i2s_ll_set_tx_pcm_long(hal->dev); - } - if (i2s_config->mode & I2S_MODE_RX) { - i2s_ll_set_rx_pcm_long(hal->dev); - } - break; - case I2S_COMM_FORMAT_STAND_PCM_LONG: - if (i2s_config->mode & I2S_MODE_TX) { + if (i2s_mode & I2S_MODE_TX) { i2s_ll_set_tx_pcm_short(hal->dev); } - if (i2s_config->mode & I2S_MODE_RX) { + if (i2s_mode & I2S_MODE_RX) { i2s_ll_set_rx_pcm_short(hal->dev); } break; + case I2S_COMM_FORMAT_STAND_PCM_LONG: + if (i2s_mode & I2S_MODE_TX) { + i2s_ll_set_tx_pcm_long(hal->dev); + } + if (i2s_mode & I2S_MODE_RX) { + i2s_ll_set_rx_pcm_long(hal->dev); + } + break; default: //I2S_COMM_FORMAT_STAND_I2S - if (i2s_config->mode & I2S_MODE_TX) { + if (i2s_mode & I2S_MODE_TX) { i2s_ll_set_tx_format_philip(hal->dev); } - if (i2s_config->mode & I2S_MODE_RX) { + if (i2s_mode & I2S_MODE_RX) { i2s_ll_set_rx_format_philip(hal->dev); } break; } + if (active_slot_num == I2S_CHANNEL_MONO) { + if (i2s_mode & I2S_MODE_TX) { + i2s_ll_tx_mono_mode_ena(hal->dev, active_slot_num == I2S_CHANNEL_MONO); + } + if (i2s_mode & I2S_MODE_RX) { + i2s_ll_rx_mono_mode_ena(hal->dev, active_slot_num == I2S_CHANNEL_MONO); + } + } +#else + int data_bits = slot_bit_cfg & 0xffff; + int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT; + int slot_num = ((slot_ch_cfg >> SLOT_CH_SHIFT) == 0 || (active_slot_num == I2S_CHANNEL_MONO)) ? 2 : (slot_ch_cfg >> SLOT_CH_SHIFT); + bool msb_shift_en = false; + int tdm_ws_width = 0; + switch (format) { + case I2S_COMM_FORMAT_STAND_MSB: + msb_shift_en = false; + tdm_ws_width = slot_num*slot_bits/2; + break; + case I2S_COMM_FORMAT_STAND_PCM_SHORT: + msb_shift_en = false; + tdm_ws_width = 1; + break; + case I2S_COMM_FORMAT_STAND_PCM_LONG: + msb_shift_en = false; + tdm_ws_width = slot_bits; + break; + default: //I2S_COMM_FORMAT_STAND_I2S + msb_shift_en = true; + tdm_ws_width = slot_num*slot_bits/2; + break; + } + if (i2s_mode & I2S_MODE_TX) { + i2s_ll_tx_msb_shift_enable(hal->dev, msb_shift_en); + i2s_ll_set_tx_tdm_ws_width(hal->dev, tdm_ws_width); + i2s_ll_set_tx_half_sample_bit(hal->dev, slot_num*slot_bits/2); + } + if (i2s_mode & I2S_MODE_RX) { + i2s_ll_rx_msb_shift_enable(hal->dev, msb_shift_en); + i2s_ll_set_rx_tdm_ws_width(hal->dev, tdm_ws_width); + i2s_ll_set_rx_half_sample_bit(hal->dev, slot_num*slot_bits/2); + } +#endif } -void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config) +void i2s_hal_samples_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t communication_format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg) { - //reset i2s - i2s_ll_reset_tx(hal->dev); - i2s_ll_reset_rx(hal->dev); - - //reset dma - i2s_ll_reset_dma_in(hal->dev); - i2s_ll_reset_dma_out(hal->dev); - - i2s_ll_enable_dma(hal->dev); - - i2s_ll_set_lcd_en(hal->dev, 0); - i2s_ll_set_camera_en(hal->dev, 0); - - i2s_ll_set_dscr_en(hal->dev, 0); - - i2s_ll_set_tx_chan_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1)); // 0-two channel;1-right;2-left;3-righ;4-left - i2s_ll_set_tx_fifo_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1); // 0-right&left channel;1-one channel - i2s_ll_set_tx_mono(hal->dev, 0); - - i2s_ll_set_rx_chan_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1)); // 0-two channel;1-right;2-left;3-righ;4-left - i2s_ll_set_rx_fifo_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1); // 0-right&left channel;1-one channel - i2s_ll_set_rx_mono(hal->dev, 0); - - i2s_ll_set_dscr_en(hal->dev, 1); //connect dma to fifo - - i2s_ll_stop_tx(hal->dev); - i2s_ll_stop_rx(hal->dev); + int active_slot_num = slot_ch_cfg & 0xffff; + int data_bits = slot_bit_cfg & 0xffff; + int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT; + int slot_num = ((slot_ch_cfg >> SLOT_CH_SHIFT) == 0 || (active_slot_num == I2S_CHANNEL_MONO)) ? 2 : (slot_ch_cfg >> SLOT_CH_SHIFT); +#if SOC_I2S_SUPPORTS_TDM + if (i2s_mode & I2S_MODE_TX) { + i2s_ll_set_tx_slot_mun(hal->dev, slot_num); + i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits); + } + if (i2s_mode & I2S_MODE_RX) { + i2s_ll_set_rx_slot_mun(hal->dev, slot_num); + i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits); + } +#else + if (i2s_mode & I2S_MODE_TX) { + i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits); + } + if (i2s_mode & I2S_MODE_RX) { + i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits); + } +#endif + //I2S standards config: Philip, MSB or PCM, Only I2S mode should do this configuration. + if ((i2s_mode & (~(I2S_MODE_I2S))) == 0) { + i2s_hal_format_config(hal, i2s_mode, communication_format, slot_bit_cfg, slot_ch_cfg); + } +} +void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_param_t *i2s_config) +{ if (i2s_config->mode & I2S_MODE_TX) { - i2s_ll_set_tx_msb_right(hal->dev, 0); - i2s_ll_set_tx_right_first(hal->dev, 0); - - i2s_ll_set_tx_slave_mod(hal->dev, 0); // Master - i2s_ll_set_tx_fifo_mod_force_en(hal->dev, 1); - + i2s_ll_tx_gen_init(hal->dev); if (i2s_config->mode & I2S_MODE_SLAVE) { i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave } } - if (i2s_config->mode & I2S_MODE_RX) { - i2s_ll_set_rx_msb_right(hal->dev, 0); - i2s_ll_set_rx_right_first(hal->dev, 0); - i2s_ll_set_rx_slave_mod(hal->dev, 0); // Master - i2s_ll_set_rx_fifo_mod_force_en(hal->dev, 1); - + i2s_ll_rx_gen_init(hal->dev); if (i2s_config->mode & I2S_MODE_SLAVE) { i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave } } - -#if SOC_I2S_SUPPORTS_PDM - if (!(i2s_config->mode & I2S_MODE_PDM)) { - i2s_ll_set_rx_pdm_en(hal->dev, 0); - i2s_ll_set_tx_pdm_en(hal->dev, 0); - } else { - if (i2s_config->mode & I2S_MODE_TX) { - i2s_ll_tx_pdm_cfg(hal->dev, I2S_TX_PDM_FP_DEF, i2s_config->sample_rate/100); - } - if(i2s_config->mode & I2S_MODE_RX) { - i2s_ll_rx_pdm_cfg(hal->dev, I2S_RX_PDM_DSR_DEF); - } - // PDM mode have nothing to do with communication format configuration. - return; - } -#endif - #if SOC_I2S_SUPPORTS_ADC_DAC if (i2s_config->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { if (i2s_config->mode & I2S_MODE_DAC_BUILT_IN) { @@ -243,32 +304,54 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config } if (i2s_config->mode & I2S_MODE_ADC_BUILT_IN) { i2s_ll_build_in_adc_ena(hal->dev); - i2s_ll_set_rx_chan_mod(hal->dev, 1); - i2s_ll_set_rx_fifo_mod(hal->dev, 1); - i2s_ll_set_rx_mono(hal->dev, 0); } // Buildin ADC and DAC have nothing to do with communication format configuration. return; } #endif - i2s_hal_format_config(hal, i2s_config); -} +#if SOC_I2S_SUPPORTS_PDM + if (!(i2s_config->mode & I2S_MODE_PDM)) { +#if SOC_I2S_SUPPORTS_PDM_RX + if (i2s_config->mode & I2S_MODE_RX) { + i2s_ll_set_rx_pdm_en(hal->dev, false); + } +#endif +#if SOC_I2S_SUPPORTS_PDM_TX + if (i2s_config->mode & I2S_MODE_TX) { + i2s_ll_set_tx_pdm_en(hal->dev, false); + } +#endif + } else { +#if SOC_I2S_SUPPORTS_PDM_TX + if (i2s_config->mode & I2S_MODE_TX) { + i2s_ll_tx_pdm_cfg(hal->dev, i2s_config->sample_rate); + } +#endif -void i2s_hal_enable_master_mode(i2s_hal_context_t *hal) -{ - i2s_ll_set_tx_slave_mod(hal->dev, 0); //MASTER Slave - i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave -} +#if SOC_I2S_SUPPORTS_PDM_RX + if(i2s_config->mode & I2S_MODE_RX) { + i2s_ll_rx_pdm_cfg(hal->dev); + } +#endif + } +#endif -void i2s_hal_enable_slave_mode(i2s_hal_context_t *hal) -{ - i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave - i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave -} +#if SOC_I2S_SUPPORTS_TDM + if (i2s_config->mode & I2S_MODE_TX) { + i2s_ll_set_tx_active_slot_mask(hal->dev, i2s_config->active_slot_mask); + i2s_ll_tx_left_align_enable(hal->dev, i2s_config->left_align_en); + i2s_ll_tx_big_endian_enable(hal->dev, i2s_config->big_edin_en); + i2s_ll_tx_set_bit_order(hal->dev, i2s_config->bit_order_msb_en); + } + if (i2s_config->mode & I2S_MODE_RX) { + i2s_ll_set_rx_active_slot_mask(hal->dev, i2s_config->active_slot_mask); + i2s_ll_rx_left_align_enable(hal->dev, i2s_config->left_align_en); + i2s_ll_rx_big_endian_enable(hal->dev, i2s_config->big_edin_en); + i2s_ll_rx_set_bit_order(hal->dev, i2s_config->bit_order_msb_en); + } +#endif -void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num) -{ - //Get hardware instance. - hal->dev = I2S_LL_GET_HW(i2s_num); + //Configure I2S slot number,sample bit. + i2s_hal_samples_config(hal, i2s_config->mode, i2s_config->communication_format, i2s_config->slot_bits_cfg, i2s_config->slot_channel_cfg); } diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index 6964bfdf94..fab3a34ee2 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -1,4 +1,4 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -25,8 +25,11 @@ #include "soc/i2s_periph.h" #include "soc/soc_caps.h" -#include "hal/i2s_ll.h" #include "hal/i2s_types.h" +#include "hal/i2s_ll.h" +#if SOC_GDMA_SUPPORTED +#include "hal/gdma_ll.h" +#endif #ifdef __cplusplus extern "C" { @@ -37,162 +40,91 @@ extern "C" { */ typedef struct { i2s_dev_t *dev; +#if SOC_GDMA_SUPPORTED + gdma_dev_t *dma; + int dma_ch; + int dma_peri_sel; +#endif uint32_t version; } i2s_hal_context_t; -/** - * @brief Get I2S interrupt status - * - * @param hal Context of the HAL layer - * @param status interrupt status - */ -#define i2s_hal_get_intr_status(hal, status) i2s_ll_get_intr_status((hal)->dev, status) /** - * @brief Clear I2S interrupt status + * @brief Reset I2S TX channel * * @param hal Context of the HAL layer - * @param mask interrupt status mask */ -#define i2s_hal_clear_intr_status(hal, mask) i2s_ll_clear_intr_status((hal)->dev, mask) +void i2s_hal_reset_tx(i2s_hal_context_t *hal); /** - * @brief Get I2S out eof des address + * @brief Reset I2S TX fifo * * @param hal Context of the HAL layer - * @param addr out eof des address */ -#define i2s_hal_get_out_eof_des_addr(hal, addr) i2s_ll_get_out_eof_des_addr((hal)->dev, addr) +void i2s_hal_reset_tx_fifo(i2s_hal_context_t *hal); /** - * @brief Get I2S in eof des address + * @brief Reset I2S RX channel * * @param hal Context of the HAL layer - * @param addr in eof des address */ -#define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_get_in_eof_des_addr((hal)->dev, addr) +void i2s_hal_reset_rx(i2s_hal_context_t *hal); /** - * @brief Enable I2S rx interrupt + * @brief Reset I2S RX fifo * * @param hal Context of the HAL layer */ -#define i2s_hal_enable_rx_intr(hal) i2s_ll_enable_rx_intr((hal)->dev) +void i2s_hal_reset_rx_fifo(i2s_hal_context_t *hal); /** - * @brief Disable I2S rx interrupt + * @brief Init the I2S hal. This function should be called first before other hal layer function is called * * @param hal Context of the HAL layer + * @param i2s_num The uart port number, the max port number is (I2S_NUM_MAX -1) */ -#define i2s_hal_disable_rx_intr(hal) i2s_ll_disable_rx_intr((hal)->dev) +void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num); /** - * @brief Disable I2S tx interrupt + * @brief Configure I2S source clock * * @param hal Context of the HAL layer + * @param sel The source clock index */ -#define i2s_hal_disable_tx_intr(hal) i2s_ll_disable_tx_intr((hal)->dev) +void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel); /** - * @brief Enable I2S tx interrupt + * @brief Configure communication format * * @param hal Context of the HAL layer + * @param i2s_mode I2S mode. Using the ored mask of I2S_MODE_MASTER, I2S_MODE_SLAVE, I2S_MODE_TX, I2S_MODE_RX + * @param communication_format I2S communication format. Can be a value of `i2s_comm_format_t`. + * @param slot_bit_cfg I2S slot bit configuration + * @param slot_ch_cfg I2S slot channel configuration */ -#define i2s_hal_enable_tx_intr(hal) i2s_ll_enable_tx_intr((hal)->dev) +void i2s_hal_samples_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t communication_format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg); /** - * @brief Set I2S tx mode + * @brief Config I2S param * * @param hal Context of the HAL layer - * @param ch i2s channel - * @param bits bits per sample + * @param i2s_config I2S paramater configuration structer, refer to `i2s_config_param_t` */ -void i2s_hal_set_tx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits); +void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_param_t *i2s_config); /** - * @brief Set I2S rx mode + * @brief Enable I2S master full-duplex mode * * @param hal Context of the HAL layer - * @param ch i2s channel - * @param bits bits per sample */ -void i2s_hal_set_rx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits); +void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal); /** - * @brief Set I2S out link address - * - * @param hal Context of the HAL layer - * @param addr out link address - */ -#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr) - -/** - * @brief Set I2S out link address - * - * @param hal Context of the HAL layer - * @param addr out link address - */ -#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr) - -/** - * @brief Set I2S out link address - * - * @param hal Context of the HAL layer - * @param addr out link address - */ -#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr) - -/** - * @brief Set I2S in link - * - * @param hal Context of the HAL layer - * @param rx_eof_num in link eof num - * @param addr in link address - */ -void i2s_hal_set_in_link(i2s_hal_context_t *hal, uint32_t rx_eof_num, uint32_t addr); - -/** - * @brief Set I2S clk div - * - * @param hal Context of the HAL layer - * @param div_num i2s clkm div num - * @param div_a i2s clkm div a - * @param div_b i2s clkm div b - * @param tx_bck_div tx bck div num - * @param rx_bck_div rx bck div num - */ -void i2s_hal_set_clk_div(i2s_hal_context_t *hal, int div_num, int div_a, int div_b, int tx_bck_div, int rx_bck_div); - -/** - * @brief Set I2S clock sel - * - * @param hal Context of the HAL layer - * @param sel clock sel - */ -#define i2s_hal_set_clock_sel(hal, sel) i2s_ll_set_clk_sel((hal)->dev, sel) - -/** - * @brief Set I2S tx bits mod - * - * @param hal Context of the HAL layer - * @param bits bit width per sample. - */ -void i2s_hal_set_tx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits); - -/** - * @brief Set I2S rx bits mod - * - * @param hal Context of the HAL layer - * @param bits bit width per sample. - */ -void i2s_hal_set_rx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits); - -/** - * @brief Reset I2S TX & RX module, including DMA and FIFO + * @brief Enable I2S slave full-duplex mode * * @param hal Context of the HAL layer */ -void i2s_hal_reset(i2s_hal_context_t *hal); +void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal); /** * @brief Start I2S tx @@ -223,76 +155,256 @@ void i2s_hal_stop_tx(i2s_hal_context_t *hal); void i2s_hal_stop_rx(i2s_hal_context_t *hal); /** - * @brief Config I2S param + * @brief Set the received data length to trigger `in_suc_eof` interrupt. * * @param hal Context of the HAL layer - * @param i2s_config I2S configurations - see i2s_config_t struct + * @param eof_byte The byte length that trigger in_suc_eof interrupt. */ -void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config); +void i2s_hal_set_rx_eof_num(i2s_hal_context_t *hal, uint32_t eof_byte); /** - * @brief Enable I2S sig loopback + * @brief Set I2S TX sample bit * * @param hal Context of the HAL layer + * @param slot_bit I2S TX slot bit + * @param data_bit The sample data bit lengh. */ -#define i2s_hal_enable_sig_loopback(hal) i2s_ll_set_sig_loopback((hal)->dev, 1) +void i2s_hal_set_tx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit); /** - * @brief Enable I2S master mode + * @brief Set I2S RX sample bit * * @param hal Context of the HAL layer + * @param slot_bit I2S RX slot bit + * @param data_bit The sample data bit lengh. */ -void i2s_hal_enable_master_mode(i2s_hal_context_t *hal); +void i2s_hal_set_rx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit); /** - * @brief Enable I2S slave mode + * @brief Configure I2S TX module clock devider * * @param hal Context of the HAL layer + * @param sclk I2S source clock freq + * @param fbck I2S bck freq + * @param factor bck factor, factor=sclk/fbck */ -void i2s_hal_enable_slave_mode(i2s_hal_context_t *hal); +void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor); /** - * @brief Init the I2S hal and set the I2S to the default configuration. This function should be called first before other hal layer function is called + * @brief Configure I2S RX module clock devider * * @param hal Context of the HAL layer - * @param i2s_num The uart port number, the max port number is (I2S_NUM_MAX -1) + * @param sclk I2S source clock freq + * @param fbck I2S bck freq + * @param factor bck factor, factor=sclk/fbck */ -void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num); +void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor); -#if SOC_I2S_SUPPORTS_PDM +#if SOC_I2S_SUPPORTS_PCM /** - * @brief Set I2S tx pdm + * @brief Configure I2S TX PCM encoder or decoder. * * @param hal Context of the HAL layer - * @param fp tx pdm fp - * @param fs tx pdm fs + * @param cfg PCM configure paramater, refer to `i2s_pcm_cfg_t` */ -void i2s_hal_tx_pdm_cfg(i2s_hal_context_t *hal, uint32_t fp, uint32_t fs); +void i2s_hal_tx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg); /** - * @brief Get I2S tx pdm + * @brief Configure I2S RX PCM encoder or decoder. * * @param hal Context of the HAL layer - * @param dsr rx pdm dsr + * @param cfg PCM configure paramater, refer to `i2s_pcm_cfg_t` */ -void i2s_hal_rx_pdm_cfg(i2s_hal_context_t *hal, uint32_t dsr); +void i2s_hal_rx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg); +#endif /** - * @brief Get I2S tx pdm configuration + * @brief Enable loopback mode * * @param hal Context of the HAL layer - * @param fp Pointer to receive tx PDM fp configuration - * @param fs Pointer to receive tx PDM fs configuration */ -void i2s_hal_get_tx_pdm(i2s_hal_context_t *hal, uint32_t *fp, uint32_t *fs); +void i2s_hal_enable_sig_loopback(i2s_hal_context_t *hal); + +#if SOC_I2S_SUPPORTS_PDM_TX +/** + * @brief Configure I2S TX PDM sample rate + * Fpdm = 64*Fpcm*fp/fs + * + * @param hal Context of the HAL layer + * @param fp TX PDM fp paramater configuration + * @param fs TX PDM fs paramater configuration + */ +void i2s_hal_set_tx_pdm_fpfs(i2s_hal_context_t *hal, int fp, int fs); /** - * @brief Get I2S rx pdm configuration + * @brief Get I2S TX PDM configuration * * @param hal Context of the HAL layer - * @param dsr rx pdm dsr + * @param fp Pointer to accept TX PDM fp paramater configuration + * @param fs Pointer to accept TX PDM fs paramater configuration */ -void i2s_hal_get_rx_pdm(i2s_hal_context_t *hal, uint32_t *dsr); +void i2s_hal_get_tx_pdm_fpfs(i2s_hal_context_t *hal, int *fp, int *fs); +#endif + +#if SOC_I2S_SUPPORTS_PDM_RX + +/** + * @brief Configure RX PDM downsample + * + * @param hal Context of the HAL layer + * @param dsr PDM downsample configuration paramater + */ +void i2s_hal_set_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t dsr); + +/** + * @brief Get RX PDM downsample configuration + * + * @param hal Context of the HAL layer + * @param dsr Pointer to accept PDM downsample configuration + */ +void i2s_hal_get_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t *dsr); +#endif + +#if !SOC_GDMA_SUPPORTED +/** + * @brief Enable I2S TX DMA + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_attach_tx_dma(hal) i2s_ll_dma_enable((hal)->dev,true) + +/** + * @brief Enable I2S RX DMA + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_attach_rx_dma(hal) i2s_ll_dma_enable((hal)->dev,true) + +/** + * @brief Get I2S interrupt status + * + * @param hal Context of the HAL layer + * @param status Pointer to accept I2S interrupt status + */ +#define i2s_hal_get_intr_status(hal, status) i2s_ll_get_intr_status((hal)->dev, status) + +/** + * @brief Get I2S interrupt status + * + * @param hal Context of the HAL layer + * @param mask Interrupt mask to be cleared. + */ +#define i2s_hal_clear_intr_status(hal, mask) i2s_ll_clear_intr_status((hal)->dev, mask) + +/** + * @brief Enable I2S RX interrupt + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_enable_rx_intr(hal) i2s_ll_enable_rx_intr((hal)->dev) + +/** + * @brief Disable I2S RX interrupt + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_disable_rx_intr(hal) i2s_ll_disable_rx_intr((hal)->dev) + +/** + * @brief Disable I2S TX interrupt + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_disable_tx_intr(hal) i2s_ll_disable_tx_intr((hal)->dev) + +/** + * @brief Enable I2S TX interrupt + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_enable_tx_intr(hal) i2s_ll_enable_tx_intr((hal)->dev) + +/** + * @brief Configure TX DMA descriptor address and start TX DMA + * + * @param hal Context of the HAL layer + * @param link_addr DMA descriptor link address. + */ +#define i2s_hal_start_tx_link(hal, link_addr) i2s_ll_start_tx_link((hal)->dev, link_addr) + +/** + * @brief Configure RX DMA descriptor address and start RX DMA + * + * @param hal Context of the HAL layer + * @param link_addr DMA descriptor link address. + */ +#define i2s_hal_start_rx_link(hal, link_addr) i2s_ll_start_rx_link((hal)->dev, link_addr) + +/** + * @brief Stop TX DMA link + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_stop_tx_link(hal) i2s_ll_stop_out_link((hal)->dev) + +/** + * @brief Stop RX DMA link + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_stop_rx_link(hal) i2s_ll_stop_in_link((hal)->dev) + +/** + * @brief Reset RX DMA + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_reset_rxdma(hal) i2s_ll_reset_dma_in((hal)->dev) + +/** + * @brief Reset TX DMA + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_reset_txdma(hal) i2s_ll_reset_dma_out((hal)->dev) + +/** + * @brief Get I2S out eof descriptor address + * + * @param hal Context of the HAL layer + * @param addr Pointer to accept out eof des address + */ +#define i2s_hal_get_out_eof_des_addr(hal, addr) i2s_ll_get_out_eof_des_addr((hal)->dev, addr) + +/** + * @brief Get I2S in suc eof descriptor address + * + * @param hal Context of the HAL layer + * @param addr Pointer to accept in suc eof des address + */ +#define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_get_in_eof_des_addr((hal)->dev, addr) +#else +#define i2s_hal_attach_tx_dma(hal) gdma_ll_tx_connect_to_periph((hal)->dma, (hal)->dma_ch, (hal)->dma_peri_sel) +#define i2s_hal_attach_rx_dma(hal) gdma_ll_rx_connect_to_periph((hal)->dma, (hal)->dma_ch, (hal)->dma_peri_sel) +#define i2s_hal_get_intr_status(hal, status) (*status = (gdma_ll_get_interrupt_status((hal)->dma, (hal)->dma_ch))) +#define i2s_hal_clear_intr_status(hal, mask) gdma_ll_clear_interrupt_status((hal)->dma, (hal)->dma_ch, mask) +#define i2s_hal_enable_rx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_IN_DSCR_ERR|I2S_INTR_IN_SUC_EOF, 1) +#define i2s_hal_disable_rx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_IN_DSCR_ERR|I2S_INTR_IN_SUC_EOF, 0) +#define i2s_hal_enable_tx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_OUT_DSCR_ERR|I2S_INTR_OUT_EOF, 1) +#define i2s_hal_disable_tx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_OUT_DSCR_ERR|I2S_INTR_OUT_EOF, 0) +#define i2s_hal_start_tx_link(hal, link_addr) do{\ + gdma_ll_tx_set_desc_addr((hal)->dma,(hal)->dma_ch,link_addr);\ + gdma_ll_tx_start((hal)->dma,(hal)->dma_ch);}while(0) +#define i2s_hal_start_rx_link(hal, link_addr) do{\ + gdma_ll_rx_set_desc_addr((hal)->dma,(hal)->dma_ch,link_addr);\ + gdma_ll_rx_start((hal)->dma,(hal)->dma_ch);}while(0) + +#define i2s_hal_stop_tx_link(hal) gdma_ll_tx_stop((hal)->dma,(hal)->dma_ch) +#define i2s_hal_stop_rx_link(hal) gdma_ll_rx_stop((hal)->dma, (hal)->dma_ch) +#define i2s_hal_reset_rxdma(hal) gdma_ll_rx_reset_channel((hal)->dma, (hal)->dma_ch) +#define i2s_hal_reset_txdma(hal) gdma_ll_tx_reset_channel((hal)->dma, (hal)->dma_ch) +#define i2s_hal_get_out_eof_des_addr(hal, addr) (*addr = (gdma_ll_tx_get_eof_desc_addr((hal)->dma, (hal)->dma_ch))) +#define i2s_hal_get_in_eof_des_addr(hal, addr) (*addr = (gdma_ll_rx_get_success_eof_desc_addr((hal)->dma, (hal)->dma_ch))) #endif #ifdef __cplusplus diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index ba150cc7b3..e9d0fac8e4 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ #include #include +#include #include #include "soc/soc_caps.h" @@ -39,12 +40,47 @@ typedef enum { * */ typedef enum { - I2S_BITS_PER_SAMPLE_8BIT = 8, /*!< I2S bits per sample: 8-bits*/ - I2S_BITS_PER_SAMPLE_16BIT = 16, /*!< I2S bits per sample: 16-bits*/ - I2S_BITS_PER_SAMPLE_24BIT = 24, /*!< I2S bits per sample: 24-bits*/ - I2S_BITS_PER_SAMPLE_32BIT = 32, /*!< I2S bits per sample: 32-bits*/ + I2S_BITS_PER_SAMPLE_8BIT = 8, + I2S_BITS_PER_SAMPLE_16BIT = 16, + I2S_BITS_PER_SAMPLE_24BIT = 24, + I2S_BITS_PER_SAMPLE_32BIT = 32, } i2s_bits_per_sample_t; +/** + * @brief I2S bit width per slot. + * + */ +typedef enum { + I2S_BITS_PER_SLOT_8BIT = (8), /*!< slot bit 8*/ + I2S_BITS_PER_SLOT_16BIT = (16), /*!< slot bit 16*/ + I2S_BITS_PER_SLOT_24BIT = (24), /*!< slot bit 24*/ + I2S_BITS_PER_SLOT_32BIT = (32), /*!< slot bit 32*/ + I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU = (0), /*!< slot bit equals to data bit*/ +} i2s_bits_per_slot_t; + +#define SLOT_BIT_SHIFT (16) //slot bit shift +#define SLOT_CH_SHIFT (16) //slot channel shift + +/** + * @brief I2S slot bit configuration paramater. The low 16bit is the audio_data_bit_width and the high 16bit is the slot_bit_width. + * e.g.: If set to (I2S_BITS_PER_SLOT_24BIT << SLOT_BIT_SHIFT) | I2S_BITS_PER_SAMPLE_16BIT, the audio data bit is 16bit and the slot bit is 24bit. + * + * + * @note: If the slot_bit_width is set to `I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU`, then the slot_bit_width equals to audio_data_bit_width. + * + */ +typedef uint32_t i2s_slot_bits_cfg_t; /*!< slot bit configuration*/ + +/** + * @brief I2S slot channel configuration paramater. The low 16bit is the active_slot_number and the high 16bit is the total_slot_num. + * The audio data only launch in active slot, otherwise, launch 0 or single data in inactive slot. + * e.g.: If set to (4 << SLOT_CH_SHIFT) | 2, the active_slot_number is 2 and the total_slot_num 4. + * + * @note: If the total_slot_num is set to 0, then the total_slot_num equals to active_slot_number. + * + */ +typedef uint32_t i2s_slot_channel_cfg_t; /*!< slot channel configuration*/ + /** * @brief I2S channel. * @@ -54,25 +90,46 @@ typedef enum { I2S_CHANNEL_STEREO = 2 /*!< I2S 2 channel (stereo)*/ } i2s_channel_t; + +#if SOC_I2S_SUPPORTS_TDM +/** + * @brief Bit map of active slot. + * For TX module, only the active slot send the audio data, the inactive slot send a constant(configurable). + * For RX module, only receive the audio data in active slot, the data in inactive slot will be ignored. + * + * @note the bit map of active slot can not exceed (0x1< 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/ -} i2s_config_t; - -/** - * @brief I2S event types - * - */ -typedef enum { - I2S_EVENT_DMA_ERROR, - I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/ - I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/ - I2S_EVENT_MAX, /*!< I2S event max index*/ -} i2s_event_type_t; +#if SOC_I2S_SUPPORTS_TDM + i2s_slot_channel_cfg_t slot_channel_cfg; /*!< slot number configuration, low 16bit is the valid slot number; high 16bit is the total slot number, if set to 0, total slot number equals to valid slot number*/ + uint32_t active_slot_mask; /*!< active slot bit mask, using the ored mask of `i2s_tdm_active_slot_t`*/ + bool left_align_en; /*!< Set to enable left aligment*/ + bool big_edin_en; /*!< Set to enable big edin*/ + bool bit_order_msb_en; /*!< Set to enable msb order*/ +#endif +} i2s_config_param_t; #if SOC_I2S_SUPPORTS_ADC_DAC /** * @brief I2S DAC mode for i2s_set_dac_mode. * - * @note PDM and built-in DAC functions are only supported on I2S0 for current ESP32 chip. + * @note Built-in DAC functions are only supported on I2S0 for current ESP32 chip. */ typedef enum { I2S_DAC_CHANNEL_DISABLE = 0, /*!< Disable I2S built-in DAC signals*/ @@ -159,15 +206,6 @@ typedef enum { } i2s_dac_mode_t; #endif //SOC_I2S_SUPPORTS_ADC_DAC -/** - * @brief Event structure used in I2S event queue - * - */ -typedef struct { - i2s_event_type_t type; /*!< I2S event type */ - size_t size; /*!< I2S data size for I2S_DATA event*/ -} i2s_event_t; - /** * @brief I2S pin number for i2s_set_pin * @@ -179,7 +217,21 @@ typedef struct { int data_in_num; /*!< DATA in pin*/ } i2s_pin_config_t; -#if SOC_I2S_SUPPORTS_PDM +#if SOC_I2S_SUPPORTS_PCM +/** + * @brief A/U-law decompress or compress configuration. + * + */ +typedef enum { + I2S_PCM_A_DECOMPRESS=0, /*!< A-law decompress*/ + I2S_PCM_A_COMPRESS, /*!< A-law compress*/ + I2S_PCM_U_DECOMPRESS, /*!< U-law decompress*/ + I2S_PCM_U_COMPRESS, /*!< U-law compress*/ + I2S_PCM_DISABLE, /*!< Disable A/U law decopress or compress*/ +} i2s_pcm_cfg_t; +#endif + +#if SOC_I2S_SUPPORTS_PDM_RX /** * @brief I2S PDM RX downsample mode */ @@ -188,7 +240,9 @@ typedef enum { I2S_PDM_DSR_16S, /*!< downsampling number is 16 for PDM RX mode*/ I2S_PDM_DSR_MAX, } i2s_pdm_dsr_t; +#endif +#if SOC_I2S_SUPPORTS_PDM /** * @brief PDM PCM convter enable/disable. * diff --git a/components/soc/esp32/i2s_periph.c b/components/soc/esp32/i2s_periph.c index 84985aaf6a..f7a3c8ebc6 100644 --- a/components/soc/esp32/i2s_periph.c +++ b/components/soc/esp32/i2s_periph.c @@ -1,9 +1,9 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at - +// // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -20,30 +20,22 @@ */ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { { - .o_bck_in_sig = I2S0O_BCK_IN_IDX, - .o_ws_in_sig = I2S0O_WS_IN_IDX, - .o_bck_out_sig = I2S0O_BCK_OUT_IDX, - .o_ws_out_sig = I2S0O_WS_OUT_IDX, - .o_data_out_sig = I2S0O_DATA_OUT23_IDX, - .i_bck_in_sig = I2S0I_BCK_OUT_IDX, - .i_ws_in_sig = I2S0I_WS_OUT_IDX, - .i_bck_out_sig = I2S0I_BCK_IN_IDX, - .i_ws_out_sig = I2S0I_WS_IN_IDX, - .i_data_in_sig = I2S0I_DATA_IN15_IDX, + .rx_bck_sig = I2S0I_BCK_IN_IDX, + .tx_bck_sig = I2S0O_BCK_OUT_IDX, + .tx_ws_sig = I2S0O_WS_OUT_IDX, + .rx_ws_sig = I2S0I_WS_IN_IDX, + .data_out_sig = I2S0O_DATA_OUT23_IDX, + .data_in_sig = I2S0I_DATA_IN15_IDX, .irq = ETS_I2S0_INTR_SOURCE, .module = PERIPH_I2S0_MODULE, }, { - .o_bck_in_sig = I2S1O_BCK_IN_IDX, - .o_ws_in_sig = I2S1O_WS_IN_IDX, - .o_bck_out_sig = I2S1O_BCK_OUT_IDX, - .o_ws_out_sig = I2S1O_WS_OUT_IDX, - .o_data_out_sig = I2S1O_DATA_OUT23_IDX, - .i_bck_in_sig = I2S1I_BCK_OUT_IDX, - .i_ws_in_sig = I2S1I_WS_OUT_IDX, - .i_bck_out_sig = I2S1I_BCK_IN_IDX, - .i_ws_out_sig = I2S1I_WS_IN_IDX, - .i_data_in_sig = I2S1I_DATA_IN15_IDX, + .rx_bck_sig = I2S1I_BCK_IN_IDX, + .tx_bck_sig = I2S1O_BCK_OUT_IDX, + .tx_ws_sig = I2S1O_WS_OUT_IDX, + .rx_ws_sig = I2S1I_WS_IN_IDX, + .data_out_sig = I2S1O_DATA_OUT23_IDX, + .data_in_sig = I2S1I_DATA_IN15_IDX, .irq = ETS_I2S1_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, } diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index dd6f994b1a..a4c2a5c07e 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -136,12 +136,12 @@ /*-------------------------- I2S CAPS ----------------------------------------*/ // ESP32 have 2 I2S #define SOC_I2S_NUM (2) - -#define SOC_I2S_SUPPORTS_PDM (1) // ESP32 support PDM +#define SOC_I2S_SUPPORTS_PDM_TX (1) +#define SOC_I2S_SUPPORTS_PDM_RX (1) +#define SOC_I2S_SUPPORTS_PDM (1) // (SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) #define SOC_I2S_SUPPORTS_ADC_DAC (1) // ESP32 support ADC and DAC -#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated - +#define SOC_I2S_SUPPORTS_APLL (1)// ESP32 support APLL #define SOC_I2S_APLL_MIN_FREQ (250000000) #define SOC_I2S_APLL_MAX_FREQ (500000000) #define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware diff --git a/components/soc/esp32c3/i2s_periph.c b/components/soc/esp32c3/i2s_periph.c index b20ff7fbf8..4a19e3972a 100644 --- a/components/soc/esp32c3/i2s_periph.c +++ b/components/soc/esp32c3/i2s_periph.c @@ -20,19 +20,13 @@ */ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { { - // TODO ESP32-C3 IDF-2098 - - // .o_bck_in_sig = I2S0O_BCK_IN_IDX, - // .o_ws_in_sig = I2S0O_WS_IN_IDX, - // .o_bck_out_sig = I2S0O_BCK_OUT_IDX, - // .o_ws_out_sig = I2S0O_WS_OUT_IDX, - // .o_data_out_sig = I2S0O_SD_OUT_IDX, - // .i_bck_in_sig = I2S0I_BCK_OUT_IDX, - // .i_ws_in_sig = I2S0I_WS_OUT_IDX, - // .i_bck_out_sig = I2S0I_BCK_IN_IDX, - // .i_ws_out_sig = I2S0I_WS_IN_IDX, - // .i_data_in_sig = I2S0I_SD_IN_IDX, - .irq = ETS_I2S1_INTR_SOURCE, + .rx_bck_sig = I2SI_BCK_IN_IDX, + .tx_bck_sig = I2SO_BCK_OUT_IDX, + .tx_ws_sig = I2SO_WS_OUT_IDX, + .rx_ws_sig = I2SI_WS_IN_IDX, + .data_out_sig = I2SO_SD_OUT_IDX, + .data_in_sig = I2SI_SD_IN_IDX, + .irq = ETS_DMA_CH0_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32c3/ld/esp32c3.peripherals.ld b/components/soc/esp32c3/ld/esp32c3.peripherals.ld index 494cbb9b6b..710ae9aeea 100644 --- a/components/soc/esp32c3/ld/esp32c3.peripherals.ld +++ b/components/soc/esp32c3/ld/esp32c3.peripherals.ld @@ -7,7 +7,7 @@ PROVIDE ( SIGMADELTA = 0x60004f00 ); PROVIDE ( RTCCNTL = 0x60008000 ); PROVIDE ( RTCIO = 0x60008400 ); PROVIDE ( HINF = 0x6000B000 ); -PROVIDE ( I2S1 = 0x6002d000 ); +PROVIDE ( I2S0 = 0x6002d000 ); PROVIDE ( I2C0 = 0x60013000 ); PROVIDE ( UHCI0 = 0x60014000 ); PROVIDE ( UHCI1 = 0x6000c000 ); diff --git a/components/soc/esp32s2/i2s_periph.c b/components/soc/esp32s2/i2s_periph.c index 5029a68c8a..e4cfd8b976 100644 --- a/components/soc/esp32s2/i2s_periph.c +++ b/components/soc/esp32s2/i2s_periph.c @@ -1,9 +1,9 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at - +// // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -20,16 +20,12 @@ */ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { { - .o_bck_in_sig = I2S0O_BCK_IN_IDX, - .o_ws_in_sig = I2S0O_WS_IN_IDX, - .o_bck_out_sig = I2S0O_BCK_OUT_IDX, - .o_ws_out_sig = I2S0O_WS_OUT_IDX, - .o_data_out_sig = I2S0O_DATA_OUT23_IDX, - .i_bck_in_sig = I2S0I_BCK_OUT_IDX, - .i_ws_in_sig = I2S0I_WS_OUT_IDX, - .i_bck_out_sig = I2S0I_BCK_IN_IDX, - .i_ws_out_sig = I2S0I_WS_IN_IDX, - .i_data_in_sig = I2S0I_DATA_IN15_IDX, + .rx_bck_sig = I2S0I_BCK_IN_IDX, + .tx_bck_sig = I2S0O_BCK_OUT_IDX, + .tx_ws_sig = I2S0O_WS_OUT_IDX, + .rx_ws_sig = I2S0I_WS_IN_IDX, + .data_out_sig = I2S0O_DATA_OUT23_IDX, + .data_in_sig = I2S0I_DATA_IN15_IDX, .irq = ETS_I2S0_INTR_SOURCE, .module = PERIPH_I2S0_MODULE, } diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 0f633b8ef7..30b85dc4b2 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -135,13 +135,9 @@ #define SOC_I2C_SUPPORT_APB (1) /*-------------------------- I2S CAPS ----------------------------------------*/ -// ESP32-S2 have 2 I2S +// ESP32-S2 have 1 I2S #define SOC_I2S_NUM (1) - -#define SOC_I2S_SUPPORTS_DMA_EQUAL (1) // ESP32-S2 need dma equal - -#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated - +#define SOC_I2S_SUPPORTS_APLL (1)// ESP32-S2 support APLL #define SOC_I2S_APLL_MIN_FREQ (250000000) #define SOC_I2S_APLL_MAX_FREQ (500000000) #define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware diff --git a/components/soc/esp32s3/i2s_periph.c b/components/soc/esp32s3/i2s_periph.c index 52f714edf7..3d4a7cd6ef 100644 --- a/components/soc/esp32s3/i2s_periph.c +++ b/components/soc/esp32s3/i2s_periph.c @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,17 +20,23 @@ */ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { { - .o_bck_in_sig = I2S0O_BCK_IN_IDX, - .o_ws_in_sig = I2S0O_WS_IN_IDX, - .o_bck_out_sig = I2S0O_BCK_OUT_IDX, - .o_ws_out_sig = I2S0O_WS_OUT_IDX, - .o_data_out_sig = I2S0O_SD_OUT_IDX, - .i_bck_in_sig = I2S0I_BCK_OUT_IDX, - .i_ws_in_sig = I2S0I_WS_OUT_IDX, - .i_bck_out_sig = I2S0I_BCK_IN_IDX, - .i_ws_out_sig = I2S0I_WS_IN_IDX, - .i_data_in_sig = I2S0I_SD_IN_IDX, - .irq = ETS_I2S0_INTR_SOURCE, + .rx_bck_sig = I2S0I_BCK_IN_IDX, + .tx_bck_sig = I2S0O_BCK_OUT_IDX, + .tx_ws_sig = I2S0O_WS_OUT_IDX, + .rx_ws_sig = I2S0I_WS_IN_IDX, + .data_out_sig = I2S0O_SD_OUT_IDX, + .data_in_sig = I2S0I_SD_IN_IDX, + .irq = ETS_DMA_CH0_INTR_SOURCE, .module = PERIPH_I2S0_MODULE, + }, + { + .rx_bck_sig = I2S1I_BCK_IN_IDX, + .tx_bck_sig = I2S1O_BCK_OUT_IDX, + .tx_ws_sig = I2S1O_WS_OUT_IDX, + .rx_ws_sig = I2S1I_WS_IN_IDX, + .data_out_sig = I2S1O_SD_OUT_IDX, + .data_in_sig = I2S1I_SD_IN_IDX, + .irq = ETS_DMA_CH3_INTR_SOURCE, + .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32s3/include/soc/i2s_caps.h b/components/soc/esp32s3/include/soc/i2s_caps.h deleted file mode 100644 index cd21be8893..0000000000 --- a/components/soc/esp32s3/include/soc/i2s_caps.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#define SOC_I2S_APLL_MIN_FREQ (250000000) -#define SOC_I2S_APLL_MAX_FREQ (500000000) -#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware -#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated - -// ESP32-S3 have 1 I2S -#define SOC_I2S_NUM (1) diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 40942446cc..b570069965 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -63,7 +63,12 @@ #include "i2c_caps.h" /*-------------------------- I2S CAPS ----------------------------------------*/ -#include "i2s_caps.h" +#define SOC_I2S_NUM (2) +#define SOC_I2S_SUPPORTS_PCM (1) +#define SOC_I2S_SUPPORTS_PDM_TX (0) +#define SOC_I2S_SUPPORTS_PDM_RX (1) +#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) +#define SOC_I2S_SUPPORTS_TDM (1) /*-------------------------- LEDC CAPS ---------------------------------------*/ #include "ledc_caps.h" diff --git a/components/soc/esp32s3/ld/esp32s3.peripherals.ld b/components/soc/esp32s3/ld/esp32s3.peripherals.ld index 5b15a44618..bae22f0205 100644 --- a/components/soc/esp32s3/ld/esp32s3.peripherals.ld +++ b/components/soc/esp32s3/ld/esp32s3.peripherals.ld @@ -8,6 +8,7 @@ PROVIDE ( RTCIO = 0x60008400 ); PROVIDE ( SENS = 0x60008800 ); PROVIDE ( HINF = 0x6000B000 ); PROVIDE ( I2S0 = 0x6000F000 ); +PROVIDE ( I2S1 = 0x6002D000 ); PROVIDE ( UART1 = 0x60010000 ); PROVIDE ( I2C0 = 0x60013000 ); PROVIDE ( UHCI0 = 0x60014000 ); diff --git a/components/soc/include/soc/i2s_periph.h b/components/soc/include/soc/i2s_periph.h index a2b9c54274..1c3248e4ff 100644 --- a/components/soc/include/soc/i2s_periph.h +++ b/components/soc/include/soc/i2s_periph.h @@ -1,4 +1,4 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -27,16 +27,12 @@ extern "C" { Stores a bunch of per-I2S-peripheral data. */ typedef struct { - const uint8_t o_bck_in_sig; - const uint8_t o_ws_in_sig; - const uint8_t o_bck_out_sig; - const uint8_t o_ws_out_sig; - const uint8_t o_data_out_sig; - const uint8_t i_bck_in_sig; - const uint8_t i_ws_in_sig; - const uint8_t i_bck_out_sig; - const uint8_t i_ws_out_sig; - const uint8_t i_data_in_sig; + const uint8_t tx_bck_sig; + const uint8_t rx_bck_sig; + const uint8_t tx_ws_sig; + const uint8_t rx_ws_sig; + const uint8_t data_out_sig; + const uint8_t data_in_sig; const uint8_t irq; const periph_module_t module; } i2s_signal_conn_t; diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index feb582dc25..cef7378ad2 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -75,11 +75,13 @@ Configuration example: static const int i2s_num = 0; // i2s port number static const i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = 44100, - .bits_per_sample = 16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = 44100, + .slot_bits_cfg = 16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, + }, .intr_alloc_flags = 0, // default interrupt priority .dma_buf_count = 8, .dma_buf_len = 64, @@ -154,11 +156,13 @@ I2S configuration static const int i2s_num = 0; // i2s port number static const i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, - .sample_rate = 44100, - .bits_per_sample = 16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = 44100, + .slot_bits_cfg = 16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, + }, .intr_alloc_flags = 0, // default interrupt priority .dma_buf_count = 8, .dma_buf_len = 64, @@ -194,10 +198,12 @@ Configuring I2S to use internal DAC for analog output static const int i2s_num = 0; // i2s port number static const i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, - .sample_rate = 44100, - .bits_per_sample = 16, /* the DAC module will only take the 8bits from MSB */ - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, + .sample_rate = 44100, + .slot_bits_cfg = 16, /* the DAC module will only take the 8bits from MSB */ + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + }, .intr_alloc_flags = 0, // default interrupt priority .dma_buf_count = 8, .dma_buf_len = 64, diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c index c6b37034d9..fc6530d68e 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c @@ -53,15 +53,25 @@ void app_main(void) ESP_ERROR_CHECK(err); i2s_config_t i2s_config = { + .param_cfg = { #ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, #else - .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX + .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX #endif - .sample_rate = 44100, - .bits_per_sample = 16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = I2S_COMM_FORMAT_STAND_MSB, + .sample_rate = 44100, + .slot_bits_cfg = 16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = I2S_COMM_FORMAT_STAND_MSB, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, + .dma_buf_count = 6, .dma_buf_len = 60, .intr_alloc_flags = 0, //Default interrupt priority diff --git a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c index 82b3390f95..fd4db45b2e 100644 --- a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c +++ b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c @@ -684,15 +684,24 @@ void app_main(void) ESP_ERROR_CHECK(err); i2s_config_t i2s_config = { + .param_cfg = { #ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC - .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, #else - .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX + .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX #endif - .communication_format = I2S_COMM_FORMAT_STAND_MSB, - .sample_rate = 44100, - .bits_per_sample = 16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = I2S_COMM_FORMAT_STAND_MSB, + .sample_rate = 44100, + .slot_bits_cfg = 16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 60, .intr_alloc_flags = 0, //Default interrupt priority diff --git a/examples/peripherals/i2s/i2s_adc_dac/main/app_main.c b/examples/peripherals/i2s/i2s_adc_dac/main/app_main.c index 8d5f20db86..b7f00fa1ad 100644 --- a/examples/peripherals/i2s/i2s_adc_dac/main/app_main.c +++ b/examples/peripherals/i2s/i2s_adc_dac/main/app_main.c @@ -63,11 +63,13 @@ void example_i2s_init(void) { int i2s_num = EXAMPLE_I2S_NUM; i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN, - .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, - .bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS, - .communication_format = I2S_COMM_FORMAT_STAND_MSB, - .channel_format = EXAMPLE_I2S_FORMAT, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN, + .sample_rate = EXAMPLE_I2S_SAMPLE_RATE, + .slot_bits_cfg = EXAMPLE_I2S_SAMPLE_BITS, + .communication_format = I2S_COMM_FORMAT_STAND_MSB, + .channel_format = EXAMPLE_I2S_FORMAT, + }, .intr_alloc_flags = 0, .dma_buf_count = 2, .dma_buf_len = 1024, diff --git a/examples/peripherals/i2s/i2s_basic/main/i2s_example_main.c b/examples/peripherals/i2s/i2s_basic/main/i2s_example_main.c index 0eca7953df..00c0d62013 100644 --- a/examples/peripherals/i2s/i2s_basic/main/i2s_example_main.c +++ b/examples/peripherals/i2s/i2s_basic/main/i2s_example_main.c @@ -87,11 +87,20 @@ void app_main(void) //if 2-channels, 16-bit each channel, total buffer is 360*4 = 1440 bytes //if 2-channels, 24/32-bit each channel, total buffer is 360*8 = 2880 bytes i2s_config_t i2s_config = { - .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX - .sample_rate = SAMPLE_RATE, - .bits_per_sample = 16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = I2S_COMM_FORMAT_STAND_MSB, + .param_cfg = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .slot_bits_cfg = (I2S_BITS_PER_SLOT_16BIT << SLOT_BIT_SHIFT) | I2S_BITS_PER_SAMPLE_16BIT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_MSB, +#if SOC_I2S_SUPPORTS_TDM + .slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2, + .active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1, + .left_align_en = false, + .big_edin_en = false, + .bit_order_msb_en = false, +#endif + }, .dma_buf_count = 6, .dma_buf_len = 60, .use_apll = false,