mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-06 22:24:33 +02:00
driver: support I2S on ESP32-S3 & ESP32-C3
1. refactor I2S driver. 2. support TDM mode for esp2s3 & esp32c3.
This commit is contained in:
@@ -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
|
||||
|
@@ -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
|
||||
/**
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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));
|
||||
|
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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.
|
||||
*
|
||||
|
@@ -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,
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
}
|
||||
};
|
||||
|
@@ -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 );
|
||||
|
@@ -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,
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
}
|
||||
};
|
||||
|
@@ -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)
|
@@ -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"
|
||||
|
@@ -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 );
|
||||
|
@@ -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;
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
Reference in New Issue
Block a user