doc/i2s: update i2s programming guide on s3 & c3

This commit is contained in:
laokaiyao
2021-06-17 18:49:44 +08:00
parent f7f8c9c11f
commit d51b85989b
20 changed files with 722 additions and 854 deletions

View File

@@ -14,12 +14,13 @@
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "soc/lldesc.h" #include "soc/lldesc.h"
#include "driver/periph_ctrl.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/i2s.h" #include "driver/i2s.h"
#include "hal/gpio_hal.h" #include "hal/gpio_hal.h"
#include "hal/i2s_hal.h"
#if SOC_I2S_SUPPORTS_ADC_DAC #if SOC_I2S_SUPPORTS_ADC_DAC
#include "driver/dac.h" #include "driver/dac.h"
#include "hal/i2s_hal.h"
#include "adc1_private.h" #include "adc1_private.h"
#endif #endif
@@ -138,22 +139,6 @@ static void gpio_matrix_in_check_and_set(int gpio, uint32_t signal_idx, bool inv
} }
} }
#if SOC_I2S_SUPPORTS_PCM
esp_err_t i2s_pcm_config(i2s_port_t i2s_num, i2s_mode_t mode, i2s_pcm_mode_t pcm_cfg)
{
ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error");
if (mode & I2S_MODE_TX) {
i2s_hal_tx_pcm_cfg(&(p_i2s[i2s_num]->hal), pcm_cfg);
} else if (mode & I2S_MODE_RX) {
i2s_hal_rx_pcm_cfg(&(p_i2s[i2s_num]->hal), pcm_cfg);
} else {
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
#endif
float i2s_get_clk(i2s_port_t i2s_num) float i2s_get_clk(i2s_port_t i2s_num)
{ {
ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error");
@@ -428,7 +413,6 @@ static esp_err_t i2s_fbclk_cal(int i2s_num, uint32_t rate, int channel, int chan
} }
#endif // SOC_I2S_SUPPORTS_ADC_DAC #endif // SOC_I2S_SUPPORTS_ADC_DAC
#if SOC_I2S_SUPPORTS_PDM
if ( p_i2s[i2s_num]->mode & I2S_MODE_PDM) { if ( p_i2s[i2s_num]->mode & I2S_MODE_PDM) {
#if SOC_I2S_SUPPORTS_PDM_TX #if SOC_I2S_SUPPORTS_PDM_TX
if ( p_i2s[i2s_num]->mode & I2S_MODE_TX) { if ( p_i2s[i2s_num]->mode & I2S_MODE_TX) {
@@ -447,7 +431,6 @@ static esp_err_t i2s_fbclk_cal(int i2s_num, uint32_t rate, int channel, int chan
#endif // SOC_I2S_SUPPORTS_PDM_RX #endif // SOC_I2S_SUPPORTS_PDM_RX
_bck_div = 8; _bck_div = 8;
} }
#endif // SOC_I2S_SUPPORTS_PDM
#if SOC_I2S_SUPPORTS_APLL #if SOC_I2S_SUPPORTS_APLL
int sdm0 = 0; int sdm0 = 0;
@@ -487,7 +470,7 @@ static uint32_t i2s_get_active_chan_num(i2s_hal_config_t *hal_cfg)
case I2S_CHANNEL_FMT_TDM: { case I2S_CHANNEL_FMT_TDM: {
uint32_t num = 0; uint32_t num = 0;
uint32_t max_chan = 0; uint32_t max_chan = 0;
uint32_t chan_mask = hal_cfg->chan_cfg.chan_mask; uint32_t chan_mask = hal_cfg->chan_mask;
for (int i = 0; chan_mask && i < 16; i++, chan_mask >>= 1) { for (int i = 0; chan_mask && i < 16; i++, chan_mask >>= 1) {
if ((chan_mask & 0x01) == 1) { if ((chan_mask & 0x01) == 1) {
@@ -495,10 +478,9 @@ static uint32_t i2s_get_active_chan_num(i2s_hal_config_t *hal_cfg)
max_chan = i + 1; max_chan = i + 1;
} }
} }
if (max_chan > hal_cfg->chan_cfg.total_chan) { if (max_chan > hal_cfg->total_chan) {
hal_cfg->chan_cfg.total_chan = max_chan; hal_cfg->total_chan = max_chan;
} }
hal_cfg->chan_cfg.active_chan = num;
return num; return num;
} }
#endif #endif
@@ -514,9 +496,9 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_
i2s_hal_config_t *cfg = &p_i2s[i2s_num]->hal_cfg; i2s_hal_config_t *cfg = &p_i2s[i2s_num]->hal_cfg;
int data_bits = 0; int data_bits = 0;
int slot_bits = 0; int chan_bits = 0;
int active_slot_num = 0; int active_chan_num = 0;
int slot_num = 0; int chan_num = 0;
cfg->ch = ch; cfg->ch = ch;
cfg->sample_rate = rate; cfg->sample_rate = rate;
@@ -524,16 +506,16 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_
cfg->bits_cfg.chan_bits = cfg->bits_cfg.chan_bits < cfg->bits_cfg.sample_bits ? cfg->bits_cfg.chan_bits = cfg->bits_cfg.chan_bits < cfg->bits_cfg.sample_bits ?
cfg->bits_cfg.sample_bits : cfg->bits_cfg.chan_bits; cfg->bits_cfg.sample_bits : cfg->bits_cfg.chan_bits;
slot_bits = cfg->bits_cfg.chan_bits; chan_bits = cfg->bits_cfg.chan_bits;
data_bits = cfg->bits_cfg.sample_bits; data_bits = cfg->bits_cfg.sample_bits;
#if SOC_I2S_SUPPORTS_TDM #if SOC_I2S_SUPPORTS_TDM
cfg->chan_cfg.chan_mask = ch & 0xFFFF; cfg->chan_mask = ch & 0xFFFF;
active_slot_num = i2s_get_active_chan_num(cfg); active_chan_num = i2s_get_active_chan_num(cfg);
slot_num = cfg->chan_cfg.total_chan; chan_num = cfg->total_chan;
#else #else
active_slot_num = i2s_get_active_chan_num(cfg); active_chan_num = i2s_get_active_chan_num(cfg);
slot_num = ch == I2S_CHANNEL_MONO ? 2 : active_slot_num; chan_num = ch == I2S_CHANNEL_MONO ? 2 : active_chan_num;
#endif #endif
ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error");
@@ -551,7 +533,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_
xSemaphoreTake(p_i2s[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); xSemaphoreTake(p_i2s[i2s_num]->rx->mux, (portTickType)portMAX_DELAY);
} }
//malloc DMA buffer //malloc DMA buffer
if (i2s_alloc_dma_buffer(i2s_num, data_bits, active_slot_num) != ESP_OK ) { if (i2s_alloc_dma_buffer(i2s_num, data_bits, active_chan_num) != ESP_OK ) {
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
@@ -559,13 +541,13 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_
uint32_t i2s_bck = 0; // I2S back clock uint32_t i2s_bck = 0; // I2S back clock
uint32_t bck_div = 0; // I2S bck div uint32_t bck_div = 0; // I2S bck div
//calculate bck_div, f_bck and select source clock //calculate bck_div, f_bck and select source clock
if (i2s_fbclk_cal(i2s_num, rate, slot_num, slot_bits, &i2s_clk, &i2s_bck, &bck_div) != ESP_OK) { if (i2s_fbclk_cal(i2s_num, rate, chan_num, chan_bits, &i2s_clk, &i2s_bck, &bck_div) != ESP_OK) {
return ESP_FAIL; return ESP_FAIL;
} }
//configure i2s clock //configure i2s clock
if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { if (p_i2s[i2s_num]->mode & I2S_MODE_TX) {
i2s_hal_tx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); i2s_hal_tx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div);
i2s_hal_set_tx_sample_bit(&(p_i2s[i2s_num]->hal), slot_bits, data_bits); i2s_hal_set_tx_sample_bit(&(p_i2s[i2s_num]->hal), chan_bits, data_bits);
// wait all writing on-going finish // wait all writing on-going finish
if (p_i2s[i2s_num]->tx) { if (p_i2s[i2s_num]->tx) {
xSemaphoreGive(p_i2s[i2s_num]->tx->mux); xSemaphoreGive(p_i2s[i2s_num]->tx->mux);
@@ -573,7 +555,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_
} }
if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { if (p_i2s[i2s_num]->mode & I2S_MODE_RX) {
i2s_hal_rx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); i2s_hal_rx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div);
i2s_hal_set_rx_sample_bit(&(p_i2s[i2s_num]->hal), slot_bits, data_bits); i2s_hal_set_rx_sample_bit(&(p_i2s[i2s_num]->hal), chan_bits, data_bits);
// wait all writing on-going finish // wait all writing on-going finish
if (p_i2s[i2s_num]->rx) { if (p_i2s[i2s_num]->rx) {
xSemaphoreGive(p_i2s[i2s_num]->rx->mux); xSemaphoreGive(p_i2s[i2s_num]->rx->mux);
@@ -1002,11 +984,9 @@ static esp_err_t i2s_check_cfg_static(i2s_port_t i2s_num)
ESP_RETURN_ON_FALSE(!((cfg->mode & I2S_MODE_DAC_BUILT_IN) && (i2s_num != I2S_NUM_0)), ESP_ERR_INVALID_ARG, TAG, "I2S DAC built-in only support on I2S0"); ESP_RETURN_ON_FALSE(!((cfg->mode & I2S_MODE_DAC_BUILT_IN) && (i2s_num != I2S_NUM_0)), ESP_ERR_INVALID_ARG, TAG, "I2S DAC built-in only support on I2S0");
return ESP_OK; return ESP_OK;
#endif #endif
#if SOC_I2S_SUPPORTS_PDM
//We only check if the I2S number is invalid when set to PDM mode. //We only check if the I2S number is invalid when set to PDM mode.
ESP_RETURN_ON_FALSE(!((cfg->mode & I2S_MODE_PDM) && (i2s_num != I2S_NUM_0)), ESP_ERR_INVALID_ARG, TAG, "I2S DAC PDM only support on I2S0"); ESP_RETURN_ON_FALSE(!((cfg->mode & I2S_MODE_PDM) && (i2s_num != I2S_NUM_0)), ESP_ERR_INVALID_ARG, TAG, "I2S DAC PDM only support on I2S0");
return ESP_OK; return ESP_OK;
#endif
ESP_RETURN_ON_FALSE(cfg->comm_fmt && (cfg->comm_fmt < I2S_COMM_FORMAT_STAND_MAX), ESP_ERR_INVALID_ARG, TAG, "invalid communication formats"); ESP_RETURN_ON_FALSE(cfg->comm_fmt && (cfg->comm_fmt < I2S_COMM_FORMAT_STAND_MAX), ESP_ERR_INVALID_ARG, TAG, "invalid communication formats");
ESP_RETURN_ON_FALSE(!((cfg->comm_fmt & I2S_COMM_FORMAT_STAND_MSB) && (cfg->comm_fmt & I2S_COMM_FORMAT_STAND_PCM_LONG)), ESP_ERR_INVALID_ARG, TAG, "multiple communication formats specified"); ESP_RETURN_ON_FALSE(!((cfg->comm_fmt & I2S_COMM_FORMAT_STAND_MSB) && (cfg->comm_fmt & I2S_COMM_FORMAT_STAND_PCM_LONG)), ESP_ERR_INVALID_ARG, TAG, "multiple communication formats specified");
@@ -1096,29 +1076,30 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
p_i2s[i2s_num]->hal_cfg.comm_fmt = i2s_config->communication_format; p_i2s[i2s_num]->hal_cfg.comm_fmt = i2s_config->communication_format;
p_i2s[i2s_num]->hal_cfg.chan_fmt = i2s_config->channel_format; p_i2s[i2s_num]->hal_cfg.chan_fmt = i2s_config->channel_format;
p_i2s[i2s_num]->hal_cfg.bits_cfg.sample_bits = i2s_config->bits_per_sample; p_i2s[i2s_num]->hal_cfg.bits_cfg.sample_bits = i2s_config->bits_per_sample;
p_i2s[i2s_num]->hal_cfg.bits_cfg.chan_bits = i2s_config->bits_per_slot; p_i2s[i2s_num]->hal_cfg.bits_cfg.chan_bits = i2s_config->bits_per_chan;
#if SOC_I2S_SUPPORTS_TDM #if SOC_I2S_SUPPORTS_TDM
int active_chan = 0;
switch (i2s_config->channel_format) { switch (i2s_config->channel_format) {
case I2S_CHANNEL_FMT_RIGHT_LEFT: case I2S_CHANNEL_FMT_RIGHT_LEFT:
case I2S_CHANNEL_FMT_ALL_RIGHT: case I2S_CHANNEL_FMT_ALL_RIGHT:
case I2S_CHANNEL_FMT_ALL_LEFT: case I2S_CHANNEL_FMT_ALL_LEFT:
p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1; p_i2s[i2s_num]->hal_cfg.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1;
p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 2; p_i2s[i2s_num]->hal_cfg.total_chan = 2;
p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 2; active_chan = 2;
break; break;
case I2S_CHANNEL_FMT_ONLY_RIGHT: case I2S_CHANNEL_FMT_ONLY_RIGHT:
p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0; p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0;
p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 1; p_i2s[i2s_num]->hal_cfg.total_chan = 1;
p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 1; active_chan = 1;
break; break;
case I2S_CHANNEL_FMT_ONLY_LEFT: case I2S_CHANNEL_FMT_ONLY_LEFT:
p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1; p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1;
p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 1; p_i2s[i2s_num]->hal_cfg.total_chan = 1;
p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 1; active_chan = 1;
break; break;
case I2S_CHANNEL_FMT_TDM: case I2S_CHANNEL_FMT_TDM:
ESP_RETURN_ON_FALSE((i2s_config->tdm_chan_cfg.chan_mask != 0), ESP_ERR_INVALID_ARG, TAG, "i2s all channel are disabled"); ESP_RETURN_ON_FALSE((i2s_config->chan_mask != 0), ESP_ERR_INVALID_ARG, TAG, "i2s all channel are disabled");
p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_chan_cfg.chan_mask; p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->chan_mask;
i2s_get_active_chan_num(&p_i2s[i2s_num]->hal_cfg); i2s_get_active_chan_num(&p_i2s[i2s_num]->hal_cfg);
break; break;
default: default:
@@ -1138,6 +1119,18 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
p_i2s[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; p_i2s[i2s_num]->dma_buf_count = i2s_config->dma_buf_count;
p_i2s[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; p_i2s[i2s_num]->dma_buf_len = i2s_config->dma_buf_len;
#if SOC_I2S_SUPPORTS_PCM
// Set PCM compress type for PCM communication mode
if (p_i2s[i2s_num]->communication_format & I2S_COMM_FORMAT_STAND_PCM_SHORT) {
if (p_i2s[i2s_num]->mode & I2S_MODE_TX) {
i2s_hal_tx_pcm_cfg(&(p_i2s[i2s_num]->hal), i2s_config->pcm_compress_type);
}
if (p_i2s[i2s_num]->mode & I2S_MODE_RX) {
i2s_hal_rx_pcm_cfg(&(p_i2s[i2s_num]->hal), i2s_config->pcm_compress_type);
}
}
#endif // SOC_I2S_SUPPORTS_PCM
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
if (i2s_config->use_apll) { if (i2s_config->use_apll) {
ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i2s_driver", &p_i2s[i2s_num]->pm_lock); ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i2s_driver", &p_i2s[i2s_num]->pm_lock);
@@ -1198,7 +1191,7 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
#if SOC_I2S_SUPPORTS_TDM #if SOC_I2S_SUPPORTS_TDM
ret = i2s_set_clk(i2s_num, i2s_config->sample_rate, ret = i2s_set_clk(i2s_num, i2s_config->sample_rate,
p_i2s[i2s_num]->hal_cfg.bits_cfg.val, p_i2s[i2s_num]->hal_cfg.bits_cfg.val,
(i2s_channel_t)p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan); (i2s_channel_t)active_chan);
#else #else
ret = i2s_set_clk(i2s_num, i2s_config->sample_rate, ret = i2s_set_clk(i2s_num, i2s_config->sample_rate,
p_i2s[i2s_num]->hal_cfg.bits_cfg.val, p_i2s[i2s_num]->hal_cfg.bits_cfg.val,

View File

@@ -13,9 +13,7 @@
#include "soc/i2s_periph.h" #include "soc/i2s_periph.h"
#include "soc/rtc_periph.h" #include "soc/rtc_periph.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "hal/i2s_hal.h"
#include "hal/i2s_types.h" #include "hal/i2s_types.h"
#include "driver/periph_ctrl.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
#if SOC_I2S_SUPPORTS_ADC_DAC #if SOC_I2S_SUPPORTS_ADC_DAC
@@ -50,9 +48,15 @@ typedef struct {
int data_in_num; /*!< DATA in pin*/ int data_in_num; /*!< DATA in pin*/
} i2s_pin_config_t; } i2s_pin_config_t;
#if SOC_I2S_SUPPORTS_TDM #if SOC_I2S_SUPPORTS_PCM
typedef i2s_hal_chan_cfg_t tdm_chan_cfg_t; /**
typedef i2s_hal_tdm_flags_t tdm_flags_t; * @brief I2S PCM configuration
*
*/
typedef struct {
i2s_pcm_compress_t pcm_mode; /*!< I2S PCM a/u-law decompress or compress mode */
} i2s_pcm_cfg_t;
#endif #endif
/** /**
@@ -72,15 +76,30 @@ typedef struct {
bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */ 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) */ bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */
int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/ int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/
i2s_bits_per_slot_t bits_per_slot; /*!< I2S total bits in one channel Should not be smaller than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */ i2s_bits_per_chan_t bits_per_chan; /*!< I2S total bits in one channel Should not be smaller than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */
#if SOC_I2S_SUPPORTS_PCM
i2s_pcm_compress_t pcm_compress_type; /*!< I2S PCM a/u-law decompress or compress mode. Set this field if `communication_format` is set to `I2S_COMM_FORMAT_STAND_PCM_SHORT` or `I2S_COMM_FORMAT_STAND_PCM_LONG` */
#endif // SOC_I2S_SUPPORTS_PCM
#if SOC_I2S_SUPPORTS_TDM #if SOC_I2S_SUPPORTS_TDM
tdm_chan_cfg_t tdm_chan_cfg; /*!< I2S TDM channel configurations*/ i2s_channel_t chan_mask; /*!< I2S active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<<total_chan). */
tdm_flags_t tdm_flags; /*!< I2S TDM flags*/ uint32_t total_chan; /*!< I2S Total number of channels. If it is smaller than the biggest active channel number, it will be set to this number automatically. */
#endif union {
struct {
uint32_t left_align_en : 1; /*!< Set to enable left aligment */
uint32_t big_edin_en : 1; /*!< Set to enable big edin */
uint32_t bit_order_msb_en : 1; /*!< Set to enable msb order */
uint32_t skip_msk_en : 1; /*!< Set to enable skip mask. If it is enabled, only the data of the enabled channels will be sent, otherwise all data stored in DMA TX buffer will be sent */
};
uint32_t val; /*!< TDM flag value*/
} tdm_flags; /*!< I2S TDM flags*/
#endif // SOC_I2S_SUPPORTS_TDM
} i2s_driver_config_t; } i2s_driver_config_t;
typedef i2s_driver_config_t i2s_config_t; typedef i2s_driver_config_t i2s_config_t; // for backward compatible
typedef intr_handle_t i2s_isr_handle_t; typedef intr_handle_t i2s_isr_handle_t; // for backward compatible
/** /**
* @brief I2S event queue types * @brief I2S event queue types
@@ -340,23 +359,6 @@ esp_err_t i2s_start(i2s_port_t i2s_num);
*/ */
esp_err_t i2s_zero_dma_buffer(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, i2s_mode_t mode, i2s_pcm_mode_t pcm_cfg);
#endif
/** /**
* @brief Set clock & bit width used for I2S RX and TX. * @brief Set clock & bit width used for I2S RX and TX.
* *
@@ -373,7 +375,7 @@ esp_err_t i2s_pcm_config(i2s_port_t i2s_num, i2s_mode_t mode, i2s_pcm_mode_t pcm
* *
* @param bits_cfg I2S bits configuation * @param bits_cfg I2S bits configuation
* the low 16 bits is for data bits per sample in one channel (see 'i2s_bits_per_sample_t') * the low 16 bits is for data bits per sample in one channel (see 'i2s_bits_per_sample_t')
* the high 16 bits is for total bits in one channel (see 'i2s_bits_per_slot_t') * the high 16 bits is for total bits in one channel (see 'i2s_bits_per_chan_t')
* *
* @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO) * @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO)
* *

View File

@@ -232,7 +232,7 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]")
i2s_driver_uninstall(I2S_NUM_0); i2s_driver_uninstall(I2S_NUM_0);
} }
#if !DISABLED_FOR_TARGETS(ESP32S2, ESP32C3) #if SOC_I2S_NUM > 1
/* ESP32S2 and ESP32C3 has only single I2S port and hence following test cases are not applicable */ /* ESP32S2 and ESP32C3 has only single I2S port and hence following test cases are not applicable */
TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]")
{ {
@@ -492,7 +492,7 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]")
TEST_ASSERT(initial_size == esp_get_free_heap_size()); TEST_ASSERT(initial_size == esp_get_free_heap_size());
} }
#if DISABLED_FOR_TARGETS(ESP32) #if SOC_I2S_SUPPORTS_ADC_DAC
/* Only ESP32 need I2S adc/dac test */ /* Only ESP32 need I2S adc/dac test */
TEST_CASE("I2S adc test", "[i2s]") TEST_CASE("I2S adc test", "[i2s]")
{ {

View File

@@ -14,13 +14,13 @@ if(NOT BOOTLOADER_BUILD)
"spi_hal_iram.c" "spi_hal_iram.c"
"spi_slave_hal.c" "spi_slave_hal.c"
"spi_slave_hal_iram.c" "spi_slave_hal_iram.c"
"i2s_hal.c"
"sigmadelta_hal.c" "sigmadelta_hal.c"
"timer_hal.c" "timer_hal.c"
"ledc_hal.c" "ledc_hal.c"
"ledc_hal_iram.c" "ledc_hal_iram.c"
"i2c_hal.c" "i2c_hal.c"
"i2c_hal_iram.c" "i2c_hal_iram.c"
"i2s_hal.c"
"gpio_hal.c" "gpio_hal.c"
"uart_hal.c" "uart_hal.c"
"uart_hal_iram.c" "uart_hal_iram.c"

View File

@@ -453,10 +453,10 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num)
} }
/** /**
* @brief Congfigure TX slot bit and audio data bit, on ESP32, sample_bit should equals to data_bit * @brief Congfigure TX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param sample_bit The slot bit width * @param sample_bit The chan bit width
* @param data_bit The audio data bit width * @param data_bit The audio data bit width
*/ */
static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)
@@ -466,10 +466,10 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i
} }
/** /**
* @brief Congfigure RX slot bit and audio data bit, on ESP32, sample_bit should equals to data_bit * @brief Congfigure RX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param sample_bit The slot bit width * @param sample_bit The chan bit width
* @param data_bit The audio data bit width * @param data_bit The audio data bit width
*/ */
static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)

View File

@@ -28,7 +28,6 @@
extern "C" { extern "C" {
#endif #endif
#define I2S_LL_GET_HW(num) (&I2S0) #define I2S_LL_GET_HW(num) (&I2S0)
#define I2S_LL_TDM_CH_MASK (0xffff) #define I2S_LL_TDM_CH_MASK (0xffff)
@@ -320,10 +319,10 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num)
} }
/** /**
* @brief Congfigure TX slot bit and audio data bit * @brief Congfigure TX chan bit and audio data bit
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param sample_bit The slot bit width * @param sample_bit The chan bit width
* @param data_bit The audio data bit width * @param data_bit The audio data bit width
*/ */
static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)
@@ -333,10 +332,10 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i
} }
/** /**
* @brief Congfigure RX slot bit and audio data bit * @brief Congfigure RX chan bit and audio data bit
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param sample_bit The slot bit width * @param sample_bit The chan bit width
* @param data_bit The audio data bit width * @param data_bit The audio data bit width
*/ */
static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)
@@ -390,52 +389,52 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab
} }
/** /**
* @brief Configure TX total slot number * @brief Configure TX total chan number
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param total_num Total slot number * @param total_num Total chan number
*/ */
static inline void i2s_ll_set_tx_slot_num(i2s_dev_t *hw, int total_num) static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num)
{ {
hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1;
} }
/** /**
* @brief Configure RX total slot number * @brief Configure RX total chan number
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param total_num Total slot number * @param total_num Total chan number
*/ */
static inline void i2s_ll_set_rx_slot_num(i2s_dev_t *hw, int total_num) static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num)
{ {
hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1;
} }
/** /**
* @brief Set the bimap of the active TX slot, only the active slot can launch audio data. * @brief Set the bimap of the active TX chan, only the active chan can launch audio data.
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param slot_mask mask of tx active slot * @param chan_mask mask of tx active chan
*/ */
static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask)
{ {
typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl;
tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK;
tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK;
hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val;
} }
/** /**
* @brief Set the bimap of the active RX slot, only the active slot can receive audio data. * @brief Set the bimap of the active RX chan, only the active chan can receive audio data.
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param slot_mask mask of rx active slot * @param chan_mask mask of rx active chan
*/ */
static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask)
{ {
typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl;
tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK;
tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK;
hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val;
} }
@@ -556,7 +555,7 @@ static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable)
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param pcm_cfg PCM configuration paramater * @param pcm_cfg PCM configuration paramater
*/ */
static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg)
{ {
if (pcm_cfg == I2S_PCM_DISABLE) { if (pcm_cfg == I2S_PCM_DISABLE) {
hw->tx_conf.tx_pcm_bypass = 1; hw->tx_conf.tx_pcm_bypass = 1;
@@ -572,7 +571,7 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg)
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param pcm_cfg PCM configuration paramater * @param pcm_cfg PCM configuration paramater
*/ */
static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg)
{ {
if (pcm_cfg == I2S_PCM_DISABLE) { if (pcm_cfg == I2S_PCM_DISABLE) {
hw->rx_conf.rx_pcm_bypass = 1; hw->rx_conf.rx_pcm_bypass = 1;

File diff suppressed because it is too large Load Diff

View File

@@ -448,10 +448,10 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t eof_num)
} }
/** /**
* @brief Congfigure TX slot bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * @brief Congfigure TX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param sample_bit The slot bit width * @param sample_bit The chan bit width
* @param data_bit The audio data bit width * @param data_bit The audio data bit width
*/ */
static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)
@@ -461,10 +461,10 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i
} }
/** /**
* @brief Congfigure RX slot bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * @brief Congfigure RX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param sample_bit The slot bit width * @param sample_bit The chan bit width
* @param data_bit The audio data bit width * @param data_bit The audio data bit width
*/ */
static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)

View File

@@ -322,10 +322,10 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num)
} }
/** /**
* @brief Congfigure TX slot bit and audio data bit * @brief Congfigure TX chan bit and audio data bit
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param sample_bit The slot bit width * @param sample_bit The chan bit width
* @param data_bit The audio data bit width * @param data_bit The audio data bit width
*/ */
static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)
@@ -335,10 +335,10 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i
} }
/** /**
* @brief Congfigure RX slot bit and audio data bit * @brief Congfigure RX chan bit and audio data bit
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param sample_bit The slot bit width * @param sample_bit The chan bit width
* @param data_bit The audio data bit width * @param data_bit The audio data bit width
*/ */
static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)
@@ -392,52 +392,52 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab
} }
/** /**
* @brief Configure TX total slot number * @brief Configure TX total chan number
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param total_num Total slot number * @param total_num Total chan number
*/ */
static inline void i2s_ll_set_tx_slot_num(i2s_dev_t *hw, int total_num) static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num)
{ {
hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1;
} }
/** /**
* @brief Configure RX total slot number * @brief Configure RX total chan number
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param total_num Total slot number * @param total_num Total chan number
*/ */
static inline void i2s_ll_set_rx_slot_num(i2s_dev_t *hw, int total_num) static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num)
{ {
hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1;
} }
/** /**
* @brief Set the bimap of the active TX slot, only the active slot can launch audio data. * @brief Set the bimap of the active TX chan, only the active chan can launch audio data.
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param slot_mask mask of tx active slot * @param chan_mask mask of tx active chan
*/ */
static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask)
{ {
typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl;
tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK;
tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK;
hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val;
} }
/** /**
* @brief Set the bimap of the active RX slot, only the active slot can receive audio data. * @brief Set the bimap of the active RX chan, only the active chan can receive audio data.
* *
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param slot_mask mask of rx active slot * @param chan_mask mask of rx active chan
*/ */
static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask)
{ {
typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl;
tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK;
tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK;
hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val;
} }
@@ -588,7 +588,7 @@ static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr)
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param pcm_cfg PCM configuration paramater * @param pcm_cfg PCM configuration paramater
*/ */
static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg)
{ {
if (pcm_cfg == I2S_PCM_DISABLE) { if (pcm_cfg == I2S_PCM_DISABLE) {
hw->tx_conf.tx_pcm_bypass = 1; hw->tx_conf.tx_pcm_bypass = 1;
@@ -604,7 +604,7 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg)
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param pcm_cfg PCM configuration paramater * @param pcm_cfg PCM configuration paramater
*/ */
static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg)
{ {
if (pcm_cfg == I2S_PCM_DISABLE) { if (pcm_cfg == I2S_PCM_DISABLE) {
hw->rx_conf.rx_pcm_bypass = 1; hw->rx_conf.rx_pcm_bypass = 1;

View File

@@ -148,14 +148,14 @@ static void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_hal_config_t
} }
} }
#else #else
int slot_bits = hal_cfg->bits_cfg.chan_bits; int chan_bits = hal_cfg->bits_cfg.chan_bits;
int slot_num = hal_cfg->chan_cfg.total_chan; int chan_num = hal_cfg->total_chan;
bool msb_shift_en = false; bool msb_shift_en = false;
int tdm_ws_width = 0; int tdm_ws_width = 0;
switch (hal_cfg->comm_fmt) { switch (hal_cfg->comm_fmt) {
case I2S_COMM_FORMAT_STAND_MSB: case I2S_COMM_FORMAT_STAND_MSB:
msb_shift_en = false; msb_shift_en = false;
tdm_ws_width = slot_num * slot_bits / 2; tdm_ws_width = chan_num * chan_bits / 2;
break; break;
case I2S_COMM_FORMAT_STAND_PCM_SHORT: case I2S_COMM_FORMAT_STAND_PCM_SHORT:
msb_shift_en = false; msb_shift_en = false;
@@ -163,22 +163,22 @@ static void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_hal_config_t
break; break;
case I2S_COMM_FORMAT_STAND_PCM_LONG: case I2S_COMM_FORMAT_STAND_PCM_LONG:
msb_shift_en = false; msb_shift_en = false;
tdm_ws_width = slot_bits; tdm_ws_width = chan_bits;
break; break;
default: //I2S_COMM_FORMAT_STAND_I2S default: //I2S_COMM_FORMAT_STAND_I2S
msb_shift_en = true; msb_shift_en = true;
tdm_ws_width = slot_num * slot_bits / 2; tdm_ws_width = chan_num * chan_bits / 2;
break; break;
} }
if (hal_cfg->mode & I2S_MODE_TX) { if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_tx_msb_shift_enable(hal->dev, msb_shift_en); 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_tdm_ws_width(hal->dev, tdm_ws_width);
i2s_ll_set_tx_half_sample_bit(hal->dev, slot_num * slot_bits / 2); i2s_ll_set_tx_half_sample_bit(hal->dev, chan_num * chan_bits / 2);
} }
if (hal_cfg->mode & I2S_MODE_RX) { if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_rx_msb_shift_enable(hal->dev, msb_shift_en); 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_tdm_ws_width(hal->dev, tdm_ws_width);
i2s_ll_set_rx_half_sample_bit(hal->dev, slot_num * slot_bits / 2); i2s_ll_set_rx_half_sample_bit(hal->dev, chan_num * chan_bits / 2);
} }
#endif #endif
} }
@@ -186,23 +186,23 @@ static void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_hal_config_t
void i2s_hal_samples_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) void i2s_hal_samples_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
{ {
int data_bits = hal_cfg->bits_cfg.sample_bits; int data_bits = hal_cfg->bits_cfg.sample_bits;
int slot_bits = hal_cfg->bits_cfg.chan_bits; int chan_bits = hal_cfg->bits_cfg.chan_bits;
#if SOC_I2S_SUPPORTS_TDM #if SOC_I2S_SUPPORTS_TDM
int slot_num = hal_cfg->chan_cfg.total_chan; int chan_num = hal_cfg->total_chan;
if (hal_cfg->mode & I2S_MODE_TX) { if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_set_tx_slot_num(hal->dev, slot_num); i2s_ll_set_tx_chan_num(hal->dev, chan_num);
i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits); i2s_ll_set_tx_sample_bit(hal->dev, chan_bits, data_bits);
} }
if (hal_cfg->mode & I2S_MODE_RX) { if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_set_rx_slot_num(hal->dev, slot_num); i2s_ll_set_rx_chan_num(hal->dev, chan_num);
i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits); i2s_ll_set_rx_sample_bit(hal->dev, chan_bits, data_bits);
} }
#else #else
if (hal_cfg->mode & I2S_MODE_TX) { if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits); i2s_ll_set_tx_sample_bit(hal->dev, chan_bits, data_bits);
} }
if (hal_cfg->mode & I2S_MODE_RX) { if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits); i2s_ll_set_rx_sample_bit(hal->dev, chan_bits, data_bits);
} }
#endif #endif
//I2S standards config: Philip, MSB or PCM, Only I2S mode should do this configuration. //I2S standards config: Philip, MSB or PCM, Only I2S mode should do this configuration.
@@ -224,7 +224,7 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf
i2s_ll_set_tx_clk_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default i2s_ll_set_tx_clk_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default
i2s_ll_mclk_use_tx_clk(hal->dev); i2s_ll_mclk_use_tx_clk(hal->dev);
i2s_ll_set_tx_active_slot_mask(hal->dev, hal_cfg->chan_cfg.chan_mask); i2s_ll_set_tx_active_chan_mask(hal->dev, hal_cfg->chan_mask);
i2s_ll_tx_left_align_enable(hal->dev, hal_cfg->flags.left_align_en); i2s_ll_tx_left_align_enable(hal->dev, hal_cfg->flags.left_align_en);
i2s_ll_tx_big_endian_enable(hal->dev, hal_cfg->flags.big_edin_en); i2s_ll_tx_big_endian_enable(hal->dev, hal_cfg->flags.big_edin_en);
i2s_ll_tx_set_bit_order(hal->dev, hal_cfg->flags.bit_order_msb_en); i2s_ll_tx_set_bit_order(hal->dev, hal_cfg->flags.bit_order_msb_en);
@@ -247,7 +247,7 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf
i2s_ll_set_rx_clk_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default i2s_ll_set_rx_clk_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default
i2s_ll_mclk_use_rx_clk(hal->dev); i2s_ll_mclk_use_rx_clk(hal->dev);
i2s_ll_set_rx_active_slot_mask(hal->dev, hal_cfg->chan_cfg.chan_mask); i2s_ll_set_rx_active_chan_mask(hal->dev, hal_cfg->chan_mask);
i2s_ll_rx_left_align_enable(hal->dev, hal_cfg->flags.left_align_en); i2s_ll_rx_left_align_enable(hal->dev, hal_cfg->flags.left_align_en);
i2s_ll_rx_big_endian_enable(hal->dev, hal_cfg->flags.big_edin_en); i2s_ll_rx_big_endian_enable(hal->dev, hal_cfg->flags.big_edin_en);
i2s_ll_rx_set_bit_order(hal->dev, hal_cfg->flags.bit_order_msb_en); i2s_ll_rx_set_bit_order(hal->dev, hal_cfg->flags.bit_order_msb_en);
@@ -271,11 +271,9 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf
} }
#endif #endif
#if SOC_I2S_SUPPORTS_PDM
bool is_pdm = ((hal_cfg->mode & I2S_MODE_PDM) > 0);
#if SOC_I2S_SUPPORTS_PDM_TX #if SOC_I2S_SUPPORTS_PDM_TX
if (hal_cfg->mode & I2S_MODE_TX) { if (hal_cfg->mode & I2S_MODE_TX) {
if (is_pdm) { if (hal_cfg->mode & I2S_MODE_PDM) {
i2s_ll_tx_pdm_cfg(hal->dev, hal_cfg->sample_rate); i2s_ll_tx_pdm_cfg(hal->dev, hal_cfg->sample_rate);
} else { } else {
i2s_ll_set_tx_pdm_en(hal->dev, false); i2s_ll_set_tx_pdm_en(hal->dev, false);
@@ -284,15 +282,13 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf
#endif // SOC_I2S_SUPPORTS_PDM_TX #endif // SOC_I2S_SUPPORTS_PDM_TX
#if SOC_I2S_SUPPORTS_PDM_RX #if SOC_I2S_SUPPORTS_PDM_RX
if (hal_cfg->mode & I2S_MODE_RX) { if (hal_cfg->mode & I2S_MODE_RX) {
if (is_pdm) { if (hal_cfg->mode & I2S_MODE_PDM) {
i2s_ll_rx_pdm_cfg(hal->dev); i2s_ll_rx_pdm_cfg(hal->dev);
} else { } else {
i2s_ll_set_rx_pdm_en(hal->dev, false); i2s_ll_set_rx_pdm_en(hal->dev, false);
} }
} }
#endif // SOC_I2S_SUPPORTS_PDM_RX #endif // SOC_I2S_SUPPORTS_PDM_RX
#endif // SOC_I2S_SUPPORTS_PDM //Configure I2S chan number,sample bit.
//Configure I2S slot number,sample bit.
i2s_hal_samples_config(hal, hal_cfg); i2s_hal_samples_config(hal, hal_cfg);
} }

View File

@@ -44,35 +44,6 @@ typedef union {
uint32_t val; /*!< I2S cannel bits configiration value */ uint32_t val; /*!< I2S cannel bits configiration value */
} i2s_hal_bits_cfg_t; } i2s_hal_bits_cfg_t;
#if SOC_I2S_SUPPORTS_TDM
/**
* @brief I2S channel configurations
*
*/
typedef union {
struct {
uint32_t total_chan : 8; /*!< Total number of I2S channels */
uint32_t active_chan : 8; /*!< Active channel number it will be set automatically if chan_mask is set */
uint32_t chan_mask : 16; /*!< Active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<<total_slot_num). */
};
uint32_t val; /*!< Slot data bits value*/
} i2s_hal_chan_cfg_t;
/**
* @brief I2S TDM flags
*
*/
typedef union {
struct {
uint32_t left_align_en : 1; /*!< Set to enable left aligment */
uint32_t big_edin_en : 1; /*!< Set to enable big edin */
uint32_t bit_order_msb_en : 1; /*!< Set to enable msb order */
uint32_t skip_msk_en : 1; /*!< Set to enable skip mask. If it is enabled, only the data of the enabled channels will be sent, otherwise all data stored in DMA TX buffer will be sent */
};
uint32_t val;
} i2s_hal_tdm_flags_t;
#endif
/** /**
* @brief I2S HAL configurations * @brief I2S HAL configurations
*/ */
@@ -84,8 +55,17 @@ typedef struct {
i2s_channel_fmt_t chan_fmt; /*!< I2S channel format, there are total 16 channels in TDM mode.*/ i2s_channel_fmt_t chan_fmt; /*!< I2S channel format, there are total 16 channels in TDM mode.*/
i2s_hal_bits_cfg_t bits_cfg; /*!< Channel bits configuration*/ i2s_hal_bits_cfg_t bits_cfg; /*!< Channel bits configuration*/
#if SOC_I2S_SUPPORTS_TDM #if SOC_I2S_SUPPORTS_TDM
i2s_hal_chan_cfg_t chan_cfg; /*!< active slot bit mask, using the ored mask of `i2s_channel_t`*/ uint32_t total_chan; /*!< Total number of I2S channels */
i2s_hal_tdm_flags_t flags; /*!< Set TDM flags*/ uint32_t chan_mask; /*!< Active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<<total_chan_num). */
union {
struct {
uint32_t left_align_en : 1; /*!< Set to enable left aligment */
uint32_t big_edin_en : 1; /*!< Set to enable big edin */
uint32_t bit_order_msb_en : 1; /*!< Set to enable msb order */
uint32_t skip_msk_en : 1; /*!< Set to enable skip mask. If it is enabled, only the data of the enabled channels will be sent, otherwise all data stored in DMA TX buffer will be sent */
};
uint32_t val; /*!< TDM flags value */
} flags; /*!< Set TDM flags */
#endif #endif
} i2s_hal_config_t; } i2s_hal_config_t;
@@ -211,19 +191,19 @@ void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal);
* @brief Set I2S TX sample bit * @brief Set I2S TX sample bit
* *
* @param hal Context of the HAL layer * @param hal Context of the HAL layer
* @param slot_bit I2S TX slot bit * @param chan_bit I2S TX chan bit
* @param data_bit The sample data bit length. * @param data_bit The sample data bit length.
*/ */
#define i2s_hal_set_tx_sample_bit(hal, slot_bit, data_bit) i2s_ll_set_tx_sample_bit((hal)->dev, slot_bit, data_bit) #define i2s_hal_set_tx_sample_bit(hal, chan_bit, data_bit) i2s_ll_set_tx_sample_bit((hal)->dev, chan_bit, data_bit)
/** /**
* @brief Set I2S RX sample bit * @brief Set I2S RX sample bit
* *
* @param hal Context of the HAL layer * @param hal Context of the HAL layer
* @param slot_bit I2S RX slot bit * @param chan_bit I2S RX chan bit
* @param data_bit The sample data bit length. * @param data_bit The sample data bit length.
*/ */
#define i2s_hal_set_rx_sample_bit(hal, slot_bit, data_bit) i2s_ll_set_rx_sample_bit((hal)->dev, slot_bit, data_bit) #define i2s_hal_set_rx_sample_bit(hal, chan_bit, data_bit) i2s_ll_set_rx_sample_bit((hal)->dev, chan_bit, data_bit)
/** /**
* @brief Configure I2S TX module clock devider * @brief Configure I2S TX module clock devider
@@ -250,7 +230,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc
* @brief Configure I2S TX PCM encoder or decoder. * @brief Configure I2S TX PCM encoder or decoder.
* *
* @param hal Context of the HAL layer * @param hal Context of the HAL layer
* @param cfg PCM configure paramater, refer to `i2s_pcm_mode_t` * @param cfg PCM configure paramater, refer to `i2s_pcm_compress_t`
*/ */
#define i2s_hal_tx_pcm_cfg(hal, cfg) i2s_ll_tx_pcm_cfg((hal)->dev, cfg) #define i2s_hal_tx_pcm_cfg(hal, cfg) i2s_ll_tx_pcm_cfg((hal)->dev, cfg)
@@ -258,7 +238,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc
* @brief Configure I2S RX PCM encoder or decoder. * @brief Configure I2S RX PCM encoder or decoder.
* *
* @param hal Context of the HAL layer * @param hal Context of the HAL layer
* @param cfg PCM configure paramater, refer to `i2s_pcm_mode_t` * @param cfg PCM configure paramater, refer to `i2s_pcm_compress_t`
*/ */
#define i2s_hal_rx_pcm_cfg(hal, cfg) i2s_ll_rx_pcm_cfg((hal)->dev, cfg) #define i2s_hal_rx_pcm_cfg(hal, cfg) i2s_ll_rx_pcm_cfg((hal)->dev, cfg)
#endif #endif

View File

@@ -36,16 +36,16 @@ typedef enum {
} i2s_bits_per_sample_t; } i2s_bits_per_sample_t;
/** /**
* @brief I2S bit width per slot. * @brief I2S bit width per chan.
* *
*/ */
typedef enum { typedef enum {
I2S_BITS_PER_SLOT_8BIT = (8), /*!< slot bit 8*/ I2S_BITS_PER_CHAN_DEFAULT = (0), /*!< chan bit equals to data bit*/
I2S_BITS_PER_SLOT_16BIT = (16), /*!< slot bit 16*/ I2S_BITS_PER_CHAN_8BIT = (8), /*!< chan bit 8*/
I2S_BITS_PER_SLOT_24BIT = (24), /*!< slot bit 24*/ I2S_BITS_PER_CHAN_16BIT = (16), /*!< chan bit 16*/
I2S_BITS_PER_SLOT_32BIT = (32), /*!< slot bit 32*/ I2S_BITS_PER_CHAN_24BIT = (24), /*!< chan bit 24*/
I2S_BITS_PER_SLOT_EQU_SAMPLE = (0), /*!< slot bit equals to data bit*/ I2S_BITS_PER_CHAN_32BIT = (32), /*!< chan bit 32*/
} i2s_bits_per_slot_t; } i2s_bits_per_chan_t;
/** /**
* @brief I2S channel. * @brief I2S channel.
@@ -84,9 +84,6 @@ typedef enum {
#endif #endif
} i2s_channel_t; } i2s_channel_t;
/** /**
* @brief I2S communication standard format * @brief I2S communication standard format
* *
@@ -134,10 +131,8 @@ typedef enum {
I2S_MODE_DAC_BUILT_IN = (0x1 << 4), /*!< Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB*/ I2S_MODE_DAC_BUILT_IN = (0x1 << 4), /*!< Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB*/
I2S_MODE_ADC_BUILT_IN = (0x1 << 5), /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/ I2S_MODE_ADC_BUILT_IN = (0x1 << 5), /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/
#endif #endif
#if SOC_I2S_SUPPORTS_PDM
// PDM functions are only supported on I2S0 (all chips). // PDM functions are only supported on I2S0 (all chips).
I2S_MODE_PDM = (0x1 << 6), /*!< I2S PDM mode*/ I2S_MODE_PDM = (0x1 << 6), /*!< I2S PDM mode*/
#endif
} i2s_mode_t; } i2s_mode_t;
/** /**
@@ -169,12 +164,12 @@ typedef enum {
* *
*/ */
typedef enum { typedef enum {
I2S_PCM_A_DECOMPRESS=0, /*!< A-law decompress*/ I2S_PCM_DISABLE = 0, /*!< Disable A/U law decopress or compress*/
I2S_PCM_A_DECOMPRESS, /*!< A-law decompress*/
I2S_PCM_A_COMPRESS, /*!< A-law compress*/ I2S_PCM_A_COMPRESS, /*!< A-law compress*/
I2S_PCM_U_DECOMPRESS, /*!< U-law decompress*/ I2S_PCM_U_DECOMPRESS, /*!< U-law decompress*/
I2S_PCM_U_COMPRESS, /*!< U-law compress*/ I2S_PCM_U_COMPRESS, /*!< U-law compress*/
I2S_PCM_DISABLE, /*!< Disable A/U law decopress or compress*/ } i2s_pcm_compress_t;
} i2s_pcm_mode_t;
#endif #endif
#if SOC_I2S_SUPPORTS_PDM_RX #if SOC_I2S_SUPPORTS_PDM_RX
@@ -188,7 +183,6 @@ typedef enum {
} i2s_pdm_dsr_t; } i2s_pdm_dsr_t;
#endif #endif
#if SOC_I2S_SUPPORTS_PDM
/** /**
* @brief PDM PCM convter enable/disable. * @brief PDM PCM convter enable/disable.
* *
@@ -197,7 +191,6 @@ typedef enum {
PDM_PCM_CONV_ENABLE, /*!< Enable PDM PCM convert*/ PDM_PCM_CONV_ENABLE, /*!< Enable PDM PCM convert*/
PDM_PCM_CONV_DISABLE, /*!< Disable PDM PCM convert*/ PDM_PCM_CONV_DISABLE, /*!< Disable PDM PCM convert*/
} pdm_pcm_conv_t; } pdm_pcm_conv_t;
#endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -138,7 +138,6 @@
#define SOC_I2S_NUM (2) #define SOC_I2S_NUM (2)
#define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_RX (1) #define SOC_I2S_SUPPORTS_PDM_RX (1)
#define SOC_I2S_SUPPORTS_PDM (1) // (SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX)
#define SOC_I2S_SUPPORTS_ADC_DAC (1) // ESP32 support ADC and DAC #define SOC_I2S_SUPPORTS_ADC_DAC (1) // ESP32 support ADC and DAC
#define SOC_I2S_SUPPORTS_APLL (1)// ESP32 support APLL #define SOC_I2S_SUPPORTS_APLL (1)// ESP32 support APLL

View File

@@ -26,6 +26,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.rx_ws_sig = I2SI_WS_IN_IDX, .rx_ws_sig = I2SI_WS_IN_IDX,
.data_out_sig = I2SO_SD_OUT_IDX, .data_out_sig = I2SO_SD_OUT_IDX,
.data_in_sig = I2SI_SD_IN_IDX, .data_in_sig = I2SI_SD_IN_IDX,
.irq = -1,
.module = PERIPH_I2S1_MODULE, .module = PERIPH_I2S1_MODULE,
} }
}; };

View File

@@ -112,7 +112,6 @@
#define SOC_I2S_SUPPORTS_PCM (1) #define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_RX (0) #define SOC_I2S_SUPPORTS_PDM_RX (0)
#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX)
#define SOC_I2S_SUPPORTS_TDM (1) #define SOC_I2S_SUPPORTS_TDM (1)
#define SOC_I2S_APLL_MIN_FREQ (250000000) #define SOC_I2S_APLL_MIN_FREQ (250000000)
#define SOC_I2S_APLL_MAX_FREQ (500000000) #define SOC_I2S_APLL_MAX_FREQ (500000000)

View File

@@ -106,7 +106,10 @@
/*-------------------------- I2S CAPS ----------------------------------------*/ /*-------------------------- I2S CAPS ----------------------------------------*/
#define SOC_I2S_NUM (1) #define SOC_I2S_NUM (1)
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_RX (0)
#define SOC_I2S_SUPPORTS_TDM (1)
#define SOC_I2S_APLL_MIN_FREQ (250000000) #define SOC_I2S_APLL_MIN_FREQ (250000000)
#define SOC_I2S_APLL_MAX_FREQ (500000000) #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_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware

View File

@@ -7,7 +7,7 @@ PROVIDE ( SIGMADELTA = 0x60004f00 );
PROVIDE ( RTCCNTL = 0x60008000 ); PROVIDE ( RTCCNTL = 0x60008000 );
PROVIDE ( RTCIO = 0x60008400 ); PROVIDE ( RTCIO = 0x60008400 );
PROVIDE ( HINF = 0x6000B000 ); PROVIDE ( HINF = 0x6000B000 );
PROVIDE ( I2S1 = 0x6002d000 ); PROVIDE ( I2S0 = 0x6002d000 );
PROVIDE ( I2C0 = 0x60013000 ); PROVIDE ( I2C0 = 0x60013000 );
PROVIDE ( UHCI0 = 0x60014000 ); PROVIDE ( UHCI0 = 0x60014000 );
PROVIDE ( UHCI1 = 0x6000c000 ); PROVIDE ( UHCI1 = 0x6000c000 );

View File

@@ -26,6 +26,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.rx_ws_sig = I2S0I_WS_IN_IDX, .rx_ws_sig = I2S0I_WS_IN_IDX,
.data_out_sig = I2S0O_SD_OUT_IDX, .data_out_sig = I2S0O_SD_OUT_IDX,
.data_in_sig = I2S0I_SD_IN_IDX, .data_in_sig = I2S0I_SD_IN_IDX,
.irq = -1,
.module = PERIPH_I2S0_MODULE, .module = PERIPH_I2S0_MODULE,
}, },
{ {
@@ -35,6 +36,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.rx_ws_sig = I2S1I_WS_IN_IDX, .rx_ws_sig = I2S1I_WS_IN_IDX,
.data_out_sig = I2S1O_SD_OUT_IDX, .data_out_sig = I2S1O_SD_OUT_IDX,
.data_in_sig = I2S1I_SD_IN_IDX, .data_in_sig = I2S1I_SD_IN_IDX,
.irq = -1,
.module = PERIPH_I2S1_MODULE, .module = PERIPH_I2S1_MODULE,
} }
}; };

View File

@@ -67,7 +67,6 @@
#define SOC_I2S_SUPPORTS_PCM (1) #define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_RX (1) #define SOC_I2S_SUPPORTS_PDM_RX (1)
#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX)
#define SOC_I2S_SUPPORTS_TDM (1) #define SOC_I2S_SUPPORTS_TDM (1)
/*-------------------------- LEDC CAPS ---------------------------------------*/ /*-------------------------- LEDC CAPS ---------------------------------------*/

View File

@@ -1,24 +1,14 @@
I2S I2S
=== ===
.. only:: esp32c3 {IDF_TARGET_I2S_NUM:default="two", esp32s2="one", esp32c3="one"}
.. warning::
This document is not updated for ESP32-C3 yet.
Overview Overview
-------- --------
I2S (Inter-IC Sound) is a serial, synchronous communication protocol that is usually used for transmitting audio data between two digital audio devices. I2S (Inter-IC Sound) is a serial, synchronous communication protocol that is usually used for transmitting audio data between two digital audio devices.
.. only:: esp32 {IDF_TARGET_NAME} contains {IDF_TARGET_I2S_NUM} I2S peripheral(s). These peripherals can be configured to input and output sample data via the I2S driver.
{IDF_TARGET_NAME} contains two I2S peripherals. These peripherals can be configured to input and output sample data via the I2S driver.
.. only:: esp32s2
{IDF_TARGET_NAME} contains one I2S peripheral. These peripherals can be configured to input and output sample data via the I2S driver.
An I2S bus consists of the following lines: An I2S bus consists of the following lines:
@@ -30,20 +20,22 @@ Each I2S controller has the following features that can be configured using the
- Operation as system master or slave - Operation as system master or slave
- Capable of acting as transmitter or receiver - Capable of acting as transmitter or receiver
- Dedicated DMA controller that allows for streaming sample data without requiring the CPU to copy each data sample - DMA controller that allows for streaming sample data without requiring the CPU to copy each data sample
Each controller can operate in half-duplex communication mode. Thus, the two controllers can be combined to establish full-duplex communication. Each controller can operate in half-duplex communication mode. Thus, the two controllers can be combined to establish full-duplex communication.
I2S0 output can be routed directly to the digital-to-analog converter's (DAC) output channels (GPIO 25 & GPIO 26) to produce direct analog output without involving any external I2S codecs. I2S0 can also be used for transmitting PDM (Pulse-density modulation) signals.
The I2S peripherals also support LCD mode for communicating data over a parallel bus, as used by some LCD displays and camera modules. LCD mode has the following operational modes:
- LCD master transmitting mode
- Camera slave receiving mode
- ADC/DAC mode
.. only:: esp32 .. only:: esp32
I2S0 output can be routed directly to the digital-to-analog converter's (DAC) output channels (GPIO 25 & GPIO 26) to produce direct analog output without involving any external I2S codecs. I2S0 can also be used for transmitting PDM (Pulse-density modulation) signals.
.. only:: esp32 or esp32s2
The I2S peripherals also support LCD mode for communicating data over a parallel bus, as used by some LCD displays and camera modules. LCD mode has the following operational modes:
- LCD master transmitting mode
- Camera slave receiving mode
- ADC/DAC mode
For more information, see *{IDF_TARGET_NAME} Technical Reference Manual* > *I2S Controller (I2S)* > LCD Mode [`PDF <{IDF_TARGET_TRM_EN_URL}#camlcdctrl>`__]. For more information, see *{IDF_TARGET_NAME} Technical Reference Manual* > *I2S Controller (I2S)* > LCD Mode [`PDF <{IDF_TARGET_TRM_EN_URL}#camlcdctrl>`__].
.. note:: .. note::
@@ -68,26 +60,50 @@ Install the I2S driver by calling the function :cpp:func`i2s_driver_install` and
- The structure :cpp:type:`i2s_config_t` with defined communication parameters - The structure :cpp:type:`i2s_config_t` with defined communication parameters
- Event queue size and handle - Event queue size and handle
I2S will start automatically once :cpp:func`i2s_driver_install` returns ``ESP_OK``.
Configuration example: Configuration example:
.. code-block:: c .. only:: not SOC_I2S_SUPPORTS_TDM
static const int i2s_num = 0; // i2s port number .. code-block:: c
static const i2s_config_t i2s_config = { static const int i2s_num = 0; // i2s port number
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
};
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S
.tx_desc_auto_clear = false,
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 // Interrupt level 1, default 0
};
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
.. only:: SOC_I2S_SUPPORTS_TDM
.. code-block:: c
static const int i2s_num = 0; // i2s port number
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.tx_desc_auto_clear = false,
.dma_buf_count = 8,
.dma_buf_len = 64,
.bits_per_chan = I2S_BITS_PER_SAMPLE_16BIT
};
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
Setting Communication Pins Setting Communication Pins
^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,15 +116,14 @@ Once the driver is installed, configure physical GPIO pins to which signals will
.. code-block:: c .. code-block:: c
static const i2s_pin_config_t pin_config = { static const i2s_pin_config_t pin_config = {
.bck_io_num = 26, .bck_io_num = 4,
.ws_io_num = 25, .ws_io_num = 5,
.data_out_num = 22, .data_out_num = 18,
.data_in_num = I2S_PIN_NO_CHANGE .data_in_num = I2S_PIN_NO_CHANGE
}; };
i2s_set_pin(i2s_num, &pin_config); i2s_set_pin(i2s_num, &pin_config);
Running I2S Communication Running I2S Communication
^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -117,14 +132,17 @@ To perform a transmission:
- Prepare the data for sending - Prepare the data for sending
- Call the function :cpp:func:`i2s_write` and pass the data buffer address and data length to it - Call the function :cpp:func:`i2s_write` and pass the data buffer address and data length to it
The function will write the data to the I2S DMA Tx buffer, and then the data will be transmitted automatically. The function will write the data to the DMA Tx buffer, and then the data will be transmitted automatically.
.. code-block:: c .. code-block:: c
i2s_write(I2S_NUM, samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100); i2s_write(I2S_NUM, samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100);
To retrieve received data, use the function :cpp:func:`i2s_read`. It will retrieve the data from the DMA Rx buffer, once the data is received by the I2S controller.
To retrieve received data, use the function :cpp:func:`i2s_read`. It will retrieve the data from the I2S DMA Rx buffer, once the data is received by the I2S controller. .. code-block:: c
i2s_read(I2S_NUM, data_recv, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_read, 100);
You can temporarily stop the I2S driver by calling the function :cpp:func:`i2s_stop`, which will disable the I2S Tx/Rx units until the function :cpp:func:`i2s_start` is called. If the function :cpp:func`i2s_driver_install` is used, the driver will start up automatically eliminating the need to call :cpp:func:`i2s_start`. You can temporarily stop the I2S driver by calling the function :cpp:func:`i2s_stop`, which will disable the I2S Tx/Rx units until the function :cpp:func:`i2s_start` is called. If the function :cpp:func`i2s_driver_install` is used, the driver will start up automatically eliminating the need to call :cpp:func:`i2s_start`.
@@ -140,87 +158,184 @@ Application Example
A code example for the I2S driver can be found in the directory :example:`peripherals/i2s`. A code example for the I2S driver can be found in the directory :example:`peripherals/i2s`.
In addition, there are two short configuration examples for the I2S driver. .. only:: SOC_I2S_SUPPORTS_ADC_DAC
In addition, there are two short configuration examples for the I2S driver.
.. only:: not SOC_I2S_SUPPORTS_ADC_DAC
In addition, there is a short configuration examples for the I2S driver.
I2S configuration I2S configuration
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
.. code-block:: c Example for general usage.
#include "driver/i2s.h" .. only:: not SOC_I2S_SUPPORTS_TDM
#include "freertos/queue.h"
static const int i2s_num = 0; // i2s port number .. code-block:: c
static const i2s_config_t i2s_config = { #include "driver/i2s.h"
.param_cfg = {
static const int i2s_num = 0; // i2s port number
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX, .mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100, .sample_rate = 44100,
.slot_bits_cfg = 16, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S, .communication_format = I2S_COMM_FORMAT_STAND_I2S
}, .tx_desc_auto_clear = false,
.intr_alloc_flags = 0, // default interrupt priority .dma_buf_count = 8,
.dma_buf_count = 8, .dma_buf_len = 64,
.dma_buf_len = 64, .use_apll = false,
.use_apll = false .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 // Interrupt level 1, default 0
}; };
static const i2s_pin_config_t pin_config = { static const i2s_pin_config_t pin_config = {
.bck_io_num = 26, .bck_io_num = 4,
.ws_io_num = 25, .ws_io_num = 5,
.data_out_num = 22, .data_out_num = 18,
.data_in_num = I2S_PIN_NO_CHANGE .data_in_num = I2S_PIN_NO_CHANGE
}; };
...
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
i2s_set_pin(i2s_num, &pin_config); i2s_set_pin(i2s_num, &pin_config);
i2s_set_sample_rates(i2s_num, 22050); //set sample rates ...
/* You can reset parameters by calling 'i2s_set_clk'
*
* The low 16 bits are the valid data bits in one chan and the high 16 bits are
* the total bits in one chan. If high 16 bits is smaller than low 16 bits, it will
* be set to a same value as low 16 bits.
*/
uint32_t bits_cfg = (I2S_BITS_PER_CHAN_32BIT << 16) | I2S_BITS_PER_SAMPLE_16BIT;
i2s_set_clk(i2s_num, 22050, bits_cfg, I2S_CHANNEL_STEREO);
...
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
.. only:: SOC_I2S_SUPPORTS_TDM
Configuring I2S to use internal DAC for analog output .. code-block:: c
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: c #include "driver/i2s.h"
#include "driver/i2s.h" static const int i2s_num = 0; // i2s port number
#include "freertos/queue.h"
static const int i2s_num = 0; // i2s port number i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
static const i2s_config_t i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
.sample_rate = 44100, .sample_rate = 44100,
.slot_bits_cfg = 16, /* the DAC module will only take the 8bits from MSB */ .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
}, .communication_format = I2S_COMM_FORMAT_STAND_I2S
.intr_alloc_flags = 0, // default interrupt priority .tx_desc_auto_clear = false,
.dma_buf_count = 8, .dma_buf_count = 8,
.dma_buf_len = 64, .dma_buf_len = 64
.use_apll = false };
};
... static const i2s_pin_config_t pin_config = {
.bck_io_num = 4,
.ws_io_num = 5,
.data_out_num = 18,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
i2s_set_pin(i2s_num, &pin_config);
i2s_set_pin(i2s_num, NULL); //for internal DAC, this will enable both of the internal channels ...
/* You can reset parameters by calling 'i2s_set_clk'
//You can call i2s_set_dac_mode to set built-in DAC output mode. *
//i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); * The low 16 bits are the valid data bits in one chan and the high 16 bits are
* the total bits in one chan. If high 16 bits is smaller than low 16 bits, it will
i2s_set_sample_rates(i2s_num, 22050); //set sample rates * be set to a same value as low 16 bits.
*/
uint32_t bits_cfg = (I2S_BITS_PER_CHAN_32BIT << 16) | I2S_BITS_PER_SAMPLE_16BIT;
i2s_set_clk(i2s_num, 22050, bits_cfg, I2S_CHANNEL_STEREO);
...
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
I2S on {IDF_TARGET_NAME} support TDM mode, up to 16 channels are available in TDM mode. If you want to use TDM mode, set field ``channel_format`` of :cpp:type:`i2s_config_t` to ``I2S_CHANNEL_FMT_TDM``. Then enable the channels by setting ``tdm_chan_cfg.chan_mask`` using masks in :cpp:type:`i2s_channel_t`, the number of active channels and total channels will be calculate automatically. Also you can set a particular total channel number for it, but it shouldn't be smaller than the largest channel you use.
.. code-block:: c
#include "driver/i2s.h"
static const int i2s_num = 0; // i2s port number
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_TDM,
.communication_format = I2S_COMM_FORMAT_STAND_I2S
.tx_desc_auto_clear = false,
.dma_buf_count = 8,
.dma_buf_len = 64,
.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH2
};
static const i2s_pin_config_t pin_config = {
.bck_io_num = 4,
.ws_io_num = 5,
.data_out_num = 18,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
i2s_set_pin(i2s_num, &pin_config);
...
/* You can reset parameters by calling 'i2s_set_clk'
*
* The low 16 bits are the valid data bits in one chan and the high 16 bits are
* the total bits in one chan. If high 16 bits is smaller than low 16 bits, it will
* be set to a same value as low 16 bits.
*/
uint32_t bits_cfg = (I2S_BITS_PER_CHAN_32BIT << 16) | I2S_BITS_PER_SAMPLE_16BIT;
i2s_set_clk(i2s_port_t i2s_num, 22050, bits_cfg, I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1); // set clock
...
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
.. only:: SOC_I2S_SUPPORTS_ADC_DAC
Configuring I2S to use internal DAC for analog output
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: c
#include "driver/i2s.h"
#include "freertos/queue.h"
static const int i2s_num = 0; // i2s port number
static const i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
.sample_rate = 44100,
.bits_per_sample = 16, /* the DAC module will only take the 8bits from MSB */
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
};
...
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
i2s_set_pin(i2s_num, NULL); //for internal DAC, this will enable both of the internal channels
//You can call i2s_set_dac_mode to set built-in DAC output mode.
//i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
i2s_set_sample_rates(i2s_num, 22050); //set sample rates
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
API Reference API Reference
------------- -------------