|
|
|
@@ -5,8 +5,10 @@
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <inttypes.h>
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
|
#include "freertos/task.h"
|
|
|
|
|
#include "freertos/queue.h"
|
|
|
|
@@ -17,6 +19,7 @@
|
|
|
|
|
#include "esp_private/gpio.h"
|
|
|
|
|
#include "esp_err.h"
|
|
|
|
|
#include "esp_attr.h"
|
|
|
|
|
#include "esp_memory_utils.h"
|
|
|
|
|
#include "unity.h"
|
|
|
|
|
#include "math.h"
|
|
|
|
|
#include "esp_rom_gpio.h"
|
|
|
|
@@ -45,12 +48,11 @@
|
|
|
|
|
|
|
|
|
|
#include "../../test_inc/test_i2s.h"
|
|
|
|
|
|
|
|
|
|
#if I2S_LL_GET(INST_NUM) > 1 && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
|
|
|
|
|
#define I2S_TEST_MODE_SLAVE_TO_MASTER 0
|
|
|
|
|
#define I2S_TEST_MODE_MASTER_TO_SLAVE 1
|
|
|
|
|
#define I2S_TEST_MODE_LOOPBACK 2
|
|
|
|
|
|
|
|
|
|
// mode: 0, master rx, slave tx. mode: 1, master tx, slave rx. mode: 2, master tx rx loop-back
|
|
|
|
|
// Since ESP32-S2 has only one I2S, only loop back test can be tested.
|
|
|
|
|
// mode: 0, master rx, slave tx. mode: 1, master tx, slave rx.
|
|
|
|
|
static void i2s_test_io_config(int mode)
|
|
|
|
|
{
|
|
|
|
|
// Connect internal signals using IO matrix.
|
|
|
|
@@ -88,18 +90,13 @@ static void i2s_test_io_config(int mode)
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
case I2S_TEST_MODE_LOOPBACK: {
|
|
|
|
|
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, i2s_periph_signal[0].data_out_sig, 0, 0);
|
|
|
|
|
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, i2s_periph_signal[0].data_in_sig, 0);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: {
|
|
|
|
|
TEST_FAIL_MESSAGE("error: mode not supported");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void i2s_read_write_test(i2s_chan_handle_t tx_chan, i2s_chan_handle_t rx_chan)
|
|
|
|
|
{
|
|
|
|
@@ -879,41 +876,270 @@ TEST_CASE("I2S_memory_leak_test", "[i2s]")
|
|
|
|
|
printf("\r\nHeap size after: %"PRIu32"\n", esp_get_free_heap_size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("I2S_loopback_test", "[i2s]")
|
|
|
|
|
#if SOC_PSRAM_DMA_CAPABLE && CONFIG_SPIRAM
|
|
|
|
|
static IRAM_ATTR bool i2s_record_external_ram_buf(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx)
|
|
|
|
|
{
|
|
|
|
|
*((volatile bool *)user_ctx) |= esp_ptr_external_ram(event->dma_buf);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Re-enable after disable checks that the circular DMA link restarts from its head. */
|
|
|
|
|
static void i2s_std_master_loopback_test(bool dma_buffer_in_psram)
|
|
|
|
|
{
|
|
|
|
|
i2s_chan_handle_t tx_handle;
|
|
|
|
|
i2s_chan_handle_t rx_handle;
|
|
|
|
|
|
|
|
|
|
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
|
|
|
|
chan_cfg.dma_buffer_in_psram = dma_buffer_in_psram;
|
|
|
|
|
i2s_std_config_t std_cfg = {
|
|
|
|
|
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
|
|
|
|
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO),
|
|
|
|
|
.gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN,
|
|
|
|
|
};
|
|
|
|
|
std_cfg.gpio_cfg.din = std_cfg.gpio_cfg.dout;
|
|
|
|
|
#if SOC_PSRAM_DMA_CAPABLE && CONFIG_SPIRAM
|
|
|
|
|
volatile bool tx_in_ext = false;
|
|
|
|
|
volatile bool rx_in_ext = false;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_init_std_mode(tx_handle, &std_cfg));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
|
|
|
|
|
i2s_test_io_config(I2S_TEST_MODE_LOOPBACK);
|
|
|
|
|
#if SOC_PSRAM_DMA_CAPABLE && CONFIG_SPIRAM
|
|
|
|
|
if (dma_buffer_in_psram) {
|
|
|
|
|
i2s_event_callbacks_t tx_cbs = {
|
|
|
|
|
.on_sent = i2s_record_external_ram_buf,
|
|
|
|
|
};
|
|
|
|
|
i2s_event_callbacks_t rx_cbs = {
|
|
|
|
|
.on_recv = i2s_record_external_ram_buf,
|
|
|
|
|
};
|
|
|
|
|
TEST_ESP_OK(i2s_channel_register_event_callback(tx_handle, &tx_cbs, (void *)&tx_in_ext));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_register_event_callback(rx_handle, &rx_cbs, (void *)&rx_in_ext));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
TEST_ESP_OK(i2s_channel_enable(tx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_enable(rx_handle));
|
|
|
|
|
|
|
|
|
|
i2s_read_write_test(tx_handle, rx_handle);
|
|
|
|
|
|
|
|
|
|
TEST_ESP_OK(i2s_channel_disable(tx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_disable(rx_handle));
|
|
|
|
|
|
|
|
|
|
/* Verify the circular DMA link restarts from its head after both channels are re-enabled. */
|
|
|
|
|
TEST_ESP_OK(i2s_channel_enable(tx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_enable(rx_handle));
|
|
|
|
|
i2s_read_write_test(tx_handle, rx_handle);
|
|
|
|
|
TEST_ESP_OK(i2s_channel_disable(tx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_disable(rx_handle));
|
|
|
|
|
|
|
|
|
|
TEST_ESP_OK(i2s_channel_enable(tx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_enable(rx_handle));
|
|
|
|
|
i2s_read_write_test(tx_handle, rx_handle);
|
|
|
|
|
TEST_ESP_OK(i2s_channel_disable(tx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_disable(rx_handle));
|
|
|
|
|
|
|
|
|
|
#if SOC_PSRAM_DMA_CAPABLE && CONFIG_SPIRAM
|
|
|
|
|
if (dma_buffer_in_psram) {
|
|
|
|
|
TEST_ASSERT_TRUE(tx_in_ext);
|
|
|
|
|
TEST_ASSERT_TRUE(rx_in_ext);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
TEST_ESP_OK(i2s_del_channel(tx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_del_channel(rx_handle));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("I2S_loopback_test", "[i2s]")
|
|
|
|
|
{
|
|
|
|
|
i2s_std_master_loopback_test(false);
|
|
|
|
|
|
|
|
|
|
#if SOC_PSRAM_DMA_CAPABLE && CONFIG_SPIRAM
|
|
|
|
|
i2s_std_master_loopback_test(true);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if !(SOC_PSRAM_DMA_CAPABLE && CONFIG_SPIRAM)
|
|
|
|
|
TEST_CASE("I2S_psram_dma_buffer_rejected_when_unavailable", "[i2s]")
|
|
|
|
|
{
|
|
|
|
|
i2s_chan_handle_t tx_handle = NULL;
|
|
|
|
|
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
|
|
|
|
|
chan_cfg.dma_buffer_in_psram = true;
|
|
|
|
|
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, i2s_new_channel(&chan_cfg, &tx_handle, NULL));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if CONFIG_I2S_ISR_IRAM_SAFE && SOC_PSRAM_DMA_CAPABLE && CONFIG_SPIRAM
|
|
|
|
|
TEST_CASE("I2S_psram_auto_clear_rejected_with_iram_safe", "[i2s]")
|
|
|
|
|
{
|
|
|
|
|
i2s_chan_handle_t tx_handle = NULL;
|
|
|
|
|
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
|
|
|
|
|
chan_cfg.dma_buffer_in_psram = true;
|
|
|
|
|
|
|
|
|
|
chan_cfg.auto_clear_before_cb = true;
|
|
|
|
|
chan_cfg.auto_clear_after_cb = false;
|
|
|
|
|
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, i2s_new_channel(&chan_cfg, &tx_handle, NULL));
|
|
|
|
|
|
|
|
|
|
chan_cfg.auto_clear_before_cb = false;
|
|
|
|
|
chan_cfg.auto_clear_after_cb = true;
|
|
|
|
|
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, i2s_new_channel(&chan_cfg, &tx_handle, NULL));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if SOC_I2S_SUPPORTS_TDM
|
|
|
|
|
#define I2S_TDM_INTEGRITY_MAGIC 0xA55A5AA5UL
|
|
|
|
|
#define I2S_TDM_INTEGRITY_DESC_NUM 6
|
|
|
|
|
#define I2S_TDM_INTEGRITY_FRAME_NUM 32
|
|
|
|
|
#define I2S_TDM_INTEGRITY_VERIFY_FRAMES 1024
|
|
|
|
|
#define I2S_TDM_INTEGRITY_PREAMBLE_FRAMES 200
|
|
|
|
|
#define I2S_TDM_INTEGRITY_SEND_FRAMES (I2S_TDM_INTEGRITY_PREAMBLE_FRAMES + I2S_TDM_INTEGRITY_VERIFY_FRAMES)
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
uint32_t magic;
|
|
|
|
|
uint32_t seq;
|
|
|
|
|
uint32_t seq_inv;
|
|
|
|
|
uint32_t checksum;
|
|
|
|
|
} i2s_tdm_integrity_frame_t;
|
|
|
|
|
|
|
|
|
|
_Static_assert(sizeof(i2s_tdm_integrity_frame_t) == 16, "TDM integrity frame must be 16 bytes");
|
|
|
|
|
|
|
|
|
|
static uint32_t i2s_tdm_integrity_checksum(uint32_t magic, uint32_t seq, uint32_t seq_inv)
|
|
|
|
|
{
|
|
|
|
|
/* Mix seq before combining with seq_inv so seq ^ ~seq cannot collapse to a constant. */
|
|
|
|
|
uint32_t c = magic ^ (seq * 0x9E3779B1UL);
|
|
|
|
|
c = (c << 7) | (c >> 25);
|
|
|
|
|
return c ^ seq_inv ^ 0x13579BDFUL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void i2s_tdm_integrity_fill_frame(i2s_tdm_integrity_frame_t *frame, uint32_t seq)
|
|
|
|
|
{
|
|
|
|
|
frame->magic = I2S_TDM_INTEGRITY_MAGIC;
|
|
|
|
|
frame->seq = seq;
|
|
|
|
|
frame->seq_inv = ~seq;
|
|
|
|
|
frame->checksum = i2s_tdm_integrity_checksum(frame->magic, frame->seq, frame->seq_inv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool i2s_tdm_integrity_frame_valid(const i2s_tdm_integrity_frame_t *frame)
|
|
|
|
|
{
|
|
|
|
|
return frame->magic == I2S_TDM_INTEGRITY_MAGIC &&
|
|
|
|
|
frame->seq_inv == ~frame->seq &&
|
|
|
|
|
frame->checksum == i2s_tdm_integrity_checksum(frame->magic, frame->seq, frame->seq_inv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
i2s_chan_handle_t tx_handle;
|
|
|
|
|
const uint8_t *buf;
|
|
|
|
|
size_t len;
|
|
|
|
|
volatile esp_err_t ret;
|
|
|
|
|
volatile bool done;
|
|
|
|
|
} i2s_tdm_integrity_writer_ctx_t;
|
|
|
|
|
|
|
|
|
|
static void i2s_tdm_integrity_writer_task(void *args)
|
|
|
|
|
{
|
|
|
|
|
i2s_tdm_integrity_writer_ctx_t *ctx = (i2s_tdm_integrity_writer_ctx_t *)args;
|
|
|
|
|
size_t bytes_written = 0;
|
|
|
|
|
ctx->ret = i2s_channel_write(ctx->tx_handle, ctx->buf, ctx->len, &bytes_written, 2000);
|
|
|
|
|
if (ctx->ret == ESP_OK && bytes_written != ctx->len) {
|
|
|
|
|
ctx->ret = ESP_ERR_INVALID_SIZE;
|
|
|
|
|
}
|
|
|
|
|
ctx->done = true;
|
|
|
|
|
vTaskDelete(NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void i2s_tdm_integrity_loopback_test(bool dma_buffer_in_psram)
|
|
|
|
|
{
|
|
|
|
|
i2s_chan_handle_t tx_handle = NULL;
|
|
|
|
|
i2s_chan_handle_t rx_handle = NULL;
|
|
|
|
|
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
|
|
|
|
chan_cfg.dma_desc_num = I2S_TDM_INTEGRITY_DESC_NUM;
|
|
|
|
|
chan_cfg.dma_frame_num = I2S_TDM_INTEGRITY_FRAME_NUM;
|
|
|
|
|
chan_cfg.dma_buffer_in_psram = dma_buffer_in_psram;
|
|
|
|
|
|
|
|
|
|
i2s_tdm_config_t tdm_cfg = {
|
|
|
|
|
.clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
|
|
|
|
.slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO, 0x0F),
|
|
|
|
|
.gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN,
|
|
|
|
|
};
|
|
|
|
|
tdm_cfg.gpio_cfg.din = tdm_cfg.gpio_cfg.dout;
|
|
|
|
|
/* Full-duplex RX is forced to slave; default mclk/bclk=3 is below the driver's measured minimum of 4. */
|
|
|
|
|
tdm_cfg.clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_512;
|
|
|
|
|
#if CONFIG_IDF_TARGET_ESP32S31
|
|
|
|
|
// S31 uses XTAL as default clock source, which cannot support high sample rate in this test
|
|
|
|
|
tdm_cfg.clk_cfg.clk_src = I2S_CLK_SRC_APLL;
|
|
|
|
|
#endif
|
|
|
|
|
const size_t send_bytes = I2S_TDM_INTEGRITY_SEND_FRAMES * sizeof(i2s_tdm_integrity_frame_t);
|
|
|
|
|
/* Read less than we write so TX is still feeding the bus while RX finishes. */
|
|
|
|
|
const size_t recv_frame_budget = I2S_TDM_INTEGRITY_PREAMBLE_FRAMES + I2S_TDM_INTEGRITY_VERIFY_FRAMES;
|
|
|
|
|
const size_t recv_bytes = recv_frame_budget * sizeof(i2s_tdm_integrity_frame_t);
|
|
|
|
|
i2s_tdm_integrity_frame_t *send_frames = calloc(I2S_TDM_INTEGRITY_SEND_FRAMES, sizeof(i2s_tdm_integrity_frame_t));
|
|
|
|
|
uint8_t *recv_buf = calloc(1, recv_bytes);
|
|
|
|
|
TEST_ASSERT_NOT_NULL(send_frames);
|
|
|
|
|
TEST_ASSERT_NOT_NULL(recv_buf);
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < I2S_TDM_INTEGRITY_SEND_FRAMES; i++) {
|
|
|
|
|
i2s_tdm_integrity_fill_frame(&send_frames[i], i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_init_tdm_mode(tx_handle, &tdm_cfg));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_init_tdm_mode(rx_handle, &tdm_cfg));
|
|
|
|
|
|
|
|
|
|
TEST_ESP_OK(i2s_channel_enable(tx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_enable(rx_handle));
|
|
|
|
|
|
|
|
|
|
i2s_tdm_integrity_writer_ctx_t writer_ctx = {
|
|
|
|
|
.tx_handle = tx_handle,
|
|
|
|
|
.buf = (const uint8_t *)send_frames,
|
|
|
|
|
.len = send_bytes,
|
|
|
|
|
.ret = ESP_FAIL,
|
|
|
|
|
.done = false,
|
|
|
|
|
};
|
|
|
|
|
TEST_ASSERT_EQUAL(pdPASS, xTaskCreate(i2s_tdm_integrity_writer_task, "i2s_tdm_wr", 4096, &writer_ctx, 5, NULL));
|
|
|
|
|
|
|
|
|
|
size_t bytes_read = 0;
|
|
|
|
|
TEST_ESP_OK(i2s_channel_read(rx_handle, recv_buf, recv_bytes, &bytes_read, 2000));
|
|
|
|
|
TEST_ASSERT_EQUAL(recv_bytes, bytes_read);
|
|
|
|
|
|
|
|
|
|
while (!writer_ctx.done) {
|
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(1));
|
|
|
|
|
}
|
|
|
|
|
/* Writer already called vTaskDelete; yield so idle can reclaim its TCB/stack. */
|
|
|
|
|
vTaskDelay(1);
|
|
|
|
|
TEST_ESP_OK(writer_ctx.ret);
|
|
|
|
|
|
|
|
|
|
TEST_ESP_OK(i2s_channel_disable(tx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_channel_disable(rx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_del_channel(tx_handle));
|
|
|
|
|
TEST_ESP_OK(i2s_del_channel(rx_handle));
|
|
|
|
|
|
|
|
|
|
const i2s_tdm_integrity_frame_t *recv_frames = (const i2s_tdm_integrity_frame_t *)recv_buf;
|
|
|
|
|
const size_t recv_frame_count = bytes_read / sizeof(i2s_tdm_integrity_frame_t);
|
|
|
|
|
bool synced = false;
|
|
|
|
|
uint32_t expected_seq = 0;
|
|
|
|
|
uint32_t verified = 0;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i + 1 < recv_frame_count && verified < I2S_TDM_INTEGRITY_VERIFY_FRAMES; i++) {
|
|
|
|
|
if (!synced) {
|
|
|
|
|
if (i2s_tdm_integrity_frame_valid(&recv_frames[i])) {
|
|
|
|
|
expected_seq = recv_frames[i].seq;
|
|
|
|
|
synced = true;
|
|
|
|
|
} else { // skip non-synced preamble frames
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_ASSERT_TRUE_MESSAGE(i2s_tdm_integrity_frame_valid(&recv_frames[i]),
|
|
|
|
|
"corrupted TDM integrity frame after sync");
|
|
|
|
|
TEST_ASSERT_EQUAL_UINT32(expected_seq, recv_frames[i].seq);
|
|
|
|
|
expected_seq++;
|
|
|
|
|
verified++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_ASSERT_TRUE_MESSAGE(synced, "failed to find TDM integrity sync frame\n");
|
|
|
|
|
TEST_ASSERT_EQUAL_UINT32(I2S_TDM_INTEGRITY_VERIFY_FRAMES, verified);
|
|
|
|
|
free(send_frames);
|
|
|
|
|
free(recv_buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("I2S_tdm_integrity_loopback_test", "[i2s]")
|
|
|
|
|
{
|
|
|
|
|
i2s_tdm_integrity_loopback_test(false);
|
|
|
|
|
#if SOC_PSRAM_DMA_CAPABLE && CONFIG_SPIRAM
|
|
|
|
|
i2s_tdm_integrity_loopback_test(true);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#endif // SOC_I2S_SUPPORTS_TDM
|
|
|
|
|
|
|
|
|
|
#if I2S_LL_GET(INST_NUM) > 1 && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
|
|
|
|
|
TEST_CASE("I2S_master_write_slave_read_test", "[i2s]")
|
|
|
|
|
{
|
|
|
|
|