From 86a552e4e25d3448fec700e41e8027d8af9ae615 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 9 Jul 2024 19:44:52 +0800 Subject: [PATCH] feat(i2s): support i2s etm event and task --- components/esp_driver_i2s/CMakeLists.txt | 3 + components/esp_driver_i2s/i2s_etm.c | 81 +++++++ .../esp_driver_i2s/include/driver/i2s_etm.h | 72 ++++++ .../test_apps/i2s/main/CMakeLists.txt | 6 +- .../test_apps/i2s/main/test_i2s.c | 26 --- .../test_apps/i2s/main/test_i2s_etm.c | 215 ++++++++++++++++++ .../test_apps/test_inc/test_i2s.h | 26 +++ .../include/esp_private/etm_interface.h | 1 + components/hal/esp32c5/include/hal/etm_ll.h | 2 + components/hal/esp32c5/include/hal/i2s_ll.h | 125 ++++++++++ components/hal/esp32c6/include/hal/i2s_ll.h | 67 +++++- components/hal/esp32h2/include/hal/i2s_ll.h | 67 +++++- components/hal/esp32p4/include/hal/etm_ll.h | 2 + components/hal/esp32p4/include/hal/i2s_ll.h | 209 ++++++++++++++++- components/hal/include/hal/i2s_types.h | 34 ++- .../esp32c5/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32c5/include/soc/soc_caps.h | 1 + .../esp32c6/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32c6/include/soc/soc_caps.h | 1 + .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32h2/include/soc/soc_caps.h | 1 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32p4/include/soc/soc_caps.h | 1 + 23 files changed, 895 insertions(+), 61 deletions(-) create mode 100644 components/esp_driver_i2s/i2s_etm.c create mode 100644 components/esp_driver_i2s/include/driver/i2s_etm.h create mode 100644 components/esp_driver_i2s/test_apps/i2s/main/test_i2s_etm.c diff --git a/components/esp_driver_i2s/CMakeLists.txt b/components/esp_driver_i2s/CMakeLists.txt index e68980e63f..6c8bd1ced2 100644 --- a/components/esp_driver_i2s/CMakeLists.txt +++ b/components/esp_driver_i2s/CMakeLists.txt @@ -18,6 +18,9 @@ if(CONFIG_SOC_I2S_SUPPORTED) if(CONFIG_SOC_I2S_SUPPORTS_TDM) list(APPEND srcs "i2s_tdm.c") endif() + if(CONFIG_SOC_I2S_SUPPORTS_ETM) + list(APPEND srcs "i2s_etm.c") + endif() endif() idf_component_register(SRCS ${srcs} diff --git a/components/esp_driver_i2s/i2s_etm.c b/components/esp_driver_i2s/i2s_etm.c new file mode 100644 index 0000000000..8fb5083477 --- /dev/null +++ b/components/esp_driver_i2s/i2s_etm.c @@ -0,0 +1,81 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG + +#include +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "driver/i2s_etm.h" +#include "i2s_private.h" +#include "hal/i2s_ll.h" +#include "esp_private/etm_interface.h" + +#define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT + +static const char *TAG = "i2s-etm"; + +static esp_err_t 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) +{ + free(task); + return ESP_OK; +} + +esp_err_t i2s_new_etm_event(i2s_chan_handle_t handle, const i2s_etm_event_config_t *config, esp_etm_event_handle_t *out_event) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(handle && config && out_event, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(config->event_type < I2S_ETM_EVENT_MAX, ESP_ERR_INVALID_ARG, TAG, "invalid event type"); + 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"); + + uint32_t event_id = I2S_LL_ETM_EVENT_TABLE(handle->controller->id, handle->dir, config->event_type); + if (config->event_type == I2S_ETM_EVENT_REACH_THRESH) { + 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) { + i2s_ll_tx_set_etm_threshold(handle->controller->hal.dev, config->threshold); + } else { + i2s_ll_rx_set_etm_threshold(handle->controller->hal.dev, config->threshold); + } + } + + // fill the ETM event object + event->event_id = event_id; + event->trig_periph = ETM_TRIG_PERIPH_I2S; + event->del = i2s_del_etm_event; + *out_event = event; + return ret; +err: + free(event); + return ret; +} + +esp_err_t i2s_new_etm_task(i2s_chan_handle_t handle, const i2s_etm_task_config_t *config, esp_etm_task_handle_t *out_task) +{ + 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); + ESP_RETURN_ON_FALSE(task, ESP_ERR_NO_MEM, TAG, "no memory for ETM task"); + + 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; + return ESP_OK; +} diff --git a/components/esp_driver_i2s/include/driver/i2s_etm.h b/components/esp_driver_i2s/include/driver/i2s_etm.h new file mode 100644 index 0000000000..a140ae3c88 --- /dev/null +++ b/components/esp_driver_i2s/include/driver/i2s_etm.h @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "driver/i2s_types.h" +#include "hal/i2s_types.h" + +#include "esp_etm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_I2S_SUPPORTS_ETM +/** + * @brief I2S ETM event configuration + */ +typedef struct { + i2s_etm_event_type_t event_type; /*!< I2S ETM event type */ + uint32_t threshold; /*!< The threshold word number that triggers `I2S_ETM_EVENT_REACH_THRESH` event, + only take effect when the event type is `I2S_ETM_EVENT_REACH_THRESH` + Unit is in word (4 bytes) */ +} i2s_etm_event_config_t; + +/** + * @brief Register the ETM event for I2S channel + * + * @note The created ETM event object can be deleted later by calling `esp_etm_del_event` + * + * @param[in] handle I2S channel handle, allocated by `i2s_new_channel` + * @param[in] config I2S ETM event configuration + * @param[out] out_event Returned ETM event handle + * @return + * - ESP_OK: Get ETM event successfully + * - ESP_ERR_INVALID_ARG: Get ETM event failed because of invalid argument + * - ESP_ERR_NOT_SUPPORTED: Get ETM event failed because the I2S hardware doesn't support ETM event + * - ESP_FAIL: Get ETM event failed because of other error + */ +esp_err_t i2s_new_etm_event(i2s_chan_handle_t handle, const i2s_etm_event_config_t *config, esp_etm_event_handle_t *out_event); + +/** + * @brief I2S ETM task configuration + */ +typedef struct { + i2s_etm_task_type_t task_type; /*!< I2S ETM task type */ +} i2s_etm_task_config_t; + +/** + * @brief Register the ETM task for I2S channel + * + * @note The created ETM task object can be deleted later by calling `esp_etm_del_task` + * + * @param[in] handle I2S channel handle, allocated by `i2s_new_channel` + * @param[in] config I2S ETM task configuration + * @param[out] out_task Returned ETM task handle + * @return + * - ESP_OK: Get ETM task successfully + * - ESP_ERR_INVALID_ARG: Get ETM task failed because of invalid argument + * - ESP_ERR_NOT_SUPPORTED: Get ETM task failed because the i2s hardware doesn't support ETM task + * - ESP_FAIL: Get ETM task failed because of other error + */ +esp_err_t i2s_new_etm_task(i2s_chan_handle_t handle, const i2s_etm_task_config_t *config, esp_etm_task_handle_t *out_task); + +#endif // SOC_I2S_SUPPORTS_ETM + +#ifdef __cplusplus +} +#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 1e48b532a3..7b75f96a4f 100644 --- a/components/esp_driver_i2s/test_apps/i2s/main/CMakeLists.txt +++ b/components/esp_driver_i2s/test_apps/i2s/main/CMakeLists.txt @@ -2,6 +2,10 @@ set(srcs "test_app_main.c" "test_i2s.c" "test_i2s_iram.c") +if(CONFIG_SOC_I2S_SUPPORTS_ETM AND CONFIG_SOC_GPIO_SUPPORT_ETM) + set(srcs ${srcs} "test_i2s_etm.c") +endif() + idf_component_register(SRCS ${srcs} - PRIV_REQUIRES unity esp_driver_pcnt driver spi_flash + PRIV_REQUIRES unity esp_driver_pcnt driver spi_flash esp_driver_gpio WHOLE_ARCHIVE) diff --git a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c index 1b7206d8c0..280ccb1fec 100644 --- a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c +++ b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c @@ -41,32 +41,6 @@ #define I2S_TEST_MODE_MASTER_TO_SLAVE 1 #define I2S_TEST_MODE_LOOPBACK 2 -#define I2S_TEST_MASTER_DEFAULT_PIN { \ - .mclk = MASTER_MCK_IO, \ - .bclk = MASTER_BCK_IO, \ - .ws = MASTER_WS_IO, \ - .dout = DATA_OUT_IO, \ - .din = DATA_IN_IO, \ - .invert_flags = { \ - .mclk_inv = false, \ - .bclk_inv = false, \ - .ws_inv = false, \ - }, \ - } - -#define I2S_TEST_SLAVE_DEFAULT_PIN { \ - .mclk = -1, \ - .bclk = SLAVE_BCK_IO, \ - .ws = SLAVE_WS_IO, \ - .dout = DATA_OUT_IO, \ - .din = DATA_IN_IO, \ - .invert_flags = { \ - .mclk_inv = false, \ - .bclk_inv = false, \ - .ws_inv = false, \ - }, \ - } - // 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. static void i2s_test_io_config(int mode) 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 new file mode 100644 index 0000000000..480a59fb7e --- /dev/null +++ b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s_etm.c @@ -0,0 +1,215 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "unity.h" +#include "unity_test_utils.h" +#include "esp_attr.h" +#include "driver/gpio_etm.h" +#include "driver/gpio.h" +#include "driver/i2s_std.h" +#include "driver/i2s_etm.h" +#include "hal/i2s_ll.h" +#include "hal/etm_ll.h" +#include "../../test_inc/test_i2s.h" + +#include "soc/soc_etm_struct.h" + +#define TEST_DESC_NUM 4 +#define TEST_FRAME_NUM 256 +#define TEST_BUFF_SIZE (TEST_DESC_NUM * TEST_FRAME_NUM) + +#define TEST_GPIO_ETM_NUM DATA_IN_IO + +static i2s_chan_handle_t s_tx_handle = NULL; +static i2s_chan_handle_t s_rx_handle = NULL; + +#if ETM_LL_SUPPORT_STATUS +static void s_i2s_etm_check_status(void) +{ + i2s_dev_t *hw = I2S_LL_GET_HW(0); + bool is_tx_done = i2s_ll_get_etm_tx_done_event_status(hw); + bool is_rx_done = i2s_ll_get_etm_rx_done_event_status(hw); + bool is_tx_reach_thresh = i2s_ll_get_etm_tx_threshold_event_status(hw); + bool is_rx_reach_thresh = i2s_ll_get_etm_rx_threshold_event_status(hw); + printf("tx done st %d, rx done st %d, tx x st %d, rx x st %d\n", + is_tx_done, is_rx_done, is_tx_reach_thresh, is_rx_reach_thresh); + // TODO: IDF-10512 enable the TX_DONE and RX_DONE check after refactor. Currently not support + // TEST_ASSERT(is_tx_done); + // TEST_ASSERT(is_rx_done); + TEST_ASSERT(is_tx_reach_thresh); + TEST_ASSERT(is_rx_reach_thresh); +} +#endif // ETM_LL_SUPPORT_STATUS + +static void s_i2s_init(uint8_t *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; + chan_cfg.dma_frame_num = TEST_FRAME_NUM; + i2s_std_config_t std_cfg = { + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(48000), + .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(32, I2S_SLOT_MODE_STEREO), + .gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN, + }; + std_cfg.gpio_cfg.mclk = -1; // no need mclk + std_cfg.gpio_cfg.din = DATA_OUT_IO; // data loopback + + /* I2S channels init */ + TEST_ESP_OK(i2s_new_channel(&chan_cfg, &s_tx_handle, &s_rx_handle)); + TEST_ESP_OK(i2s_channel_init_std_mode(s_tx_handle, &std_cfg)); + TEST_ESP_OK(i2s_channel_init_std_mode(s_rx_handle, &std_cfg)); + // TODO: IDF-10512 rx_stop_mode is necessary for rx_done event, enable it when supported + // I2S0.rx_conf.rx_stop_mode = 1; + + size_t w_bytes = TEST_BUFF_SIZE; + while (w_bytes == TEST_BUFF_SIZE) { + TEST_ESP_OK(i2s_channel_preload_data(s_tx_handle, buf, TEST_BUFF_SIZE, &w_bytes)); + } +} + +static void s_i2s_deinit(void) +{ + TEST_ESP_OK(i2s_del_channel(s_rx_handle)); + TEST_ESP_OK(i2s_del_channel(s_tx_handle)); + s_tx_handle = NULL; + s_rx_handle = NULL; +} + +static void s_gpio_init(void) +{ + gpio_config_t gpio_cfg = { + .mode = GPIO_MODE_INPUT_OUTPUT, + .pin_bit_mask = (1ULL << TEST_GPIO_ETM_NUM), + }; + TEST_ESP_OK(gpio_config(&gpio_cfg)); + TEST_ESP_OK(gpio_set_level(TEST_GPIO_ETM_NUM, 0)); +} + +TEST_CASE("i2s_etm_event_test", "[etm]") +{ + uint8_t *buf = calloc(1, TEST_BUFF_SIZE); + assert(buf); + memset(buf, 0x3C, TEST_BUFF_SIZE); + + /* I2S init */ + s_i2s_init(buf); + + /* GPIO init */ + s_gpio_init(); + + /* GPIO ETM task */ + gpio_etm_task_config_t gpio_task_cfg = { + .action = GPIO_ETM_TASK_ACTION_SET, + }; + esp_etm_task_handle_t gpio_task_handle; + TEST_ESP_OK(gpio_new_etm_task(&gpio_task_cfg, &gpio_task_handle)); + TEST_ESP_OK(gpio_etm_task_add_gpio(gpio_task_handle, TEST_GPIO_ETM_NUM)); + + /* I2S Event init */ + i2s_etm_event_config_t i2s_evt_cfg = { + .event_type = I2S_ETM_EVENT_REACH_THRESH, + .threshold = 64, + }; + esp_etm_event_handle_t i2s_evt_handle; + TEST_ESP_OK(i2s_new_etm_event(s_rx_handle, &i2s_evt_cfg, &i2s_evt_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, i2s_evt_handle, gpio_task_handle)); + TEST_ESP_OK(esp_etm_channel_enable(etm_channel)); + esp_etm_dump(stdout); + + TEST_ESP_OK(i2s_channel_enable(s_tx_handle)); + TEST_ESP_OK(i2s_channel_enable(s_rx_handle)); + + TEST_ESP_OK(i2s_channel_read(s_rx_handle, buf, TEST_BUFF_SIZE, NULL, portMAX_DELAY)); + +#if ETM_LL_SUPPORT_STATUS + s_i2s_etm_check_status(); +#else + TEST_ASSERT(gpio_get_level(TEST_GPIO_ETM_NUM)); +#endif // ETM_LL_SUPPORT_STATUS + + /* Test finished, free the resources */ + TEST_ESP_OK(i2s_channel_disable(s_rx_handle)); + 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(i2s_evt_handle)); + TEST_ESP_OK(gpio_etm_task_rm_gpio(gpio_task_handle, TEST_GPIO_ETM_NUM)); + TEST_ESP_OK(esp_etm_del_task(gpio_task_handle)); + TEST_ESP_OK(esp_etm_del_channel(etm_channel)); + + s_i2s_deinit(); +} + +TEST_CASE("i2s_etm_task_test", "[etm]") +{ + uint8_t *buf = calloc(1, TEST_BUFF_SIZE); + assert(buf); + memset(buf, 0x3C, TEST_BUFF_SIZE); + + /* I2S init */ + s_i2s_init(buf); + + /* GPIO init */ + s_gpio_init(); + + /* GPIO ETM event */ + gpio_etm_event_config_t gpio_event_cfg = { + .edge = GPIO_ETM_EVENT_EDGE_POS, + }; + 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)); + + /* I2S Task init */ + i2s_etm_task_config_t i2s_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)); + + /* 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_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 + TEST_ESP_OK(gpio_set_level(TEST_GPIO_ETM_NUM, 1)); + 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); + } + TEST_ESP_ERR(ESP_ERR_TIMEOUT, ret); + + /* Test finished, free the resources */ + TEST_ESP_OK(i2s_channel_disable(s_rx_handle)); + 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)); + + s_i2s_deinit(); +} diff --git a/components/esp_driver_i2s/test_apps/test_inc/test_i2s.h b/components/esp_driver_i2s/test_apps/test_inc/test_i2s.h index c3b4522b9a..cbf25114ce 100644 --- a/components/esp_driver_i2s/test_apps/test_inc/test_i2s.h +++ b/components/esp_driver_i2s/test_apps/test_inc/test_i2s.h @@ -72,6 +72,32 @@ extern "C" { #define DATA_OUT_IO 7 #endif +#define I2S_TEST_MASTER_DEFAULT_PIN { \ + .mclk = MASTER_MCK_IO, \ + .bclk = MASTER_BCK_IO, \ + .ws = MASTER_WS_IO, \ + .dout = DATA_OUT_IO, \ + .din = DATA_IN_IO, \ + .invert_flags = { \ + .mclk_inv = false, \ + .bclk_inv = false, \ + .ws_inv = false, \ + }, \ + } + +#define I2S_TEST_SLAVE_DEFAULT_PIN { \ + .mclk = -1, \ + .bclk = SLAVE_BCK_IO, \ + .ws = SLAVE_WS_IO, \ + .dout = DATA_OUT_IO, \ + .din = DATA_IN_IO, \ + .invert_flags = { \ + .mclk_inv = false, \ + .bclk_inv = false, \ + .ws_inv = false, \ + }, \ + } + #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/include/esp_private/etm_interface.h b/components/esp_hw_support/include/esp_private/etm_interface.h index a3924a064b..201ea67e4d 100644 --- a/components/esp_hw_support/include/esp_private/etm_interface.h +++ b/components/esp_hw_support/include/esp_private/etm_interface.h @@ -27,6 +27,7 @@ typedef enum { ETM_TRIG_PERIPH_MCPWM, /*!< ETM trigger source: MCPWM */ ETM_TRIG_PERIPH_ANA_CMPR, /*!< ETM trigger source: Analog Comparator */ ETM_TRIG_PERIPH_TSENS, /*!< ETM trigger source: Temperature Sensor */ + ETM_TRIG_PERIPH_I2S, /*!< ETM trigger source: I2S */ ETM_TRIG_PERIPH_LP_CORE, /*!< ETM trigger source: Low-Power Core */ } etm_trigger_peripheral_t; diff --git a/components/hal/esp32c5/include/hal/etm_ll.h b/components/hal/esp32c5/include/hal/etm_ll.h index a042b0f922..ee1707cd71 100644 --- a/components/hal/esp32c5/include/hal/etm_ll.h +++ b/components/hal/esp32c5/include/hal/etm_ll.h @@ -19,6 +19,8 @@ extern "C" { #endif +#define ETM_LL_SUPPORT_STATUS 1 // Support to get and clear the status of the ETM event and task + /** * @brief Enable the clock for ETM register * diff --git a/components/hal/esp32c5/include/hal/i2s_ll.h b/components/hal/esp32c5/include/hal/i2s_ll.h index 0ea81b3b27..0b9fb644cd 100644 --- a/components/hal/esp32c5/include/hal/i2s_ll.h +++ b/components/hal/esp32c5/include/hal/i2s_ll.h @@ -19,6 +19,8 @@ #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" #include "soc/pcr_struct.h" +#include "soc/soc_etm_struct.h" +#include "soc/soc_etm_source.h" #include "hal/i2s_types.h" #include "hal/hal_utils.h" @@ -28,6 +30,7 @@ extern "C" { #endif #define I2S_LL_GET_HW(num) (((num) == 0)? (&I2S0) : NULL) +#define I2S_LL_GET_ID(hw) (((hw) == &I2S0)? 0 : -1) #define I2S_LL_TDM_CH_MASK (0xffff) #define I2S_LL_PDM_BCK_FACTOR (64) @@ -38,6 +41,30 @@ extern "C" { #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz #define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_ETM_EVENT_TABLE(i2s_port, chan_dir, event) \ + (uint32_t[SOC_I2S_NUM][2][I2S_ETM_EVENT_MAX]){{ \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S0_EVT_RX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S0_EVT_X_WORDS_RECEIVED, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S0_EVT_TX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S0_EVT_X_WORDS_SENT, \ + }}}[i2s_port][(chan_dir) - 1][event] + + +#define I2S_LL_ETM_TASK_TABLE(i2s_port, chan_dir, task) \ + (uint32_t[SOC_I2S_NUM][2][I2S_ETM_TASK_MAX]){{ \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_TASK_START] = I2S0_TASK_START_RX, \ + [I2S_ETM_TASK_STOP] = I2S0_TASK_STOP_RX, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_TASK_START] = I2S0_TASK_START_TX, \ + [I2S_ETM_TASK_STOP] = I2S0_TASK_STOP_TX, \ + }}}[i2s_port][(chan_dir) - 1][task] +#define I2S_LL_ETM_MAX_THRESH_NUM (0x3FFFUL) + /** * @brief Enable the bus clock for I2S module * @@ -1191,6 +1218,104 @@ static inline uint32_t i2s_ll_tx_get_bclk_sync_count(i2s_dev_t *hw) return hw->bck_cnt.tx_bck_cnt; } +/** + * @brief Set the TX ETM threshold of REACH_THRESH event + * + * @param hw Peripheral I2S hardware instance address. + * @param thresh The threshold that send, in words (4 bytes) + */ +static inline void i2s_ll_tx_set_etm_threshold(i2s_dev_t *hw, uint32_t thresh) +{ + hw->etm_conf.etm_tx_send_word_num = thresh; +} + +/** + * @brief Set the RX ETM threshold of REACH_THRESH event + * + * @param hw Peripheral I2S hardware instance address. + * @param thresh The threshold that received, in words (4 bytes) + */ +static inline void i2s_ll_rx_set_etm_threshold(i2s_dev_t *hw, uint32_t thresh) +{ + hw->etm_conf.etm_rx_receive_word_num = thresh; +} + +/** + * @brief Get I2S ETM TX done event status + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - true TX done event triggered + * - false TX done event not triggered + */ +static inline bool i2s_ll_get_etm_tx_done_event_status(i2s_dev_t *hw) +{ + uint32_t i2s_id = I2S_LL_GET_ID(hw); + switch (i2s_id) { + case 0: + return SOC_ETM.evt_st3.i2s0_evt_tx_done_st; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Get I2S ETM TX done event status + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - true TX done event triggered + * - false TX done event not triggered + */ +static inline bool i2s_ll_get_etm_rx_done_event_status(i2s_dev_t *hw) +{ + uint32_t i2s_id = I2S_LL_GET_ID(hw); + switch (i2s_id) { + case 0: + return SOC_ETM.evt_st3.i2s0_evt_rx_done_st; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Get I2S ETM TX done event status + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - true TX done event triggered + * - false TX done event not triggered + */ +static inline bool i2s_ll_get_etm_tx_threshold_event_status(i2s_dev_t *hw) +{ + uint32_t i2s_id = I2S_LL_GET_ID(hw); + switch (i2s_id) { + case 0: + return SOC_ETM.evt_st3.i2s0_evt_x_words_sent_st; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Get I2S ETM TX done event status + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - true TX done event triggered + * - false TX done event not triggered + */ +static inline bool i2s_ll_get_etm_rx_threshold_event_status(i2s_dev_t *hw) +{ + uint32_t i2s_id = I2S_LL_GET_ID(hw); + switch (i2s_id) { + case 0: + return SOC_ETM.evt_st3.i2s0_evt_x_words_received_st; + default: + HAL_ASSERT(false); + } +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c6/include/hal/i2s_ll.h b/components/hal/esp32c6/include/hal/i2s_ll.h index 52c15d43f0..c95ab9321b 100644 --- a/components/hal/esp32c6/include/hal/i2s_ll.h +++ b/components/hal/esp32c6/include/hal/i2s_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,7 @@ #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" #include "soc/pcr_struct.h" +#include "soc/soc_etm_source.h" #include "hal/i2s_types.h" #include "hal/hal_utils.h" @@ -37,6 +38,30 @@ extern "C" { #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz #define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_ETM_EVENT_TABLE(i2s_port, chan_dir, event) \ + (uint32_t[SOC_I2S_NUM][2][I2S_ETM_EVENT_MAX]){{ \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S_EVT_RX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S_EVT_X_WORDS_RECEIVED, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S_EVT_TX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S_EVT_X_WORDS_SENT, \ + }}}[i2s_port][(chan_dir) - 1][event] + + +#define I2S_LL_ETM_TASK_TABLE(i2s_port, chan_dir, task) \ + (uint32_t[SOC_I2S_NUM][2][I2S_ETM_TASK_MAX]){{ \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_TASK_START] = I2S_TASK_START_RX, \ + [I2S_ETM_TASK_STOP] = I2S_TASK_STOP_RX, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_TASK_START] = I2S_TASK_START_TX, \ + [I2S_ETM_TASK_STOP] = I2S_TASK_STOP_TX, \ + }}}[i2s_port][(chan_dir) - 1][task] +#define I2S_LL_ETM_MAX_THRESH_NUM (0x3FFUL) + /** * * @param i2s_id The port id of I2S @@ -460,7 +485,7 @@ static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num) } /** - * @brief Congfigure TX chan bit and audio data bit + * @brief Configure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width @@ -473,7 +498,7 @@ static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int } /** - * @brief Congfigure RX chan bit and audio data bit + * @brief Configure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width @@ -873,11 +898,11 @@ static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f } /** - * @brief Get I2S TX PDM fp configuration paramater + * @brief Get I2S TX PDM fp configuration parameter * * @param hw Peripheral I2S hardware instance address. * @return - * - fp configuration paramater + * - fp configuration parameter */ static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) { @@ -885,11 +910,11 @@ static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) } /** - * @brief Get I2S TX PDM fs configuration paramater + * @brief Get I2S TX PDM fs configuration parameter * * @param hw Peripheral I2S hardware instance address. * @return - * - fs configuration paramater + * - fs configuration parameter */ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) { @@ -915,7 +940,7 @@ static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) * @brief Configura TX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param pcm_cfg PCM configuration paramater + * @param pcm_cfg PCM configuration parameter */ static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { @@ -927,7 +952,7 @@ static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_ * @brief Configure RX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param pcm_cfg PCM configuration paramater + * @param pcm_cfg PCM configuration parameter */ static inline void i2s_ll_rx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { @@ -1099,7 +1124,7 @@ static inline void i2s_ll_tx_pdm_dma_take_mode(i2s_dev_t *hw, bool is_mono, bool * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) * @param is_copy Whether the un-selected slot copies the data from the selected one * If not, the un-selected slot will transmit the data from 'conf_single_data' - * @param mask The slot mask to selet the slot + * @param mask The slot mask to select the slot */ static inline void i2s_ll_tx_pdm_slot_mode(i2s_dev_t *hw, bool is_mono, bool is_copy, i2s_pdm_slot_mask_t mask) { @@ -1132,6 +1157,28 @@ static inline void i2s_ll_tx_pdm_line_mode(i2s_dev_t *hw, i2s_pdm_tx_line_mode_t hw->tx_pcm2pdm_conf.tx_pdm_dac_2out_en = line_mode != I2S_PDM_TX_ONE_LINE_DAC; } +/** + * @brief Set the TX ETM threshold of REACH_THRESH event + * + * @param hw Peripheral I2S hardware instance address. + * @param thresh The threshold that send + */ +static inline void i2s_ll_tx_set_etm_threshold(i2s_dev_t *hw, uint32_t thresh) +{ + hw->etm_conf.etm_tx_send_word_num = thresh; +} + +/** + * @brief Set the RX ETM threshold of REACH_THRESH event + * + * @param hw Peripheral I2S hardware instance address. + * @param thresh The threshold that received + */ +static inline void i2s_ll_rx_set_etm_threshold(i2s_dev_t *hw, uint32_t thresh) +{ + hw->etm_conf.etm_rx_receive_word_num = thresh; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index 0baf7101e5..85e920a2a9 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,7 @@ #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" #include "soc/pcr_struct.h" +#include "soc/soc_etm_source.h" #include "hal/i2s_types.h" #include "hal/hal_utils.h" @@ -38,6 +39,30 @@ extern "C" { #define I2S_LL_PLL_F64M_CLK_FREQ (64 * 1000000) // PLL_F64M_CLK: 64MHz #define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_ETM_EVENT_TABLE(i2s_port, chan_dir, event) \ + (uint32_t[SOC_I2S_NUM][2][I2S_ETM_EVENT_MAX]){{ \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S_EVT_RX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S_EVT_X_WORDS_RECEIVED, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S_EVT_TX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S_EVT_X_WORDS_SENT, \ + }}}[i2s_port][(chan_dir) - 1][event] + + +#define I2S_LL_ETM_TASK_TABLE(i2s_port, chan_dir, task) \ + (uint32_t[SOC_I2S_NUM][2][I2S_ETM_TASK_MAX]){{ \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_TASK_START] = I2S_TASK_START_RX, \ + [I2S_ETM_TASK_STOP] = I2S_TASK_STOP_RX, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_TASK_START] = I2S_TASK_START_TX, \ + [I2S_ETM_TASK_STOP] = I2S_TASK_STOP_TX, \ + }}}[i2s_port][(chan_dir) - 1][task] +#define I2S_LL_ETM_MAX_THRESH_NUM (0x3FFUL) + /** * * @param i2s_id The port id of I2S @@ -467,7 +492,7 @@ static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num) } /** - * @brief Congfigure TX chan bit and audio data bit + * @brief Configure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width @@ -480,7 +505,7 @@ static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int } /** - * @brief Congfigure RX chan bit and audio data bit + * @brief Configure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width @@ -880,11 +905,11 @@ static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f } /** - * @brief Get I2S TX PDM fp configuration paramater + * @brief Get I2S TX PDM fp configuration parameter * * @param hw Peripheral I2S hardware instance address. * @return - * - fp configuration paramater + * - fp configuration parameter */ static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) { @@ -892,11 +917,11 @@ static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) } /** - * @brief Get I2S TX PDM fs configuration paramater + * @brief Get I2S TX PDM fs configuration parameter * * @param hw Peripheral I2S hardware instance address. * @return - * - fs configuration paramater + * - fs configuration parameter */ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) { @@ -922,7 +947,7 @@ static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) * @brief Configura TX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param pcm_cfg PCM configuration paramater + * @param pcm_cfg PCM configuration parameter */ static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { @@ -934,7 +959,7 @@ static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_ * @brief Configure RX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param pcm_cfg PCM configuration paramater + * @param pcm_cfg PCM configuration parameter */ static inline void i2s_ll_rx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { @@ -1106,7 +1131,7 @@ static inline void i2s_ll_tx_pdm_dma_take_mode(i2s_dev_t *hw, bool is_mono, bool * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) * @param is_copy Whether the un-selected slot copies the data from the selected one * If not, the un-selected slot will transmit the data from 'conf_single_data' - * @param mask The slot mask to selet the slot + * @param mask The slot mask to select the slot */ static inline void i2s_ll_tx_pdm_slot_mode(i2s_dev_t *hw, bool is_mono, bool is_copy, i2s_pdm_slot_mask_t mask) { @@ -1139,6 +1164,28 @@ static inline void i2s_ll_tx_pdm_line_mode(i2s_dev_t *hw, i2s_pdm_tx_line_mode_t hw->tx_pcm2pdm_conf.tx_pdm_dac_2out_en = line_mode != I2S_PDM_TX_ONE_LINE_DAC; } +/** + * @brief Set the TX ETM threshold of REACH_THRESH event + * + * @param hw Peripheral I2S hardware instance address. + * @param thresh The threshold that send + */ +static inline void i2s_ll_tx_set_etm_threshold(i2s_dev_t *hw, uint32_t thresh) +{ + hw->etm_conf.etm_tx_send_word_num = thresh; +} + +/** + * @brief Set the RX ETM threshold of REACH_THRESH event + * + * @param hw Peripheral I2S hardware instance address. + * @param thresh The threshold that received + */ +static inline void i2s_ll_rx_set_etm_threshold(i2s_dev_t *hw, uint32_t thresh) +{ + hw->etm_conf.etm_rx_receive_word_num = thresh; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32p4/include/hal/etm_ll.h b/components/hal/esp32p4/include/hal/etm_ll.h index 12e11d6432..50ef1a91e7 100644 --- a/components/hal/esp32p4/include/hal/etm_ll.h +++ b/components/hal/esp32p4/include/hal/etm_ll.h @@ -18,6 +18,8 @@ extern "C" { #endif +#define ETM_LL_SUPPORT_STATUS 1 // Support to get and clear the status of the ETM event and task + /** * @brief Enable the bus clock for ETM module * diff --git a/components/hal/esp32p4/include/hal/i2s_ll.h b/components/hal/esp32p4/include/hal/i2s_ll.h index a5fd58c118..a9009a0b94 100644 --- a/components/hal/esp32p4/include/hal/i2s_ll.h +++ b/components/hal/esp32p4/include/hal/i2s_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,7 +17,9 @@ #include "hal/assert.h" #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" +#include "soc/soc_etm_struct.h" #include "soc/hp_sys_clkrst_struct.h" +#include "soc/soc_etm_source.h" #include "hal/i2s_types.h" #include "hal/hal_utils.h" @@ -38,6 +40,77 @@ extern "C" { #define I2S_LL_XTAL_CLK_FREQ (40 * 1000000) // XTAL_CLK: 40MHz #define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_XTAL_CLK_FREQ // No PLL clock source on P4, use XTAL as default +#define I2S_LL_ETM_EVENT_TABLE(i2s_port, chan_dir, event) \ + (uint32_t[SOC_I2S_NUM][2][I2S_ETM_EVENT_MAX]){ \ + [0] = { \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S0_EVT_RX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S0_EVT_X_WORDS_RECEIVED, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S0_EVT_TX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S0_EVT_X_WORDS_SENT, \ + }, \ + }, \ + [1] = { \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S1_EVT_RX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S1_EVT_X_WORDS_RECEIVED, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S1_EVT_TX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S1_EVT_X_WORDS_SENT, \ + }, \ + }, \ + [2] = { \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S2_EVT_RX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S2_EVT_X_WORDS_RECEIVED, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_EVENT_DONE] = I2S2_EVT_TX_DONE, \ + [I2S_ETM_EVENT_REACH_THRESH] = I2S2_EVT_X_WORDS_SENT, \ + }, \ + }, \ + }[i2s_port][(chan_dir) - 1][event] + + +#define I2S_LL_ETM_TASK_TABLE(i2s_port, chan_dir, task) \ + (uint32_t[SOC_I2S_NUM][2][I2S_ETM_TASK_MAX]){ \ + [0] = { \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_TASK_START] = I2S0_TASK_START_RX, \ + [I2S_ETM_TASK_STOP] = I2S0_TASK_STOP_RX, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_TASK_START] = I2S0_TASK_START_TX, \ + [I2S_ETM_TASK_STOP] = I2S0_TASK_STOP_TX, \ + }, \ + }, \ + [1] = { \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_TASK_START] = I2S1_TASK_START_RX, \ + [I2S_ETM_TASK_STOP] = I2S1_TASK_STOP_RX, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_TASK_START] = I2S1_TASK_START_TX, \ + [I2S_ETM_TASK_STOP] = I2S1_TASK_STOP_TX, \ + }, \ + }, \ + [2] = { \ + [I2S_DIR_RX - 1] = { \ + [I2S_ETM_TASK_START] = I2S2_TASK_START_RX, \ + [I2S_ETM_TASK_STOP] = I2S2_TASK_STOP_RX, \ + }, \ + [I2S_DIR_TX - 1] = { \ + [I2S_ETM_TASK_START] = I2S2_TASK_START_TX, \ + [I2S_ETM_TASK_STOP] = I2S2_TASK_STOP_TX, \ + }, \ + }, \ + }[i2s_port][(chan_dir) - 1][task] + +#define I2S_LL_ETM_MAX_THRESH_NUM (0x3FFFUL) + /** * @brief Enable the bus clock for I2S module * @@ -638,7 +711,7 @@ static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num) } /** - * @brief Congfigure TX chan bit and audio data bit + * @brief Configure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width @@ -651,7 +724,7 @@ static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int } /** - * @brief Congfigure RX chan bit and audio data bit + * @brief Configure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. * @param chan_bit The chan bit width @@ -1052,11 +1125,11 @@ static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t f } /** - * @brief Get I2S TX PDM fp configuration paramater + * @brief Get I2S TX PDM fp configuration parameter * * @param hw Peripheral I2S hardware instance address. * @return - * - fp configuration paramater + * - fp configuration parameter */ static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) { @@ -1064,11 +1137,11 @@ static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) } /** - * @brief Get I2S TX PDM fs configuration paramater + * @brief Get I2S TX PDM fs configuration parameter * * @param hw Peripheral I2S hardware instance address. * @return - * - fs configuration paramater + * - fs configuration parameter */ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) { @@ -1091,7 +1164,7 @@ static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw) * @brief Configure RX PDM downsample * * @param hw Peripheral I2S hardware instance address. - * @param dsr PDM downsample configuration paramater + * @param dsr PDM downsample configuration parameter */ static inline void i2s_ll_rx_set_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) { @@ -1164,7 +1237,7 @@ static inline void i2s_ll_rx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) * @brief Configura TX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param pcm_cfg PCM configuration paramater + * @param pcm_cfg PCM configuration parameter */ static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { @@ -1176,7 +1249,7 @@ static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_ * @brief Configure RX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param pcm_cfg PCM configuration paramater + * @param pcm_cfg PCM configuration parameter */ static inline void i2s_ll_rx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { @@ -1348,7 +1421,7 @@ static inline void i2s_ll_tx_pdm_dma_take_mode(i2s_dev_t *hw, bool is_mono, bool * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) * @param is_copy Whether the un-selected slot copies the data from the selected one * If not, the un-selected slot will transmit the data from 'conf_single_data' - * @param mask The slot mask to selet the slot + * @param mask The slot mask to select the slot */ static inline void i2s_ll_tx_pdm_slot_mode(i2s_dev_t *hw, bool is_mono, bool is_copy, i2s_pdm_slot_mask_t mask) { @@ -1431,6 +1504,120 @@ static inline uint32_t i2s_ll_tx_get_bclk_sync_count(i2s_dev_t *hw) return hw->bck_cnt.tx_bck_cnt; } +/** + * @brief Set the TX ETM threshold of REACH_THRESH event + * + * @param hw Peripheral I2S hardware instance address. + * @param thresh The threshold that send + */ +static inline void i2s_ll_tx_set_etm_threshold(i2s_dev_t *hw, uint32_t thresh) +{ + hw->etm_conf.etm_tx_send_word_num = thresh; +} + +/** + * @brief Set the RX ETM threshold of REACH_THRESH event + * + * @param hw Peripheral I2S hardware instance address. + * @param thresh The threshold that received + */ +static inline void i2s_ll_rx_set_etm_threshold(i2s_dev_t *hw, uint32_t thresh) +{ + hw->etm_conf.etm_rx_receive_word_num = thresh; +} + +/** + * @brief Get I2S ETM TX done event status + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - true TX done event triggered + * - false TX done event not triggered + */ +static inline bool i2s_ll_get_etm_tx_done_event_status(i2s_dev_t *hw) +{ + uint32_t i2s_id = I2S_LL_GET_ID(hw); + switch (i2s_id) { + case 0: + return SOC_ETM.evt_st4.i2s0_evt_tx_done_st; + case 1: + return SOC_ETM.evt_st4.i2s1_evt_tx_done_st; + case 2: + return SOC_ETM.evt_st4.i2s2_evt_tx_done_st; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Get I2S ETM TX done event status + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - true TX done event triggered + * - false TX done event not triggered + */ +static inline bool i2s_ll_get_etm_rx_done_event_status(i2s_dev_t *hw) +{ + uint32_t i2s_id = I2S_LL_GET_ID(hw); + switch (i2s_id) { + case 0: + return SOC_ETM.evt_st4.i2s0_evt_rx_done_st; + case 1: + return SOC_ETM.evt_st4.i2s1_evt_rx_done_st; + case 2: + return SOC_ETM.evt_st4.i2s2_evt_rx_done_st; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Get I2S ETM TX done event status + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - true TX done event triggered + * - false TX done event not triggered + */ +static inline bool i2s_ll_get_etm_tx_threshold_event_status(i2s_dev_t *hw) +{ + uint32_t i2s_id = I2S_LL_GET_ID(hw); + switch (i2s_id) { + case 0: + return SOC_ETM.evt_st4.i2s0_evt_x_words_sent_st; + case 1: + return SOC_ETM.evt_st4.i2s1_evt_x_words_sent_st; + case 2: + return SOC_ETM.evt_st4.i2s2_evt_x_words_sent_st; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Get I2S ETM TX done event status + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - true TX done event triggered + * - false TX done event not triggered + */ +static inline bool i2s_ll_get_etm_rx_threshold_event_status(i2s_dev_t *hw) +{ + uint32_t i2s_id = I2S_LL_GET_ID(hw); + switch (i2s_id) { + case 0: + return SOC_ETM.evt_st4.i2s0_evt_x_words_received_st; + case 1: + return SOC_ETM.evt_st4.i2s1_evt_x_words_received_st; + case 2: + return SOC_ETM.evt_st4.i2s2_evt_x_words_received_st; + default: + HAL_ASSERT(false); + } +} + #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index 68ca08c3b2..4df488f14f 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -98,7 +98,7 @@ typedef enum { #if SOC_I2S_SUPPORTS_PDM_TX /** - * @brief pdm tx singnal scaling mode + * @brief pdm tx signal scaling mode */ typedef enum { I2S_PDM_SIG_SCALING_DIV_2 = 0, /*!< I2S TX PDM signal scaling: /2 */ @@ -124,7 +124,7 @@ typedef enum { /** * @brief I2S slot select in standard mode - * @note It has different meanings in tx/rx/mono/stereo mode, and it may have differen behaviors on different targets + * @note It has different meanings in tx/rx/mono/stereo mode, and it may have different behaviors on different targets * For the details, please refer to the I2S API reference */ typedef enum { @@ -184,6 +184,34 @@ typedef enum { } i2s_tdm_slot_mask_t; #endif // SOC_I2S_SUPPORTS_TDM +/** + * @brief I2S channel events that supported by the ETM module + */ +typedef enum { + /** Trigger condition: + * TX: no data to send in the TX FIFO, i.e., DMA need to stop (next desc is NULL) + * RX: 1. If rx_stop_mode = 0, this event will trigger when DMA is stopped (next desc is NULL) + * 2. If rx_stop_mode = 1, this event will trigger when DMA in_suc_eof. + * 3. If rx_stop_mode = 2, this event will trigger when RX FIFO is full. + */ + I2S_ETM_EVENT_DONE, /*!< Event that I2S TX or RX stopped */ + /** Trigger condition: + * TX: the sent words(in 32-bit) number reach the threshold that configured in `etm_tx_send_word_num` + * RX: the received words(in 32-bit) number reach the threshold that configured in `etm_rx_receive_word_num` + * and `etm_rx_receive_word_num` should be smaller than the size of the DMA buffer in one `in_suc_eof` event. + */ + I2S_ETM_EVENT_REACH_THRESH, /*!< Event that the I2S sent or received data reached the threshold */ + I2S_ETM_EVENT_MAX, /*!< Maximum number of events */ +} i2s_etm_event_type_t; + +/** + * @brief I2S channel tasks that supported by the ETM module + */ +typedef enum { + I2S_ETM_TASK_START, /*!< Start the I2S channel */ + I2S_ETM_TASK_STOP, /*!< Stop the I2S channel */ + I2S_ETM_TASK_MAX, /*!< Maximum number of tasks */ +} i2s_etm_task_type_t; #ifdef __cplusplus } diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index fa20d497f7..65333e5c9c 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -555,6 +555,10 @@ config SOC_I2S_HW_VERSION_2 bool default y +config SOC_I2S_SUPPORTS_ETM + bool + default y + config SOC_I2S_SUPPORTS_TX_SYNC_CNT bool default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 07ae6dd52d..8a84f18a84 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -269,6 +269,7 @@ /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (1U) #define SOC_I2S_HW_VERSION_2 (1) +#define SOC_I2S_SUPPORTS_ETM (1) #define SOC_I2S_SUPPORTS_TX_SYNC_CNT (1) // #define SOC_I2S_SUPPORTS_RX_RECOMB (1) //TODO[C5] IDF-9966 #define SOC_I2S_SUPPORTS_XTAL (1) diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 5f0e1d9ee4..077af618ff 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -639,6 +639,10 @@ config SOC_I2S_HW_VERSION_2 bool default y +config SOC_I2S_SUPPORTS_ETM + bool + default y + config SOC_I2S_SUPPORTS_XTAL bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 9a75285a3b..f9fcf1fe02 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -264,6 +264,7 @@ /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (1U) #define SOC_I2S_HW_VERSION_2 (1) +#define SOC_I2S_SUPPORTS_ETM (1) #define SOC_I2S_SUPPORTS_XTAL (1) #define SOC_I2S_SUPPORTS_PLL_F160M (1) #define SOC_I2S_SUPPORTS_PCM (1) diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index e266012a35..e8be302fb5 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -631,6 +631,10 @@ config SOC_I2S_HW_VERSION_2 bool default y +config SOC_I2S_SUPPORTS_ETM + bool + default y + config SOC_I2S_SUPPORTS_XTAL bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 681e566d53..e47941cfd0 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -262,6 +262,7 @@ /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (1U) #define SOC_I2S_HW_VERSION_2 (1) +#define SOC_I2S_SUPPORTS_ETM (1) #define SOC_I2S_SUPPORTS_XTAL (1) #define SOC_I2S_SUPPORTS_PLL_F96M (1) #define SOC_I2S_SUPPORTS_PLL_F64M (1) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index df3a8813b7..407dabbe59 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -755,6 +755,10 @@ config SOC_I2S_HW_VERSION_2 bool default y +config SOC_I2S_SUPPORTS_ETM + bool + default y + config SOC_I2S_SUPPORTS_XTAL bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 9b39b54807..3f9dfd3bd8 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -306,6 +306,7 @@ /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (3U) #define SOC_I2S_HW_VERSION_2 (1) +#define SOC_I2S_SUPPORTS_ETM (1) #define SOC_I2S_SUPPORTS_XTAL (1) // #define SOC_I2S_SUPPORTS_APLL (1) // TODO: IDF-8884 #define SOC_I2S_SUPPORTS_PCM (1)