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 "soc/lldesc.h"
#include "driver/periph_ctrl.h"
#include "driver/gpio.h"
#include "driver/i2s.h"
#include "hal/gpio_hal.h"
#include "hal/i2s_hal.h"
#if SOC_I2S_SUPPORTS_ADC_DAC
#include "driver/dac.h"
#include "hal/i2s_hal.h"
#include "adc1_private.h"
#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)
{
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
#if SOC_I2S_SUPPORTS_PDM
if ( p_i2s[i2s_num]->mode & I2S_MODE_PDM) {
#if SOC_I2S_SUPPORTS_PDM_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
_bck_div = 8;
}
#endif // SOC_I2S_SUPPORTS_PDM
#if SOC_I2S_SUPPORTS_APLL
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: {
uint32_t num = 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) {
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;
}
}
if (max_chan > hal_cfg->chan_cfg.total_chan) {
hal_cfg->chan_cfg.total_chan = max_chan;
if (max_chan > hal_cfg->total_chan) {
hal_cfg->total_chan = max_chan;
}
hal_cfg->chan_cfg.active_chan = num;
return num;
}
#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;
int data_bits = 0;
int slot_bits = 0;
int active_slot_num = 0;
int slot_num = 0;
int chan_bits = 0;
int active_chan_num = 0;
int chan_num = 0;
cfg->ch = ch;
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.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;
#if SOC_I2S_SUPPORTS_TDM
cfg->chan_cfg.chan_mask = ch & 0xFFFF;
active_slot_num = i2s_get_active_chan_num(cfg);
slot_num = cfg->chan_cfg.total_chan;
cfg->chan_mask = ch & 0xFFFF;
active_chan_num = i2s_get_active_chan_num(cfg);
chan_num = cfg->total_chan;
#else
active_slot_num = i2s_get_active_chan_num(cfg);
slot_num = ch == I2S_CHANNEL_MONO ? 2 : active_slot_num;
active_chan_num = i2s_get_active_chan_num(cfg);
chan_num = ch == I2S_CHANNEL_MONO ? 2 : active_chan_num;
#endif
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);
}
//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;
}
@@ -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 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) {
if (i2s_fbclk_cal(i2s_num, rate, chan_num, chan_bits, &i2s_clk, &i2s_bck, &bck_div) != ESP_OK) {
return ESP_FAIL;
}
//configure i2s clock
if (p_i2s[i2s_num]->mode & I2S_MODE_TX) {
i2s_hal_tx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div);
i2s_hal_set_tx_sample_bit(&(p_i2s[i2s_num]->hal), slot_bits, data_bits);
i2s_hal_set_tx_sample_bit(&(p_i2s[i2s_num]->hal), chan_bits, data_bits);
// wait all writing on-going finish
if (p_i2s[i2s_num]->tx) {
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) {
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
if (p_i2s[i2s_num]->rx) {
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");
return ESP_OK;
#endif
#if SOC_I2S_SUPPORTS_PDM
//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");
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 & 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.chan_fmt = i2s_config->channel_format;
p_i2s[i2s_num]->hal_cfg.bits_cfg.sample_bits = i2s_config->bits_per_sample;
p_i2s[i2s_num]->hal_cfg.bits_cfg.chan_bits = i2s_config->bits_per_slot;
p_i2s[i2s_num]->hal_cfg.bits_cfg.chan_bits = i2s_config->bits_per_chan;
#if SOC_I2S_SUPPORTS_TDM
int active_chan = 0;
switch (i2s_config->channel_format) {
case I2S_CHANNEL_FMT_RIGHT_LEFT:
case I2S_CHANNEL_FMT_ALL_RIGHT:
case I2S_CHANNEL_FMT_ALL_LEFT:
p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1;
p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 2;
p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 2;
p_i2s[i2s_num]->hal_cfg.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1;
p_i2s[i2s_num]->hal_cfg.total_chan = 2;
active_chan = 2;
break;
case I2S_CHANNEL_FMT_ONLY_RIGHT:
p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0;
p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 1;
p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 1;
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.total_chan = 1;
active_chan = 1;
break;
case I2S_CHANNEL_FMT_ONLY_LEFT:
p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1;
p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 1;
p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 1;
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.total_chan = 1;
active_chan = 1;
break;
case I2S_CHANNEL_FMT_TDM:
ESP_RETURN_ON_FALSE((i2s_config->tdm_chan_cfg.chan_mask != 0), ESP_ERR_INVALID_ARG, TAG, "i2s all channel are disabled");
p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_chan_cfg.chan_mask;
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_mask = i2s_config->chan_mask;
i2s_get_active_chan_num(&p_i2s[i2s_num]->hal_cfg);
break;
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_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
if (i2s_config->use_apll) {
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
ret = i2s_set_clk(i2s_num, i2s_config->sample_rate,
p_i2s[i2s_num]->hal_cfg.bits_cfg.val,
(i2s_channel_t)p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan);
(i2s_channel_t)active_chan);
#else
ret = i2s_set_clk(i2s_num, i2s_config->sample_rate,
p_i2s[i2s_num]->hal_cfg.bits_cfg.val,

View File

@@ -13,9 +13,7 @@
#include "soc/i2s_periph.h"
#include "soc/rtc_periph.h"
#include "soc/soc_caps.h"
#include "hal/i2s_hal.h"
#include "hal/i2s_types.h"
#include "driver/periph_ctrl.h"
#include "esp_intr_alloc.h"
#if SOC_I2S_SUPPORTS_ADC_DAC
@@ -50,9 +48,15 @@ typedef struct {
int data_in_num; /*!< DATA in pin*/
} i2s_pin_config_t;
#if SOC_I2S_SUPPORTS_TDM
typedef i2s_hal_chan_cfg_t tdm_chan_cfg_t;
typedef i2s_hal_tdm_flags_t tdm_flags_t;
#if SOC_I2S_SUPPORTS_PCM
/**
* @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
/**
@@ -72,15 +76,30 @@ typedef struct {
bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */
int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/
i2s_bits_per_slot_t bits_per_slot; /*!< I2S total bits in one channel Should not be smaller than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */
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
tdm_chan_cfg_t tdm_chan_cfg; /*!< I2S TDM channel configurations*/
tdm_flags_t tdm_flags; /*!< I2S TDM flags*/
#endif
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). */
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. */
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;
typedef i2s_driver_config_t i2s_config_t;
typedef intr_handle_t i2s_isr_handle_t;
typedef i2s_driver_config_t i2s_config_t; // for backward compatible
typedef intr_handle_t i2s_isr_handle_t; // for backward compatible
/**
* @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);
#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.
*
@@ -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
* 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)
*

View File

@@ -232,7 +232,7 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]")
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 */
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());
}
#if DISABLED_FOR_TARGETS(ESP32)
#if SOC_I2S_SUPPORTS_ADC_DAC
/* Only ESP32 need I2S adc/dac test */
TEST_CASE("I2S adc test", "[i2s]")
{

View File

@@ -14,13 +14,13 @@ if(NOT BOOTLOADER_BUILD)
"spi_hal_iram.c"
"spi_slave_hal.c"
"spi_slave_hal_iram.c"
"i2s_hal.c"
"sigmadelta_hal.c"
"timer_hal.c"
"ledc_hal.c"
"ledc_hal_iram.c"
"i2c_hal.c"
"i2c_hal_iram.c"
"i2s_hal.c"
"gpio_hal.c"
"uart_hal.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 sample_bit The slot bit width
* @param sample_bit The chan 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)
@@ -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 sample_bit The slot bit width
* @param sample_bit The chan 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)

View File

@@ -28,7 +28,6 @@
extern "C" {
#endif
#define I2S_LL_GET_HW(num) (&I2S0)
#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 sample_bit The slot bit width
* @param sample_bit The chan 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)
@@ -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 sample_bit The slot bit width
* @param sample_bit The chan 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)
@@ -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 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;
}
/**
* @brief Configure RX total slot number
* @brief Configure RX total chan number
*
* @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;
}
/**
* @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 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;
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;
}
/**
* @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 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;
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;
}
@@ -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 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) {
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 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) {
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 sample_bit The slot bit width
* @param sample_bit The chan 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)
@@ -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 sample_bit The slot bit width
* @param sample_bit The chan 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)

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 sample_bit The slot bit width
* @param sample_bit The chan 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)
@@ -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 sample_bit The slot bit width
* @param sample_bit The chan 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)
@@ -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 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;
}
/**
* @brief Configure RX total slot number
* @brief Configure RX total chan number
*
* @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;
}
/**
* @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 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;
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;
}
/**
* @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 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;
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;
}
@@ -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 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) {
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 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) {
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
int slot_bits = hal_cfg->bits_cfg.chan_bits;
int slot_num = hal_cfg->chan_cfg.total_chan;
int chan_bits = hal_cfg->bits_cfg.chan_bits;
int chan_num = hal_cfg->total_chan;
bool msb_shift_en = false;
int tdm_ws_width = 0;
switch (hal_cfg->comm_fmt) {
case I2S_COMM_FORMAT_STAND_MSB:
msb_shift_en = false;
tdm_ws_width = slot_num * slot_bits / 2;
tdm_ws_width = chan_num * chan_bits / 2;
break;
case I2S_COMM_FORMAT_STAND_PCM_SHORT:
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;
case I2S_COMM_FORMAT_STAND_PCM_LONG:
msb_shift_en = false;
tdm_ws_width = slot_bits;
tdm_ws_width = chan_bits;
break;
default: //I2S_COMM_FORMAT_STAND_I2S
msb_shift_en = true;
tdm_ws_width = slot_num * slot_bits / 2;
tdm_ws_width = chan_num * chan_bits / 2;
break;
}
if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_tx_msb_shift_enable(hal->dev, msb_shift_en);
i2s_ll_set_tx_tdm_ws_width(hal->dev, tdm_ws_width);
i2s_ll_set_tx_half_sample_bit(hal->dev, slot_num * slot_bits / 2);
i2s_ll_set_tx_half_sample_bit(hal->dev, chan_num * chan_bits / 2);
}
if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_rx_msb_shift_enable(hal->dev, msb_shift_en);
i2s_ll_set_rx_tdm_ws_width(hal->dev, tdm_ws_width);
i2s_ll_set_rx_half_sample_bit(hal->dev, slot_num * slot_bits / 2);
i2s_ll_set_rx_half_sample_bit(hal->dev, chan_num * chan_bits / 2);
}
#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)
{
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
int slot_num = hal_cfg->chan_cfg.total_chan;
int chan_num = hal_cfg->total_chan;
if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_set_tx_slot_num(hal->dev, slot_num);
i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits);
i2s_ll_set_tx_chan_num(hal->dev, chan_num);
i2s_ll_set_tx_sample_bit(hal->dev, chan_bits, data_bits);
}
if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_set_rx_slot_num(hal->dev, slot_num);
i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits);
i2s_ll_set_rx_chan_num(hal->dev, chan_num);
i2s_ll_set_rx_sample_bit(hal->dev, chan_bits, data_bits);
}
#else
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) {
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
//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_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_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);
@@ -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_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_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);
@@ -271,11 +271,9 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf
}
#endif
#if SOC_I2S_SUPPORTS_PDM
bool is_pdm = ((hal_cfg->mode & I2S_MODE_PDM) > 0);
#if SOC_I2S_SUPPORTS_PDM_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);
} else {
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
#if SOC_I2S_SUPPORTS_PDM_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);
} else {
i2s_ll_set_rx_pdm_en(hal->dev, false);
}
}
#endif // SOC_I2S_SUPPORTS_PDM_RX
#endif // SOC_I2S_SUPPORTS_PDM
//Configure I2S slot number,sample bit.
//Configure I2S chan number,sample bit.
i2s_hal_samples_config(hal, hal_cfg);
}

View File

@@ -44,35 +44,6 @@ typedef union {
uint32_t val; /*!< I2S cannel bits configiration value */
} i2s_hal_bits_cfg_t;
#if SOC_I2S_SUPPORTS_TDM
/**
* @brief I2S channel configurations
*
*/
typedef union {
struct {
uint32_t total_chan : 8; /*!< Total number of I2S channels */
uint32_t active_chan : 8; /*!< Active channel number it will be set automatically if chan_mask is set */
uint32_t chan_mask : 16; /*!< Active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<<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
*/
@@ -84,8 +55,17 @@ typedef struct {
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*/
#if SOC_I2S_SUPPORTS_TDM
i2s_hal_chan_cfg_t chan_cfg; /*!< active slot bit mask, using the ored mask of `i2s_channel_t`*/
i2s_hal_tdm_flags_t flags; /*!< Set TDM flags*/
uint32_t total_chan; /*!< Total number of I2S channels */
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
} 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
*
* @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.
*/
#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
*
* @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.
*/
#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
@@ -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.
*
* @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)
@@ -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.
*
* @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)
#endif

View File

@@ -36,16 +36,16 @@ typedef enum {
} i2s_bits_per_sample_t;
/**
* @brief I2S bit width per slot.
* @brief I2S bit width per chan.
*
*/
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_EQU_SAMPLE = (0), /*!< slot bit equals to data bit*/
} i2s_bits_per_slot_t;
I2S_BITS_PER_CHAN_DEFAULT = (0), /*!< chan bit equals to data bit*/
I2S_BITS_PER_CHAN_8BIT = (8), /*!< chan bit 8*/
I2S_BITS_PER_CHAN_16BIT = (16), /*!< chan bit 16*/
I2S_BITS_PER_CHAN_24BIT = (24), /*!< chan bit 24*/
I2S_BITS_PER_CHAN_32BIT = (32), /*!< chan bit 32*/
} i2s_bits_per_chan_t;
/**
* @brief I2S channel.
@@ -84,9 +84,6 @@ typedef enum {
#endif
} i2s_channel_t;
/**
* @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_ADC_BUILT_IN = (0x1 << 5), /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/
#endif
#if SOC_I2S_SUPPORTS_PDM
// PDM functions are only supported on I2S0 (all chips).
I2S_MODE_PDM = (0x1 << 6), /*!< I2S PDM mode*/
#endif
} i2s_mode_t;
/**
@@ -169,12 +164,12 @@ 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_U_DECOMPRESS, /*!< U-law decompress*/
I2S_PCM_U_COMPRESS, /*!< U-law compress*/
I2S_PCM_DISABLE, /*!< Disable A/U law decopress or compress*/
} i2s_pcm_mode_t;
} i2s_pcm_compress_t;
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
@@ -188,7 +183,6 @@ typedef enum {
} i2s_pdm_dsr_t;
#endif
#if SOC_I2S_SUPPORTS_PDM
/**
* @brief PDM PCM convter enable/disable.
*
@@ -197,7 +191,6 @@ typedef enum {
PDM_PCM_CONV_ENABLE, /*!< Enable PDM PCM convert*/
PDM_PCM_CONV_DISABLE, /*!< Disable PDM PCM convert*/
} pdm_pcm_conv_t;
#endif
#ifdef __cplusplus

View File

@@ -138,7 +138,6 @@
#define SOC_I2S_NUM (2)
#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_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,
.data_out_sig = I2SO_SD_OUT_IDX,
.data_in_sig = I2SI_SD_IN_IDX,
.irq = -1,
.module = PERIPH_I2S1_MODULE,
}
};

View File

@@ -112,7 +112,6 @@
#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_I2S_APLL_MIN_FREQ (250000000)
#define SOC_I2S_APLL_MAX_FREQ (500000000)

View File

@@ -106,7 +106,10 @@
/*-------------------------- 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_TDM (1)
#define SOC_I2S_APLL_MIN_FREQ (250000000)
#define SOC_I2S_APLL_MAX_FREQ (500000000)
#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware

View File

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

View File

@@ -26,6 +26,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.rx_ws_sig = I2S0I_WS_IN_IDX,
.data_out_sig = I2S0O_SD_OUT_IDX,
.data_in_sig = I2S0I_SD_IN_IDX,
.irq = -1,
.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,
.data_out_sig = I2S1O_SD_OUT_IDX,
.data_in_sig = I2S1I_SD_IN_IDX,
.irq = -1,
.module = PERIPH_I2S1_MODULE,
}
};

View File

@@ -67,7 +67,6 @@
#define SOC_I2S_SUPPORTS_PCM (1)
#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_TDM (1)
/*-------------------------- LEDC CAPS ---------------------------------------*/

View File

@@ -1,24 +1,14 @@
I2S
===
.. only:: esp32c3
.. warning::
This document is not updated for ESP32-C3 yet.
{IDF_TARGET_I2S_NUM:default="two", esp32s2="one", esp32c3="one"}
Overview
--------
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 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.
{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.
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
- 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.
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
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>`__].
.. 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
- Event queue size and handle
I2S will start automatically once :cpp:func`i2s_driver_install` returns ``ESP_OK``.
Configuration example:
.. code-block:: c
.. only:: not SOC_I2S_SUPPORTS_TDM
.. code-block:: c
static const int i2s_num = 0; // i2s port number
static const i2s_config_t i2s_config = {
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.bits_per_sample = 16,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = 0, // default interrupt priority
.communication_format = I2S_COMM_FORMAT_STAND_I2S
.tx_desc_auto_clear = false,
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
.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
^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,15 +116,14 @@ Once the driver is installed, configure physical GPIO pins to which signals will
.. code-block:: c
static const i2s_pin_config_t pin_config = {
.bck_io_num = 26,
.ws_io_num = 25,
.data_out_num = 22,
.bck_io_num = 4,
.ws_io_num = 5,
.data_out_num = 18,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_set_pin(i2s_num, &pin_config);
Running I2S Communication
^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -117,14 +132,17 @@ To perform a transmission:
- Prepare the data for sending
- 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
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`.
@@ -140,55 +158,154 @@ Application Example
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
^^^^^^^^^^^^^^^^^
.. code-block:: c
Example for general usage.
.. only:: not SOC_I2S_SUPPORTS_TDM
.. 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 = {
.param_cfg = {
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.slot_bits_cfg = 16,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
},
.intr_alloc_flags = 0, // default interrupt priority
.communication_format = I2S_COMM_FORMAT_STAND_I2S
.tx_desc_auto_clear = false,
.dma_buf_count = 8,
.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 = {
.bck_io_num = 26,
.ws_io_num = 25,
.data_out_num = 22,
.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);
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
.. only:: SOC_I2S_SUPPORTS_TDM
Configuring I2S to use internal DAC for analog output
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: c
.. 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_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S
.tx_desc_auto_clear = false,
.dma_buf_count = 8,
.dma_buf_len = 64
};
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_num, 22050, bits_cfg, I2S_CHANNEL_STEREO);
...
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"
@@ -196,12 +313,10 @@ 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 = {
.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 */
.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,