driver: support I2S on ESP32-S3 & ESP32-C3

1. refactor I2S driver.
  2. support TDM mode for esp2s3 & esp32c3.
This commit is contained in:
houwenxiang
2020-06-01 09:47:48 +08:00
committed by laokaiyao
parent 12c76b4c5c
commit 2f1247e1c4
29 changed files with 2929 additions and 3076 deletions

View File

@@ -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; /*!<communication standard format*/
i2s_mode_t mode; /*!< I2S Working mode*/
uint32_t sample_rate; /*!< I2S sample rate */
bool use_apll; /*!< I2S use APLL clock */
uint32_t sample_rate; /*!< I2S sample rate */
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor on underflow */
bool use_apll; /*!< I2S use APLL clock */
int fixed_mclk; /*!< I2S fixed MLCK clock */
double real_rate;
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock;
#endif
@@ -127,50 +128,38 @@ static inline void gpio_matrix_in_check(int gpio, uint32_t signal_idx, bool inv)
}
}
esp_err_t i2s_clear_intr_status(i2s_port_t i2s_num, uint32_t clr_mask)
static void i2s_tx_reset(i2s_port_t i2s_num)
{
// Reset I2S TX module first, and then, reset DMA and FIFO.
i2s_hal_reset_tx(&(p_i2s_obj[i2s_num]->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

View File

@@ -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
/**

View File

@@ -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,

View File

@@ -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,

View File

@@ -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));

View File

@@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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 <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stddef.h>
#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<<total_slot_num).
* e.g: active_slot_mask = (I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1), total_slot_num = 4, active_slot_number = 2.
*/
typedef enum {
I2S_TDM_ACTIVE_CH0 = (0x1 << 0),
I2S_TDM_ACTIVE_CH1 = (0x1 << 1),
I2S_TDM_ACTIVE_CH2 = (0x1 << 2),
I2S_TDM_ACTIVE_CH3 = (0x1 << 3),
I2S_TDM_ACTIVE_CH4 = (0x1 << 4),
I2S_TDM_ACTIVE_CH5 = (0x1 << 5),
I2S_TDM_ACTIVE_CH6 = (0x1 << 6),
I2S_TDM_ACTIVE_CH7 = (0x1 << 7),
I2S_TDM_ACTIVE_CH8 = (0x1 << 8),
I2S_TDM_ACTIVE_CH9 = (0x1 << 9),
I2S_TDM_ACTIVE_CH10 = (0x1 << 10),
I2S_TDM_ACTIVE_CH11 = (0x1 << 11),
I2S_TDM_ACTIVE_CH12 = (0x1 << 12),
I2S_TDM_ACTIVE_CH13 = (0x1 << 13),
I2S_TDM_ACTIVE_CH14 = (0x1 << 14),
I2S_TDM_ACTIVE_CH15 = (0x1 << 15),
} i2s_tdm_active_slot_t;
#endif
/**
* @brief I2S communication standard format
*
*/
typedef enum {
// In order to keep compatibility, remain the old definitions and introduce new definitions,
I2S_COMM_FORMAT_STAND_I2S = 0X01, /*!< I2S communication I2S Philips standard, data launch at second BCK*/
I2S_COMM_FORMAT_STAND_MSB = 0X03, /*!< I2S communication MSB alignment standard, data launch at first BCK*/
I2S_COMM_FORMAT_STAND_MSB = 0X02, /*!< I2S communication MSB alignment standard, data launch at first BCK*/
I2S_COMM_FORMAT_STAND_PCM_SHORT = 0x04, /*!< PCM Short standard, also known as DSP mode. The period of synchronization signal (WS) is 1 bck cycle.*/
I2S_COMM_FORMAT_STAND_PCM_LONG = 0x0C, /*!< PCM Long standard. The period of synchronization signal (WS) is channel_bit*bck cycles.*/
I2S_COMM_FORMAT_STAND_MAX, /*!< standard max*/
//old definition will be removed in the future.
I2S_COMM_FORMAT_I2S __attribute__((deprecated)) = 0x01, /*!< I2S communication format I2S, correspond to `I2S_COMM_FORMAT_STAND_I2S`*/
I2S_COMM_FORMAT_I2S_MSB __attribute__((deprecated)) = 0x01, /*!< I2S format MSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_MSB) correspond to `I2S_COMM_FORMAT_STAND_I2S`*/
I2S_COMM_FORMAT_I2S_LSB __attribute__((deprecated)) = 0x02, /*!< I2S format LSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_LSB) correspond to `I2S_COMM_FORMAT_STAND_MSB`*/
I2S_COMM_FORMAT_PCM __attribute__((deprecated)) = 0x04, /*!< I2S communication format PCM, correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/
I2S_COMM_FORMAT_PCM_SHORT __attribute__((deprecated)) = 0x04, /*!< PCM Short, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_SHORT) correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/
I2S_COMM_FORMAT_PCM_LONG __attribute__((deprecated)) = 0x08, /*!< PCM Long, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_LONG) correspond to `I2S_COMM_FORMAT_STAND_PCM_LONG`*/
} i2s_comm_format_t;
/**
@@ -87,10 +144,7 @@ typedef enum {
} i2s_channel_fmt_t;
/**
* @brief I2S Mode, defaut is I2S_MODE_MASTER | I2S_MODE_TX
*
* @note PDM and built-in DAC functions are only supported on I2S0 for current ESP32 chip.
*
* @brief I2S Mode
*/
typedef enum {
I2S_MODE_MASTER = 1, /*!< Master mode*/
@@ -98,17 +152,18 @@ typedef enum {
I2S_MODE_TX = 4, /*!< TX mode*/
I2S_MODE_RX = 8, /*!< RX mode*/
#if SOC_I2S_SUPPORTS_ADC_DAC
//built-in DAC functions are only supported on I2S0 for ESP32 chip.
I2S_MODE_DAC_BUILT_IN = 16, /*!< Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB*/
I2S_MODE_ADC_BUILT_IN = 32, /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/
#endif
#if SOC_I2S_SUPPORTS_PDM
I2S_MODE_PDM = 64, /*!< PDM mode*/
//PDM functions are only supported on I2S0.
I2S_MODE_PDM = 64, /*!< I2S PDM mode*/
#endif
} i2s_mode_t;
/**
* @brief I2S source clock
*
*/
typedef enum {
I2S_CLK_D2CLK = 0, /*!< Clock from PLL_D2_CLK(160M)*/
@@ -116,39 +171,31 @@ typedef enum {
} i2s_clock_src_t;
/**
* @brief I2S configuration parameters for i2s_param_config function
* @brief I2S bit width per sample.
*
* @note: The chip of ESP32 and ESP32S2 only needs to initialize the fields out side the `SOC_I2S_SUPPORTS_TDM` macro.
* The chip of ESP32-S3, ESP32-C3 and the later chip, all this fields should be initialized.
*/
typedef struct {
i2s_mode_t mode; /*!< I2S work mode*/
int sample_rate; /*!< I2S sample rate*/
i2s_bits_per_sample_t bits_per_sample; /*!< I2S bits per sample*/
i2s_channel_fmt_t channel_format; /*!< I2S channel format */
i2s_mode_t mode; /*!< I2S work mode, using ored mask of `i2s_mode_t`*/
uint32_t sample_rate; /*!< I2S sample rate*/
i2s_slot_bits_cfg_t slot_bits_cfg; /*!< slot bit configuration, low 16bit is the audio data bit; high 16bit is the slot bit, if set to 0, total slot bit equals to audio data bit*/
i2s_channel_fmt_t channel_format; /*!< I2S channel format*/
i2s_comm_format_t communication_format; /*!< I2S communication format */
int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
int dma_buf_count; /*!< I2S DMA Buffer Count */
int dma_buf_len; /*!< I2S DMA Buffer Length */
bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */
int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/
} i2s_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.
*

View File

@@ -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,
}

View File

@@ -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

View File

@@ -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,
}
};

View File

@@ -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 );

View File

@@ -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,
}

View File

@@ -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

View File

@@ -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,
}
};

View File

@@ -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)

View File

@@ -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"

View File

@@ -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 );

View File

@@ -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;

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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,