Merge branch 'fix/i2s_enable_test_p4_c5_multi_v5.3' into 'release/v5.3'

test(driver_i2s): p4 and c5 enable multi dut test (v5.3)

See merge request espressif/esp-idf!34238
This commit is contained in:
morris
2024-12-06 17:02:57 +08:00
4 changed files with 89 additions and 62 deletions

View File

@ -11,9 +11,5 @@ components/esp_driver_i2s/test_apps/i2s_multi_dev:
disable:
- if: SOC_I2S_SUPPORTED != 1
- if: SOC_I2S_HW_VERSION_2 != 1
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: lack of runners
depends_components:
- esp_driver_i2s

View File

@ -23,8 +23,8 @@ static const char *TAG = "i2s_multi_dev_test";
#define TEST_I2S_FRAME_SIZE (128) // Frame numbers in every writing / reading
#define TEST_I2S_ARRAY_LENGTH (1024) // The loop data length for verification
#define TEST_I2S_MAX_DATA (128) // The maximum data value in the data buffer
#define TEST_I2S_MAX_FAIL_CNT (3) // Max broken packet count
#define TEST_I2S_MAX_DATA (64) // The maximum data value in the data buffer
#define TEST_I2S_MAX_FAIL_CNT (10) // Max broken packet count
#define TEST_I2S_FRAME_TIMEOUT_SEC (10.0f) // Timeout seconds of waiting for a correct frame
#define TEST_I2S_NUM (I2S_NUM_0) // ESP32-C3 has only I2S0
@ -39,6 +39,12 @@ static const char *TAG = "i2s_multi_dev_test";
#define TEST_I2S_DI_IO (GPIO_NUM_7) // DI and DO gpio will be reversed on slave runner
#endif // CONFIG_IDF_TARGET_ESP32H2
#if I2S_LL_DEFAULT_CLK_FREQ < 160000000
#define TEST_SAMPLE_RATE (16000) // I2S source clock is relatively low, test case is not stable when sample rate is 48KHz high
#else
#define TEST_SAMPLE_RATE (48000)
#endif
typedef struct {
uint32_t *buffer;
uint32_t buffer_size;
@ -71,27 +77,25 @@ static void test_i2s_tdm_master(uint32_t sample_rate, i2s_data_bit_width_t bit_w
i2s_tdm_config_t i2s_tdm_config = {
.clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(sample_rate),
.slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(bit_width, I2S_SLOT_MODE_STEREO, slot_mask),
.gpio_cfg = TEST_I2S_DEFAULT_GPIO(GPIO_NUM_NC, true),
.gpio_cfg = TEST_I2S_DEFAULT_GPIO(I2S_GPIO_UNUSED, true),
};
i2s_tdm_config.clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_384;
i2s_tdm_config.clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_512;
TEST_ESP_OK(i2s_channel_init_tdm_mode(i2s_tdm_tx_handle, &i2s_tdm_config));
TEST_ESP_OK(i2s_channel_init_tdm_mode(i2s_tdm_rx_handle, &i2s_tdm_config));
uint32_t channel_count = 32 - __builtin_clz(slot_mask);
size_t buf_size = channel_count * TEST_I2S_FRAME_SIZE * (bit_width / 8);
size_t buf_size = channel_count * TEST_I2S_FRAME_SIZE * (bit_width / 8) * 2;
/* Allocate I2S rx buffer */
ESP_LOGI(TAG, "Allocating I2S TDM master rx buffer, size=%u", buf_size);
uint32_t *rx_buffer = malloc(buf_size);
uint8_t *rx_buffer = calloc(1, buf_size);
TEST_ASSERT(rx_buffer);
/* Allocate I2S tx buffer */
ESP_LOGI(TAG, "Allocating I2S TDM master tx buffer, size=%u", buf_size);
uint32_t *tx_buffer = malloc(buf_size);
uint8_t *tx_buffer = calloc(1, buf_size);
TEST_ASSERT(tx_buffer);
/* Fill in the tx buffer */
for (uint32_t i = 0, data_cnt = 0; i < buf_size / sizeof(uint32_t); i ++) {
tx_buffer[i] = data_cnt;
data_cnt++;
data_cnt %= TEST_I2S_MAX_DATA;
for (uint32_t i = 0; i < buf_size; i ++) {
tx_buffer[i] = i % TEST_I2S_MAX_DATA;
}
size_t w_bytes = buf_size;
while (w_bytes != 0) {
@ -107,22 +111,39 @@ static void test_i2s_tdm_master(uint32_t sample_rate, i2s_data_bit_width_t bit_w
/* Slave is ready, start the writing task */
ESP_LOGI(TAG, "I2S TDM master receive & send start");
esp_err_t read_ret = ESP_OK;
uint32_t count = 1;
uint8_t count = 1;
uint8_t fail_cnt = 0;
size_t bytes_read = 0;
unity_wait_for_signal("Slave Data Ready");
// Start to read the data from slave, and retry several times if not success
for (fail_cnt = 0; fail_cnt < TEST_I2S_MAX_FAIL_CNT && count < TEST_I2S_MAX_DATA; fail_cnt++) {
if (i2s_channel_read(i2s_tdm_rx_handle, rx_buffer, buf_size, &bytes_read, 1000) != ESP_OK) {
if (fail_cnt > 0) {
// Delay a while in case the slave has not finished to prepare the data
vTaskDelay(pdMS_TO_TICKS(50));
}
// Try to read the data from slave, continue if failed
read_ret = i2s_channel_read(i2s_tdm_rx_handle, rx_buffer, buf_size, &bytes_read, 1000);
if (read_ret != ESP_OK) {
ESP_LOGE(TAG, "master read failed: %s", esp_err_to_name(read_ret));
continue;
}
for (int i = 0; i < buf_size && count < TEST_I2S_MAX_DATA; i++) {
// When success to read, check the buffer content whether match what master sent
for (int i = 0; i < buf_size; i++) {
printf("%"PRIu8" ", rx_buffer[i]);
if (rx_buffer[i] == count) {
count++;
// If the piece of data match, means the communication between slave and master success, break the loop
if (++count >= TEST_I2S_MAX_DATA) {
break;
}
} else if (count != 1) {
ESP_LOGE(TAG, "Failed at index: %d real: %" PRIu32 " expect: %" PRIu32, i, rx_buffer[i], count);
// If the data not fully matched, reset the counter and try again
ESP_LOGE(TAG, "Failed at index: %d real: %" PRIu8 " expect: %" PRIu8, i, rx_buffer[i], count);
count = 1;
}
}
printf("\n");
}
unity_send_signal("Master Finished");
ESP_LOGI(TAG, "I2S TDM master stop");
TEST_ESP_OK(i2s_channel_disable(i2s_tdm_tx_handle));
@ -132,7 +153,7 @@ static void test_i2s_tdm_master(uint32_t sample_rate, i2s_data_bit_width_t bit_w
TEST_ESP_OK(i2s_del_channel(i2s_tdm_rx_handle));
TEST_ESP_OK(i2s_del_channel(i2s_tdm_tx_handle));
ESP_LOGI(TAG, "I2S TDM master resources freed");
TEST_ASSERT_TRUE_MESSAGE(read_ret == ESP_OK, "Master read timeout ");
TEST_ASSERT_TRUE_MESSAGE(read_ret == ESP_OK, "Master read failed ");
TEST_ASSERT_TRUE_MESSAGE(fail_cnt < TEST_I2S_MAX_FAIL_CNT, "Exceed retry times ");
TEST_ASSERT_EQUAL_UINT32(TEST_I2S_MAX_DATA, count);
}
@ -143,10 +164,11 @@ static void test_i2s_tdm_slave(uint32_t sample_rate, i2s_data_bit_width_t bit_wi
i2s_chan_handle_t i2s_tdm_rx_handle = NULL;
/* Create I2S tx and rx channels */
uint32_t desc_num = 4;
i2s_chan_config_t i2s_channel_config = {
.id = TEST_I2S_NUM,
.role = I2S_ROLE_SLAVE,
.dma_desc_num = 4,
.dma_desc_num = desc_num,
.dma_frame_num = TEST_I2S_FRAME_SIZE,
.auto_clear = false
};
@ -156,55 +178,78 @@ static void test_i2s_tdm_slave(uint32_t sample_rate, i2s_data_bit_width_t bit_wi
i2s_tdm_config_t i2s_tdm_config = {
.clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(sample_rate),
.slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(bit_width, I2S_SLOT_MODE_STEREO, slot_mask),
.gpio_cfg = TEST_I2S_DEFAULT_GPIO(GPIO_NUM_NC, false),
.gpio_cfg = TEST_I2S_DEFAULT_GPIO(I2S_GPIO_UNUSED, false),
};
if (sample_rate >= 96000) {
i2s_tdm_config.clk_cfg.bclk_div = 12;
}
#if SOC_I2S_SUPPORTS_APLL
i2s_tdm_config.clk_cfg.clk_src = I2S_CLK_SRC_APLL;
i2s_tdm_config.clk_cfg.bclk_div = 10;
#else
i2s_tdm_config.clk_cfg.bclk_div = 12;
#endif
TEST_ESP_OK(i2s_channel_init_tdm_mode(i2s_tdm_tx_handle, &i2s_tdm_config));
TEST_ESP_OK(i2s_channel_init_tdm_mode(i2s_tdm_rx_handle, &i2s_tdm_config));
/* Allocate I2S rx buffer */
uint32_t channel_count = 32 - __builtin_clz(slot_mask);
uint32_t buffer_size = TEST_I2S_FRAME_SIZE * channel_count * (bit_width / 8);
uint32_t buffer_size = TEST_I2S_FRAME_SIZE * channel_count * (bit_width / 8) * 2;
ESP_LOGI(TAG, "Allocating I2S TDM slave buffer, size=%"PRIu32, buffer_size);
uint32_t *echo_buffer = malloc(buffer_size);
uint8_t *echo_buffer = calloc(1, buffer_size);
TEST_ASSERT(echo_buffer);
unity_send_signal("Slave Ready");
unity_wait_for_signal("Master Ready");
TEST_ESP_OK(i2s_channel_enable(i2s_tdm_rx_handle));
TEST_ESP_OK(i2s_channel_enable(i2s_tdm_tx_handle));
ESP_LOGI(TAG, "I2S TDM slave receive & send start");
size_t bytes_read = 0, bytes_written = 0;
/* Loop until reading or writing failed, which indicates the master has finished and deleted the I2S peripheral */
size_t bytes_read = 0;
int read_fail_cnt = 0;
bool success_flag = true;
// Continuously read data from master until the first piece of valid data is received
while (true) {
if (i2s_channel_read(i2s_tdm_rx_handle, echo_buffer, buffer_size, &bytes_read, 500) != ESP_OK) {
break;
if (i2s_channel_read(i2s_tdm_rx_handle, echo_buffer, buffer_size, &bytes_read, 1000) != ESP_OK) {
vTaskDelay(pdMS_TO_TICKS(50));
if (read_fail_cnt++ >= TEST_I2S_MAX_FAIL_CNT) {
ESP_LOGE(TAG, "Slave failed to read after %d retries", (int)TEST_I2S_MAX_FAIL_CNT);
success_flag = false;
goto exit;
}
}
if (i2s_channel_write(i2s_tdm_tx_handle, echo_buffer, buffer_size, &bytes_written, 500) != ESP_OK) {
// When receive valid data, then break the loop and start writing
if (echo_buffer[0] || echo_buffer[1]) {
break;
}
}
size_t bytes_written = buffer_size;
/* Load the data to write */
while (bytes_written) {
esp_err_t ret = i2s_channel_preload_data(i2s_tdm_tx_handle, echo_buffer, buffer_size, &bytes_written);
printf("ret %x, bytes_written %d\n", ret, (int)bytes_written);
}
TEST_ESP_OK(i2s_channel_enable(i2s_tdm_tx_handle));
vTaskDelay(pdMS_TO_TICKS(100));
unity_send_signal("Slave Data Ready");
unity_wait_for_signal("Master Finished");
TEST_ESP_OK(i2s_channel_disable(i2s_tdm_tx_handle));
exit:
ESP_LOGI(TAG, "I2S TDM slave receive stop");
TEST_ESP_OK(i2s_channel_disable(i2s_tdm_rx_handle));
TEST_ESP_OK(i2s_channel_disable(i2s_tdm_tx_handle));
free(echo_buffer);
TEST_ESP_OK(i2s_del_channel(i2s_tdm_rx_handle));
TEST_ESP_OK(i2s_del_channel(i2s_tdm_tx_handle));
ESP_LOGI(TAG, "I2S TDM slave resources freed");
TEST_ASSERT_TRUE_MESSAGE(success_flag, "Slave failed to read");
}
static void test_i2s_tdm_master_48k_32bits_4slots(void)
{
test_i2s_tdm_master(48000, I2S_DATA_BIT_WIDTH_32BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
test_i2s_tdm_master(TEST_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_32BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
}
static void test_i2s_tdm_slave_48k_32bits_4slots(void)
{
test_i2s_tdm_slave(48000, I2S_DATA_BIT_WIDTH_32BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
test_i2s_tdm_slave(TEST_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_32BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
}
TEST_CASE_MULTIPLE_DEVICES("I2S_TDM_full_duplex_test_in_48k_32bits_4slots", "[I2S_TDM]",
@ -212,12 +257,12 @@ TEST_CASE_MULTIPLE_DEVICES("I2S_TDM_full_duplex_test_in_48k_32bits_4slots", "[I2
static void test_i2s_tdm_master_48k_16bits_4slots(void)
{
test_i2s_tdm_master(48000, I2S_DATA_BIT_WIDTH_16BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
test_i2s_tdm_master(TEST_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_16BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
}
static void test_i2s_tdm_slave_48k_16bits_4slots(void)
{
test_i2s_tdm_slave(48000, I2S_DATA_BIT_WIDTH_16BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
test_i2s_tdm_slave(TEST_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_16BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
}
TEST_CASE_MULTIPLE_DEVICES("I2S_TDM_full_duplex_test_in_48k_16bits_4slots", "[I2S_TDM]",
@ -225,20 +270,21 @@ TEST_CASE_MULTIPLE_DEVICES("I2S_TDM_full_duplex_test_in_48k_16bits_4slots", "[I2
static void test_i2s_tdm_master_48k_8bits_4slots(void)
{
test_i2s_tdm_master(48000, I2S_DATA_BIT_WIDTH_8BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
test_i2s_tdm_master(TEST_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_8BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
}
static void test_i2s_tdm_slave_48k_8bits_4slots(void)
{
test_i2s_tdm_slave(48000, I2S_DATA_BIT_WIDTH_8BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
test_i2s_tdm_slave(TEST_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_8BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
}
TEST_CASE_MULTIPLE_DEVICES("I2S_TDM_full_duplex_test_in_48k_8bits_4slots", "[I2S_TDM]",
test_i2s_tdm_master_48k_8bits_4slots, test_i2s_tdm_slave_48k_8bits_4slots);
/* The I2S source clock can only reach 96Mhz on ESP32H2,
and the max clock source APLL on P4 is 125M,
which can't satisfy the following configurations in slave mode */
#if !CONFIG_IDF_TARGET_ESP32H2
#if !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32P4
static void test_i2s_tdm_master_48k_16bits_8slots(void)
{
test_i2s_tdm_master(48000, I2S_DATA_BIT_WIDTH_16BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3 |
@ -266,7 +312,7 @@ static void test_i2s_tdm_slave_96k_16bits_4slots(void)
TEST_CASE_MULTIPLE_DEVICES("I2S_TDM_full_duplex_test_in_96k_16bits_4slots", "[I2S_TDM]",
test_i2s_tdm_master_96k_16bits_4slots, test_i2s_tdm_slave_96k_16bits_4slots);
#endif // !CONFIG_IDF_TARGET_ESP32H2
#endif // !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32P4
static void test_i2s_external_clk_src(bool is_master, bool is_external)
{

View File

@ -7,6 +7,7 @@ import pytest
@pytest.mark.esp32c3
@pytest.mark.esp32c6
@pytest.mark.esp32h2
@pytest.mark.esp32p4
@pytest.mark.generic_multi_device
@pytest.mark.parametrize('count', [
2,

View File

@ -22,23 +22,7 @@ extern "C" {
#define SLAVE_WS_IO 22
#define DATA_IN_IO 19
#define DATA_OUT_IO 18
#elif CONFIG_IDF_TARGET_ESP32S2
#define MASTER_MCK_IO 0
#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
#elif CONFIG_IDF_TARGET_ESP32C3
#define MASTER_MCK_IO 0
#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
#elif CONFIG_IDF_TARGET_ESP32S3
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3
#define MASTER_MCK_IO 0
#define MASTER_BCK_IO 4
#define MASTER_WS_IO 5
@ -50,8 +34,8 @@ extern "C" {
#define MASTER_MCK_IO 51
#define MASTER_BCK_IO 45
#define MASTER_WS_IO 46
#define SLAVE_BCK_IO 22
#define SLAVE_WS_IO 23
#define SLAVE_BCK_IO 49
#define SLAVE_WS_IO 50
#define DATA_IN_IO 47
#define DATA_OUT_IO 48
#else