From cd5f2c3d76f755f7a68b1b4a32ef2eb60484b240 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 29 Nov 2022 11:43:37 +0800 Subject: [PATCH 1/3] i2s_test: add unity signal for synchronization --- .../i2s_test_apps/i2s_tdm/CMakeLists.txt | 4 + .../i2s_tdm/main/test_app_main.c | 2 +- .../i2s_tdm/main/test_i2s_tdm_full_duplex.c | 137 +++++++++--------- .../i2s_tdm/pytest_i2s_tdm_full_duplex.py | 2 +- .../i2s_test_apps/i2s_tdm/sdkconfig.defaults | 1 + components/hal/esp32c3/include/hal/i2s_ll.h | 10 +- 6 files changed, 82 insertions(+), 74 deletions(-) diff --git a/components/driver/test_apps/i2s_test_apps/i2s_tdm/CMakeLists.txt b/components/driver/test_apps/i2s_test_apps/i2s_tdm/CMakeLists.txt index 4f993f8d1f..c66f4b2e96 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s_tdm/CMakeLists.txt +++ b/components/driver/test_apps/i2s_test_apps/i2s_tdm/CMakeLists.txt @@ -2,5 +2,9 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) +set(EXTRA_COMPONENT_DIRS + "$ENV{IDF_PATH}/tools/unit-test-app/components" +) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(i2s_tdm_full_duplex_test) diff --git a/components/driver/test_apps/i2s_test_apps/i2s_tdm/main/test_app_main.c b/components/driver/test_apps/i2s_test_apps/i2s_tdm/main/test_app_main.c index ff68044bfe..fefaf1c6a3 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s_tdm/main/test_app_main.c +++ b/components/driver/test_apps/i2s_test_apps/i2s_tdm/main/test_app_main.c @@ -9,7 +9,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#define TEST_MEMORY_LEAK_THRESHOLD (-300) +#define TEST_MEMORY_LEAK_THRESHOLD (-400) static size_t before_free_8bit; static size_t before_free_32bit; diff --git a/components/driver/test_apps/i2s_test_apps/i2s_tdm/main/test_i2s_tdm_full_duplex.c b/components/driver/test_apps/i2s_test_apps/i2s_tdm/main/test_i2s_tdm_full_duplex.c index 209058b034..921a6f9ca7 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s_tdm/main/test_i2s_tdm_full_duplex.c +++ b/components/driver/test_apps/i2s_test_apps/i2s_tdm/main/test_i2s_tdm_full_duplex.c @@ -11,14 +11,16 @@ #include "esp_log.h" #include "unity.h" #include "unity_test_utils.h" +#include "test_utils.h" #include "driver/gpio.h" #include "driver/i2s_tdm.h" static const char *TAG = "i2s_tdm_full_duplex_test"; -#define TEST_I2S_FRAME_SIZE (128) -#define TEST_I2S_PACKET_COUNT (512) -#define TEST_I2S_BAD_PACKET_THRESHOLD (10) +#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_FAIL_CNT (3) // 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 #define TEST_I2S_BCK_IO (GPIO_NUM_4) @@ -52,20 +54,22 @@ static void test_i2s_tdm_master_write_task(void *args) uint32_t data_cnt = 0; size_t bytes_written = 0; + + /* Block here waiting for the main thread receiving Slave Ready signals */ + xTaskNotifyWait(0, ULONG_MAX, NULL, portMAX_DELAY); + ESP_LOGI(TAG, "I2S TDM master send start"); - TEST_ESP_OK(i2s_channel_enable(task_args->tx_channel_handle)); while (xTaskNotifyWait(0, ULONG_MAX, NULL, 0) == pdFALSE) { // if main task sends terminate signal, exit the loop /* Fill in the tx buffer */ for (uint32_t i = 0; i < tx_buffer_size / sizeof(uint32_t); i ++) { tx_buffer[i] = data_cnt; - data_cnt ++; + data_cnt++; + data_cnt %= TEST_I2S_ARRAY_LENGTH; } TEST_ESP_OK(i2s_channel_write(task_args->tx_channel_handle, tx_buffer, tx_buffer_size, - &bytes_written, portMAX_DELAY)); - TEST_ASSERT_EQUAL(tx_buffer_size, bytes_written); + &bytes_written, 1000)); } - ESP_LOGI(TAG, "I2S TDM master send stop"); - TEST_ESP_OK(i2s_channel_disable(task_args->tx_channel_handle)); + ESP_LOGI(TAG, "Freeing I2S TDM master tx buffer"); free(tx_buffer); @@ -106,12 +110,12 @@ static void test_i2s_tdm_master(uint32_t sample_rate, i2s_data_bit_width_t bit_w /* Create TDM write task */ TaskHandle_t subtask_handle = NULL; - test_i2s_tdm_write_task_args_t task_args = { - .tx_channel_handle = i2s_tdm_tx_handle, - .maintask_handle = xTaskGetCurrentTaskHandle(), - .tx_data_bit_width = bit_width, - .tdm_slot_mask = slot_mask - }; + /* Make the variable static in case it become invalid in the write task */ + static test_i2s_tdm_write_task_args_t task_args; + task_args.tx_channel_handle = i2s_tdm_tx_handle; + task_args.maintask_handle = xTaskGetCurrentTaskHandle(); + task_args.tx_data_bit_width = bit_width; + task_args.tdm_slot_mask = slot_mask; xTaskCreate(test_i2s_tdm_master_write_task, "I2S TDM Write Task", 4096, &task_args, 5, &subtask_handle); /* Allocate I2S rx buffer */ @@ -121,42 +125,44 @@ static void test_i2s_tdm_master(uint32_t sample_rate, i2s_data_bit_width_t bit_w uint32_t *rx_buffer = malloc(rx_buffer_size); TEST_ASSERT(rx_buffer); - uint8_t is_packet_valid = 0; - uint32_t good_packet_cnt = 0; + uint32_t count = 1; + bool is_start = false; + uint8_t fail_cnt = 0; size_t bytes_read = 0; - ESP_LOGI(TAG, "I2S TDM master receive start"); + float time = 0; TEST_ESP_OK(i2s_channel_enable(i2s_tdm_rx_handle)); - for(uint32_t packet_cnt = 0; packet_cnt < TEST_I2S_PACKET_COUNT; packet_cnt ++) { - TEST_ESP_OK(i2s_channel_read(i2s_tdm_rx_handle, rx_buffer, rx_buffer_size, - &bytes_read, portMAX_DELAY)); - TEST_ASSERT_EQUAL(rx_buffer_size, bytes_read); + TEST_ESP_OK(i2s_channel_enable(i2s_tdm_tx_handle)); + unity_send_signal("Master Ready"); + unity_wait_for_signal("Slave Ready"); - /* Check for empty packet */ - if (rx_buffer[0] == 0) { // empty packet - if (is_packet_valid == 0) { // omit leading empty packets - packet_cnt = 0; - } else { - ESP_LOGW(TAG, "empty packet %"PRIu32, packet_cnt); - } - continue; + /* Slave is ready, start the writing task */ + ESP_LOGI(TAG, "I2S TDM master receive & send start"); + esp_err_t read_ret = ESP_OK; + xTaskNotifyGive(subtask_handle); + while (count < TEST_I2S_ARRAY_LENGTH && fail_cnt < TEST_I2S_MAX_FAIL_CNT && time < TEST_I2S_FRAME_TIMEOUT_SEC) { + read_ret = i2s_channel_read(i2s_tdm_rx_handle, rx_buffer, rx_buffer_size, &bytes_read, 1000); + if (read_ret != ESP_OK) { + break; } - is_packet_valid = 1; - /* Check received packet */ - uint8_t is_good_packet = 1; - uint32_t last_value = rx_buffer[0]; - for (uint32_t j = 1; j < rx_buffer_size / sizeof(uint32_t); j ++) { - if (rx_buffer[j] == last_value + 1) { // increased by 1 - last_value = rx_buffer[j]; - } else { - is_good_packet = 0; - ESP_LOGW(TAG, "corrupted packet %"PRIu32, packet_cnt); - break; // corrupted packet + for (int i = 0; i < rx_buffer_size / sizeof(uint32_t); i++) { + if (rx_buffer[i] == count) { + count++; + if (count >= TEST_I2S_ARRAY_LENGTH) { + break; + } + if (!is_start) { + is_start = true; + } + } else if (is_start) { + ESP_LOGE(TAG, "Failed at index: %d real: %"PRIu32" expect: %"PRIu32"\n", i, rx_buffer[i], count); + is_start = false; + count = 1; + fail_cnt++; } } - if (is_good_packet) { - good_packet_cnt ++; - } + time += (float)TEST_I2S_MAX_FAIL_CNT / (float)sample_rate; } + unity_send_signal("Master Finished"); ESP_LOGI(TAG, "Send signal to terminate subtask"); xTaskNotifyGive(subtask_handle); // notify subtask to exit @@ -164,6 +170,8 @@ static void test_i2s_tdm_master(uint32_t sample_rate, i2s_data_bit_width_t bit_w ESP_LOGI(TAG, "Deleting subtask"); unity_utils_task_delete(subtask_handle); // delete subtask + ESP_LOGI(TAG, "I2S TDM master send stop"); + TEST_ESP_OK(i2s_channel_disable(i2s_tdm_tx_handle)); ESP_LOGI(TAG, "I2S TDM master receive stop"); TEST_ESP_OK(i2s_channel_disable(i2s_tdm_rx_handle)); @@ -172,15 +180,9 @@ static void test_i2s_tdm_master(uint32_t sample_rate, i2s_data_bit_width_t bit_w ESP_LOGI(TAG, "Deleting i2s tx and rx channels"); TEST_ESP_OK(i2s_del_channel(i2s_tdm_rx_handle)); TEST_ESP_OK(i2s_del_channel(i2s_tdm_tx_handle)); - - uint32_t bad_packet_cnt = TEST_I2S_PACKET_COUNT - good_packet_cnt; - ESP_LOGI(TAG, "Total Packet: %d Good Packet: %"PRIu32" Bad Packet %"PRIu32, - TEST_I2S_PACKET_COUNT, good_packet_cnt, bad_packet_cnt); - /* if the bad packet count exceed the threshold, test failed */ - if (bad_packet_cnt > TEST_I2S_BAD_PACKET_THRESHOLD) { - ESP_LOGE(TAG, "Bad Packet count exceed the threshold %d, test failed", TEST_I2S_BAD_PACKET_THRESHOLD); - TEST_FAIL(); - } + TEST_ASSERT_TRUE_MESSAGE(read_ret == ESP_OK, "Master read timeout "); + TEST_ASSERT_TRUE_MESSAGE(fail_cnt < TEST_I2S_MAX_FAIL_CNT, "Broken data received "); + TEST_ASSERT_TRUE_MESSAGE(time < TEST_I2S_FRAME_TIMEOUT_SEC, "Waiting for valid data timeout "); } static void test_i2s_tdm_slave(uint32_t sample_rate, i2s_data_bit_width_t bit_width, i2s_tdm_slot_mask_t slot_mask) @@ -223,28 +225,23 @@ static void test_i2s_tdm_slave(uint32_t sample_rate, i2s_data_bit_width_t bit_wi uint32_t *rx_buffer = malloc(rx_buffer_size); TEST_ASSERT(rx_buffer); - ESP_LOGI(TAG, "I2S TDM slave receive & send start"); TEST_ESP_OK(i2s_channel_enable(i2s_tdm_rx_handle)); TEST_ESP_OK(i2s_channel_enable(i2s_tdm_tx_handle)); - uint32_t packet_cnt = 0; - size_t bytes_read = 0, bytes_written = 0; - while (packet_cnt < TEST_I2S_PACKET_COUNT) { - TEST_ESP_OK(i2s_channel_read(i2s_tdm_rx_handle, rx_buffer, rx_buffer_size, - &bytes_read, portMAX_DELAY)); - TEST_ASSERT_EQUAL(rx_buffer_size, bytes_read); + unity_send_signal("Slave Ready"); + unity_wait_for_signal("Master Ready"); - TEST_ESP_OK(i2s_channel_write(i2s_tdm_tx_handle, rx_buffer, rx_buffer_size, - &bytes_written, portMAX_DELAY)); - TEST_ASSERT_EQUAL(rx_buffer_size, bytes_written); - if (rx_buffer[0]) { // packet is not empty - packet_cnt ++; + 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 */ + while (true) { + if (i2s_channel_read(i2s_tdm_rx_handle, rx_buffer, rx_buffer_size, &bytes_read, 500) != ESP_OK) { + break; + } + if (i2s_channel_write(i2s_tdm_tx_handle, rx_buffer, rx_buffer_size, &bytes_written, 500) != ESP_OK) { + break; } } - - /* Send empty buffers to flush DMA ringbuffer until timeout */ - memset(rx_buffer, 0, rx_buffer_size); - while (i2s_channel_write(i2s_tdm_tx_handle, rx_buffer, rx_buffer_size, - &bytes_written, pdMS_TO_TICKS(200)) != ESP_ERR_TIMEOUT); + unity_wait_for_signal("Master Finished"); ESP_LOGI(TAG, "I2S TDM slave receive stop"); TEST_ESP_OK(i2s_channel_disable(i2s_tdm_rx_handle)); diff --git a/components/driver/test_apps/i2s_test_apps/i2s_tdm/pytest_i2s_tdm_full_duplex.py b/components/driver/test_apps/i2s_test_apps/i2s_tdm/pytest_i2s_tdm_full_duplex.py index e998b2dec7..25d4dce7b7 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s_tdm/pytest_i2s_tdm_full_duplex.py +++ b/components/driver/test_apps/i2s_test_apps/i2s_tdm/pytest_i2s_tdm_full_duplex.py @@ -11,4 +11,4 @@ import pytest 2, ], indirect=True) def test_i2s_tdm_full_duplex(case_tester) -> None: # type: ignore - case_tester.run_all_cases() + case_tester.run_all_cases(timeout=30) diff --git a/components/driver/test_apps/i2s_test_apps/i2s_tdm/sdkconfig.defaults b/components/driver/test_apps/i2s_test_apps/i2s_tdm/sdkconfig.defaults index b308cb2ddd..0cd8c36738 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s_tdm/sdkconfig.defaults +++ b/components/driver/test_apps/i2s_test_apps/i2s_tdm/sdkconfig.defaults @@ -1,2 +1,3 @@ CONFIG_FREERTOS_HZ=1000 CONFIG_ESP_TASK_WDT=n +CONFIG_I2S_ENABLE_DEBUG_LOG=y diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index 555a878aa8..196ecc8eb8 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -419,9 +419,12 @@ finish: */ static inline void i2s_ll_tx_start(i2s_dev_t *hw) { - hw->tx_conf.tx_update = 0; + // TODO: solve the bug that can't update + // hw->tx_conf.tx_update = 0; + while (hw->tx_conf.tx_update); hw->tx_conf.tx_update = 1; hw->tx_conf.tx_start = 1; + while (hw->tx_conf.tx_update); } /** @@ -431,9 +434,12 @@ static inline void i2s_ll_tx_start(i2s_dev_t *hw) */ static inline void i2s_ll_rx_start(i2s_dev_t *hw) { - hw->rx_conf.rx_update = 0; + // TODO: solve the bug that can't update + // hw->rx_conf.rx_update = 0; + while (hw->rx_conf.rx_update); hw->rx_conf.rx_update = 1; hw->rx_conf.rx_start = 1; + while (hw->rx_conf.rx_update); } /** From f44aa9bcc54de2bbbd90bdd1ea65c80ccbdf8889 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 19 Dec 2022 12:27:40 +0800 Subject: [PATCH 2/3] i2s: fixed rx update stuck bug --- components/hal/esp32c3/include/hal/i2s_ll.h | 12 ++++-------- components/hal/esp32c6/include/hal/i2s_ll.h | 6 ++++-- components/hal/esp32h4/include/hal/i2s_ll.h | 6 ++++-- components/hal/esp32s3/include/hal/i2s_ll.h | 6 ++++-- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index 196ecc8eb8..9425d65202 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -419,12 +419,10 @@ finish: */ static inline void i2s_ll_tx_start(i2s_dev_t *hw) { - // TODO: solve the bug that can't update - // hw->tx_conf.tx_update = 0; - while (hw->tx_conf.tx_update); + // Have to update registers before start hw->tx_conf.tx_update = 1; - hw->tx_conf.tx_start = 1; while (hw->tx_conf.tx_update); + hw->tx_conf.tx_start = 1; } /** @@ -434,12 +432,10 @@ static inline void i2s_ll_tx_start(i2s_dev_t *hw) */ static inline void i2s_ll_rx_start(i2s_dev_t *hw) { - // TODO: solve the bug that can't update - // hw->rx_conf.rx_update = 0; - while (hw->rx_conf.rx_update); + // Have to update registers before start hw->rx_conf.rx_update = 1; - hw->rx_conf.rx_start = 1; while (hw->rx_conf.rx_update); + hw->rx_conf.rx_start = 1; } /** diff --git a/components/hal/esp32c6/include/hal/i2s_ll.h b/components/hal/esp32c6/include/hal/i2s_ll.h index 3d36a0af89..87d3e13d08 100644 --- a/components/hal/esp32c6/include/hal/i2s_ll.h +++ b/components/hal/esp32c6/include/hal/i2s_ll.h @@ -434,8 +434,9 @@ finish: */ static inline void i2s_ll_tx_start(i2s_dev_t *hw) { - hw->tx_conf.tx_update = 0; + // Have to update registers before start hw->tx_conf.tx_update = 1; + while (hw->tx_conf.tx_update); hw->tx_conf.tx_start = 1; } @@ -446,8 +447,9 @@ static inline void i2s_ll_tx_start(i2s_dev_t *hw) */ static inline void i2s_ll_rx_start(i2s_dev_t *hw) { - hw->rx_conf.rx_update = 0; + // Have to update registers before start hw->rx_conf.rx_update = 1; + while (hw->rx_conf.rx_update); hw->rx_conf.rx_start = 1; } diff --git a/components/hal/esp32h4/include/hal/i2s_ll.h b/components/hal/esp32h4/include/hal/i2s_ll.h index b19165ad77..e9c0f74227 100644 --- a/components/hal/esp32h4/include/hal/i2s_ll.h +++ b/components/hal/esp32h4/include/hal/i2s_ll.h @@ -420,8 +420,9 @@ finish: */ static inline void i2s_ll_tx_start(i2s_dev_t *hw) { - hw->tx_conf.tx_update = 0; + // Have to update registers before start hw->tx_conf.tx_update = 1; + while (hw->tx_conf.tx_update); hw->tx_conf.tx_start = 1; } @@ -432,8 +433,9 @@ static inline void i2s_ll_tx_start(i2s_dev_t *hw) */ static inline void i2s_ll_rx_start(i2s_dev_t *hw) { - hw->rx_conf.rx_update = 0; + // Have to update registers before start hw->rx_conf.rx_update = 1; + while (hw->rx_conf.rx_update); hw->rx_conf.rx_start = 1; } diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index d9c0cf26f2..7660a3efc5 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -419,8 +419,9 @@ finish: */ static inline void i2s_ll_tx_start(i2s_dev_t *hw) { - hw->tx_conf.tx_update = 0; + // Have to update registers before start hw->tx_conf.tx_update = 1; + while (hw->tx_conf.tx_update); hw->tx_conf.tx_start = 1; } @@ -431,8 +432,9 @@ static inline void i2s_ll_tx_start(i2s_dev_t *hw) */ static inline void i2s_ll_rx_start(i2s_dev_t *hw) { - hw->rx_conf.rx_update = 0; + // Have to update registers before start hw->rx_conf.rx_update = 1; + while (hw->rx_conf.rx_update); hw->rx_conf.rx_start = 1; } From 705ddd221f913f48792ad59b85060ad36030d6ce Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Wed, 21 Dec 2022 17:31:38 +0800 Subject: [PATCH 3/3] test more freq --- .../driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c index 5916471f31..6c96b7e820 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c +++ b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c @@ -747,15 +747,15 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_c esp_rom_gpio_connect_in_signal(MASTER_WS_IO, pcnt_periph_signals.groups[0].units[0].channels[0].pulse_sig, 0); // Test common sample rate - uint32_t test_freq[15] = {8000, 11025, 12000, 16000, 22050, 24000, + uint32_t test_freq[16] = {8000, 10000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 128000, 144000, 196000}; int real_pulse = 0; - int case_cnt = 15; + int case_cnt = 16; #if SOC_I2S_HW_VERSION_2 // Can't support a very high sample rate while using XTAL as clock source if (clk_cfg->clk_src == I2S_CLK_SRC_XTAL) { - case_cnt = 9; + case_cnt = 10; } #endif for (int i = 0; i < case_cnt; i++) {