Skip to content

Commit 1e73ebc

Browse files
committed
Merge branch 'backport/recent_backport_collection_v5.4' into 'release/v5.4'
backport: backport recent i2s/parlio rx related to v5.4 See merge request espressif/esp-idf!43795
2 parents d0d43c2 + e219422 commit 1e73ebc

File tree

7 files changed

+159
-8
lines changed

7 files changed

+159
-8
lines changed

components/esp_driver_i2s/i2s_common.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,40 @@ static esp_err_t i2s_register_channel(i2s_controller_t *i2s_obj, i2s_dir_t dir,
370370
return ret;
371371
}
372372

373+
#if SOC_I2S_HW_VERSION_1
374+
esp_err_t i2s_channel_change_port(i2s_chan_handle_t handle, int id)
375+
{
376+
I2S_NULL_POINTER_CHECK(TAG, handle);
377+
ESP_RETURN_ON_FALSE(id >= 0 && id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid I2S port id");
378+
if (id == handle->controller->id) {
379+
return ESP_OK;
380+
}
381+
i2s_controller_t *i2s_obj = i2s_acquire_controller_obj(id);
382+
if (!i2s_obj || !i2s_take_available_channel(i2s_obj, handle->dir)) {
383+
return ESP_ERR_NOT_FOUND;
384+
}
385+
i2s_controller_t *old_i2s_obj = handle->controller;
386+
portENTER_CRITICAL(&g_i2s.spinlock);
387+
if (handle->dir == I2S_DIR_TX) {
388+
i2s_obj->tx_chan = handle;
389+
i2s_obj->chan_occupancy |= I2S_DIR_TX;
390+
old_i2s_obj->tx_chan = NULL;
391+
old_i2s_obj->full_duplex = false;
392+
old_i2s_obj->chan_occupancy &= ~I2S_DIR_TX;
393+
} else {
394+
i2s_obj->rx_chan = handle;
395+
i2s_obj->chan_occupancy |= I2S_DIR_RX;
396+
old_i2s_obj->rx_chan = NULL;
397+
old_i2s_obj->full_duplex = false;
398+
old_i2s_obj->chan_occupancy &= ~I2S_DIR_RX;
399+
}
400+
handle->controller = i2s_obj;
401+
portEXIT_CRITICAL(&g_i2s.spinlock);
402+
403+
return ESP_OK;
404+
}
405+
#endif
406+
373407
#ifndef __cplusplus
374408
/* To make sure the i2s_event_callbacks_t is same size as i2s_event_callbacks_internal_t */
375409
_Static_assert(sizeof(i2s_event_callbacks_t) == sizeof(i2s_event_callbacks_internal_t), "Invalid size of i2s_event_callbacks_t structure");
@@ -416,6 +450,9 @@ uint32_t i2s_get_buf_size(i2s_chan_handle_t handle, uint32_t data_bit_width, uin
416450
uint32_t bytes_per_sample = (data_bit_width + 7) / 8;
417451
#endif // CONFIG_IDF_TARGET_ESP32
418452
uint32_t bytes_per_frame = bytes_per_sample * active_chan;
453+
if (bytes_per_frame == 0) {
454+
return 0;
455+
}
419456
uint32_t bufsize = dma_frame_num * bytes_per_frame;
420457
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
421458
/* bufsize need to align with cache line size */
@@ -980,6 +1017,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
9801017
ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_TX, chan_cfg->dma_desc_num),
9811018
err, TAG, "register I2S tx channel failed");
9821019
i2s_obj->tx_chan->role = chan_cfg->role;
1020+
i2s_obj->tx_chan->is_port_auto = id == I2S_NUM_AUTO;
9831021
i2s_obj->tx_chan->intr_prio_flags = chan_cfg->intr_priority ? BIT(chan_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED;
9841022
i2s_obj->tx_chan->dma.auto_clear_after_cb = chan_cfg->auto_clear_after_cb;
9851023
i2s_obj->tx_chan->dma.auto_clear_before_cb = chan_cfg->auto_clear_before_cb;
@@ -995,6 +1033,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
9951033
ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_RX, chan_cfg->dma_desc_num),
9961034
err, TAG, "register I2S rx channel failed");
9971035
i2s_obj->rx_chan->role = chan_cfg->role;
1036+
i2s_obj->rx_chan->is_port_auto = id == I2S_NUM_AUTO;
9981037
i2s_obj->rx_chan->intr_prio_flags = chan_cfg->intr_priority ? BIT(chan_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED;
9991038
i2s_obj->rx_chan->dma.desc_num = chan_cfg->dma_desc_num;
10001039
i2s_obj->rx_chan->dma.frame_num = chan_cfg->dma_frame_num;

components/esp_driver_i2s/i2s_pdm.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ static esp_err_t i2s_pdm_tx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_tx_
9494
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
9595

9696
uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num);
97+
ESP_RETURN_ON_FALSE(buf_size != 0, ESP_ERR_INVALID_ARG, TAG, "invalid data_bit_width");
9798
/* The DMA buffer need to re-allocate if the buffer size changed */
9899
if (handle->dma.buf_size != buf_size) {
99100
ESP_RETURN_ON_ERROR(i2s_free_dma_desc(handle), TAG, "failed to free the old dma descriptor");
@@ -397,6 +398,7 @@ static esp_err_t i2s_pdm_rx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_rx_
397398
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
398399

399400
uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num);
401+
ESP_RETURN_ON_FALSE(buf_size != 0, ESP_ERR_INVALID_ARG, TAG, "invalid data_bit_width");
400402
/* The DMA buffer need to re-allocate if the buffer size changed */
401403
if (handle->dma.buf_size != buf_size) {
402404
ESP_RETURN_ON_ERROR(i2s_free_dma_desc(handle), TAG, "failed to free the old dma descriptor");

components/esp_driver_i2s/i2s_private.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -159,6 +159,7 @@ struct i2s_channel_obj_t {
159159
/* Stored configurations */
160160
int intr_prio_flags;/*!< i2s interrupt priority flags */
161161
void *mode_info; /*!< Slot, clock and gpio information of each mode */
162+
bool is_port_auto; /*!< Whether the port is auto-assigned */
162163
bool is_etm_start; /*!< Whether start by etm tasks */
163164
bool is_etm_stop; /*!< Whether stop by etm tasks */
164165
bool full_duplex_slave; /*!< whether the channel is forced to switch to slave role for full duplex */
@@ -333,6 +334,19 @@ void i2s_output_gpio_reserve(i2s_chan_handle_t handle, int gpio_num);
333334
*/
334335
void i2s_output_gpio_revoke(i2s_chan_handle_t handle, uint64_t gpio_mask);
335336

337+
#if SOC_I2S_HW_VERSION_1
338+
/**
339+
* @brief Change the port of the I2S channel
340+
*
341+
* @param handle I2S channel handle
342+
* @param id I2S port id
343+
* @return
344+
* - ESP_OK Change port success
345+
* - ESP_ERR_NOT_FOUND No available I2S port found
346+
*/
347+
esp_err_t i2s_channel_change_port(i2s_chan_handle_t handle, int id);
348+
#endif
349+
336350
#ifdef __cplusplus
337351
}
338352
#endif

components/esp_driver_i2s/i2s_std.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ static esp_err_t i2s_std_set_slot(i2s_chan_handle_t handle, const i2s_std_slot_c
106106
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
107107

108108
uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num);
109+
ESP_RETURN_ON_FALSE(buf_size != 0, ESP_ERR_INVALID_ARG, TAG, "invalid data_bit_width");
109110
/* The DMA buffer need to re-allocate if the buffer size changed */
110111
if (handle->dma.buf_size != buf_size) {
111112
ESP_RETURN_ON_ERROR(i2s_free_dma_desc(handle), TAG, "failed to free the old dma descriptor");
@@ -237,13 +238,34 @@ static esp_err_t s_i2s_channel_try_to_constitude_std_duplex(i2s_chan_handle_t ha
237238
if (memcmp(another_handle->mode_info, &curr_cfg, sizeof(i2s_std_config_t)) == 0) {
238239
handle->controller->full_duplex = true;
239240
ESP_LOGD(TAG, "Constitude full-duplex on port %d", handle->controller->id);
240-
}
241+
} else {
241242
#if SOC_I2S_HW_VERSION_1
242-
else {
243-
ESP_LOGE(TAG, "Can't set different channel configurations on a same port");
244-
return ESP_ERR_INVALID_ARG;
245-
}
243+
bool port_changed = false;
244+
if (handle->is_port_auto) {
245+
ESP_LOGD(TAG, "TX & RX on I2S%d are simplex", handle->controller->id);
246+
for (int i = 0; i < SOC_I2S_NUM; i++) {
247+
if (i == handle->controller->id) {
248+
continue;
249+
}
250+
ESP_LOGD(TAG, "Trying to move %s channel from port %d to %d",
251+
handle->dir == I2S_DIR_TX ? "TX" : "RX", handle->controller->id, i);
252+
if (i2s_channel_change_port(handle, i) == ESP_OK) {
253+
ESP_LOGD(TAG, "Move success!");
254+
port_changed = true;
255+
break;
256+
} else {
257+
ESP_LOGD(TAG, "Move failed...");
258+
}
259+
}
260+
}
261+
if (!port_changed) {
262+
ESP_LOGE(TAG, "Can't set different channel configurations on a same port");
263+
return ESP_ERR_INVALID_ARG;
264+
}
265+
#else
266+
ESP_LOGD(TAG, "TX & RX on I2S%d are simplex", handle->controller->id);
246267
#endif
268+
}
247269
}
248270
/* Switch to the slave role if needed */
249271
if (handle->controller->full_duplex &&

components/esp_driver_i2s/i2s_tdm.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ static esp_err_t i2s_tdm_set_slot(i2s_chan_handle_t handle, const i2s_tdm_slot_c
114114
"total slots(%"PRIu32") * slot_bit_width(%"PRIu32") exceeds the maximum %d",
115115
handle->total_slot, slot_bits, (int)I2S_LL_SLOT_FRAME_BIT_MAX);
116116
uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num);
117+
ESP_RETURN_ON_FALSE(buf_size != 0, ESP_ERR_INVALID_ARG, TAG, "invalid data_bit_width");
117118
/* The DMA buffer need to re-allocate if the buffer size changed */
118119
if (handle->dma.buf_size != buf_size) {
119120
ESP_RETURN_ON_ERROR(i2s_free_dma_desc(handle), TAG, "failed to free the old dma descriptor");
@@ -245,6 +246,8 @@ static void s_i2s_channel_try_to_constitude_tdm_duplex(i2s_chan_handle_t handle,
245246
if (memcmp(another_handle->mode_info, &curr_cfg, sizeof(i2s_tdm_config_t)) == 0) {
246247
handle->controller->full_duplex = true;
247248
ESP_LOGD(TAG, "Constitude full-duplex on port %d", handle->controller->id);
249+
} else {
250+
ESP_LOGD(TAG, "TX & RX on I2S%d are simplex", handle->controller->id);
248251
}
249252
}
250253
/* Switch to the slave role if needed */

components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ TEST_CASE("I2S_basic_channel_allocation_reconfig_deleting_test", "[i2s]")
238238
}
239239

240240
static volatile bool task_run_flag;
241+
static volatile bool read_task_success = true;
242+
static volatile bool write_task_success = true;
241243

242244
#define TEST_I2S_DATA 0x78
243245

@@ -270,6 +272,7 @@ static void i2s_read_task(void *args)
270272
ret = i2s_channel_read(rx_handle, recv_buf, 2000, &recv_size, 300);
271273
if (ret == ESP_ERR_TIMEOUT) {
272274
printf("Read timeout count: %"PRIu32"\n", cnt++);
275+
read_task_success = false;
273276
}
274277
}
275278

@@ -291,6 +294,7 @@ static void i2s_write_task(void *args)
291294
ret = i2s_channel_write(tx_handle, send_buf, 2000, &send_size, 300);
292295
if (ret == ESP_ERR_TIMEOUT) {
293296
printf("Write timeout count: %"PRIu32"\n", cnt++);
297+
write_task_success = false;
294298
}
295299
}
296300

@@ -431,6 +435,7 @@ TEST_CASE("I2S_lazy_duplex_test", "[i2s]")
431435
},
432436
},
433437
};
438+
/* Part 1: test common lazy duplex mode */
434439
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, NULL));
435440
TEST_ESP_OK(i2s_channel_init_std_mode(tx_handle, &std_cfg));
436441
TEST_ESP_OK(i2s_channel_enable(tx_handle));
@@ -451,7 +456,70 @@ TEST_CASE("I2S_lazy_duplex_test", "[i2s]")
451456
xTaskCreate(i2s_read_check_task, "i2s_read_check_task", 4096, rx_handle, 5, NULL);
452457
printf("RX started\n");
453458

454-
/* Wait 3 seconds to see if any failures occur */
459+
/* Wait 1 seconds to see if any failures occur */
460+
vTaskDelay(pdMS_TO_TICKS(1000));
461+
printf("Finished\n");
462+
463+
/* Stop those three tasks */
464+
task_run_flag = false;
465+
466+
/* Wait for the three thread deleted */
467+
vTaskDelay(pdMS_TO_TICKS(1000));
468+
469+
/* Disable the channels, they will keep waiting until the current reading / writing finished */
470+
TEST_ESP_OK(i2s_channel_disable(tx_handle));
471+
TEST_ESP_OK(i2s_channel_disable(rx_handle));
472+
/* Delete the channels */
473+
TEST_ESP_OK(i2s_del_channel(tx_handle));
474+
TEST_ESP_OK(i2s_del_channel(rx_handle));
475+
476+
/* Part 2: Test no lazy duplex mode with port auto assignment */
477+
chan_cfg.id = I2S_NUM_AUTO;
478+
TEST_ESP_OK(i2s_new_channel(&chan_cfg, NULL, &rx_handle));
479+
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, NULL));
480+
TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
481+
482+
/* Change the config to not constitute full-duplex */
483+
std_cfg.gpio_cfg.mclk = I2S_GPIO_UNUSED;
484+
std_cfg.gpio_cfg.bclk = I2S_GPIO_UNUSED;
485+
std_cfg.gpio_cfg.ws = I2S_GPIO_UNUSED;
486+
std_cfg.gpio_cfg.dout = I2S_GPIO_UNUSED;
487+
std_cfg.gpio_cfg.din = I2S_GPIO_UNUSED;
488+
#if CONFIG_IDF_TARGET_ESP32S2
489+
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, i2s_channel_init_std_mode(tx_handle, &std_cfg));
490+
/* Delete the channels */
491+
TEST_ESP_OK(i2s_del_channel(tx_handle));
492+
TEST_ESP_OK(i2s_del_channel(rx_handle));
493+
return;
494+
#else
495+
TEST_ESP_OK(i2s_channel_init_std_mode(tx_handle, &std_cfg));
496+
#endif
497+
498+
#if CONFIG_IDF_TARGET_ESP32
499+
/* On ESP32, if failed to constitute full-duplex with `I2S_NUM_AUTO`,
500+
the channel will be re-assigned to the next availableport */
501+
i2s_chan_info_t chan_info;
502+
TEST_ESP_OK(i2s_channel_get_info(rx_handle, &chan_info));
503+
TEST_ASSERT(chan_info.id == I2S_NUM_0);
504+
TEST_ESP_OK(i2s_channel_get_info(tx_handle, &chan_info));
505+
TEST_ASSERT(chan_info.id == I2S_NUM_1);
506+
#endif
507+
508+
TEST_ESP_OK(i2s_channel_enable(tx_handle));
509+
TEST_ESP_OK(i2s_channel_enable(rx_handle));
510+
511+
task_run_flag = true;
512+
read_task_success = true;
513+
write_task_success = true;
514+
/* writing task to keep writing */
515+
xTaskCreate(i2s_write_task, "i2s_write_task", 4096, tx_handle, 5, NULL);
516+
printf("TX started\n");
517+
vTaskDelay(pdMS_TO_TICKS(1000));
518+
/* reading task to keep reading */
519+
xTaskCreate(i2s_read_task, "i2s_read_task", 4096, rx_handle, 5, NULL);
520+
printf("RX started\n");
521+
522+
/* Wait 1 seconds to see if any failures occur */
455523
vTaskDelay(pdMS_TO_TICKS(1000));
456524
printf("Finished\n");
457525

@@ -467,6 +535,9 @@ TEST_CASE("I2S_lazy_duplex_test", "[i2s]")
467535
/* Delete the channels */
468536
TEST_ESP_OK(i2s_del_channel(tx_handle));
469537
TEST_ESP_OK(i2s_del_channel(rx_handle));
538+
/* Check if the reading and writing tasks are successful */
539+
TEST_ASSERT(read_task_success);
540+
TEST_ASSERT(write_task_success);
470541
}
471542

472543
static bool whether_contains_exapected_data(uint16_t *src, uint32_t src_len, uint32_t src_step, uint32_t start_val, uint32_t val_step)

components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ static bool test_delimiter(parlio_rx_delimiter_handle_t deli, bool free_running_
292292
static uint32_t task_flags = 0;
293293
xTaskCreate(sender_task_thread, "sender task", 4096, &task_flags, 5, &sender_task);
294294
// Waiting for the data ready on line
295-
while ((task_flags & TEST_TASK_DATA_READY_BIT)) {
295+
while (!(task_flags & TEST_TASK_DATA_READY_BIT)) {
296296
vTaskDelay(1);
297297
}
298298

0 commit comments

Comments
 (0)