mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
Merge branch 'test/add_i2s_tdm_full_duplex_test_app' into 'master'
test: add i2s tdm full duplex multi device test app Closes IDFGH-8003 See merge request espressif/esp-idf!19904
This commit is contained in:
commit
740a8b5729
@ -228,6 +228,14 @@ component_ut_pytest_esp32_generic:
|
||||
- build_pytest_components_esp32
|
||||
tags: [ esp32, generic ]
|
||||
|
||||
component_ut_pytest_esp32_generic_multi_device:
|
||||
extends:
|
||||
- .pytest_components_dir_template
|
||||
- .rules:test:component_ut-esp32
|
||||
needs:
|
||||
- build_pytest_components_esp32
|
||||
tags: [ esp32, generic_multi_device ]
|
||||
|
||||
component_ut_pytest_esp32_adc:
|
||||
extends:
|
||||
- .pytest_components_dir_template
|
||||
@ -276,6 +284,14 @@ component_ut_pytest_esp32s2_generic:
|
||||
- build_pytest_components_esp32s2
|
||||
tags: [ esp32s2, generic ]
|
||||
|
||||
component_ut_pytest_esp32s2_generic_multi_device:
|
||||
extends:
|
||||
- .pytest_components_dir_template
|
||||
- .rules:test:component_ut-esp32s2
|
||||
needs:
|
||||
- build_pytest_components_esp32s2
|
||||
tags: [ esp32s2, generic_multi_device ]
|
||||
|
||||
component_ut_pytest_esp32s2_adc:
|
||||
extends:
|
||||
- .pytest_components_dir_template
|
||||
@ -300,6 +316,14 @@ component_ut_pytest_esp32s3_generic:
|
||||
- build_pytest_components_esp32s3
|
||||
tags: [ esp32s3, generic ]
|
||||
|
||||
component_ut_pytest_esp32s3_generic_multi_device:
|
||||
extends:
|
||||
- .pytest_components_dir_template
|
||||
- .rules:test:component_ut-esp32s3
|
||||
needs:
|
||||
- build_pytest_components_esp32s3
|
||||
tags: [ esp32s3, generic_multi_device ]
|
||||
|
||||
component_ut_pytest_esp32s3_adc:
|
||||
extends:
|
||||
- .pytest_components_dir_template
|
||||
@ -372,6 +396,14 @@ component_ut_pytest_esp32c3_generic:
|
||||
- build_pytest_components_esp32c3
|
||||
tags: [ esp32c3, generic ]
|
||||
|
||||
component_ut_pytest_esp32c3_generic_multi_device:
|
||||
extends:
|
||||
- .pytest_components_dir_template
|
||||
- .rules:test:component_ut-esp32c3
|
||||
needs:
|
||||
- build_pytest_components_esp32c3
|
||||
tags: [ esp32c3, generic_multi_device ]
|
||||
|
||||
component_ut_pytest_esp32c3_adc:
|
||||
extends:
|
||||
- .pytest_components_dir_template
|
||||
|
@ -4,6 +4,10 @@ components/driver/test_apps/i2s_test_apps:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTED != 1
|
||||
|
||||
components/driver/test_apps/i2s_test_apps/i2s_tdm:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTS_TDM != 1
|
||||
|
||||
components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTS_ADC_DAC != 1
|
||||
|
@ -49,8 +49,12 @@ static esp_err_t i2s_tdm_calculate_clock(i2s_chan_handle_t handle, const i2s_tdm
|
||||
}
|
||||
} while (clk_info->bclk_div <= 2);
|
||||
} else {
|
||||
/* For slave mode, mclk >= bclk * 8, so fix bclk_div to 2 first */
|
||||
clk_info->bclk_div = 8;
|
||||
if (clk_cfg->bclk_div < 8) {
|
||||
ESP_LOGW(TAG, "the current bclk division is too small, adjust the bclk division to 8");
|
||||
clk_info->bclk_div = 8;
|
||||
} else {
|
||||
clk_info->bclk_div = clk_cfg->bclk_div;
|
||||
}
|
||||
clk_info->bclk = rate * handle->total_slot * slot_bits;
|
||||
clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
|
||||
}
|
||||
|
@ -118,6 +118,7 @@ extern "C" {
|
||||
.sample_rate_hz = rate, \
|
||||
.clk_src = I2S_CLK_SRC_DEFAULT, \
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE_256, \
|
||||
.bclk_div = 8, \
|
||||
}
|
||||
|
||||
/**
|
||||
@ -150,7 +151,8 @@ typedef struct {
|
||||
/* General fields */
|
||||
uint32_t sample_rate_hz; /*!< I2S sample rate */
|
||||
i2s_clock_src_t clk_src; /*!< Choose clock source */
|
||||
i2s_mclk_multiple_t mclk_multiple; /*!< The multiple of mclk to the sample rate */
|
||||
i2s_mclk_multiple_t mclk_multiple; /*!< The multiple of mclk to the sample rate, only take effect for master role */
|
||||
uint32_t bclk_div; /*!< The division from mclk to bclk, only take effect for slave role, it shouldn't be smaller than 8. Increase this field when data sent by slave lag behind */
|
||||
} i2s_tdm_clk_config_t;
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(i2s_tdm_full_duplex_test)
|
@ -0,0 +1,3 @@
|
||||
| Supported Targets | ESP32-C3 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- |
|
||||
|
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "test_app_main.c" "test_i2s_tdm_full_duplex.c"
|
||||
INCLUDE_DIRS "."
|
||||
WHOLE_ARCHIVE
|
||||
)
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-300)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
unity_run_menu();
|
||||
}
|
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "unity.h"
|
||||
#include "unity_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_NUM (I2S_NUM_0) // ESP32-C3 has only I2S0
|
||||
#define TEST_I2S_BCK_IO (GPIO_NUM_4)
|
||||
#define TEST_I2S_WS_IO (GPIO_NUM_5)
|
||||
#define TEST_I2S_DO_IO (GPIO_NUM_6)
|
||||
#define TEST_I2S_DI_IO (GPIO_NUM_7) // DI and DO gpio will be reversed on slave runner
|
||||
|
||||
typedef struct {
|
||||
TaskHandle_t maintask_handle;
|
||||
QueueHandle_t tx_queue;
|
||||
i2s_chan_handle_t tx_channel_handle;
|
||||
i2s_data_bit_width_t tx_data_bit_width;
|
||||
i2s_tdm_slot_mask_t tdm_slot_mask;
|
||||
} test_i2s_tdm_write_task_args_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t *buffer;
|
||||
uint32_t buffer_size;
|
||||
} test_i2s_tdm_write_buffer_t;
|
||||
|
||||
static void test_i2s_tdm_master_write_task(void *args)
|
||||
{
|
||||
test_i2s_tdm_write_task_args_t *task_args = (test_i2s_tdm_write_task_args_t*)args;
|
||||
|
||||
/* Allocate I2S tx buffer */
|
||||
uint32_t channel_count = 32 - __builtin_clz(task_args->tdm_slot_mask);
|
||||
uint32_t tx_buffer_size = TEST_I2S_FRAME_SIZE * channel_count * (task_args->tx_data_bit_width / 8);
|
||||
ESP_LOGI(TAG, "Allocating I2S TDM master tx buffer, size=%ld", tx_buffer_size);
|
||||
uint32_t *tx_buffer = malloc(tx_buffer_size);
|
||||
TEST_ASSERT(tx_buffer);
|
||||
|
||||
uint32_t data_cnt = 0;
|
||||
size_t bytes_written = 0;
|
||||
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 ++;
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
||||
xTaskNotifyGive(task_args->maintask_handle); // notify main task that cleanup is done
|
||||
vTaskSuspend(NULL); // wait to be deleted
|
||||
}
|
||||
|
||||
static void test_i2s_tdm_master(uint32_t sample_rate, i2s_data_bit_width_t bit_width, i2s_tdm_slot_mask_t slot_mask)
|
||||
{
|
||||
i2s_chan_handle_t i2s_tdm_tx_handle = NULL;
|
||||
i2s_chan_handle_t i2s_tdm_rx_handle = NULL;
|
||||
|
||||
/* Create I2S tx and rx channels */
|
||||
i2s_chan_config_t i2s_channel_config = {
|
||||
.id = TEST_I2S_NUM,
|
||||
.role = I2S_ROLE_MASTER,
|
||||
.dma_desc_num = 4,
|
||||
.dma_frame_num = TEST_I2S_FRAME_SIZE,
|
||||
.auto_clear = false
|
||||
};
|
||||
TEST_ESP_OK(i2s_new_channel(&i2s_channel_config, &i2s_tdm_tx_handle, &i2s_tdm_rx_handle));
|
||||
|
||||
/* Configure channels to TDM mode */
|
||||
i2s_tdm_config_t i2s_tdm_config = {
|
||||
.clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(sample_rate),
|
||||
.slot_cfg = I2S_TDM_PHILIP_SLOT_DEFAULT_CONFIG(bit_width, I2S_SLOT_MODE_STEREO, slot_mask),
|
||||
.gpio_cfg = {
|
||||
.mclk = GPIO_NUM_NC,
|
||||
.bclk = TEST_I2S_BCK_IO,
|
||||
.ws = TEST_I2S_WS_IO,
|
||||
.dout = TEST_I2S_DO_IO,
|
||||
.din = TEST_I2S_DI_IO
|
||||
},
|
||||
};
|
||||
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));
|
||||
|
||||
/* 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
|
||||
};
|
||||
xTaskCreate(test_i2s_tdm_master_write_task, "I2S TDM Write Task", 4096, &task_args, 5, &subtask_handle);
|
||||
|
||||
/* Allocate I2S rx buffer */
|
||||
uint32_t channel_count = 32 - __builtin_clz(slot_mask);
|
||||
uint32_t rx_buffer_size = channel_count * TEST_I2S_FRAME_SIZE * (bit_width / 8);
|
||||
ESP_LOGI(TAG, "Allocating I2S TDM master rx buffer, size=%"PRIu32, rx_buffer_size);
|
||||
uint32_t *rx_buffer = malloc(rx_buffer_size);
|
||||
TEST_ASSERT(rx_buffer);
|
||||
|
||||
uint8_t is_packet_valid = 0;
|
||||
uint32_t good_packet_cnt = 0;
|
||||
size_t bytes_read = 0;
|
||||
ESP_LOGI(TAG, "I2S TDM master receive start");
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
if (is_good_packet) {
|
||||
good_packet_cnt ++;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Send signal to terminate subtask");
|
||||
xTaskNotifyGive(subtask_handle); // notify subtask to exit
|
||||
xTaskNotifyWait(0, ULONG_MAX, NULL, portMAX_DELAY); // wait subtask to do some cleanups
|
||||
ESP_LOGI(TAG, "Deleting subtask");
|
||||
unity_utils_task_delete(subtask_handle); // delete subtask
|
||||
|
||||
ESP_LOGI(TAG, "I2S TDM master receive stop");
|
||||
TEST_ESP_OK(i2s_channel_disable(i2s_tdm_rx_handle));
|
||||
|
||||
ESP_LOGI(TAG, "Freeing I2S TDM master rx buffer");
|
||||
free(rx_buffer);
|
||||
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));
|
||||
|
||||
if (good_packet_cnt < TEST_I2S_PACKET_COUNT-4) { // if there are enough good packets
|
||||
ESP_LOGE(TAG, "Good packet count(%"PRIu32") less than threshold", good_packet_cnt);
|
||||
TEST_FAIL();
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Good packet count: %"PRIu32, good_packet_cnt);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_i2s_tdm_slave(uint32_t sample_rate, i2s_data_bit_width_t bit_width, i2s_tdm_slot_mask_t slot_mask)
|
||||
{
|
||||
i2s_chan_handle_t i2s_tdm_tx_handle = NULL;
|
||||
i2s_chan_handle_t i2s_tdm_rx_handle = NULL;
|
||||
|
||||
/* Create I2S tx and rx channels */
|
||||
i2s_chan_config_t i2s_channel_config = {
|
||||
.id = TEST_I2S_NUM,
|
||||
.role = I2S_ROLE_SLAVE,
|
||||
.dma_desc_num = 4,
|
||||
.dma_frame_num = TEST_I2S_FRAME_SIZE,
|
||||
.auto_clear = false
|
||||
};
|
||||
TEST_ESP_OK(i2s_new_channel(&i2s_channel_config, &i2s_tdm_tx_handle, &i2s_tdm_rx_handle));
|
||||
|
||||
/* Configure channels to TDM mode */
|
||||
i2s_tdm_config_t i2s_tdm_config = {
|
||||
.clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(sample_rate),
|
||||
.slot_cfg = I2S_TDM_PHILIP_SLOT_DEFAULT_CONFIG(bit_width, I2S_SLOT_MODE_STEREO, slot_mask),
|
||||
.gpio_cfg = {
|
||||
.mclk = GPIO_NUM_NC,
|
||||
.bclk = TEST_I2S_BCK_IO,
|
||||
.ws = TEST_I2S_WS_IO,
|
||||
.dout = TEST_I2S_DI_IO,
|
||||
.din = TEST_I2S_DO_IO // on slave, swap DI and DO pin
|
||||
},
|
||||
};
|
||||
if (sample_rate >= 96000) {
|
||||
i2s_tdm_config.clk_cfg.bclk_div = 12;
|
||||
}
|
||||
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 rx_buffer_size = TEST_I2S_FRAME_SIZE * channel_count * (bit_width / 8);
|
||||
ESP_LOGI(TAG, "Allocating I2S TDM slave buffer, size=%ld", rx_buffer_size);
|
||||
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);
|
||||
|
||||
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 ++;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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));
|
||||
|
||||
ESP_LOGI(TAG, "Freeing I2S TDM slave buffer");
|
||||
free(rx_buffer);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_CASE_MULTIPLE_DEVICES("I2S TDM full duplex multiple device test (48k, 32bits, 4slots)", "[I2S_TDM]",
|
||||
test_i2s_tdm_master_48k_32bits_4slots, test_i2s_tdm_slave_48k_32bits_4slots);
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_CASE_MULTIPLE_DEVICES("I2S TDM full duplex multiple device test (48k, 16bits, 4slots)", "[I2S_TDM]",
|
||||
test_i2s_tdm_master_48k_16bits_4slots, test_i2s_tdm_slave_48k_16bits_4slots);
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_CASE_MULTIPLE_DEVICES("I2S TDM full duplex multiple device test (48k, 8bits, 4slots)", "[I2S_TDM]",
|
||||
test_i2s_tdm_master_48k_8bits_4slots, test_i2s_tdm_slave_48k_8bits_4slots);
|
||||
|
||||
|
||||
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 |
|
||||
I2S_TDM_SLOT4 | I2S_TDM_SLOT5 | I2S_TDM_SLOT6 | I2S_TDM_SLOT7);
|
||||
}
|
||||
|
||||
static void test_i2s_tdm_slave_48k_16bits_8slots(void)
|
||||
{
|
||||
test_i2s_tdm_slave(48000, I2S_DATA_BIT_WIDTH_16BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3 |
|
||||
I2S_TDM_SLOT4 | I2S_TDM_SLOT5 | I2S_TDM_SLOT6 | I2S_TDM_SLOT7);
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2S TDM full duplex multiple device test (48k, 16bits, 8slots)", "[I2S_TDM]",
|
||||
test_i2s_tdm_master_48k_16bits_8slots, test_i2s_tdm_slave_48k_16bits_8slots);
|
||||
|
||||
|
||||
static void test_i2s_tdm_master_96k_16bits_4slots(void)
|
||||
{
|
||||
test_i2s_tdm_master(96000, I2S_DATA_BIT_WIDTH_16BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
|
||||
}
|
||||
|
||||
static void test_i2s_tdm_slave_96k_16bits_8slots(void)
|
||||
{
|
||||
test_i2s_tdm_slave(96000, 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 multiple device test (96k, 16bits, 4slots)", "[I2S_TDM]",
|
||||
test_i2s_tdm_master_96k_16bits_4slots, test_i2s_tdm_slave_96k_16bits_8slots);
|
@ -0,0 +1,41 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
from typing import Tuple
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
def run_multi_device_case(master: Dut, slave: Dut, case_name: str) -> None:
|
||||
master.write(case_name)
|
||||
slave.write(case_name)
|
||||
|
||||
slave.expect(r'\t\(2\)\s+\".+\"')
|
||||
slave.write('2')
|
||||
master.expect(r'\t\(2\)\s+\".+\"')
|
||||
master.write('1')
|
||||
|
||||
master.expect_unity_test_output()
|
||||
slave.expect_unity_test_output()
|
||||
|
||||
master.expect_exact("Enter next test, or 'enter' to see menu")
|
||||
slave.expect_exact("Enter next test, or 'enter' to see menu")
|
||||
|
||||
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.generic_multi_device
|
||||
@pytest.mark.parametrize('count', [
|
||||
2,
|
||||
], indirect=True)
|
||||
def test_i2s_tdm_full_duplex(dut: Tuple[Dut, Dut]) -> None:
|
||||
master = dut[0]
|
||||
slave = dut[1]
|
||||
master.expect_exact('Press ENTER to see the list of tests')
|
||||
slave.expect_exact('Press ENTER to see the list of tests')
|
||||
|
||||
run_multi_device_case(master, slave, '"I2S TDM full duplex multiple device test (48k, 32bits, 4slots)"')
|
||||
run_multi_device_case(master, slave, '"I2S TDM full duplex multiple device test (48k, 16bits, 4slots)"')
|
||||
run_multi_device_case(master, slave, '"I2S TDM full duplex multiple device test (48k, 8bits, 4slots)"')
|
||||
run_multi_device_case(master, slave, '"I2S TDM full duplex multiple device test (48k, 16bits, 8slots)"')
|
||||
run_multi_device_case(master, slave, '"I2S TDM full duplex multiple device test (96k, 16bits, 4slots)"')
|
@ -0,0 +1,2 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT=n
|
@ -108,7 +108,7 @@ Overview of All Modes
|
||||
========= ======== ======== ======== ======== ======== ==========
|
||||
ESP32 I2S 0/1 I2S 0 I2S 0 none I2S 0 I2S 0
|
||||
ESP32S2 I2S 0 none none none none I2S 0
|
||||
ESP32C3 I2S 0 I2S 0 none I2S0 none none
|
||||
ESP32C3 I2S 0 I2S 0 none I2S 0 none none
|
||||
ESP32S3 I2S 0/1 I2S 0 I2S 0 I2S 0/1 none none
|
||||
========= ======== ======== ======== ======== ======== ==========
|
||||
|
||||
@ -723,6 +723,12 @@ Here is the table of the data that received in the buffer with different :cpp:me
|
||||
Please refer to :ref:`i2s-api-reference-i2s_tdm` for TDM API information.
|
||||
And for more details, please refer to :component_file:`driver/include/driver/i2s_tdm.h`.
|
||||
|
||||
.. note::
|
||||
|
||||
When setting the clock configuration for a slave role, please be aware that :cpp:member:`i2s_tdm_clk_config_t::bclk_div` should not be smaller than 8 (hardware limitation), increase this field can reduce the data lagging that sent from the slave. In the high sample rate case, the data might lag behind more than one ``bclk`` which will lead data malposition, you can try to increase :cpp:member:`i2s_tdm_clk_config_t::bclk_div` gradually to correct it.
|
||||
|
||||
As :cpp:member:`i2s_tdm_clk_config_t::bclk_div` is the division of ``mclk`` to ``bclk``, increase it will also increase the ``mclk`` frequency, therefore, the clock calculation might failed if the ``mclk`` is too high to divide from the source clock, which means :cpp:member:`i2s_tdm_clk_config_t::bclk_div` is not the bigger the better.
|
||||
|
||||
TDM TX Mode
|
||||
~~~~~~~~~~~
|
||||
|
||||
|
@ -66,6 +66,7 @@ markers =
|
||||
|
||||
# multi-dut markers
|
||||
multi_dut_generic: tests should be run on generic runners, at least have two duts connected.
|
||||
generic_multi_device: generic multiple devices whose corresponding gpio pins are connected to each other.
|
||||
|
||||
# host_test markers
|
||||
host_test: tests which shouldn not be built at the build stage, and instead built in host_test stage.
|
||||
|
Loading…
x
Reference in New Issue
Block a user