diff --git a/components/esp_driver_i2s/i2s_common.c b/components/esp_driver_i2s/i2s_common.c index 407abb042a..cae8b50708 100644 --- a/components/esp_driver_i2s/i2s_common.c +++ b/components/esp_driver_i2s/i2s_common.c @@ -97,7 +97,9 @@ static void i2s_tx_channel_start(i2s_chan_handle_t handle) i2s_hal_tx_enable_dma(&(handle->controller->hal)); i2s_hal_tx_start_link(&(handle->controller->hal), (uint32_t) handle->dma.desc[0]); #endif - i2s_hal_tx_start(&(handle->controller->hal)); + if (!handle->is_etm_start) { + i2s_hal_tx_start(&(handle->controller->hal)); + } } static void i2s_rx_channel_start(i2s_chan_handle_t handle) @@ -117,12 +119,16 @@ static void i2s_rx_channel_start(i2s_chan_handle_t handle) i2s_hal_rx_enable_dma(&(handle->controller->hal)); i2s_hal_rx_start_link(&(handle->controller->hal), (uint32_t) handle->dma.desc[0]); #endif - i2s_hal_rx_start(&(handle->controller->hal)); + if (!handle->is_etm_start) { + i2s_hal_rx_start(&(handle->controller->hal)); + } } static void i2s_tx_channel_stop(i2s_chan_handle_t handle) { - i2s_hal_tx_stop(&(handle->controller->hal)); + if (!handle->is_etm_stop) { + i2s_hal_tx_stop(&(handle->controller->hal)); + } #if SOC_GDMA_SUPPORTED gdma_stop(handle->dma.dma_chan); #else @@ -135,7 +141,9 @@ static void i2s_tx_channel_stop(i2s_chan_handle_t handle) static void i2s_rx_channel_stop(i2s_chan_handle_t handle) { - i2s_hal_rx_stop(&(handle->controller->hal)); + if (!handle->is_etm_stop) { + i2s_hal_rx_stop(&(handle->controller->hal)); + } #if SOC_GDMA_SUPPORTED gdma_stop(handle->dma.dma_chan); #else diff --git a/components/esp_driver_i2s/i2s_etm.c b/components/esp_driver_i2s/i2s_etm.c index 8fb5083477..c73058a4c7 100644 --- a/components/esp_driver_i2s/i2s_etm.c +++ b/components/esp_driver_i2s/i2s_etm.c @@ -21,15 +21,29 @@ static const char *TAG = "i2s-etm"; -static esp_err_t i2s_del_etm_event(esp_etm_event_t *event) +typedef struct { + esp_etm_task_t base; /*!< Base ETM task object */ + i2s_chan_handle_t handle; /*!< I2S channel handle of this etm task */ + i2s_etm_task_type_t task_type; /*!< I2S ETM task type */ +} i2s_etm_task_t; + +static esp_err_t s_i2s_del_etm_event(esp_etm_event_t *event) { free(event); return ESP_OK; } -static esp_err_t i2s_del_etm_task(esp_etm_task_t *task) +static esp_err_t s_i2s_del_etm_task(esp_etm_task_t *task) { - free(task); + i2s_etm_task_t *i2s_task = __containerof(task, i2s_etm_task_t, base); + if (i2s_task->task_type == I2S_ETM_TASK_START) { + // The i2s start no longer be controlled by etm + i2s_task->handle->is_etm_start = false; + } else { + // The i2s stop no longer be controlled by etm + i2s_task->handle->is_etm_stop = false; + } + free(i2s_task); return ESP_OK; } @@ -41,8 +55,11 @@ esp_err_t i2s_new_etm_event(i2s_chan_handle_t handle, const i2s_etm_event_config esp_etm_event_t *event = heap_caps_calloc(1, sizeof(esp_etm_event_t), ETM_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(event, ESP_ERR_NO_MEM, TAG, "no memory for ETM event"); + // Get the event id from the I2S ETM event table uint32_t event_id = I2S_LL_ETM_EVENT_TABLE(handle->controller->id, handle->dir, config->event_type); + // If the event type is threshold, set the threshold to the hardware if (config->event_type == I2S_ETM_EVENT_REACH_THRESH) { + // Check if the threshold within the supported range ESP_GOTO_ON_FALSE(config->threshold <= I2S_LL_ETM_MAX_THRESH_NUM, ESP_ERR_INVALID_ARG, err, TAG, "exceed the max threshold %"PRIu32, (uint32_t)I2S_LL_ETM_MAX_THRESH_NUM); if (handle->dir == I2S_DIR_TX) { @@ -55,7 +72,7 @@ esp_err_t i2s_new_etm_event(i2s_chan_handle_t handle, const i2s_etm_event_config // fill the ETM event object event->event_id = event_id; event->trig_periph = ETM_TRIG_PERIPH_I2S; - event->del = i2s_del_etm_event; + event->del = s_i2s_del_etm_event; *out_event = event; return ret; err: @@ -67,15 +84,26 @@ esp_err_t i2s_new_etm_task(i2s_chan_handle_t handle, const i2s_etm_task_config_t { ESP_RETURN_ON_FALSE(handle && config && out_task, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(config->task_type < I2S_ETM_TASK_MAX, ESP_ERR_INVALID_ARG, TAG, "invalid task type"); - esp_etm_task_t *task = heap_caps_calloc(1, sizeof(esp_etm_task_t), ETM_MEM_ALLOC_CAPS); + i2s_etm_task_t *task = heap_caps_calloc(1, sizeof(i2s_etm_task_t), ETM_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(task, ESP_ERR_NO_MEM, TAG, "no memory for ETM task"); + // Get the task id from the I2S ETM task table uint32_t task_id = I2S_LL_ETM_TASK_TABLE(handle->controller->id, handle->dir, config->task_type); // fill the ETM task object - task->task_id = task_id; - task->trig_periph = ETM_TRIG_PERIPH_I2S; - task->del = i2s_del_etm_task; - *out_task = task; + task->base.task_id = task_id; + task->base.trig_periph = ETM_TRIG_PERIPH_I2S; + task->base.del = s_i2s_del_etm_task; + task->handle = handle; + task->task_type = config->task_type; + if (config->task_type == I2S_ETM_TASK_START) { + // The i2s start will be controlled by etm + handle->is_etm_start = true; + } else { + // The i2s stop will be controlled by etm + handle->is_etm_stop = true; + } + *out_task = &(task->base); + return ESP_OK; } diff --git a/components/esp_driver_i2s/i2s_private.h b/components/esp_driver_i2s/i2s_private.h index 0071d157f8..5295300196 100644 --- a/components/esp_driver_i2s/i2s_private.h +++ b/components/esp_driver_i2s/i2s_private.h @@ -147,6 +147,8 @@ struct i2s_channel_obj_t { /* Stored configurations */ int intr_prio_flags;/*!< i2s interrupt priority flags */ void *mode_info; /*!< Slot, clock and gpio information of each mode */ + bool is_etm_start; /*!< Whether start/stop by etm tasks */ + bool is_etm_stop; /*!< Whether start/stop by etm tasks */ #if SOC_I2S_SUPPORTS_APLL bool apll_en; /*!< Flag of whether APLL enabled */ #endif diff --git a/components/esp_driver_i2s/test_apps/i2s/main/CMakeLists.txt b/components/esp_driver_i2s/test_apps/i2s/main/CMakeLists.txt index 7b75f96a4f..34b5a6d39f 100644 --- a/components/esp_driver_i2s/test_apps/i2s/main/CMakeLists.txt +++ b/components/esp_driver_i2s/test_apps/i2s/main/CMakeLists.txt @@ -7,5 +7,5 @@ if(CONFIG_SOC_I2S_SUPPORTS_ETM AND CONFIG_SOC_GPIO_SUPPORT_ETM) endif() idf_component_register(SRCS ${srcs} - PRIV_REQUIRES unity esp_driver_pcnt driver spi_flash esp_driver_gpio + PRIV_REQUIRES unity esp_driver_pcnt spi_flash esp_driver_gpio esp_driver_i2s WHOLE_ARCHIVE) diff --git a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s_etm.c b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s_etm.c index 480a59fb7e..603dd9d8d2 100644 --- a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s_etm.c +++ b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s_etm.c @@ -46,7 +46,7 @@ static void s_i2s_etm_check_status(void) } #endif // ETM_LL_SUPPORT_STATUS -static void s_i2s_init(uint8_t *buf) +static void s_i2s_init(void *buf) { i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); chan_cfg.dma_desc_num = TEST_DESC_NUM; @@ -92,9 +92,11 @@ static void s_gpio_init(void) TEST_CASE("i2s_etm_event_test", "[etm]") { - uint8_t *buf = calloc(1, TEST_BUFF_SIZE); + uint32_t *buf = calloc(1, TEST_BUFF_SIZE); assert(buf); - memset(buf, 0x3C, TEST_BUFF_SIZE); + for (int i = 0; i < TEST_BUFF_SIZE / 4; i++) { + buf[i] = i; + } /* I2S init */ s_i2s_init(buf); @@ -153,9 +155,11 @@ TEST_CASE("i2s_etm_event_test", "[etm]") TEST_CASE("i2s_etm_task_test", "[etm]") { - uint8_t *buf = calloc(1, TEST_BUFF_SIZE); + uint32_t *buf = calloc(1, TEST_BUFF_SIZE); assert(buf); - memset(buf, 0x3C, TEST_BUFF_SIZE); + for (int i = 0; i < TEST_BUFF_SIZE / 4; i++) { + buf[i] = i; + } /* I2S init */ s_i2s_init(buf); @@ -165,39 +169,55 @@ TEST_CASE("i2s_etm_task_test", "[etm]") /* GPIO ETM event */ gpio_etm_event_config_t gpio_event_cfg = { - .edge = GPIO_ETM_EVENT_EDGE_POS, + .edges = {GPIO_ETM_EVENT_EDGE_POS, GPIO_ETM_EVENT_EDGE_NEG}, }; - esp_etm_event_handle_t gpio_event_handle; - TEST_ESP_OK(gpio_new_etm_event(&gpio_event_cfg, &gpio_event_handle)); - TEST_ESP_OK(gpio_etm_event_bind_gpio(gpio_event_handle, TEST_GPIO_ETM_NUM)); + esp_etm_event_handle_t gpio_pos_event_handle; + esp_etm_event_handle_t gpio_neg_event_handle; + TEST_ESP_OK(gpio_new_etm_event(&gpio_event_cfg, &gpio_pos_event_handle, &gpio_neg_event_handle)); + TEST_ESP_OK(gpio_etm_event_bind_gpio(gpio_pos_event_handle, TEST_GPIO_ETM_NUM)); + TEST_ESP_OK(gpio_etm_event_bind_gpio(gpio_neg_event_handle, TEST_GPIO_ETM_NUM)); /* I2S Task init */ - i2s_etm_task_config_t i2s_task_cfg = { + i2s_etm_task_config_t i2s_start_task_cfg = { + .task_type = I2S_ETM_TASK_START, + }; + esp_etm_task_handle_t i2s_start_task_handle; + TEST_ESP_OK(i2s_new_etm_task(s_tx_handle, &i2s_start_task_cfg, &i2s_start_task_handle)); + i2s_etm_task_config_t i2s_stop_task_cfg = { .task_type = I2S_ETM_TASK_STOP, }; - esp_etm_task_handle_t i2s_task_handle; - TEST_ESP_OK(i2s_new_etm_task(s_tx_handle, &i2s_task_cfg, &i2s_task_handle)); + esp_etm_task_handle_t i2s_stop_task_handle; + TEST_ESP_OK(i2s_new_etm_task(s_tx_handle, &i2s_stop_task_cfg, &i2s_stop_task_handle)); /* ETM connect */ esp_etm_channel_config_t etm_config = {}; - esp_etm_channel_handle_t etm_channel = NULL; - TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel)); - TEST_ESP_OK(esp_etm_channel_connect(etm_channel, gpio_event_handle, i2s_task_handle)); - TEST_ESP_OK(esp_etm_channel_enable(etm_channel)); + esp_etm_channel_handle_t i2s_etm_start_chan = NULL; + esp_etm_channel_handle_t i2s_etm_stop_chan = NULL; + TEST_ESP_OK(esp_etm_new_channel(&etm_config, &i2s_etm_start_chan)); + TEST_ESP_OK(esp_etm_new_channel(&etm_config, &i2s_etm_stop_chan)); + TEST_ESP_OK(esp_etm_channel_connect(i2s_etm_start_chan, gpio_pos_event_handle, i2s_start_task_handle)); + TEST_ESP_OK(esp_etm_channel_connect(i2s_etm_stop_chan, gpio_neg_event_handle, i2s_stop_task_handle)); + TEST_ESP_OK(esp_etm_channel_enable(i2s_etm_start_chan)); + TEST_ESP_OK(esp_etm_channel_enable(i2s_etm_stop_chan)); esp_etm_dump(stdout); TEST_ESP_OK(i2s_channel_enable(s_tx_handle)); TEST_ESP_OK(i2s_channel_enable(s_rx_handle)); /* Test */ - // receive normally - i2s_channel_read(s_rx_handle, buf, TEST_BUFF_SIZE, NULL, portMAX_DELAY); - // Set the GPIO to stop the I2S TX via ETM + // TX not started, read timeout + TEST_ESP_ERR(ESP_ERR_TIMEOUT, i2s_channel_read(s_rx_handle, buf, TEST_BUFF_SIZE, NULL, 100)); + // start TX via GPIO pos event TEST_ESP_OK(gpio_set_level(TEST_GPIO_ETM_NUM, 1)); + // RX can receive data normally + TEST_ESP_OK(i2s_channel_read(s_rx_handle, buf, TEST_BUFF_SIZE, NULL, 100)); + // Stop TX via GPIO neg event + TEST_ESP_OK(gpio_set_level(TEST_GPIO_ETM_NUM, 0)); + // TX stopped, read will timeout when no legacy data in the queue esp_err_t ret = ESP_OK; // Receive will timeout after TX stopped for (int i = 0; i < 20 && ret == ESP_OK; i++) { - ret = i2s_channel_read(s_rx_handle, buf, TEST_BUFF_SIZE, NULL, 1000); + ret = i2s_channel_read(s_rx_handle, buf, TEST_BUFF_SIZE, NULL, 100); } TEST_ESP_ERR(ESP_ERR_TIMEOUT, ret); @@ -206,10 +226,14 @@ TEST_CASE("i2s_etm_task_test", "[etm]") TEST_ESP_OK(i2s_channel_disable(s_tx_handle)); free(buf); - TEST_ESP_OK(esp_etm_channel_disable(etm_channel)); - TEST_ESP_OK(esp_etm_del_event(gpio_event_handle)); - TEST_ESP_OK(esp_etm_del_task(i2s_task_handle)); - TEST_ESP_OK(esp_etm_del_channel(etm_channel)); + TEST_ESP_OK(esp_etm_channel_disable(i2s_etm_start_chan)); + TEST_ESP_OK(esp_etm_channel_disable(i2s_etm_stop_chan)); + TEST_ESP_OK(esp_etm_del_event(gpio_pos_event_handle)); + TEST_ESP_OK(esp_etm_del_event(gpio_neg_event_handle)); + TEST_ESP_OK(esp_etm_del_task(i2s_start_task_handle)); + TEST_ESP_OK(esp_etm_del_task(i2s_stop_task_handle)); + TEST_ESP_OK(esp_etm_del_channel(i2s_etm_start_chan)); + TEST_ESP_OK(esp_etm_del_channel(i2s_etm_stop_chan)); s_i2s_deinit(); } diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 5e1f813b1f..92e7392889 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -415,10 +415,6 @@ config SOC_ETM_CHANNELS_PER_GROUP int default 50 -config SOC_ETM_SUPPORT_STATUS - bool - default y - config SOC_GPIO_PORT int default 1 diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 3e65dba720..297c43f8e4 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -187,7 +187,6 @@ /*-------------------------- ETM CAPS --------------------------------------*/ #define SOC_ETM_GROUPS 1U // Number of ETM groups #define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group -#define SOC_ETM_SUPPORT_STATUS 1 // Support to get and clear the status of the ETM event and task /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-C5 has 1 GPIO peripheral diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index e6c3141f6a..5f96bc2684 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -187,10 +187,6 @@ config SOC_ETM_CHANNELS_PER_GROUP int default 50 -config SOC_ETM_SUPPORT_STATUS - bool - default y - config SOC_GPIO_PORT int default 1 diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index 2789c9682a..69b3dfe8a4 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -177,7 +177,6 @@ /*-------------------------- ETM CAPS --------------------------------------*/ #define SOC_ETM_GROUPS 1U // Number of ETM groups #define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group -#define SOC_ETM_SUPPORT_STATUS 1 // Support to get and clear the status of the ETM event and task /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-C61 has 1 GPIO peripheral diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index bfd57ec563..fd4fb65c29 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -575,10 +575,6 @@ config SOC_ETM_CHANNELS_PER_GROUP int default 50 -config SOC_ETM_SUPPORT_STATUS - bool - default y - config SOC_GPIO_PORT int default 1 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 2683701975..0dce165cf3 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -219,7 +219,6 @@ /*-------------------------- ETM CAPS --------------------------------------*/ #define SOC_ETM_GROUPS 1U // Number of ETM groups #define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group -#define SOC_ETM_SUPPORT_STATUS 1 // Support to get and clear the status of the ETM event and task /*-------------------------- GPIO CAPS ---------------------------------------*/ // ESP32-P4 has 1 GPIO peripheral