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