Skip to content

Commit f3c95b6

Browse files
committed
Merge branch 'ci/fix_i2s_multi_dev_test_potential_overflow' into 'master'
ci(i2s): fix the potential overflow in multi_dev test Closes IDFCI-2486 and IDFCI-2487 See merge request espressif/esp-idf!34681
2 parents 393b741 + 978896a commit f3c95b6

File tree

3 files changed

+92
-39
lines changed

3 files changed

+92
-39
lines changed

components/esp_driver_i2s/test_apps/i2s_multi_dev/main/test_i2s_multi_dev.c

Lines changed: 88 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ static const char *TAG = "i2s_multi_dev_test";
2323

2424
#define TEST_I2S_FRAME_SIZE (128) // Frame numbers in every writing / reading
2525
#define TEST_I2S_ARRAY_LENGTH (1024) // The loop data length for verification
26-
#define TEST_I2S_MAX_DATA (128) // The maximum data value in the data buffer
27-
#define TEST_I2S_MAX_FAIL_CNT (3) // Max broken packet count
26+
#define TEST_I2S_MAX_DATA (64) // The maximum data value in the data buffer
27+
#define TEST_I2S_MAX_FAIL_CNT (10) // Max broken packet count
2828
#define TEST_I2S_FRAME_TIMEOUT_SEC (10.0f) // Timeout seconds of waiting for a correct frame
2929

3030
#define TEST_I2S_NUM (I2S_NUM_0) // ESP32-C3 has only I2S0
@@ -39,6 +39,12 @@ static const char *TAG = "i2s_multi_dev_test";
3939
#define TEST_I2S_DI_IO (GPIO_NUM_7) // DI and DO gpio will be reversed on slave runner
4040
#endif // CONFIG_IDF_TARGET_ESP32H2
4141

42+
#if I2S_LL_DEFAULT_CLK_FREQ < 160000000
43+
#define TEST_SAMPLE_RATE (16000) // I2S source clock is relatively low, test case is not stable when sample rate is 48KHz high
44+
#else
45+
#define TEST_SAMPLE_RATE (48000)
46+
#endif
47+
4248
typedef struct {
4349
uint32_t *buffer;
4450
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
7177
i2s_tdm_config_t i2s_tdm_config = {
7278
.clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(sample_rate),
7379
.slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(bit_width, I2S_SLOT_MODE_STEREO, slot_mask),
74-
.gpio_cfg = TEST_I2S_DEFAULT_GPIO(GPIO_NUM_NC, true),
80+
.gpio_cfg = TEST_I2S_DEFAULT_GPIO(I2S_GPIO_UNUSED, true),
7581
};
76-
i2s_tdm_config.clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_384;
82+
i2s_tdm_config.clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_512;
7783
TEST_ESP_OK(i2s_channel_init_tdm_mode(i2s_tdm_tx_handle, &i2s_tdm_config));
7884
TEST_ESP_OK(i2s_channel_init_tdm_mode(i2s_tdm_rx_handle, &i2s_tdm_config));
7985

8086
uint32_t channel_count = 32 - __builtin_clz(slot_mask);
81-
size_t buf_size = channel_count * TEST_I2S_FRAME_SIZE * (bit_width / 8);
87+
size_t buf_size = channel_count * TEST_I2S_FRAME_SIZE * (bit_width / 8) * 2;
8288
/* Allocate I2S rx buffer */
8389
ESP_LOGI(TAG, "Allocating I2S TDM master rx buffer, size=%u", buf_size);
84-
uint32_t *rx_buffer = malloc(buf_size);
90+
uint8_t *rx_buffer = calloc(1, buf_size);
8591
TEST_ASSERT(rx_buffer);
8692
/* Allocate I2S tx buffer */
8793
ESP_LOGI(TAG, "Allocating I2S TDM master tx buffer, size=%u", buf_size);
88-
uint32_t *tx_buffer = malloc(buf_size);
94+
uint8_t *tx_buffer = calloc(1, buf_size);
8995
TEST_ASSERT(tx_buffer);
9096
/* Fill in the tx buffer */
91-
for (uint32_t i = 0, data_cnt = 0; i < buf_size / sizeof(uint32_t); i ++) {
92-
tx_buffer[i] = data_cnt;
93-
data_cnt++;
94-
data_cnt %= TEST_I2S_MAX_DATA;
97+
for (uint32_t i = 0; i < buf_size; i ++) {
98+
tx_buffer[i] = i % TEST_I2S_MAX_DATA;
9599
}
96100
size_t w_bytes = buf_size;
97101
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
107111
/* Slave is ready, start the writing task */
108112
ESP_LOGI(TAG, "I2S TDM master receive & send start");
109113
esp_err_t read_ret = ESP_OK;
110-
uint32_t count = 1;
114+
uint8_t count = 1;
111115
uint8_t fail_cnt = 0;
112116
size_t bytes_read = 0;
117+
unity_wait_for_signal("Slave Data Ready");
118+
// Start to read the data from slave, and retry several times if not success
113119
for (fail_cnt = 0; fail_cnt < TEST_I2S_MAX_FAIL_CNT && count < TEST_I2S_MAX_DATA; fail_cnt++) {
114-
if (i2s_channel_read(i2s_tdm_rx_handle, rx_buffer, buf_size, &bytes_read, 1000) != ESP_OK) {
120+
if (fail_cnt > 0) {
121+
// Delay a while in case the slave has not finished to prepare the data
122+
vTaskDelay(pdMS_TO_TICKS(50));
123+
}
124+
// Try to read the data from slave, continue if failed
125+
read_ret = i2s_channel_read(i2s_tdm_rx_handle, rx_buffer, buf_size, &bytes_read, 1000);
126+
if (read_ret != ESP_OK) {
127+
ESP_LOGE(TAG, "master read failed: %s", esp_err_to_name(read_ret));
115128
continue;
116129
}
117-
for (int i = 0; i < buf_size && count < TEST_I2S_MAX_DATA; i++) {
130+
// When success to read, check the buffer content whether match what master sent
131+
for (int i = 0; i < buf_size; i++) {
132+
printf("%"PRIu8" ", rx_buffer[i]);
118133
if (rx_buffer[i] == count) {
119-
count++;
134+
// If the piece of data match, means the communication between slave and master success, break the loop
135+
if (++count >= TEST_I2S_MAX_DATA) {
136+
break;
137+
}
120138
} else if (count != 1) {
121-
ESP_LOGE(TAG, "Failed at index: %d real: %" PRIu32 " expect: %" PRIu32, i, rx_buffer[i], count);
139+
// If the data not fully matched, reset the counter and try again
140+
ESP_LOGE(TAG, "Failed at index: %d real: %" PRIu8 " expect: %" PRIu8, i, rx_buffer[i], count);
122141
count = 1;
123142
}
124143
}
144+
printf("\n");
125145
}
146+
unity_send_signal("Master Finished");
126147

127148
ESP_LOGI(TAG, "I2S TDM master stop");
128149
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
132153
TEST_ESP_OK(i2s_del_channel(i2s_tdm_rx_handle));
133154
TEST_ESP_OK(i2s_del_channel(i2s_tdm_tx_handle));
134155
ESP_LOGI(TAG, "I2S TDM master resources freed");
135-
TEST_ASSERT_TRUE_MESSAGE(read_ret == ESP_OK, "Master read timeout ");
156+
TEST_ASSERT_TRUE_MESSAGE(read_ret == ESP_OK, "Master read failed ");
136157
TEST_ASSERT_TRUE_MESSAGE(fail_cnt < TEST_I2S_MAX_FAIL_CNT, "Exceed retry times ");
137158
TEST_ASSERT_EQUAL_UINT32(TEST_I2S_MAX_DATA, count);
138159
}
@@ -143,10 +164,11 @@ static void test_i2s_tdm_slave(uint32_t sample_rate, i2s_data_bit_width_t bit_wi
143164
i2s_chan_handle_t i2s_tdm_rx_handle = NULL;
144165

145166
/* Create I2S tx and rx channels */
167+
uint32_t desc_num = 4;
146168
i2s_chan_config_t i2s_channel_config = {
147169
.id = TEST_I2S_NUM,
148170
.role = I2S_ROLE_SLAVE,
149-
.dma_desc_num = 4,
171+
.dma_desc_num = desc_num,
150172
.dma_frame_num = TEST_I2S_FRAME_SIZE,
151173
.auto_clear = false
152174
};
@@ -156,84 +178,113 @@ static void test_i2s_tdm_slave(uint32_t sample_rate, i2s_data_bit_width_t bit_wi
156178
i2s_tdm_config_t i2s_tdm_config = {
157179
.clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(sample_rate),
158180
.slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(bit_width, I2S_SLOT_MODE_STEREO, slot_mask),
159-
.gpio_cfg = TEST_I2S_DEFAULT_GPIO(GPIO_NUM_NC, false),
181+
.gpio_cfg = TEST_I2S_DEFAULT_GPIO(I2S_GPIO_UNUSED, false),
160182
};
161-
if (sample_rate >= 96000) {
162-
i2s_tdm_config.clk_cfg.bclk_div = 12;
163-
}
164183
#if SOC_I2S_SUPPORTS_APLL
165184
i2s_tdm_config.clk_cfg.clk_src = I2S_CLK_SRC_APLL;
185+
/* APLL clock source can only reach upto 125MHz, and the max BCLK among these cases is 6.144 MHz
186+
The BCLK can only be 10 using APLL clock source, see the reason below
187+
Formula: MAX_BCLK = 48K * 32 * 4 = 6.144 MHz. MAX_BCLK_DIV <= (125 /2) / MAX_BCLK */
188+
i2s_tdm_config.clk_cfg.bclk_div = 10;
189+
#else
190+
/* The greater the bclk division is, the greater mclk frequency will be, and the less data latency the slave will have
191+
As the sample rate of the test cases are high, we need a greater BCLK division to reduce the slave data latency,
192+
Otherwise the large data latency will cause the data shifted when receiving on the master side.
193+
However, due to the MCLK limitation(i.e., less or equal than half of the source clock),
194+
the max bclk division is depended on the source clock, sample rate and the bclk ticks in one frame
195+
Formula: MAX_BCLK = 48K * 32 * 4 = 6.144 MHz. MAX_BCLK_DIV <= (160 /2) / MAX_BCLK */
196+
i2s_tdm_config.clk_cfg.bclk_div = 12;
166197
#endif
167198
TEST_ESP_OK(i2s_channel_init_tdm_mode(i2s_tdm_tx_handle, &i2s_tdm_config));
168199
TEST_ESP_OK(i2s_channel_init_tdm_mode(i2s_tdm_rx_handle, &i2s_tdm_config));
169200

170201
/* Allocate I2S rx buffer */
171202
uint32_t channel_count = 32 - __builtin_clz(slot_mask);
172-
uint32_t buffer_size = TEST_I2S_FRAME_SIZE * channel_count * (bit_width / 8);
203+
uint32_t buffer_size = TEST_I2S_FRAME_SIZE * channel_count * (bit_width / 8) * 2;
173204
ESP_LOGI(TAG, "Allocating I2S TDM slave buffer, size=%"PRIu32, buffer_size);
174-
uint32_t *echo_buffer = malloc(buffer_size);
205+
uint8_t *echo_buffer = calloc(1, buffer_size);
175206
TEST_ASSERT(echo_buffer);
176207

177208
unity_send_signal("Slave Ready");
178209
unity_wait_for_signal("Master Ready");
179210
TEST_ESP_OK(i2s_channel_enable(i2s_tdm_rx_handle));
180-
TEST_ESP_OK(i2s_channel_enable(i2s_tdm_tx_handle));
181211

182212
ESP_LOGI(TAG, "I2S TDM slave receive & send start");
183-
size_t bytes_read = 0, bytes_written = 0;
184-
/* Loop until reading or writing failed, which indicates the master has finished and deleted the I2S peripheral */
213+
size_t bytes_read = 0;
214+
int read_fail_cnt = 0;
215+
bool success_flag = true;
216+
// Continuously read data from master until the first piece of valid data is received
185217
while (true) {
186-
if (i2s_channel_read(i2s_tdm_rx_handle, echo_buffer, buffer_size, &bytes_read, 500) != ESP_OK) {
187-
break;
218+
if (i2s_channel_read(i2s_tdm_rx_handle, echo_buffer, buffer_size, &bytes_read, 1000) != ESP_OK) {
219+
vTaskDelay(pdMS_TO_TICKS(50));
220+
if (read_fail_cnt++ >= TEST_I2S_MAX_FAIL_CNT) {
221+
ESP_LOGE(TAG, "Slave failed to read after %d retries", (int)TEST_I2S_MAX_FAIL_CNT);
222+
success_flag = false;
223+
goto exit;
224+
}
188225
}
189-
if (i2s_channel_write(i2s_tdm_tx_handle, echo_buffer, buffer_size, &bytes_written, 500) != ESP_OK) {
226+
// When receive valid data, then break the loop and start writing
227+
if (echo_buffer[0] || echo_buffer[1]) {
190228
break;
191229
}
192230
}
231+
size_t bytes_written = buffer_size;
232+
/* Load the data to write */
233+
while (bytes_written) {
234+
esp_err_t ret = i2s_channel_preload_data(i2s_tdm_tx_handle, echo_buffer, buffer_size, &bytes_written);
235+
printf("ret %x, bytes_written %d\n", ret, (int)bytes_written);
236+
}
237+
TEST_ESP_OK(i2s_channel_enable(i2s_tdm_tx_handle));
238+
vTaskDelay(pdMS_TO_TICKS(100));
239+
unity_send_signal("Slave Data Ready");
240+
unity_wait_for_signal("Master Finished");
241+
242+
TEST_ESP_OK(i2s_channel_disable(i2s_tdm_tx_handle));
193243

244+
exit:
194245
ESP_LOGI(TAG, "I2S TDM slave receive stop");
195246
TEST_ESP_OK(i2s_channel_disable(i2s_tdm_rx_handle));
196-
TEST_ESP_OK(i2s_channel_disable(i2s_tdm_tx_handle));
197247
free(echo_buffer);
198248
TEST_ESP_OK(i2s_del_channel(i2s_tdm_rx_handle));
199249
TEST_ESP_OK(i2s_del_channel(i2s_tdm_tx_handle));
200250
ESP_LOGI(TAG, "I2S TDM slave resources freed");
251+
TEST_ASSERT_TRUE_MESSAGE(success_flag, "Slave failed to read");
201252
}
202253

203254
static void test_i2s_tdm_master_48k_32bits_4slots(void)
204255
{
205-
test_i2s_tdm_master(48000, I2S_DATA_BIT_WIDTH_32BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
256+
test_i2s_tdm_master(TEST_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_32BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
206257
}
207258

208259
static void test_i2s_tdm_slave_48k_32bits_4slots(void)
209260
{
210-
test_i2s_tdm_slave(48000, I2S_DATA_BIT_WIDTH_32BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
261+
test_i2s_tdm_slave(TEST_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_32BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
211262
}
212263

213264
TEST_CASE_MULTIPLE_DEVICES("I2S_TDM_full_duplex_test_in_48k_32bits_4slots", "[I2S_TDM]",
214265
test_i2s_tdm_master_48k_32bits_4slots, test_i2s_tdm_slave_48k_32bits_4slots);
215266

216267
static void test_i2s_tdm_master_48k_16bits_4slots(void)
217268
{
218-
test_i2s_tdm_master(48000, I2S_DATA_BIT_WIDTH_16BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
269+
test_i2s_tdm_master(TEST_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_16BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
219270
}
220271

221272
static void test_i2s_tdm_slave_48k_16bits_4slots(void)
222273
{
223-
test_i2s_tdm_slave(48000, I2S_DATA_BIT_WIDTH_16BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
274+
test_i2s_tdm_slave(TEST_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_16BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
224275
}
225276

226277
TEST_CASE_MULTIPLE_DEVICES("I2S_TDM_full_duplex_test_in_48k_16bits_4slots", "[I2S_TDM]",
227278
test_i2s_tdm_master_48k_16bits_4slots, test_i2s_tdm_slave_48k_16bits_4slots);
228279

229280
static void test_i2s_tdm_master_48k_8bits_4slots(void)
230281
{
231-
test_i2s_tdm_master(48000, I2S_DATA_BIT_WIDTH_8BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
282+
test_i2s_tdm_master(TEST_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_8BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
232283
}
233284

234285
static void test_i2s_tdm_slave_48k_8bits_4slots(void)
235286
{
236-
test_i2s_tdm_slave(48000, I2S_DATA_BIT_WIDTH_8BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
287+
test_i2s_tdm_slave(TEST_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_8BIT, I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3);
237288
}
238289

239290
TEST_CASE_MULTIPLE_DEVICES("I2S_TDM_full_duplex_test_in_48k_8bits_4slots", "[I2S_TDM]",

docs/en/api-reference/peripherals/i2s.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ ESP32-C6 I2S 0 I2S 0 none I2S 0 none none
125125
ESP32-S3 I2S 0/1 I2S 0 I2S 0 I2S 0/1 none none
126126
ESP32-H2 I2S 0 I2S 0 none I2S 0 none none
127127
ESP32-P4 I2S 0~2 I2S 0 I2S 0 I2S 0~2 none none
128-
ESP32-C5 I2S 0 I2S 0 none I2S 0 none none
128+
ESP32-C5 I2S 0 I2S 0 I2S 0 I2S 0 none none
129+
ESP32-C61 I2S 0 I2S 0 I2S 0 I2S 0 none none
129130
========= ======== ======== ======== ======== ======== ==========
130131

131132
Standard Mode

docs/zh_CN/api-reference/peripherals/i2s.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ ESP32-C6 I2S 0 I2S 0 无 I2S 0 无 无
125125
ESP32-S3 I2S 0/1 I2S 0 I2S 0 I2S 0/1 无 无
126126
ESP32-H2 I2S 0 I2S 0 无 I2S 0 无 无
127127
ESP32-P4 I2S 0~2 I2S 0 I2S 0 I2S 0~2 无 无
128-
ESP32-C5 I2S 0 I2S 0 无 I2S 0 无 无
128+
ESP32-C5 I2S 0 I2S 0 I2S 0 I2S 0 无 无
129+
ESP32-C61 I2S 0 I2S 0 I2S 0 I2S 0 无 无
129130
========= ======== ======== ======== ======== ======== ==========
130131

131132
标准模式

0 commit comments

Comments
 (0)