driver/i2s: support i2s on c3 and s3

1. Support i2s on esp32c3 and esp32s3
    2. Refactor i2s_config_t to avoid breaking change
    2. Fix a bug that receiving unavailable values from message queue when dma queue has been re-allocted
    4. Support i2s unit test on esp32c3 and esp32s3
This commit is contained in:
laokaiyao 2021-06-15 15:43:03 +08:00
parent 2f1247e1c4
commit f7f8c9c11f
23 changed files with 1605 additions and 1511 deletions

File diff suppressed because it is too large Load Diff

View File

@ -28,42 +28,70 @@ extern "C" {
#define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */
/**
* @brief I2S port number, the max port number is (I2S_NUM_MAX -1).
*/
typedef enum {
I2S_NUM_0 = 0, /*!< I2S port 0 */
#if SOC_I2S_NUM > 1
I2S_NUM_1 = 1, /*!< I2S port 1 */
#endif
I2S_NUM_MAX, /*!< I2S port max */
} i2s_port_t;
/**
* @brief I2S pin number for i2s_set_pin
*
*/
typedef struct {
int bck_io_num; /*!< BCK in out pin*/
int ws_io_num; /*!< WS in out pin*/
int data_out_num; /*!< DATA out pin*/
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;
#endif
/**
* @brief I2S driver configuration parameters
*
*/
typedef struct {
union {
// Compatible with previous versions. For ESP32-S3, ESP32-C3 and the later chip, you should use `param_cfg` fields to initialize I2S.
struct {
i2s_mode_t mode; /*!< I2S work mode*/
uint32_t sample_rate; /*!< I2S sample rate*/
uint32_t bits_per_sample; /*!< I2S bits per sample*/
i2s_channel_fmt_t channel_format; /*!< I2S channel format */
i2s_comm_format_t communication_format; /*!< I2S communication format */
};
i2s_config_param_t param_cfg; /*!< I2S config paramater */
};
int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
int dma_buf_count; /*!< I2S DMA Buffer Count */
int dma_buf_len; /*!< I2S DMA Buffer Length */
bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */
int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/
i2s_mode_t mode; /*!< I2S work mode */
uint32_t sample_rate; /*!< I2S sample rate */
i2s_bits_per_sample_t bits_per_sample; /*!< I2S sample bits in one channel */
i2s_channel_fmt_t channel_format; /*!< I2S channel format.*/
i2s_comm_format_t communication_format; /*!< I2S communication format */
int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
int dma_buf_count; /*!< I2S DMA Buffer Count */
int dma_buf_len; /*!< I2S DMA Buffer Length */
bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */
int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/
i2s_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' */
#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_driver_config_t;
typedef i2s_driver_config_t i2s_config_t;
typedef intr_handle_t i2s_isr_handle_t;
/**
* @brief I2S event types
* @brief I2S event queue types
*
*/
typedef enum {
I2S_EVENT_DMA_ERROR,
I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/
I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/
I2S_EVENT_TX_Q_OVF, /*!< I2S DMA sent queue overflow*/
I2S_EVENT_RX_Q_OVF, /*!< I2S DMA receive queue overflow*/
I2S_EVENT_MAX, /*!< I2S event max index*/
} i2s_event_type_t;
/**
@ -123,7 +151,7 @@ esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr);
#if SOC_I2S_SUPPORTS_PDM_TX
/**
* @brief Set TX PDM mode up-sample rate
* TX PDM have two type upsampling rate configurations:
* TX PDM can only be set to the following two upsampling rate configurations:
* 1: fp = 960, fs = sample_rate / 100, in this case, Fpdm = 128*48000
* 2: fp = 960, fs = 480, in this case, Fpdm = 128*Fpcm = 128*sample_rate
* If the pdm receiver do not care the pdm serial clock, it's recommended set Fpdm = 128*48000
@ -162,7 +190,7 @@ esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, int sample_rate, int fp,
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue);
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void *i2s_queue);
/**
* @brief Uninstall I2S driver.
@ -326,7 +354,7 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_pcm_config(i2s_port_t i2s_num, int mode, i2s_pcm_cfg_t pcm_cfg);
esp_err_t i2s_pcm_config(i2s_port_t i2s_num, i2s_mode_t mode, i2s_pcm_mode_t pcm_cfg);
#endif
/**
@ -334,20 +362,27 @@ esp_err_t i2s_pcm_config(i2s_port_t i2s_num, int mode, i2s_pcm_cfg_t pcm_cfg);
*
* Similar to i2s_set_sample_rates(), but also sets bit width.
*
* 1. stop i2s;
* 2. calculate mclk, bck, bck_factor
* 3. malloc dma buffer;
* 4. start i2s
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param rate I2S sample rate (ex: 8000, 44100...)
*
* @param slot_bits i2s slot bit configuration
* @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')
*
* @param sloct_ch I2S slot number configuration
* @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_slot_bits_cfg_t slot_bits, i2s_slot_channel_cfg_t sloct_ch);
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_channel_t ch);
/**
* @brief get clock set on particular port number.
@ -357,7 +392,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_slot_bits_cfg_t slo
* @return
* - actual clock set by i2s driver
*/
uint32_t i2s_get_clk(i2s_port_t i2s_num);
float i2s_get_clk(i2s_port_t i2s_num);
#if SOC_I2S_SUPPORTS_ADC_DAC
/**

View File

@ -54,12 +54,10 @@ static void example_i2s_init(void)
{
int i2s_num = EXAMPLE_I2S_NUM;
i2s_config_t i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
.sample_rate = EXAMPLE_I2S_SAMPLE_RATE,
.slot_bits_cfg = EXAMPLE_I2S_SAMPLE_BITS,
.channel_format = EXAMPLE_I2S_FORMAT,
},
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
.sample_rate = EXAMPLE_I2S_SAMPLE_RATE,
.bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS,
.channel_format = EXAMPLE_I2S_FORMAT,
.intr_alloc_flags = 0,
.dma_buf_count = 2,
.dma_buf_len = 1024,

View File

@ -56,12 +56,10 @@ static void example_i2s_init(void)
{
int i2s_num = EXAMPLE_I2S_NUM;
i2s_config_t i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
.sample_rate = EXAMPLE_I2S_SAMPLE_RATE,
.slot_bits_cfg = EXAMPLE_I2S_SAMPLE_BITS,
.channel_format = EXAMPLE_I2S_FORMAT,
},
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
.sample_rate = EXAMPLE_I2S_SAMPLE_RATE,
.bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS,
.channel_format = EXAMPLE_I2S_FORMAT,
.intr_alloc_flags = 0,
.dma_buf_count = 2,
.dma_buf_len = 1024,

View File

@ -21,22 +21,51 @@
#include "math.h"
#include "esp_rom_gpio.h"
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3, ESP32C3)
#define SAMPLE_RATE (36000)
#define SAMPLE_BITS (16)
#if CONFIG_IDF_TARGET_ESP32
#define MASTER_BCK_IO 15
#define MASTER_WS_IO 25
#define SLAVE_BCK_IO 19
#define SLAVE_WS_IO 26
#define DATA_IN_IO 21
#if CONFIG_IDF_TARGET_ESP32
#define MASTER_WS_IO 25
#define DATA_OUT_IO 22
#define ADC1_CHANNEL_4_IO 32
#define I2S0_DATA_OUT_IDX I2S0O_DATA_OUT23_IDX
#define I2S0_DATA_IN_IDX I2S0I_DATA_IN15_IDX
#define I2S1_DATA_OUT_IDX I2S1O_DATA_OUT23_IDX
#define I2S1_DATA_IN_IDX I2S1I_DATA_IN15_IDX
#elif CONFIG_IDF_TARGET_ESP32S2
#define MASTER_BCK_IO 15
#define MASTER_WS_IO 28
#define SLAVE_BCK_IO 19
#define SLAVE_WS_IO 26
#define DATA_IN_IO 21
#define DATA_OUT_IO 20
#define I2S0_DATA_OUT_IDX I2S0O_DATA_OUT23_IDX
#define I2S0_DATA_IN_IDX I2S0I_DATA_IN15_IDX
#elif CONFIG_IDF_TARGET_ESP32C3
// TODO: change pins
#define MASTER_BCK_IO 4
#define MASTER_WS_IO 5
#define SLAVE_BCK_IO 14
#define SLAVE_WS_IO 15
#define DATA_IN_IO 19
#define DATA_OUT_IO 18
#define I2S0_DATA_OUT_IDX I2SO_SD_OUT_IDX
#define I2S0_DATA_IN_IDX I2SI_SD_IN_IDX
#elif CONFIG_IDF_TARGET_ESP32S3
#define MASTER_BCK_IO 4
#define MASTER_WS_IO 5
#define SLAVE_BCK_IO 14
#define SLAVE_WS_IO 15
#define DATA_IN_IO 19
#define DATA_OUT_IO 18
#define I2S0_DATA_OUT_IDX I2S0O_SD_OUT_IDX
#define I2S0_DATA_IN_IDX I2S0I_SD_IN_IDX
#define I2S1_DATA_OUT_IDX I2S1O_SD_OUT_IDX
#define I2S1_DATA_IN_IDX I2S1I_SD_IN_IDX
#endif
#define PERCENT_DIFF 0.0001
@ -67,8 +96,8 @@ static void i2s_test_io_config(int mode)
esp_rom_gpio_connect_out_signal(MASTER_WS_IO, I2S0I_WS_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(MASTER_WS_IO, I2S1O_WS_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S1O_DATA_OUT23_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0I_DATA_IN15_IDX, 0);
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S1_DATA_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0_DATA_IN_IDX, 0);
}
break;
@ -79,14 +108,14 @@ static void i2s_test_io_config(int mode)
esp_rom_gpio_connect_out_signal(MASTER_WS_IO, I2S0O_WS_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(MASTER_WS_IO, I2S1I_WS_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0O_DATA_OUT23_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S1I_DATA_IN15_IDX, 0);
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0_DATA_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S1_DATA_IN_IDX, 0);
}
break;
#endif
case I2S_TEST_MODE_LOOPBACK: {
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0O_DATA_OUT23_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0I_DATA_IN15_IDX, 0);
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0_DATA_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0_DATA_IN_IDX, 0);
}
break;
@ -107,35 +136,17 @@ TEST_CASE("I2S basic driver install, uninstall, set pin test", "[i2s]")
{
// dac, adc i2s
i2s_config_t i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.slot_bits_cfg = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
#if SOC_I2S_SUPPORTS_TDM
.slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2,
.active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
.left_align_en = false,
.big_edin_en = false,
.bit_order_msb_en = false,
#endif
},
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = 6,
.dma_buf_len = 60,
.use_apll = 0,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
};
#if CONFIG_IDF_TARGET_ESP32
//install and start i2s driver
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
//for internal DAC, this will enable both of the internal channels
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, NULL));
//stop & destroy i2s driver
TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0));
#endif
// normal i2s
i2s_pin_config_t pin_config = {
.bck_io_num = MASTER_BCK_IO,
@ -161,20 +172,11 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]")
{
// master driver installed and send data
i2s_config_t master_i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX,
.sample_rate = SAMPLE_RATE,
.slot_bits_cfg = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
#if SOC_I2S_SUPPORTS_TDM
.slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2,
.active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
.left_align_en = false,
.big_edin_en = false,
.bit_order_msb_en = false,
#endif
},
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = 6,
.dma_buf_len = 100,
.use_apll = 0,
@ -230,89 +232,17 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]")
i2s_driver_uninstall(I2S_NUM_0);
}
#if !DISABLED_FOR_TARGETS(ESP32S2)
/* ESP32S2 has only single I2S port and hence following test cases are not applicable */
TEST_CASE("I2S adc test", "[i2s]")
{
// init I2S ADC
i2s_config_t i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
.sample_rate = SAMPLE_RATE,
.slot_bits_cfg = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
#if SOC_I2S_SUPPORTS_TDM
.slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2,
.active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
.left_align_en = false,
.big_edin_en = false,
.bit_order_msb_en = false,
#endif
},
.intr_alloc_flags = 0,
.dma_buf_count = 2,
.dma_buf_len = 1024,
.use_apll = 0,
};
// install and start I2S driver
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
// init ADC pad
i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_4);
// enable adc sampling, ADC_WIDTH_BIT_12, ADC_ATTEN_DB_11 hard-coded in adc_i2s_mode_init
i2s_adc_enable(I2S_NUM_0);
// init read buffer
uint16_t* i2sReadBuffer = (uint16_t*)calloc(1024, sizeof(uint16_t));
size_t bytesRead;
for (int loop = 0; loop < 10; loop++) {
for (int level = 0; level <= 1; level++) {
if (level == 0) {
gpio_set_pull_mode(ADC1_CHANNEL_4_IO, GPIO_PULLDOWN_ONLY);
} else {
gpio_set_pull_mode(ADC1_CHANNEL_4_IO, GPIO_PULLUP_ONLY);
}
vTaskDelay(200 / portTICK_RATE_MS);
// read data from adc, will block until buffer is full
i2s_read(I2S_NUM_0, (void*)i2sReadBuffer, 1024 * sizeof(uint16_t), &bytesRead, portMAX_DELAY);
// calc average
int64_t adcSumValue = 0;
for (size_t i = 0; i < 1024; i++) {
adcSumValue += i2sReadBuffer[i] & 0xfff;
}
int adcAvgValue = adcSumValue / 1024;
printf("adc average val: %d\n", adcAvgValue);
if (level == 0) {
TEST_ASSERT_LESS_THAN(100, adcAvgValue);
} else {
TEST_ASSERT_GREATER_THAN(4000, adcAvgValue);
}
}
}
i2s_adc_disable(I2S_NUM_0);
free(i2sReadBuffer);
i2s_driver_uninstall(I2S_NUM_0);
}
#if !DISABLED_FOR_TARGETS(ESP32S2, ESP32C3)
/* 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]")
{
// master driver installed and send data
i2s_config_t master_i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.slot_bits_cfg = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
#if SOC_I2S_SUPPORTS_TDM
.slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2,
.active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
.left_align_en = false,
.big_edin_en = false,
.bit_order_msb_en = false,
#endif
},
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = 6,
.dma_buf_len = 100,
.use_apll = 0,
@ -330,20 +260,11 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]")
printf("\r\nheap size: %d\n", esp_get_free_heap_size());
i2s_config_t slave_i2s_config = {
.param_cfg = {
.mode = I2S_MODE_SLAVE | I2S_MODE_RX,
.sample_rate = SAMPLE_RATE,
.slot_bits_cfg = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
#if SOC_I2S_SUPPORTS_TDM
.slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2,
.active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
.left_align_en = false,
.big_edin_en = false,
.bit_order_msb_en = false,
#endif
},
.mode = I2S_MODE_SLAVE | I2S_MODE_RX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = 6,
.dma_buf_len = 100,
.use_apll = 0,
@ -374,6 +295,7 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]")
int end_position = 0;
// write data to slave
i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t)*400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS);
printf("write data size: %d\n", i2s_bytes_write);
while(!flag){
i2s_read(I2S_NUM_1, i2s_read_buff + length, sizeof(uint8_t)*500, &bytes_read, 1000/portMAX_DELAY);
if(bytes_read>0) {
@ -402,20 +324,11 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]")
{
// master driver installed and send data
i2s_config_t master_i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX,
.sample_rate = SAMPLE_RATE,
.slot_bits_cfg = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
#if SOC_I2S_SUPPORTS_TDM
.slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2,
.active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
.left_align_en = false,
.big_edin_en = false,
.bit_order_msb_en = false,
#endif
},
.mode = I2S_MODE_MASTER | I2S_MODE_RX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = 6,
.dma_buf_len = 100,
.use_apll = 1,
@ -433,20 +346,11 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]")
printf("\r\nheap size: %d\n", esp_get_free_heap_size());
i2s_config_t slave_i2s_config = {
.param_cfg = {
.mode = I2S_MODE_SLAVE | I2S_MODE_TX, // Only RX
.sample_rate = SAMPLE_RATE,
.slot_bits_cfg = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
#if SOC_I2S_SUPPORTS_TDM
.slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2,
.active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
.left_align_en = false,
.big_edin_en = false,
.bit_order_msb_en = false,
#endif
},
.mode = I2S_MODE_SLAVE | I2S_MODE_TX, // Only RX
.sample_rate = SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = 6,
.dma_buf_len = 100,
.use_apll = 1,
@ -474,7 +378,7 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]")
}
// slave write data to master
i2s_write(I2S_NUM_1, data_wr, sizeof(uint8_t)*400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS);
printf("write data size: %d\n", i2s_bytes_write);
int flag=0; // break loop flag
int end_position = 0;
// write data to slave
@ -505,20 +409,11 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]")
TEST_CASE("I2S memory leaking test", "[i2s]")
{
i2s_config_t master_i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX,
.sample_rate = SAMPLE_RATE,
.slot_bits_cfg = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
#if SOC_I2S_SUPPORTS_TDM
.slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2,
.active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
.left_align_en = false,
.big_edin_en = false,
.bit_order_msb_en = false,
#endif
},
.mode = I2S_MODE_MASTER | I2S_MODE_RX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = 6,
.dma_buf_len = 100,
.use_apll = 0,
@ -561,20 +456,11 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]")
};
i2s_config_t i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.slot_bits_cfg = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
#if SOC_I2S_SUPPORTS_TDM
.slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2,
.active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
.left_align_en = false,
.big_edin_en = false,
.bit_order_msb_en = false,
#endif
},
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = 6,
.dma_buf_len = 60,
.use_apll = true,
@ -591,8 +477,8 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]")
for (int i = 0; i < (sizeof(sample_rate_arr)/sizeof(sample_rate_arr[0])); i++) {
for (int j = 0; j < (sizeof(bits_per_sample_arr)/sizeof(bits_per_sample_arr[0])); j++) {
i2s_config.param_cfg.sample_rate = sample_rate_arr[i];
i2s_config.param_cfg.slot_bits_cfg = bits_per_sample_arr[j];
i2s_config.sample_rate = sample_rate_arr[i];
i2s_config.bits_per_sample = bits_per_sample_arr[j];
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config));
@ -606,4 +492,93 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]")
TEST_ASSERT(initial_size == esp_get_free_heap_size());
}
#if DISABLED_FOR_TARGETS(ESP32)
/* Only ESP32 need I2S adc/dac test */
TEST_CASE("I2S adc test", "[i2s]")
{
// init I2S ADC
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.intr_alloc_flags = 0,
.dma_buf_count = 2,
.dma_buf_len = 1024,
.use_apll = 0,
};
// install and start I2S driver
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
// init ADC pad
i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_4);
// enable adc sampling, ADC_WIDTH_BIT_12, ADC_ATTEN_DB_11 hard-coded in adc_i2s_mode_init
i2s_adc_enable(I2S_NUM_0);
// init read buffer
uint16_t* i2sReadBuffer = (uint16_t*)calloc(1024, sizeof(uint16_t));
size_t bytesRead;
for (int loop = 0; loop < 10; loop++) {
for (int level = 0; level <= 1; level++) {
if (level == 0) {
gpio_set_pull_mode(ADC1_CHANNEL_4_IO, GPIO_PULLDOWN_ONLY);
} else {
gpio_set_pull_mode(ADC1_CHANNEL_4_IO, GPIO_PULLUP_ONLY);
}
vTaskDelay(200 / portTICK_RATE_MS);
// read data from adc, will block until buffer is full
i2s_read(I2S_NUM_0, (void*)i2sReadBuffer, 1024 * sizeof(uint16_t), &bytesRead, portMAX_DELAY);
// calc average
int64_t adcSumValue = 0;
for (size_t i = 0; i < 1024; i++) {
adcSumValue += i2sReadBuffer[i] & 0xfff;
}
int adcAvgValue = adcSumValue / 1024;
printf("adc average val: %d\n", adcAvgValue);
if (level == 0) {
if (adcAvgValue > 100) {
i2s_adc_disable(I2S_NUM_0);
free(i2sReadBuffer);
i2s_driver_uninstall(I2S_NUM_0);
TEST_ASSERT_LESS_THAN(100, adcAvgValue);
}
} else {
if (adcAvgValue < 4000) {
i2s_adc_disable(I2S_NUM_0);
free(i2sReadBuffer);
i2s_driver_uninstall(I2S_NUM_0);
TEST_ASSERT_GREATER_THAN(4000, adcAvgValue);
}
}
}
}
i2s_adc_disable(I2S_NUM_0);
free(i2sReadBuffer);
i2s_driver_uninstall(I2S_NUM_0);
}
TEST_CASE("I2S dac test", "[i2s]")
{
// dac, adc i2s
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = 6,
.dma_buf_len = 60,
.use_apll = 0,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
};
//install and start i2s driver
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
//for internal DAC, this will enable both of the internal channels
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, NULL));
//stop & destroy i2s driver
TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0));
}
#endif

View File

@ -16,16 +16,6 @@ extern "C" {
#define ESP_EFUSE_FIELD_CORRESPONDS_CODING_SCHEME(scheme, max_num_bit)
/*-------------------------- I2S CAPS ----------------------------------------*/
#define SOC_I2S_NUM (1)
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_RX (0)
#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX)
#define SOC_I2S_SUPPORTS_TDM (1)
#define SOC_GDMA_I2S0_DMA_CHANNEL (0)
#ifdef __cplusplus
}
#endif

View File

@ -33,12 +33,12 @@ extern "C" {
// Get I2S hardware instance with giving i2s num
#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : (((num) == 1) ? (&I2S1) : NULL))
#define I2S_INTR_IN_SUC_EOF BIT(9)
#define I2S_INTR_OUT_EOF BIT(12)
#define I2S_INTR_IN_DSCR_ERR BIT(13)
#define I2S_INTR_OUT_DSCR_ERR BIT(14)
#define I2S_INTR_MAX (0xFFFFFFFF)
#define I2S_LL_AD_BCK_FACTOR (2)
#define I2S_LL_PDM_BCK_FACTOR (64)
#define I2S_LL_BASE_CLK (2*APB_CLK_FREQ)
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (6)
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
/* I2S clock configuration structure */
typedef struct {
@ -46,56 +46,14 @@ typedef struct {
uint16_t a;
uint16_t b; // The decimal part of module clock devider, the decimal is: b/a
uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div
} i2s_clk_cal_t;
/**
* @brief Calculate the closest sample rate clock configuration.
* clock relationship:
* Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a)
*
* @param fsclk I2S source clock freq.
* @param fbck BCK freuency.
* @param bck_div The BCK devider of bck. Generally, set bck_div to 8.
* @param cal Point to `i2s_clk_cal_t` structure.
*/
static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal)
{
int ma = 0;
int mb = 0;
uint32_t mclk = fbck*bck_div;
cal->mclk_div = fsclk / mclk;
cal->bck_div = bck_div;
cal->a = 1;
cal->b = 0;
uint32_t freq_diff = fsclk - mclk * cal->mclk_div;
uint32_t min = ~0;
if (freq_diff == 0) {
return;
}
for (int a = 2; a <= 63; a++) {
for (int b = 1; b < a; b++) {
ma = freq_diff*a;
mb = mclk*b;
if (ma == mb) {
cal->a = a;
cal->b = b;
return;
}
if (abs((mb - ma)) < min) {
cal->a = a;
cal->b = b;
min = abs(mb - ma);
}
}
}
}
} i2s_ll_clk_cal_t;
/**
* @brief I2S module general init, enable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_general_init(i2s_dev_t *hw)
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
{
if (hw->clkm_conf.clk_en == 0) {
hw->clkm_conf.clk_en = 1;
@ -104,37 +62,70 @@ static inline void i2s_ll_general_init(i2s_dev_t *hw)
}
/**
* @brief I2S TX module general init.
* @brief I2S tx msb right enable
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable tx msb right
*/
static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw)
static inline void i2s_ll_tx_msb_right_en(i2s_dev_t *hw, bool enable)
{
hw->conf.tx_start = 0;
hw->conf.tx_reset = 1;
hw->conf.tx_reset = 0;
hw->conf.tx_msb_right = 0;
hw->conf.tx_right_first = 0;
hw->conf.tx_slave_mod = 0;
hw->fifo_conf.tx_fifo_mod_force_en = 1;
hw->conf.tx_msb_right = enable;
}
/**
* @brief I2S RX module general init.
* @brief I2S rx msb right enable
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable rx msb right
*/
static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw)
static inline void i2s_ll_rx_msb_right_en(i2s_dev_t *hw, bool enable)
{
hw->conf.rx_start = 0;
hw->conf.rx_reset = 1;
hw->conf.rx_reset = 0;
hw->conf.rx_msb_right = 0;
hw->conf.rx_right_first = 0;
hw->conf.rx_slave_mod = 0;
hw->fifo_conf.rx_fifo_mod_force_en = 1;
hw->conf.rx_msb_right = enable;
}
/**
* @brief I2S tx right channel first
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable send right channel first
*/
static inline void i2s_ll_tx_right_first_en(i2s_dev_t *hw, bool enable)
{
hw->conf.tx_right_first = enable;
}
/**
* @brief I2S rx right channel first
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable receive right channel first
*/
static inline void i2s_ll_rx_right_first_en(i2s_dev_t *hw, bool enable)
{
hw->conf.rx_right_first = enable;
}
/**
* @brief I2S tx fifo module force enable
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable tx fifo module
*/
static inline void i2s_ll_tx_fifo_mod_force_en(i2s_dev_t *hw, bool enable)
{
hw->fifo_conf.tx_fifo_mod_force_en = enable;
}
/**
* @brief I2S rx fifo module force enable
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable rx fifo module
*/
static inline void i2s_ll_rx_fifo_mod_force_en(i2s_dev_t *hw, bool enable)
{
hw->fifo_conf.rx_fifo_mod_force_en = enable;
}
/**
* @brief Enable I2S TX slave mode
*
@ -233,7 +224,7 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src)
* @param hw Peripheral I2S hardware instance address.
* @param set Pointer to I2S clock devider configuration paramater
*/
static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set)
{
hw->clkm_conf.clkm_div_num = set->mclk_div;
hw->clkm_conf.clkm_div_b = set->b;
@ -247,7 +238,7 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
* @param hw Peripheral I2S hardware instance address.
* @param set Pointer to I2S clock devider configuration paramater
*/
static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set)
{
hw->clkm_conf.clkm_div_num = set->mclk_div;
hw->clkm_conf.clkm_div_b = set->b;
@ -495,11 +486,7 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i
*/
static inline void i2s_ll_dma_enable(i2s_dev_t *hw, bool ena)
{
if (ena && !hw->fifo_conf.dscr_en) {
hw->fifo_conf.dscr_en = 1;
} else if (!ena && hw->fifo_conf.dscr_en) {
hw->fifo_conf.dscr_en = 0;
}
hw->fifo_conf.dscr_en = ena;
}
/**
@ -666,7 +653,7 @@ static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr)
*/
static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr)
{
*dsr = hw->pdm_conf.rx_sinc_dsr_16_en;
*dsr = hw->pdm_conf.rx_sinc_dsr_16_en;
}
/**
@ -691,7 +678,7 @@ static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate)
uint32_t fp = 960;
uint32_t fs = sample_rate / 100;
typeof(hw->pdm_conf) pdm_conf_reg = hw->pdm_conf;
pdm_conf_reg.tx_sinc_osr2 = fp/fs;
pdm_conf_reg.tx_sinc_osr2 = fp / fs;
pdm_conf_reg.tx_prescale = 0;
pdm_conf_reg.tx_hp_in_shift = 1;
pdm_conf_reg.tx_lp_in_shift = 1;

View File

@ -1,4 +1,4 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// The LL layer for I2C register operations
// The LL layer for I2S register operations
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
@ -29,14 +29,14 @@ extern "C" {
#endif
#define I2S_LL_GET_HW(num) (&I2S0)
#define I2S_INTR_OUT_DSCR_ERR (0x1 << 6)
#define I2S_INTR_OUT_EOF (0x1 << 4)
#define I2S_INTR_IN_DSCR_ERR (0x1 << 5)
#define I2S_INTR_IN_SUC_EOF (0x1 << 1)
#define I2S_INTR_MAX (~0)
#define I2S_LL_GET_HW(num) (&I2S0)
#define I2S_TDM_CH_MASK (0xffff)
#define I2S_LL_TDM_CH_MASK (0xffff)
#define I2S_LL_PDM_BCK_FACTOR (64)
#define I2S_LL_BASE_CLK (2*APB_CLK_FREQ)
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9)
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
/* I2S clock configuration structure */
typedef struct {
@ -44,95 +44,58 @@ typedef struct {
uint16_t a;
uint16_t b; // The decimal part of module clock devider, the decimal is: b/a
uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div
} i2s_clk_cal_t;
/**
* @brief Calculate the closest sample rate clock configuration.
* clock relationship:
* Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a)
*
* @param fsclk I2S source clock freq.
* @param fbck BCK freuency.
* @param bck_div The BCK devider of bck. Generally, set bck_div to 8.
* @param cal Point to `i2s_clk_cal_t` structure.
*/
static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal)
{
int ma = 0;
int mb = 0;
uint32_t mclk = fbck*bck_div;
cal->mclk_div = fsclk / mclk;
cal->bck_div = bck_div;
cal->a = 1;
cal->b = 0;
uint32_t freq_diff = fsclk - mclk * cal->mclk_div;
uint32_t min = freq_diff * 512;
if (freq_diff == 0) {
return;
}
for (int a = 2; a <= 512; a++) {
for (int b = 1; b < a; b++) {
ma = freq_diff*a;
mb = mclk*b;
if (ma == mb) {
cal->a = a;
cal->b = b;
return;
}
if (abs((mb - ma)) < min) {
cal->a = a;
cal->b = b;
min = abs(mb - ma);
}
}
}
}
} i2s_ll_clk_cal_t;
/**
* @brief I2S module general init, enable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_general_init(i2s_dev_t *hw)
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
{
hw->tx_clkm_conf.clk_en = 1;
}
/**
* @brief Reset I2S TX module, enable default source clock and set to TDM mode.
* @brief Enable I2S tx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw)
static inline void i2s_ll_enable_tx_clock(i2s_dev_t *hw)
{
hw->tx_conf.tx_start = 0;
hw->tx_conf.tx_reset = 1;
hw->tx_conf.tx_reset = 0;
hw->tx_conf.tx_slave_mod = 0;
hw->tx_conf.tx_tdm_en = 1;
hw->tx_conf.tx_pdm_en = 0;
hw->tx_clkm_conf.tx_clk_active = 1;
hw->tx_clkm_conf.tx_clk_sel = 2;
}
/**
* @brief Reset I2S RX module, enable default source clock and set to TDM mode.
* @brief Enable I2S rx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw)
static inline void i2s_ll_enable_rx_clock(i2s_dev_t *hw)
{
hw->rx_conf.rx_start = 0;
hw->rx_conf.rx_reset = 1;
hw->rx_conf.rx_reset = 0;
hw->rx_conf.rx_slave_mod = 0;
hw->rx_conf.rx_tdm_en = 1;
hw->rx_conf.rx_pdm_en = 0;
hw->rx_clkm_conf.rx_clk_active = 1;
hw->rx_clkm_conf.rx_clk_sel = 2;
}
/**
* @brief I2S mclk use tx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_mclk_use_tx_clk(i2s_dev_t *hw)
{
hw->rx_clkm_conf.mclk_sel = 0;
}
/**
* @brief I2S mclk use rx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_mclk_use_rx_clk(i2s_dev_t *hw)
{
hw->rx_clkm_conf.mclk_sel = 1;
}
/**
* @brief Enable I2S TX slave mode
*
@ -203,7 +166,7 @@ static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw)
* @brief Set TX source clock
*
* @param hw Peripheral I2S hardware instance address.
* @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK`
* @param src I2S source clock.
*/
static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src)
{
@ -227,27 +190,27 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src)
* @param hw Peripheral I2S hardware instance address.
* @param set Pointer to I2S clock devider configuration paramater
*/
static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set)
{
if (set->a == 0 || set->b == 0) {
hw->tx_clkm_div_conf.tx_clkm_div_x = 0;
hw->tx_clkm_div_conf.tx_clkm_div_y = 0;
hw->tx_clkm_div_conf.tx_clkm_div_z = 0;
} else {
if(set->b > set->a/2) {
hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/(set->a-set->b) -1;
hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%(set->a-set->b);
hw->tx_clkm_div_conf.tx_clkm_div_z = set->a-set->b;
if (set->b > set->a / 2) {
hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / (set->a - set->b) - 1;
hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % (set->a - set->b);
hw->tx_clkm_div_conf.tx_clkm_div_z = set->a - set->b;
hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 1;
} else {
hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/set->b-1;
hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%set->b+1;
hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / set->b - 1;
hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % set->b + 1;
hw->tx_clkm_div_conf.tx_clkm_div_z = set->b;
hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0;
}
}
hw->tx_clkm_conf.tx_clkm_div_num = set->mclk_div;
hw->tx_conf1.tx_bck_div_num = set->bck_div-1;
hw->tx_conf1.tx_bck_div_num = set->bck_div - 1;
}
/**
@ -256,27 +219,27 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
* @param hw Peripheral I2S hardware instance address.
* @param set Pointer to I2S clock devider configuration paramater
*/
static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set)
{
if (set->a == 0 || set->b == 0) {
hw->rx_clkm_div_conf.rx_clkm_div_x = 0;
hw->rx_clkm_div_conf.rx_clkm_div_y = 0;
hw->rx_clkm_div_conf.rx_clkm_div_z = 0;
} else {
if(set->b > set->a/2) {
hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/(set->a-set->b)-1;
hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%(set->a-set->b);
hw->rx_clkm_div_conf.rx_clkm_div_z = set->a-set->b;
if (set->b > set->a / 2) {
hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / (set->a - set->b) - 1;
hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % (set->a - set->b);
hw->rx_clkm_div_conf.rx_clkm_div_z = set->a - set->b;
hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 1;
} else {
hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/set->b-1;
hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%set->b+1;
hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / set->b - 1;
hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % set->b + 1;
hw->rx_clkm_div_conf.rx_clkm_div_z = set->b;
hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0;
}
}
hw->rx_clkm_conf.rx_clkm_div_num = set->mclk_div;
hw->rx_conf1.rx_bck_div_num = set->bck_div-1;
hw->rx_conf1.rx_bck_div_num = set->bck_div - 1;
}
/**
@ -331,7 +294,7 @@ static inline void i2s_ll_stop_rx(i2s_dev_t *hw)
*/
static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width)
{
hw->tx_conf1.tx_tdm_ws_width = width-1;
hw->tx_conf1.tx_tdm_ws_width = width - 1;
}
/**
@ -342,7 +305,7 @@ static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width)
*/
static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width)
{
hw->rx_conf1.rx_tdm_ws_width = width-1;
hw->rx_conf1.rx_tdm_ws_width = width - 1;
}
/**
@ -366,7 +329,7 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num)
static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)
{
hw->tx_conf1.tx_bits_mod = data_bit - 1;
hw->tx_conf1.tx_tdm_chan_bits = sample_bit-1;
hw->tx_conf1.tx_tdm_chan_bits = sample_bit - 1;
}
/**
@ -379,7 +342,7 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i
static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)
{
hw->rx_conf1.rx_bits_mod = data_bit - 1;
hw->rx_conf1.rx_tdm_chan_bits = sample_bit-1;
hw->rx_conf1.rx_tdm_chan_bits = sample_bit - 1;
}
/**
@ -390,7 +353,7 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i
*/
static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits)
{
hw->tx_conf1.tx_half_sample_bits = half_sample_bits-1;
hw->tx_conf1.tx_half_sample_bits = half_sample_bits - 1;
}
/**
@ -401,7 +364,7 @@ static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_
*/
static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits)
{
hw->rx_conf1.rx_half_sample_bits = half_sample_bits-1;
hw->rx_conf1.rx_half_sample_bits = half_sample_bits - 1;
}
/**
@ -432,9 +395,9 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab
* @param hw Peripheral I2S hardware instance address.
* @param total_num Total slot number
*/
static inline void i2s_ll_set_tx_slot_mun(i2s_dev_t *hw, int total_num)
static inline void i2s_ll_set_tx_slot_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;
}
/**
@ -443,22 +406,22 @@ static inline void i2s_ll_set_tx_slot_mun(i2s_dev_t *hw, int total_num)
* @param hw Peripheral I2S hardware instance address.
* @param total_num Total slot number
*/
static inline void i2s_ll_set_rx_slot_mun(i2s_dev_t *hw, int total_num)
static inline void i2s_ll_set_rx_slot_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.
*
* @param hw Peripheral I2S hardware instance address.
* @param
* @param slot_mask mask of tx active slot
*/
static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask)
{
typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl;
tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK;
tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK;
tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK;
tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK;
hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val;
}
@ -466,13 +429,13 @@ static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_m
* @brief Set the bimap of the active RX slot, only the active slot can receive audio data.
*
* @param hw Peripheral I2S hardware instance address.
* @param
* @param slot_mask mask of rx active slot
*/
static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask)
{
typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl;
tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK;
tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK;
tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK;
tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK;
hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val;
}
@ -480,7 +443,7 @@ static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_m
* @brief Set TX WS signal pol level
*
* @param hw Peripheral I2S hardware instance address.
* @param
* @param ws_pol_level pin level of WS(output) when receiving left channel data
*/
static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level)
{
@ -491,7 +454,7 @@ static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level)
* @brief Set RX WS signal pol level
*
* @param hw Peripheral I2S hardware instance address.
* @param
* @param ws_pol_level pin level of WS(input) when receiving left channel data
*/
static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level)
{
@ -533,7 +496,7 @@ static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate)
pdm_conf_reg.tx_pdm_lp_in_shift = 1;
pdm_conf_reg.tx_pdm_sinc_in_shift = 1;
pdm_conf_reg.tx_pdm_sigmadelta_in_shift = 1;
pdm_conf_reg.tx_pdm_sinc_osr2 = fp/fs;
pdm_conf_reg.tx_pdm_sinc_osr2 = fp / fs;
pdm_conf_reg.tx_pdm_dac_mode_en = 1;
pdm_conf_reg.tx_pdm_sigmadelta_dither = 0;
pdm_conf_reg.tx_pdm_sigmadelta_dither2 = 0;
@ -541,7 +504,7 @@ static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate)
pdm_conf1_reg.tx_pdm_fp = fp;
pdm_conf1_reg.tx_pdm_fs = fs;
pdm_conf1_reg.tx_iir_hp_mult12_5 = 7;
pdm_conf1_reg.tx_iir_hp_mult12_0 =6;
pdm_conf1_reg.tx_iir_hp_mult12_0 = 6;
pdm_conf_reg.tx_pdm_hp_bypass = 0;
hw->tx_pcm2pdm_conf = pdm_conf_reg;
hw->tx_pcm2pdm_conf1 = pdm_conf1_reg;
@ -583,13 +546,8 @@ static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t
*/
static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable)
{
if (pdm_enable) {
hw->rx_conf.rx_tdm_en = 0;
hw->rx_conf.rx_pdm_en = 1;
} else {
hw->rx_conf.rx_pdm_en = 0;
hw->rx_conf.rx_tdm_en = 1;
}
hw->rx_conf.rx_pdm_en = pdm_enable;
hw->rx_conf.rx_tdm_en = !pdm_enable;
}
/**
@ -598,7 +556,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_cfg_t pcm_cfg)
static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg)
{
if (pcm_cfg == I2S_PCM_DISABLE) {
hw->tx_conf.tx_pcm_bypass = 1;
@ -614,7 +572,7 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_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_cfg_t pcm_cfg)
static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg)
{
if (pcm_cfg == I2S_PCM_DISABLE) {
hw->rx_conf.rx_pcm_bypass = 1;
@ -690,6 +648,18 @@ static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena)
hw->rx_conf.rx_bit_order = lsb_order_ena;
}
/**
* @brief Configure TX skip mask enable
*
* @param hw Peripheral I2S hardware instance address.
* @param skip_mask_ena Set true to skip inactive channels.
*/
static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena)
{
hw->tx_tdm_ctrl.tx_tdm_skip_msk_en = skip_mask_ena;
}
/**
* @brief Configure single data
*

View File

@ -31,13 +31,12 @@ extern "C" {
#endif
// Get I2S hardware instance with giving i2s num
#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL)
#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL)
#define I2S_INTR_IN_SUC_EOF BIT(9)
#define I2S_INTR_OUT_EOF BIT(12)
#define I2S_INTR_IN_DSCR_ERR BIT(13)
#define I2S_INTR_OUT_DSCR_ERR BIT(14)
#define I2S_INTR_MAX (0xFFFFFFFF)
#define I2S_LL_BASE_CLK (2*APB_CLK_FREQ)
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (6)
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
/* I2S clock configuration structure */
typedef struct {
@ -45,56 +44,14 @@ typedef struct {
uint16_t a;
uint16_t b; // The decimal part of module clock devider, the decimal is: b/a
uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div
} i2s_clk_cal_t;
/**
* @brief Calculate the closest sample rate clock configuration.
* clock relationship:
* Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a)
*
* @param fsclk I2S source clock freq.
* @param fbck BCK freuency.
* @param bck_div The BCK devider of bck. Generally, set bck_div to 8.
* @param cal Point to `i2s_clk_cal_t` structure.
*/
static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal)
{
int ma = 0;
int mb = 0;
uint32_t mclk = fbck*bck_div;
cal->mclk_div = fsclk / mclk;
cal->bck_div = bck_div;
cal->a = 1;
cal->b = 0;
uint32_t freq_diff = fsclk - mclk * cal->mclk_div;
uint32_t min = ~0;
if (freq_diff == 0) {
return;
}
for (int a = 2; a <= 63; a++) {
for (int b = 1; b < a; b++) {
ma = freq_diff*a;
mb = mclk*b;
if (ma == mb) {
cal->a = a;
cal->b = b;
return;
}
if (abs((mb - ma)) < min) {
cal->a = a;
cal->b = b;
min = abs(mb - ma);
}
}
}
}
} i2s_ll_clk_cal_t;
/**
* @brief I2S module general init, enable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_general_init(i2s_dev_t *hw)
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
{
if (hw->clkm_conf.clk_en == 0) {
hw->clkm_conf.clk_sel = 2;
@ -104,35 +61,69 @@ static inline void i2s_ll_general_init(i2s_dev_t *hw)
}
/**
* @brief I2S TX module general init.
* @brief I2S tx msb right enable
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable tx msb right
*/
static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw)
static inline void i2s_ll_tx_msb_right_en(i2s_dev_t *hw, bool enable)
{
hw->conf.tx_start = 0;
hw->conf.tx_reset = 1;
hw->conf.tx_reset = 0;
hw->conf.tx_msb_right = 0;
hw->conf.tx_right_first = 0;
hw->conf.tx_slave_mod = 0;
hw->fifo_conf.tx_fifo_mod_force_en = 1;
hw->conf.tx_msb_right = enable;
}
/**
* @brief I2S RX module general init.
* @brief I2S rx msb right enable
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable rx msb right
*/
static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw)
static inline void i2s_ll_rx_msb_right_en(i2s_dev_t *hw, bool enable)
{
hw->conf.rx_start = 0;
hw->conf.rx_reset = 1;
hw->conf.rx_reset = 0;
hw->conf.rx_msb_right = 0;
hw->conf.rx_right_first = 0;
hw->conf.rx_slave_mod = 0;
hw->fifo_conf.rx_fifo_mod_force_en = 1;
hw->conf.rx_msb_right = enable;
}
/**
* @brief I2S tx right channel first
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable send right channel first
*/
static inline void i2s_ll_tx_right_first_en(i2s_dev_t *hw, bool enable)
{
hw->conf.tx_right_first = enable;
}
/**
* @brief I2S rx right channel first
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable receive right channel first
*/
static inline void i2s_ll_rx_right_first_en(i2s_dev_t *hw, bool enable)
{
hw->conf.rx_right_first = enable;
}
/**
* @brief I2S tx fifo module force enable
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable tx fifo module
*/
static inline void i2s_ll_tx_fifo_mod_force_en(i2s_dev_t *hw, bool enable)
{
hw->fifo_conf.tx_fifo_mod_force_en = enable;
}
/**
* @brief I2S rx fifo module force enable
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable rx fifo module
*/
static inline void i2s_ll_rx_fifo_mod_force_en(i2s_dev_t *hw, bool enable)
{
hw->fifo_conf.rx_fifo_mod_force_en = enable;
}
/**
@ -229,7 +220,7 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src)
* @param hw Peripheral I2S hardware instance address.
* @param set Pointer to I2S clock devider configuration paramater
*/
static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set)
{
hw->clkm_conf.clkm_div_num = set->mclk_div;
hw->clkm_conf.clkm_div_b = set->b;
@ -243,7 +234,7 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
* @param hw Peripheral I2S hardware instance address.
* @param set Pointer to I2S clock devider configuration paramater
*/
static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set)
{
hw->clkm_conf.clkm_div_num = set->mclk_div;
hw->clkm_conf.clkm_div_b = set->b;
@ -490,11 +481,7 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i
*/
static inline void i2s_ll_dma_enable(i2s_dev_t *hw, bool ena)
{
if (ena && !hw->fifo_conf.dscr_en) {
hw->fifo_conf.dscr_en = 1;
} else if (!ena && hw->fifo_conf.dscr_en) {
hw->fifo_conf.dscr_en = 0;
}
hw->fifo_conf.dscr_en = ena;
}
/**

View File

@ -1,4 +1,4 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// The LL layer for I2C register operations
// The LL layer for I2S register operations
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
@ -30,13 +30,13 @@ extern "C" {
#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : &I2S1)
#define I2S_INTR_OUT_DSCR_ERR (0x1 << 6)
#define I2S_INTR_OUT_EOF (0x1 << 4)
#define I2S_INTR_IN_DSCR_ERR (0x1 << 5)
#define I2S_INTR_IN_SUC_EOF (0x1 << 1)
#define I2S_INTR_MAX (~0)
#define I2S_TDM_CH_MASK (0xffff)
#define I2S_LL_TDM_CH_MASK (0xffff)
#define I2S_LL_PDM_BCK_FACTOR (64)
#define I2S_LL_BASE_CLK (2*APB_CLK_FREQ)
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9)
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
/* I2S clock configuration structure */
typedef struct {
@ -44,95 +44,58 @@ typedef struct {
uint16_t a;
uint16_t b; // The decimal part of module clock devider, the decimal is: b/a
uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div
} i2s_clk_cal_t;
/**
* @brief Calculate the closest sample rate clock configuration.
* clock relationship:
* Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a)
*
* @param fsclk I2S source clock freq.
* @param fbck BCK freuency.
* @param bck_div The BCK devider of bck. Generally, set bck_div to 8.
* @param cal Point to `i2s_clk_cal_t` structure.
*/
static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal)
{
int ma = 0;
int mb = 0;
uint32_t mclk = fbck*bck_div;
cal->mclk_div = fsclk / mclk;
cal->bck_div = bck_div;
cal->a = 1;
cal->b = 0;
uint32_t freq_diff = fsclk - mclk * cal->mclk_div;
uint32_t min = freq_diff * 512;
if (freq_diff == 0) {
return;
}
for (int a = 2; a <= 512; a++) {
for (int b = 1; b < a; b++) {
ma = freq_diff*a;
mb = mclk*b;
if (ma == mb) {
cal->a = a;
cal->b = b;
return;
}
if (abs((mb - ma)) < min) {
cal->a = a;
cal->b = b;
min = abs(mb - ma);
}
}
}
}
} i2s_ll_clk_cal_t;
/**
* @brief I2S module general init, enable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_general_init(i2s_dev_t *hw)
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
{
hw->tx_clkm_conf.clk_en = 1;
}
/**
* @brief Reset I2S TX module, enable default source clock and set to TDM mode.
* @brief Enable I2S tx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw)
static inline void i2s_ll_enable_tx_clock(i2s_dev_t *hw)
{
hw->tx_conf.tx_start = 0;
hw->tx_conf.tx_reset = 1;
hw->tx_conf.tx_reset = 0;
hw->tx_conf.tx_slave_mod = 0;
hw->tx_conf.tx_tdm_en = 1;
hw->tx_conf.tx_pdm_en = 0;
hw->tx_clkm_conf.tx_clk_active = 1;
hw->tx_clkm_conf.tx_clk_sel = 2;
}
/**
* @brief Reset I2S RX module, enable default source clock and set to TDM mode.
* @brief Enable I2S rx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw)
static inline void i2s_ll_enable_rx_clock(i2s_dev_t *hw)
{
hw->rx_conf.rx_start = 0;
hw->rx_conf.rx_reset = 1;
hw->rx_conf.rx_reset = 0;
hw->rx_conf.rx_slave_mod = 0;
hw->rx_conf.rx_tdm_en = 1;
hw->rx_conf.rx_pdm_en = 0;
hw->rx_clkm_conf.rx_clk_active = 1;
hw->rx_clkm_conf.rx_clk_sel = 2;
}
/**
* @brief I2S mclk use tx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_mclk_use_tx_clk(i2s_dev_t *hw)
{
hw->rx_clkm_conf.mclk_sel = 0;
}
/**
* @brief I2S mclk use rx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_mclk_use_rx_clk(i2s_dev_t *hw)
{
hw->rx_clkm_conf.mclk_sel = 1;
}
/**
* @brief Enable I2S TX slave mode
*
@ -204,6 +167,7 @@ static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw)
*
* @param hw Peripheral I2S hardware instance address.
* @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK`
* TX and RX share the same clock setting
*/
static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src)
{
@ -215,6 +179,7 @@ static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src)
*
* @param hw Peripheral I2S hardware instance address.
* @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK`
* TX and RX share the same clock setting
*/
static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src)
{
@ -227,27 +192,27 @@ static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src)
* @param hw Peripheral I2S hardware instance address.
* @param set Pointer to I2S clock devider configuration paramater
*/
static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set)
{
if (set->a == 0 || set->b == 0) {
hw->tx_clkm_div_conf.tx_clkm_div_x = 0;
hw->tx_clkm_div_conf.tx_clkm_div_y = 0;
hw->tx_clkm_div_conf.tx_clkm_div_z = 0;
} else {
if(set->b > set->a/2) {
hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/(set->a-set->b) -1;
hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%(set->a-set->b);
hw->tx_clkm_div_conf.tx_clkm_div_z = set->a-set->b;
if (set->b > set->a / 2) {
hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / (set->a - set->b) - 1;
hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % (set->a - set->b);
hw->tx_clkm_div_conf.tx_clkm_div_z = set->a - set->b;
hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 1;
} else {
hw->tx_clkm_div_conf.tx_clkm_div_x = set->a/set->b-1;
hw->tx_clkm_div_conf.tx_clkm_div_y = set->a%set->b+1;
hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / set->b - 1;
hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % set->b + 1;
hw->tx_clkm_div_conf.tx_clkm_div_z = set->b;
hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0;
}
}
hw->tx_clkm_conf.tx_clkm_div_num = set->mclk_div;
hw->tx_conf1.tx_bck_div_num = set->bck_div-1;
hw->tx_conf1.tx_bck_div_num = set->bck_div - 1;
}
/**
@ -256,27 +221,27 @@ static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
* @param hw Peripheral I2S hardware instance address.
* @param set Pointer to I2S clock devider configuration paramater
*/
static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set)
{
if (set->a == 0 || set->b == 0) {
hw->rx_clkm_div_conf.rx_clkm_div_x = 0;
hw->rx_clkm_div_conf.rx_clkm_div_y = 0;
hw->rx_clkm_div_conf.rx_clkm_div_z = 0;
} else {
if(set->b > set->a/2) {
hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/(set->a-set->b)-1;
hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%(set->a-set->b);
hw->rx_clkm_div_conf.rx_clkm_div_z = set->a-set->b;
if (set->b > set->a / 2) {
hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / (set->a - set->b) - 1;
hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % (set->a - set->b);
hw->rx_clkm_div_conf.rx_clkm_div_z = set->a - set->b;
hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 1;
} else {
hw->rx_clkm_div_conf.rx_clkm_div_x = set->a/set->b-1;
hw->rx_clkm_div_conf.rx_clkm_div_y = set->a%set->b+1;
hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / set->b - 1;
hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % set->b + 1;
hw->rx_clkm_div_conf.rx_clkm_div_z = set->b;
hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0;
}
}
hw->rx_clkm_conf.rx_clkm_div_num = set->mclk_div;
hw->rx_conf1.rx_bck_div_num = set->bck_div-1;
hw->rx_conf1.rx_bck_div_num = set->bck_div - 1;
}
/**
@ -331,7 +296,7 @@ static inline void i2s_ll_stop_rx(i2s_dev_t *hw)
*/
static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width)
{
hw->tx_conf1.tx_tdm_ws_width = width-1;
hw->tx_conf1.tx_tdm_ws_width = width - 1;
}
/**
@ -342,7 +307,7 @@ static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width)
*/
static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width)
{
hw->rx_conf1.rx_tdm_ws_width = width-1;
hw->rx_conf1.rx_tdm_ws_width = width - 1;
}
/**
@ -366,7 +331,7 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num)
static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)
{
hw->tx_conf1.tx_bits_mod = data_bit - 1;
hw->tx_conf1.tx_tdm_chan_bits = sample_bit-1;
hw->tx_conf1.tx_tdm_chan_bits = sample_bit - 1;
}
/**
@ -379,7 +344,7 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i
static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)
{
hw->rx_conf1.rx_bits_mod = data_bit - 1;
hw->rx_conf1.rx_tdm_chan_bits = sample_bit-1;
hw->rx_conf1.rx_tdm_chan_bits = sample_bit - 1;
}
/**
@ -390,7 +355,7 @@ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i
*/
static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits)
{
hw->tx_conf1.tx_half_sample_bits = half_sample_bits-1;
hw->tx_conf1.tx_half_sample_bits = half_sample_bits - 1;
}
/**
@ -401,7 +366,7 @@ static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_
*/
static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits)
{
hw->rx_conf1.rx_half_sample_bits = half_sample_bits-1;
hw->rx_conf1.rx_half_sample_bits = half_sample_bits - 1;
}
/**
@ -432,9 +397,9 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab
* @param hw Peripheral I2S hardware instance address.
* @param total_num Total slot number
*/
static inline void i2s_ll_set_tx_slot_mun(i2s_dev_t *hw, int total_num)
static inline void i2s_ll_set_tx_slot_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;
}
/**
@ -443,22 +408,22 @@ static inline void i2s_ll_set_tx_slot_mun(i2s_dev_t *hw, int total_num)
* @param hw Peripheral I2S hardware instance address.
* @param total_num Total slot number
*/
static inline void i2s_ll_set_rx_slot_mun(i2s_dev_t *hw, int total_num)
static inline void i2s_ll_set_rx_slot_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.
*
* @param hw Peripheral I2S hardware instance address.
* @param
* @param slot_mask mask of tx active slot
*/
static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask)
{
typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl;
tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK;
tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK;
tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK;
tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK;
hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val;
}
@ -466,13 +431,13 @@ static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_m
* @brief Set the bimap of the active RX slot, only the active slot can receive audio data.
*
* @param hw Peripheral I2S hardware instance address.
* @param
* @param slot_mask mask of rx active slot
*/
static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask)
{
typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl;
tdm_ctrl_reg.val &= ~I2S_TDM_CH_MASK;
tdm_ctrl_reg.val |= slot_mask&I2S_TDM_CH_MASK;
tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK;
tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK;
hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val;
}
@ -480,7 +445,7 @@ static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_m
* @brief Set TX WS signal pol level
*
* @param hw Peripheral I2S hardware instance address.
* @param
* @param ws_pol_level pin level of WS(output) when receiving left channel data
*/
static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level)
{
@ -491,7 +456,7 @@ static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level)
* @brief Set RX WS signal pol level
*
* @param hw Peripheral I2S hardware instance address.
* @param
* @param ws_pol_level pin level of WS(input) when receiving left channel data
*/
static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level)
{
@ -506,13 +471,8 @@ static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level)
*/
static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable)
{
if (pdm_enable) {
hw->tx_conf.tx_tdm_en = 0;
hw->tx_conf.tx_pdm_en = 1;
} else {
hw->tx_conf.tx_pdm_en = 0;
hw->tx_conf.tx_tdm_en = 1;
}
hw->tx_conf.tx_pdm_en = pdm_enable;
hw->tx_conf.tx_tdm_en = !pdm_enable;
}
/**
@ -523,13 +483,68 @@ static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable)
*/
static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable)
{
if (pdm_enable) {
hw->rx_conf.rx_tdm_en = 0;
hw->rx_conf.rx_pdm_en = 1;
} else {
hw->rx_conf.rx_pdm_en = 0;
hw->rx_conf.rx_tdm_en = 1;
}
hw->rx_conf.rx_pdm_en = pdm_enable;
hw->rx_conf.rx_tdm_en = !pdm_enable;
}
/**
* @brief Configure I2S TX PDM sample rate
* Fpdm = 64*Fpcm*fp/fs
*
* @param hw Peripheral I2S hardware instance address.
* @param fp The fp value of TX PDM filter module group0.
* @param fs The fs value of TX PDM filter module group0.
*/
static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs)
{
hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp;
hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs;
hw->tx_pcm2pdm_conf.tx_sinc_osr2 = fp / fs;
}
/**
* @brief Get I2S TX PDM configuration
*
* @param hw Peripheral I2S hardware instance address.
* @param fp Pointer to accept TX PDM fp configuration paramater
* @param fs Pointer to accept TX PDM fs configuration paramater
*/
static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs)
{
*fp = hw->tx_pcm2pdm_conf1.tx_pdm_fp;
*fs = hw->tx_pcm2pdm_conf1.tx_pdm_fs;
}
/**
* @brief Configure I2S TX pdm
*
* @param hw Peripheral I2S hardware instance address.
* @param sample_rate The sample rate to be set.
*/
static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate)
{
uint32_t fp = 960;
uint32_t fs = sample_rate / 100;
typeof(hw->tx_pcm2pdm_conf) pdm_conf_reg = hw->tx_pcm2pdm_conf;
typeof(hw->tx_pcm2pdm_conf1) pdm_conf1_reg = hw->tx_pcm2pdm_conf1;
pdm_conf_reg.pcm2pdm_conv_en = 1;
pdm_conf_reg.tx_prescale = 0;
pdm_conf_reg.tx_hp_in_shift = 1;
pdm_conf_reg.tx_lp_in_shift = 1;
pdm_conf_reg.tx_sinc_in_shift = 1;
pdm_conf_reg.tx_sigmadelta_in_shift = 1;
pdm_conf_reg.tx_sinc_osr2 = fp / fs;
pdm_conf_reg.tx_dac_mode_en = 1;
pdm_conf_reg.tx_sigmadelta_dither = 0;
pdm_conf_reg.tx_sigmadelta_dither2 = 0;
pdm_conf_reg.tx_dac_2out_en = 1;
pdm_conf1_reg.tx_pdm_fp = fp;
pdm_conf1_reg.tx_pdm_fs = fs;
pdm_conf1_reg.tx_iir_hp_mult12_5 = 7;
pdm_conf1_reg.tx_iir_hp_mult12_0 = 6;
pdm_conf_reg.tx_hp_bypass = 0;
hw->tx_pcm2pdm_conf = pdm_conf_reg;
hw->tx_pcm2pdm_conf1 = pdm_conf1_reg;
}
/**
@ -541,7 +556,7 @@ static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw)
{
hw->rx_conf.rx_tdm_en = 0;
hw->rx_conf.rx_pdm2pcm_en = 1;
hw->rx_conf.rx_sinc_dsr_16_en = 0;
hw->rx_conf.rx_pdm_sinc_dsr_16_en = 0;
hw->rx_conf.rx_pdm_en = 1;
}
@ -553,7 +568,7 @@ static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw)
*/
static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr)
{
hw->rx_conf.rx_sinc_dsr_16_en = dsr;
hw->rx_conf.rx_pdm_sinc_dsr_16_en = dsr;
}
/**
@ -564,7 +579,7 @@ static inline void i2s_ll_set_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr)
*/
static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr)
{
*dsr = hw->rx_conf.rx_sinc_dsr_16_en;
*dsr = hw->rx_conf.rx_pdm_sinc_dsr_16_en;
}
/**
@ -573,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_cfg_t pcm_cfg)
static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg)
{
if (pcm_cfg == I2S_PCM_DISABLE) {
hw->tx_conf.tx_pcm_bypass = 1;
@ -589,7 +604,7 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_cfg_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_cfg_t pcm_cfg)
static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg)
{
if (pcm_cfg == I2S_PCM_DISABLE) {
hw->rx_conf.rx_pcm_bypass = 1;
@ -665,6 +680,18 @@ static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena)
hw->rx_conf.rx_bit_order = lsb_order_ena;
}
/**
* @brief Configure TX skip mask enable
*
* @param hw Peripheral I2S hardware instance address.
* @param skip_mask_ena Set true to skip inactive channels.
*/
static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena)
{
hw->tx_tdm_ctrl.tx_tdm_skip_msk_en = skip_mask_ena;
}
/**
* @brief Configure single data
*
@ -673,7 +700,7 @@ static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena)
*/
static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data)
{
hw->conf_single_data = data;
hw->conf_signal_data = data;
}
/**

View File

@ -17,59 +17,50 @@
#include "soc/soc.h"
#include "soc/soc_caps.h"
#include "soc/gdma_channel.h"
#include "hal/i2s_hal.h"
#define I2S_MODE_I2S (I2S_MODE_MASTER|I2S_MODE_SLAVE|I2S_MODE_TX|I2S_MODE_RX) /*!< I2S normal mode*/
void i2s_hal_reset_tx(i2s_hal_context_t *hal)
/**
* @brief Calculate the closest sample rate clock configuration.
* clock relationship:
* Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a)
*
* @param fsclk I2S source clock freq.
* @param fbck BCK freuency.
* @param bck_div The BCK devider of bck. Generally, set bck_div to 8.
* @param cal Point to `i2s_ll_clk_cal_t` structure.
*/
static void i2s_hal_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_ll_clk_cal_t *cal)
{
i2s_ll_reset_tx(hal->dev);
}
void i2s_hal_reset_rx(i2s_hal_context_t *hal)
{
i2s_ll_reset_rx(hal->dev);
}
void i2s_hal_reset_tx_fifo(i2s_hal_context_t *hal)
{
i2s_ll_reset_tx_fifo(hal->dev);
}
void i2s_hal_reset_rx_fifo(i2s_hal_context_t *hal)
{
i2s_ll_reset_rx_fifo(hal->dev);
}
void i2s_hal_start_tx(i2s_hal_context_t *hal)
{
i2s_ll_start_tx(hal->dev);
}
void i2s_hal_start_rx(i2s_hal_context_t *hal)
{
i2s_ll_start_rx(hal->dev);
}
void i2s_hal_stop_tx(i2s_hal_context_t *hal)
{
i2s_ll_stop_tx(hal->dev);
}
void i2s_hal_stop_rx(i2s_hal_context_t *hal)
{
i2s_ll_stop_rx(hal->dev);
}
void i2s_hal_set_tx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit)
{
i2s_ll_set_tx_sample_bit(hal->dev, slot_bit, data_bit);
}
void i2s_hal_set_rx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit)
{
i2s_ll_set_rx_sample_bit(hal->dev, slot_bit, data_bit);
int ma = 0;
int mb = 0;
uint32_t mclk = fbck * bck_div;
cal->mclk_div = fsclk / mclk;
cal->bck_div = bck_div;
cal->a = 1;
cal->b = 0;
uint32_t freq_diff = fsclk - mclk * cal->mclk_div;
uint32_t min = ~0;
if (freq_diff == 0) {
return;
}
for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) {
for (int b = 1; b < a; b++) {
ma = freq_diff * a;
mb = mclk * b;
if (ma == mb) {
cal->a = a;
cal->b = b;
return;
}
if (abs((mb - ma)) < min) {
cal->a = a;
cal->b = b;
min = abs(mb - ma);
}
}
}
}
void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel)
@ -80,23 +71,18 @@ void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel)
void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor)
{
i2s_clk_cal_t clk_set = {0};
i2s_ll_clk_cal(sclk, fbck, factor, &clk_set);
i2s_ll_clk_cal_t clk_set = {0};
i2s_hal_clk_cal(sclk, fbck, factor, &clk_set);
i2s_ll_set_tx_clk(hal->dev, &clk_set);
}
void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor)
{
i2s_clk_cal_t clk_set = {0};
i2s_ll_clk_cal(sclk, fbck, factor, &clk_set);
i2s_ll_clk_cal_t clk_set = {0};
i2s_hal_clk_cal(sclk, fbck, factor, &clk_set);
i2s_ll_set_rx_clk(hal->dev, &clk_set);
}
void i2s_hal_set_rx_eof_num(i2s_hal_context_t *hal, uint32_t eof_byte)
{
i2s_ll_set_rx_eof_num(hal->dev, eof_byte);
}
void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal)
{
i2s_ll_set_tx_slave_mod(hal->dev, 0); //TX master
@ -109,200 +95,175 @@ void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal)
i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave
}
#if SOC_I2S_SUPPORTS_PCM
void i2s_hal_tx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg)
{
i2s_ll_tx_pcm_cfg(hal->dev, cfg);
}
void i2s_hal_rx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg)
{
i2s_ll_rx_pcm_cfg(hal->dev, cfg);
}
#endif
void i2s_hal_enable_sig_loopback(i2s_hal_context_t *hal)
{
i2s_ll_loop_back_ena(hal->dev, 1);
}
#if SOC_I2S_SUPPORTS_PDM_TX
void i2s_hal_set_tx_pdm_fpfs(i2s_hal_context_t *hal, int fp, int fs)
{
i2s_ll_set_tx_pdm_fpfs(hal->dev, fp, fs);
}
void i2s_hal_get_tx_pdm_fpfs(i2s_hal_context_t *hal, int *fp, int *fs)
{
i2s_ll_get_tx_pdm_fpfs(hal->dev, (uint32_t *)fp, (uint32_t *)fs);
}
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
void i2s_hal_set_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t dsr)
{
i2s_ll_set_pdm_rx_dsr(hal->dev, dsr);
}
void i2s_hal_get_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t *dsr)
{
i2s_ll_get_pdm_rx_dsr(hal->dev, dsr);
}
#endif
void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num)
{
//Get hardware instance.
hal->dev = I2S_LL_GET_HW(i2s_num);
#if SOC_GDMA_SUPPORTED
hal->dma = &GDMA;
if (i2s_num == 0) {
hal->dma_ch = SOC_GDMA_I2S0_DMA_CHANNEL;
hal->dma_peri_sel = SOC_GDMA_TRIG_PERIPH_I2S0;
}
#if SOC_I2S_NUM > 1
if (i2s_num == 1) {
hal->dma_ch = SOC_GDMA_I2S1_DMA_CHANNEL;
hal->dma_peri_sel = SOC_GDMA_TRIG_PERIPH_I2S1;
}
#endif
gdma_ll_enable_m2m_mode(hal->dma, hal->dma_ch, false);
#endif
i2s_ll_general_init(hal->dev);
i2s_ll_enable_clock(hal->dev);
}
static void i2s_hal_format_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg)
static void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
{
int active_slot_num = slot_ch_cfg & 0xffff;
#if !SOC_I2S_SUPPORTS_TDM
switch (format) {
case I2S_COMM_FORMAT_STAND_MSB:
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_set_tx_format_msb_align(hal->dev);
}
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_set_rx_format_msb_align(hal->dev);
}
break;
case I2S_COMM_FORMAT_STAND_PCM_SHORT:
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_set_tx_pcm_short(hal->dev);
}
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_set_rx_pcm_short(hal->dev);
}
break;
case I2S_COMM_FORMAT_STAND_PCM_LONG:
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_set_tx_pcm_long(hal->dev);
}
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_set_rx_pcm_long(hal->dev);
}
break;
default: //I2S_COMM_FORMAT_STAND_I2S
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_set_tx_format_philip(hal->dev);
}
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_set_rx_format_philip(hal->dev);
}
break;
}
if (active_slot_num == I2S_CHANNEL_MONO) {
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_tx_mono_mode_ena(hal->dev, active_slot_num == I2S_CHANNEL_MONO);
switch (hal_cfg->comm_fmt) {
case I2S_COMM_FORMAT_STAND_MSB:
if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_set_tx_format_msb_align(hal->dev);
}
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_rx_mono_mode_ena(hal->dev, active_slot_num == I2S_CHANNEL_MONO);
if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_set_rx_format_msb_align(hal->dev);
}
break;
case I2S_COMM_FORMAT_STAND_PCM_SHORT:
if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_set_tx_pcm_short(hal->dev);
}
if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_set_rx_pcm_short(hal->dev);
}
break;
case I2S_COMM_FORMAT_STAND_PCM_LONG:
if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_set_tx_pcm_long(hal->dev);
}
if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_set_rx_pcm_long(hal->dev);
}
break;
default: //I2S_COMM_FORMAT_STAND_I2S
if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_set_tx_format_philip(hal->dev);
}
if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_set_rx_format_philip(hal->dev);
}
break;
}
if (hal_cfg->ch == I2S_CHANNEL_MONO) {
if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_tx_mono_mode_ena(hal->dev, true);
}
if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_rx_mono_mode_ena(hal->dev, true);
}
}
#else
int data_bits = slot_bit_cfg & 0xffff;
int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT;
int slot_num = ((slot_ch_cfg >> SLOT_CH_SHIFT) == 0 || (active_slot_num == I2S_CHANNEL_MONO)) ? 2 : (slot_ch_cfg >> SLOT_CH_SHIFT);
int slot_bits = hal_cfg->bits_cfg.chan_bits;
int slot_num = hal_cfg->chan_cfg.total_chan;
bool msb_shift_en = false;
int tdm_ws_width = 0;
switch (format) {
case I2S_COMM_FORMAT_STAND_MSB:
msb_shift_en = false;
tdm_ws_width = slot_num*slot_bits/2;
break;
case I2S_COMM_FORMAT_STAND_PCM_SHORT:
msb_shift_en = false;
tdm_ws_width = 1;
break;
case I2S_COMM_FORMAT_STAND_PCM_LONG:
msb_shift_en = false;
tdm_ws_width = slot_bits;
break;
default: //I2S_COMM_FORMAT_STAND_I2S
msb_shift_en = true;
tdm_ws_width = slot_num*slot_bits/2;
break;
switch (hal_cfg->comm_fmt) {
case I2S_COMM_FORMAT_STAND_MSB:
msb_shift_en = false;
tdm_ws_width = slot_num * slot_bits / 2;
break;
case I2S_COMM_FORMAT_STAND_PCM_SHORT:
msb_shift_en = false;
tdm_ws_width = 1;
break;
case I2S_COMM_FORMAT_STAND_PCM_LONG:
msb_shift_en = false;
tdm_ws_width = slot_bits;
break;
default: //I2S_COMM_FORMAT_STAND_I2S
msb_shift_en = true;
tdm_ws_width = slot_num * slot_bits / 2;
break;
}
if (i2s_mode & I2S_MODE_TX) {
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, slot_num * slot_bits / 2);
}
if (i2s_mode & I2S_MODE_RX) {
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, slot_num * slot_bits / 2);
}
#endif
}
void i2s_hal_samples_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t communication_format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg)
void i2s_hal_samples_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
{
int active_slot_num = slot_ch_cfg & 0xffff;
int data_bits = slot_bit_cfg & 0xffff;
int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT;
int slot_num = ((slot_ch_cfg >> SLOT_CH_SHIFT) == 0 || (active_slot_num == I2S_CHANNEL_MONO)) ? 2 : (slot_ch_cfg >> SLOT_CH_SHIFT);
int data_bits = hal_cfg->bits_cfg.sample_bits;
int slot_bits = hal_cfg->bits_cfg.chan_bits;
#if SOC_I2S_SUPPORTS_TDM
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_set_tx_slot_mun(hal->dev, slot_num);
int slot_num = hal_cfg->chan_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);
}
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_set_rx_slot_mun(hal->dev, slot_num);
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);
}
#else
if (i2s_mode & I2S_MODE_TX) {
if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits);
}
if (i2s_mode & I2S_MODE_RX) {
if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits);
}
#endif
//I2S standards config: Philip, MSB or PCM, Only I2S mode should do this configuration.
if ((i2s_mode & (~(I2S_MODE_I2S))) == 0) {
i2s_hal_format_config(hal, i2s_mode, communication_format, slot_bit_cfg, slot_ch_cfg);
if ((hal_cfg->mode & (~(I2S_MODE_I2S))) == 0) {
i2s_hal_format_config(hal, hal_cfg);
}
}
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_param_t *i2s_config)
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
{
if (i2s_config->mode & I2S_MODE_TX) {
i2s_ll_tx_gen_init(hal->dev);
if (i2s_config->mode & I2S_MODE_SLAVE) {
i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave
}
bool is_slave = ((hal_cfg->mode & I2S_MODE_SLAVE) > 0);
if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_stop_tx(hal->dev);
i2s_ll_reset_tx(hal->dev);
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_set_tx_pdm_en(hal->dev, false);
i2s_ll_enable_tx_clock(hal->dev);
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_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);
i2s_ll_tx_set_skip_mask(hal->dev, hal_cfg->flags.skip_msk_en);
#else
i2s_ll_tx_msb_right_en(hal->dev, false);
i2s_ll_tx_right_first_en(hal->dev, false);
i2s_ll_tx_fifo_mod_force_en(hal->dev, true);
#endif
i2s_ll_set_tx_slave_mod(hal->dev, is_slave); //TX Slave
}
if (i2s_config->mode & I2S_MODE_RX) {
i2s_ll_rx_gen_init(hal->dev);
if (i2s_config->mode & I2S_MODE_SLAVE) {
i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave
}
if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_stop_rx(hal->dev);
i2s_ll_reset_rx(hal->dev);
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_set_rx_pdm_en(hal->dev, false);
i2s_ll_enable_rx_clock(hal->dev);
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_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);
#else
i2s_ll_rx_msb_right_en(hal->dev, false);
i2s_ll_rx_right_first_en(hal->dev, false);
i2s_ll_rx_fifo_mod_force_en(hal->dev, true);
#endif
i2s_ll_set_rx_slave_mod(hal->dev, is_slave); //RX Slave
}
#if SOC_I2S_SUPPORTS_ADC_DAC
if (i2s_config->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) {
if (i2s_config->mode & I2S_MODE_DAC_BUILT_IN) {
if (hal_cfg->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) {
if (hal_cfg->mode & I2S_MODE_DAC_BUILT_IN) {
i2s_ll_build_in_dac_ena(hal->dev);
}
if (i2s_config->mode & I2S_MODE_ADC_BUILT_IN) {
if (hal_cfg->mode & I2S_MODE_ADC_BUILT_IN) {
i2s_ll_build_in_adc_ena(hal->dev);
}
// Buildin ADC and DAC have nothing to do with communication format configuration.
@ -311,47 +272,27 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_param_t *i2s_
#endif
#if SOC_I2S_SUPPORTS_PDM
if (!(i2s_config->mode & I2S_MODE_PDM)) {
#if SOC_I2S_SUPPORTS_PDM_RX
if (i2s_config->mode & I2S_MODE_RX) {
i2s_ll_set_rx_pdm_en(hal->dev, false);
}
#endif
bool is_pdm = ((hal_cfg->mode & I2S_MODE_PDM) > 0);
#if SOC_I2S_SUPPORTS_PDM_TX
if (i2s_config->mode & I2S_MODE_TX) {
if (hal_cfg->mode & I2S_MODE_TX) {
if (is_pdm) {
i2s_ll_tx_pdm_cfg(hal->dev, hal_cfg->sample_rate);
} else {
i2s_ll_set_tx_pdm_en(hal->dev, false);
}
#endif
} else {
#if SOC_I2S_SUPPORTS_PDM_TX
if (i2s_config->mode & I2S_MODE_TX) {
i2s_ll_tx_pdm_cfg(hal->dev, i2s_config->sample_rate);
}
#endif
}
#endif // SOC_I2S_SUPPORTS_PDM_TX
#if SOC_I2S_SUPPORTS_PDM_RX
if(i2s_config->mode & I2S_MODE_RX) {
if (hal_cfg->mode & I2S_MODE_RX) {
if (is_pdm) {
i2s_ll_rx_pdm_cfg(hal->dev);
} else {
i2s_ll_set_rx_pdm_en(hal->dev, false);
}
#endif
}
#endif
#if SOC_I2S_SUPPORTS_TDM
if (i2s_config->mode & I2S_MODE_TX) {
i2s_ll_set_tx_active_slot_mask(hal->dev, i2s_config->active_slot_mask);
i2s_ll_tx_left_align_enable(hal->dev, i2s_config->left_align_en);
i2s_ll_tx_big_endian_enable(hal->dev, i2s_config->big_edin_en);
i2s_ll_tx_set_bit_order(hal->dev, i2s_config->bit_order_msb_en);
}
if (i2s_config->mode & I2S_MODE_RX) {
i2s_ll_set_rx_active_slot_mask(hal->dev, i2s_config->active_slot_mask);
i2s_ll_rx_left_align_enable(hal->dev, i2s_config->left_align_en);
i2s_ll_rx_big_endian_enable(hal->dev, i2s_config->big_edin_en);
i2s_ll_rx_set_bit_order(hal->dev, i2s_config->bit_order_msb_en);
}
#endif
#endif // SOC_I2S_SUPPORTS_PDM_RX
#endif // SOC_I2S_SUPPORTS_PDM
//Configure I2S slot number,sample bit.
i2s_hal_samples_config(hal, i2s_config->mode, i2s_config->communication_format, i2s_config->slot_bits_cfg, i2s_config->slot_channel_cfg);
i2s_hal_samples_config(hal, hal_cfg);
}

View File

@ -27,55 +27,103 @@
#include "soc/soc_caps.h"
#include "hal/i2s_types.h"
#include "hal/i2s_ll.h"
#if SOC_GDMA_SUPPORTED
#include "hal/gdma_ll.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief I2S channel bits configurations
*
*/
typedef union {
struct {
uint32_t sample_bits : 16; /*!< I2S sample bits in one channel */
uint32_t chan_bits : 16; /*!< I2S total bits in one channel. Should not be smaller than 'sample_bits', default '0' means equal to 'sample_bits' */
};
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
*/
typedef struct {
i2s_mode_t mode; /*!< I2S work mode, using ored mask of `i2s_mode_t`*/
uint32_t sample_rate; /*!< I2S sample rate*/
i2s_channel_t ch; /*!< I2S channels*/
i2s_comm_format_t comm_fmt; /*!< I2S communication format */
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*/
#endif
} i2s_hal_config_t;
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
i2s_dev_t *dev;
#if SOC_GDMA_SUPPORTED
gdma_dev_t *dma;
int dma_ch;
int dma_peri_sel;
#endif
uint32_t version;
} i2s_hal_context_t;
/**
* @brief Reset I2S TX channel
*
* @param hal Context of the HAL layer
*/
void i2s_hal_reset_tx(i2s_hal_context_t *hal);
#define i2s_hal_reset_tx(hal) i2s_ll_reset_tx((hal)->dev)
/**
* @brief Reset I2S TX fifo
*
* @param hal Context of the HAL layer
*/
void i2s_hal_reset_tx_fifo(i2s_hal_context_t *hal);
#define i2s_hal_reset_tx_fifo(hal) i2s_ll_reset_tx_fifo((hal)->dev)
/**
* @brief Reset I2S RX channel
*
* @param hal Context of the HAL layer
*/
void i2s_hal_reset_rx(i2s_hal_context_t *hal);
#define i2s_hal_reset_rx(hal) i2s_ll_reset_rx((hal)->dev)
/**
* @brief Reset I2S RX fifo
*
* @param hal Context of the HAL layer
*/
void i2s_hal_reset_rx_fifo(i2s_hal_context_t *hal);
#define i2s_hal_reset_rx_fifo(hal) i2s_ll_reset_rx_fifo((hal)->dev)
/**
* @brief Init the I2S hal. This function should be called first before other hal layer function is called
@ -97,20 +145,17 @@ void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel);
* @brief Configure communication format
*
* @param hal Context of the HAL layer
* @param i2s_mode I2S mode. Using the ored mask of I2S_MODE_MASTER, I2S_MODE_SLAVE, I2S_MODE_TX, I2S_MODE_RX
* @param communication_format I2S communication format. Can be a value of `i2s_comm_format_t`.
* @param slot_bit_cfg I2S slot bit configuration
* @param slot_ch_cfg I2S slot channel configuration
* @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t`
*/
void i2s_hal_samples_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t communication_format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg);
void i2s_hal_samples_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg);
/**
* @brief Config I2S param
*
* @param hal Context of the HAL layer
* @param i2s_config I2S paramater configuration structer, refer to `i2s_config_param_t`
* @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t`
*/
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_param_t *i2s_config);
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg);
/**
* @brief Enable I2S master full-duplex mode
@ -131,28 +176,28 @@ void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal);
*
* @param hal Context of the HAL layer
*/
void i2s_hal_start_tx(i2s_hal_context_t *hal);
#define i2s_hal_start_tx(hal) i2s_ll_start_tx((hal)->dev)
/**
* @brief Start I2S rx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_start_rx(i2s_hal_context_t *hal);
#define i2s_hal_start_rx(hal) i2s_ll_start_rx((hal)->dev)
/**
* @brief Stop I2S tx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_stop_tx(i2s_hal_context_t *hal);
#define i2s_hal_stop_tx(hal) i2s_ll_stop_tx((hal)->dev)
/**
* @brief Stop I2S rx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_stop_rx(i2s_hal_context_t *hal);
#define i2s_hal_stop_rx(hal) i2s_ll_stop_rx((hal)->dev)
/**
* @brief Set the received data length to trigger `in_suc_eof` interrupt.
@ -160,25 +205,25 @@ void i2s_hal_stop_rx(i2s_hal_context_t *hal);
* @param hal Context of the HAL layer
* @param eof_byte The byte length that trigger in_suc_eof interrupt.
*/
void i2s_hal_set_rx_eof_num(i2s_hal_context_t *hal, uint32_t eof_byte);
#define i2s_hal_set_rx_eof_num(hal, eof_byte) i2s_ll_set_rx_eof_num((hal)->dev, eof_byte)
/**
* @brief Set I2S TX sample bit
*
* @param hal Context of the HAL layer
* @param slot_bit I2S TX slot bit
* @param data_bit The sample data bit lengh.
* @param data_bit The sample data bit length.
*/
void i2s_hal_set_tx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit);
#define i2s_hal_set_tx_sample_bit(hal, slot_bit, data_bit) i2s_ll_set_tx_sample_bit((hal)->dev, slot_bit, data_bit)
/**
* @brief Set I2S RX sample bit
*
* @param hal Context of the HAL layer
* @param slot_bit I2S RX slot bit
* @param data_bit The sample data bit lengh.
* @param data_bit The sample data bit length.
*/
void i2s_hal_set_rx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit);
#define i2s_hal_set_rx_sample_bit(hal, slot_bit, data_bit) i2s_ll_set_rx_sample_bit((hal)->dev, slot_bit, data_bit)
/**
* @brief Configure I2S TX module clock devider
@ -205,17 +250,17 @@ 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_cfg_t`
* @param cfg PCM configure paramater, refer to `i2s_pcm_mode_t`
*/
void i2s_hal_tx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg);
#define i2s_hal_tx_pcm_cfg(hal, cfg) i2s_ll_tx_pcm_cfg((hal)->dev, cfg)
/**
* @brief Configure I2S RX PCM encoder or decoder.
*
* @param hal Context of the HAL layer
* @param cfg PCM configure paramater, refer to `i2s_pcm_cfg_t`
* @param cfg PCM configure paramater, refer to `i2s_pcm_mode_t`
*/
void i2s_hal_rx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg);
#define i2s_hal_rx_pcm_cfg(hal, cfg) i2s_ll_rx_pcm_cfg((hal)->dev, cfg)
#endif
/**
@ -223,7 +268,7 @@ void i2s_hal_rx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg);
*
* @param hal Context of the HAL layer
*/
void i2s_hal_enable_sig_loopback(i2s_hal_context_t *hal);
#define i2s_hal_enable_sig_loopback(hal) i2s_ll_loop_back_ena((hal)->dev, true)
#if SOC_I2S_SUPPORTS_PDM_TX
/**
@ -234,7 +279,7 @@ void i2s_hal_enable_sig_loopback(i2s_hal_context_t *hal);
* @param fp TX PDM fp paramater configuration
* @param fs TX PDM fs paramater configuration
*/
void i2s_hal_set_tx_pdm_fpfs(i2s_hal_context_t *hal, int fp, int fs);
#define i2s_hal_set_tx_pdm_fpfs(hal, fp, fs) i2s_ll_set_tx_pdm_fpfs((hal)->dev, fp, fs)
/**
* @brief Get I2S TX PDM configuration
@ -243,7 +288,7 @@ void i2s_hal_set_tx_pdm_fpfs(i2s_hal_context_t *hal, int fp, int fs);
* @param fp Pointer to accept TX PDM fp paramater configuration
* @param fs Pointer to accept TX PDM fs paramater configuration
*/
void i2s_hal_get_tx_pdm_fpfs(i2s_hal_context_t *hal, int *fp, int *fs);
#define i2s_hal_get_tx_pdm_fpfs(hal, fp, fs) i2s_ll_get_tx_pdm_fpfs((hal)->dev, (uint32_t *)fp, (uint32_t *)fs)
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
@ -254,7 +299,7 @@ void i2s_hal_get_tx_pdm_fpfs(i2s_hal_context_t *hal, int *fp, int *fs);
* @param hal Context of the HAL layer
* @param dsr PDM downsample configuration paramater
*/
void i2s_hal_set_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t dsr);
#define i2s_hal_set_rx_pdm_dsr(hal, dsr) i2s_ll_set_pdm_rx_dsr((hal)->dev, dsr)
/**
* @brief Get RX PDM downsample configuration
@ -262,7 +307,7 @@ void i2s_hal_set_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t dsr);
* @param hal Context of the HAL layer
* @param dsr Pointer to accept PDM downsample configuration
*/
void i2s_hal_get_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t *dsr);
#define i2s_hal_get_rx_pdm_dsr(hal, dsr) i2s_ll_get_pdm_rx_dsr((hal)->dev, dsr)
#endif
#if !SOC_GDMA_SUPPORTED
@ -383,28 +428,6 @@ void i2s_hal_get_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t *dsr);
* @param addr Pointer to accept in suc eof des address
*/
#define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_get_in_eof_des_addr((hal)->dev, addr)
#else
#define i2s_hal_attach_tx_dma(hal) gdma_ll_tx_connect_to_periph((hal)->dma, (hal)->dma_ch, (hal)->dma_peri_sel)
#define i2s_hal_attach_rx_dma(hal) gdma_ll_rx_connect_to_periph((hal)->dma, (hal)->dma_ch, (hal)->dma_peri_sel)
#define i2s_hal_get_intr_status(hal, status) (*status = (gdma_ll_get_interrupt_status((hal)->dma, (hal)->dma_ch)))
#define i2s_hal_clear_intr_status(hal, mask) gdma_ll_clear_interrupt_status((hal)->dma, (hal)->dma_ch, mask)
#define i2s_hal_enable_rx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_IN_DSCR_ERR|I2S_INTR_IN_SUC_EOF, 1)
#define i2s_hal_disable_rx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_IN_DSCR_ERR|I2S_INTR_IN_SUC_EOF, 0)
#define i2s_hal_enable_tx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_OUT_DSCR_ERR|I2S_INTR_OUT_EOF, 1)
#define i2s_hal_disable_tx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_OUT_DSCR_ERR|I2S_INTR_OUT_EOF, 0)
#define i2s_hal_start_tx_link(hal, link_addr) do{\
gdma_ll_tx_set_desc_addr((hal)->dma,(hal)->dma_ch,link_addr);\
gdma_ll_tx_start((hal)->dma,(hal)->dma_ch);}while(0)
#define i2s_hal_start_rx_link(hal, link_addr) do{\
gdma_ll_rx_set_desc_addr((hal)->dma,(hal)->dma_ch,link_addr);\
gdma_ll_rx_start((hal)->dma,(hal)->dma_ch);}while(0)
#define i2s_hal_stop_tx_link(hal) gdma_ll_tx_stop((hal)->dma,(hal)->dma_ch)
#define i2s_hal_stop_rx_link(hal) gdma_ll_rx_stop((hal)->dma, (hal)->dma_ch)
#define i2s_hal_reset_rxdma(hal) gdma_ll_rx_reset_channel((hal)->dma, (hal)->dma_ch)
#define i2s_hal_reset_txdma(hal) gdma_ll_tx_reset_channel((hal)->dma, (hal)->dma_ch)
#define i2s_hal_get_out_eof_des_addr(hal, addr) (*addr = (gdma_ll_tx_get_eof_desc_addr((hal)->dma, (hal)->dma_ch)))
#define i2s_hal_get_in_eof_des_addr(hal, addr) (*addr = (gdma_ll_rx_get_success_eof_desc_addr((hal)->dma, (hal)->dma_ch)))
#endif
#ifdef __cplusplus

View File

@ -24,17 +24,6 @@
extern "C" {
#endif
/**
* @brief I2S port number, the max port number is (I2S_NUM_MAX -1).
*/
typedef enum {
I2S_NUM_0 = 0, /*!< I2S port 0 */
#if SOC_I2S_NUM > 1
I2S_NUM_1 = 1, /*!< I2S port 1 */
#endif
I2S_NUM_MAX, /*!< I2S port max */
} i2s_port_t;
/**
* @brief I2S bit width per sample.
*
@ -55,81 +44,67 @@ typedef enum {
I2S_BITS_PER_SLOT_16BIT = (16), /*!< slot bit 16*/
I2S_BITS_PER_SLOT_24BIT = (24), /*!< slot bit 24*/
I2S_BITS_PER_SLOT_32BIT = (32), /*!< slot bit 32*/
I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU = (0), /*!< slot bit equals to data bit*/
I2S_BITS_PER_SLOT_EQU_SAMPLE = (0), /*!< slot bit equals to data bit*/
} i2s_bits_per_slot_t;
#define SLOT_BIT_SHIFT (16) //slot bit shift
#define SLOT_CH_SHIFT (16) //slot channel shift
/**
* @brief I2S slot bit configuration paramater. The low 16bit is the audio_data_bit_width and the high 16bit is the slot_bit_width.
* e.g.: If set to (I2S_BITS_PER_SLOT_24BIT << SLOT_BIT_SHIFT) | I2S_BITS_PER_SAMPLE_16BIT, the audio data bit is 16bit and the slot bit is 24bit.
*
*
* @note: If the slot_bit_width is set to `I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU`, then the slot_bit_width equals to audio_data_bit_width.
*
*/
typedef uint32_t i2s_slot_bits_cfg_t; /*!< slot bit configuration*/
/**
* @brief I2S slot channel configuration paramater. The low 16bit is the active_slot_number and the high 16bit is the total_slot_num.
* The audio data only launch in active slot, otherwise, launch 0 or single data in inactive slot.
* e.g.: If set to (4 << SLOT_CH_SHIFT) | 2, the active_slot_number is 2 and the total_slot_num 4.
*
* @note: If the total_slot_num is set to 0, then the total_slot_num equals to active_slot_number.
*
*/
typedef uint32_t i2s_slot_channel_cfg_t; /*!< slot channel configuration*/
/**
* @brief I2S channel.
*
*/
typedef enum {
I2S_CHANNEL_MONO = 1, /*!< I2S 1 channel (mono)*/
I2S_CHANNEL_STEREO = 2 /*!< I2S 2 channel (stereo)*/
// I2S_CHANNEL_MONO and I2S_CHANNEL_STEREO values are changed to be compatible with TDM mode
// The lower 16 bits is for enabling specific channels
// The highest bit in I2S_CHANNEL_MONO is for differentiating I2S_CHANNEL_MONO and I2S_CHANNEL_STEREO because they both use two channels
// Two channels will transmit same data in I2S_CHANNEL_MONO mode, and different data in I2S_CHANNEL_STEREO mode
I2S_CHANNEL_MONO = (0x01 << 31) | 0x03, /*!< I2S channel (mono), two channel enabled */
I2S_CHANNEL_STEREO = 0x03, /*!< I2S channel (stereo), two channel enabled */
#if SOC_I2S_SUPPORTS_TDM
// Bit map of active chan.
// There are 16 channels in TDM mode.
// For TX module, only the active channel send the audio data, the inactive channel send a constant(configurable) or will be skiped if 'skip_msk_en' in 'i2s_hal_tdm_flags_t' is set.
// For RX module, only receive the audio data in active channels, the data in inactive channels will be ignored.
// the bit map of active channel can not exceed (0x1<<total_chan_num).
// e.g: active_chan_mask = (I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH3), here the active_chan_number is 2 and total_chan_num is not supposed to be smaller than 4.
I2S_TDM_ACTIVE_CH0 = (0x1 << 0), /*!< I2S channel 0 enabled */
I2S_TDM_ACTIVE_CH1 = (0x1 << 1), /*!< I2S channel 1 enabled */
I2S_TDM_ACTIVE_CH2 = (0x1 << 2), /*!< I2S channel 2 enabled */
I2S_TDM_ACTIVE_CH3 = (0x1 << 3), /*!< I2S channel 3 enabled */
I2S_TDM_ACTIVE_CH4 = (0x1 << 4), /*!< I2S channel 4 enabled */
I2S_TDM_ACTIVE_CH5 = (0x1 << 5), /*!< I2S channel 5 enabled */
I2S_TDM_ACTIVE_CH6 = (0x1 << 6), /*!< I2S channel 6 enabled */
I2S_TDM_ACTIVE_CH7 = (0x1 << 7), /*!< I2S channel 7 enabled */
I2S_TDM_ACTIVE_CH8 = (0x1 << 8), /*!< I2S channel 8 enabled */
I2S_TDM_ACTIVE_CH9 = (0x1 << 9), /*!< I2S channel 9 enabled */
I2S_TDM_ACTIVE_CH10 = (0x1 << 10), /*!< I2S channel 10 enabled */
I2S_TDM_ACTIVE_CH11 = (0x1 << 11), /*!< I2S channel 11 enabled */
I2S_TDM_ACTIVE_CH12 = (0x1 << 12), /*!< I2S channel 12 enabled */
I2S_TDM_ACTIVE_CH13 = (0x1 << 13), /*!< I2S channel 13 enabled */
I2S_TDM_ACTIVE_CH14 = (0x1 << 14), /*!< I2S channel 14 enabled */
I2S_TDM_ACTIVE_CH15 = (0x1 << 15), /*!< I2S channel 15 enabled */
#endif
} i2s_channel_t;
#if SOC_I2S_SUPPORTS_TDM
/**
* @brief Bit map of active slot.
* For TX module, only the active slot send the audio data, the inactive slot send a constant(configurable).
* For RX module, only receive the audio data in active slot, the data in inactive slot will be ignored.
*
* @note the bit map of active slot can not exceed (0x1<<total_slot_num).
* e.g: active_slot_mask = (I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1), total_slot_num = 4, active_slot_number = 2.
*/
typedef enum {
I2S_TDM_ACTIVE_CH0 = (0x1 << 0),
I2S_TDM_ACTIVE_CH1 = (0x1 << 1),
I2S_TDM_ACTIVE_CH2 = (0x1 << 2),
I2S_TDM_ACTIVE_CH3 = (0x1 << 3),
I2S_TDM_ACTIVE_CH4 = (0x1 << 4),
I2S_TDM_ACTIVE_CH5 = (0x1 << 5),
I2S_TDM_ACTIVE_CH6 = (0x1 << 6),
I2S_TDM_ACTIVE_CH7 = (0x1 << 7),
I2S_TDM_ACTIVE_CH8 = (0x1 << 8),
I2S_TDM_ACTIVE_CH9 = (0x1 << 9),
I2S_TDM_ACTIVE_CH10 = (0x1 << 10),
I2S_TDM_ACTIVE_CH11 = (0x1 << 11),
I2S_TDM_ACTIVE_CH12 = (0x1 << 12),
I2S_TDM_ACTIVE_CH13 = (0x1 << 13),
I2S_TDM_ACTIVE_CH14 = (0x1 << 14),
I2S_TDM_ACTIVE_CH15 = (0x1 << 15),
} i2s_tdm_active_slot_t;
#endif
/**
* @brief I2S communication standard format
*
*/
typedef enum {
I2S_COMM_FORMAT_STAND_I2S = 0X01, /*!< I2S communication I2S Philips standard, data launch at second BCK*/
I2S_COMM_FORMAT_STAND_MSB = 0X02, /*!< I2S communication MSB alignment standard, data launch at first BCK*/
I2S_COMM_FORMAT_STAND_I2S = 0X01, /*!< I2S communication I2S Philips standard, data launch at second BCK*/
I2S_COMM_FORMAT_STAND_MSB = 0X02, /*!< I2S communication MSB alignment standard, data launch at first BCK*/
I2S_COMM_FORMAT_STAND_PCM_SHORT = 0x04, /*!< PCM Short standard, also known as DSP mode. The period of synchronization signal (WS) is 1 bck cycle.*/
I2S_COMM_FORMAT_STAND_PCM_LONG = 0x0C, /*!< PCM Long standard. The period of synchronization signal (WS) is channel_bit*bck cycles.*/
I2S_COMM_FORMAT_STAND_MAX, /*!< standard max*/
//old definition will be removed in the future.
I2S_COMM_FORMAT_I2S __attribute__((deprecated)) = 0x01, /*!< I2S communication format I2S, correspond to `I2S_COMM_FORMAT_STAND_I2S`*/
I2S_COMM_FORMAT_I2S_MSB __attribute__((deprecated)) = 0x01, /*!< I2S format MSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_MSB) correspond to `I2S_COMM_FORMAT_STAND_I2S`*/
I2S_COMM_FORMAT_I2S_LSB __attribute__((deprecated)) = 0x02, /*!< I2S format LSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_LSB) correspond to `I2S_COMM_FORMAT_STAND_MSB`*/
I2S_COMM_FORMAT_PCM __attribute__((deprecated)) = 0x04, /*!< I2S communication format PCM, correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/
I2S_COMM_FORMAT_PCM_SHORT __attribute__((deprecated)) = 0x04, /*!< PCM Short, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_SHORT) correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/
I2S_COMM_FORMAT_PCM_LONG __attribute__((deprecated)) = 0x08, /*!< PCM Long, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_LONG) correspond to `I2S_COMM_FORMAT_STAND_PCM_LONG`*/
} i2s_comm_format_t;
/**
@ -141,24 +116,27 @@ typedef enum {
I2S_CHANNEL_FMT_ALL_LEFT,
I2S_CHANNEL_FMT_ONLY_RIGHT,
I2S_CHANNEL_FMT_ONLY_LEFT,
} i2s_channel_fmt_t;
#if SOC_I2S_SUPPORTS_TDM
I2S_CHANNEL_FMT_TDM, // Up to 16 channels
#endif
} i2s_channel_fmt_t;
/**
* @brief I2S Mode
*/
typedef enum {
I2S_MODE_MASTER = 1, /*!< Master mode*/
I2S_MODE_SLAVE = 2, /*!< Slave mode*/
I2S_MODE_TX = 4, /*!< TX mode*/
I2S_MODE_RX = 8, /*!< RX mode*/
I2S_MODE_MASTER = (0x1 << 0), /*!< Master mode*/
I2S_MODE_SLAVE = (0x1 << 1), /*!< Slave mode*/
I2S_MODE_TX = (0x1 << 2), /*!< TX mode*/
I2S_MODE_RX = (0x1 << 3), /*!< RX mode*/
#if SOC_I2S_SUPPORTS_ADC_DAC
//built-in DAC functions are only supported on I2S0 for ESP32 chip.
I2S_MODE_DAC_BUILT_IN = 16, /*!< Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB*/
I2S_MODE_ADC_BUILT_IN = 32, /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/
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.
I2S_MODE_PDM = 64, /*!< I2S PDM mode*/
// PDM functions are only supported on I2S0 (all chips).
I2S_MODE_PDM = (0x1 << 6), /*!< I2S PDM mode*/
#endif
} i2s_mode_t;
@ -170,27 +148,6 @@ typedef enum {
I2S_CLK_APLL, /*!< Clock from APLL*/
} i2s_clock_src_t;
/**
* @brief I2S bit width per sample.
*
* @note: The chip of ESP32 and ESP32S2 only needs to initialize the fields out side the `SOC_I2S_SUPPORTS_TDM` macro.
* The chip of ESP32-S3, ESP32-C3 and the later chip, all this fields should be initialized.
*/
typedef struct {
i2s_mode_t mode; /*!< I2S work mode, using ored mask of `i2s_mode_t`*/
uint32_t sample_rate; /*!< I2S sample rate*/
i2s_slot_bits_cfg_t slot_bits_cfg; /*!< slot bit configuration, low 16bit is the audio data bit; high 16bit is the slot bit, if set to 0, total slot bit equals to audio data bit*/
i2s_channel_fmt_t channel_format; /*!< I2S channel format*/
i2s_comm_format_t communication_format; /*!< I2S communication format */
#if SOC_I2S_SUPPORTS_TDM
i2s_slot_channel_cfg_t slot_channel_cfg; /*!< slot number configuration, low 16bit is the valid slot number; high 16bit is the total slot number, if set to 0, total slot number equals to valid slot number*/
uint32_t active_slot_mask; /*!< active slot bit mask, using the ored mask of `i2s_tdm_active_slot_t`*/
bool left_align_en; /*!< Set to enable left aligment*/
bool big_edin_en; /*!< Set to enable big edin*/
bool bit_order_msb_en; /*!< Set to enable msb order*/
#endif
} i2s_config_param_t;
#if SOC_I2S_SUPPORTS_ADC_DAC
/**
* @brief I2S DAC mode for i2s_set_dac_mode.
@ -206,17 +163,6 @@ typedef enum {
} i2s_dac_mode_t;
#endif //SOC_I2S_SUPPORTS_ADC_DAC
/**
* @brief I2S pin number for i2s_set_pin
*
*/
typedef struct {
int bck_io_num; /*!< BCK in out pin*/
int ws_io_num; /*!< WS in out pin*/
int data_out_num; /*!< DATA out pin*/
int data_in_num; /*!< DATA in pin*/
} i2s_pin_config_t;
#if SOC_I2S_SUPPORTS_PCM
/**
* @brief A/U-law decompress or compress configuration.
@ -228,7 +174,7 @@ typedef enum {
I2S_PCM_U_DECOMPRESS, /*!< U-law decompress*/
I2S_PCM_U_COMPRESS, /*!< U-law compress*/
I2S_PCM_DISABLE, /*!< Disable A/U law decopress or compress*/
} i2s_pcm_cfg_t;
} i2s_pcm_mode_t;
#endif
#if SOC_I2S_SUPPORTS_PDM_RX

View File

@ -26,7 +26,6 @@ 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 = ETS_DMA_CH0_INTR_SOURCE,
.module = PERIPH_I2S1_MODULE,
}
};

View File

@ -109,7 +109,11 @@
/*-------------------------- I2S CAPS ----------------------------------------*/
#define SOC_I2S_NUM (1)
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_RX (0)
#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX)
#define SOC_I2S_SUPPORTS_TDM (1)
#define SOC_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

@ -26,7 +26,6 @@ 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 = ETS_DMA_CH0_INTR_SOURCE,
.module = PERIPH_I2S0_MODULE,
},
{
@ -36,7 +35,6 @@ 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 = ETS_DMA_CH3_INTR_SOURCE,
.module = PERIPH_I2S1_MODULE,
}
};

View File

@ -318,8 +318,8 @@ typedef volatile struct {
uint32_t reserved12 : 20; /* Reserved*/
};
uint32_t val;
} rxeof_num;
uint32_t conf_sigle_data;
} rx_eof_num;
uint32_t conf_signal_data; /*I2S signal data register*/
union {
struct {
uint32_t tx_idle : 1; /*1: i2s_tx is idle state. 0: i2s_tx is working.*/

View File

@ -65,7 +65,7 @@
/*-------------------------- I2S CAPS ----------------------------------------*/
#define SOC_I2S_NUM (2)
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (0)
#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)

View File

@ -75,13 +75,11 @@ Configuration example:
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,
.sample_rate = 44100,
.slot_bits_cfg = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
},
.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,

View File

@ -53,25 +53,15 @@ void app_main(void)
ESP_ERROR_CHECK(err);
i2s_config_t i2s_config = {
.param_cfg = {
#ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
#else
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX
#endif
.sample_rate = 44100,
.slot_bits_cfg = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
#if SOC_I2S_SUPPORTS_TDM
.slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2,
.active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
.left_align_en = false,
.big_edin_en = false,
.bit_order_msb_en = false,
#endif
},
.sample_rate = 44100,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
.dma_buf_count = 6,
.dma_buf_len = 60,
.intr_alloc_flags = 0, //Default interrupt priority

View File

@ -684,24 +684,15 @@ void app_main(void)
ESP_ERROR_CHECK(err);
i2s_config_t i2s_config = {
.param_cfg = {
#ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
#else
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX
#endif
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
.sample_rate = 44100,
.slot_bits_cfg = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
#if SOC_I2S_SUPPORTS_TDM
.slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2,
.active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
.left_align_en = false,
.big_edin_en = false,
.bit_order_msb_en = false,
#endif
},
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
.sample_rate = 44100,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.dma_buf_count = 6,
.dma_buf_len = 60,
.intr_alloc_flags = 0, //Default interrupt priority

View File

@ -63,13 +63,11 @@ void example_i2s_init(void)
{
int i2s_num = EXAMPLE_I2S_NUM;
i2s_config_t i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN,
.sample_rate = EXAMPLE_I2S_SAMPLE_RATE,
.slot_bits_cfg = EXAMPLE_I2S_SAMPLE_BITS,
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
.channel_format = EXAMPLE_I2S_FORMAT,
},
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN,
.sample_rate = EXAMPLE_I2S_SAMPLE_RATE,
.bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS,
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
.channel_format = EXAMPLE_I2S_FORMAT,
.intr_alloc_flags = 0,
.dma_buf_count = 2,
.dma_buf_len = 1024,

View File

@ -15,6 +15,7 @@
#include "driver/i2s.h"
#include "driver/gpio.h"
#include "esp_system.h"
#include "esp_log.h"
#include <math.h>
@ -22,13 +23,15 @@
#define I2S_NUM (0)
#define WAVE_FREQ_HZ (100)
#define PI (3.14159265)
#define I2S_BCK_IO (GPIO_NUM_13)
#define I2S_WS_IO (GPIO_NUM_15)
#define I2S_DO_IO (GPIO_NUM_21)
#define I2S_BCK_IO (GPIO_NUM_4)
#define I2S_WS_IO (GPIO_NUM_5)
#define I2S_DO_IO (GPIO_NUM_18)
#define I2S_DI_IO (-1)
#define SAMPLE_PER_CYCLE (SAMPLE_RATE/WAVE_FREQ_HZ)
static const char* TAG = "i2s_example";
static void setup_triangle_sine_waves(int bits)
{
int *samples_data = malloc(((bits+8)/16)*SAMPLE_PER_CYCLE*4);
@ -64,7 +67,7 @@ static void setup_triangle_sine_waves(int bits)
}
}
ESP_LOGI(TAG, "set clock");
i2s_set_clk(I2S_NUM, SAMPLE_RATE, bits, 2);
//Using push
// for(i = 0; i < SAMPLE_PER_CYCLE; i++) {
@ -74,6 +77,7 @@ static void setup_triangle_sine_waves(int bits)
// i2s_push_sample(0, &samples_data[i*2], 100);
// }
// or write
ESP_LOGI(TAG, "write data");
i2s_write(I2S_NUM, samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100);
free(samples_data);
@ -87,20 +91,11 @@ void app_main(void)
//if 2-channels, 16-bit each channel, total buffer is 360*4 = 1440 bytes
//if 2-channels, 24/32-bit each channel, total buffer is 360*8 = 2880 bytes
i2s_config_t i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.slot_bits_cfg = (I2S_BITS_PER_SLOT_16BIT << SLOT_BIT_SHIFT) | I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
#if SOC_I2S_SUPPORTS_TDM
.slot_channel_cfg = (2 << SLOT_CH_SHIFT) | 2,
.active_slot_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
.left_align_en = false,
.big_edin_en = false,
.bit_order_msb_en = false,
#endif
},
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
.dma_buf_count = 6,
.dma_buf_len = 60,
.use_apll = false,