From f90f05e09b0e4bdae4b709f98883283fe9c119f5 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Thu, 5 Feb 2026 15:11:47 +0800 Subject: [PATCH] feat(mcpwm): ETM support mcpwm timer TEZ/TEP events --- .../include/driver/mcpwm_etm.h | 24 +++- .../include/driver/mcpwm_timer.h | 2 +- components/esp_driver_mcpwm/src/mcpwm_etm.c | 69 +++++++++++- .../test_apps/mcpwm/main/test_mcpwm_etm.c | 105 +++++++++++++++++- .../esp32c5/include/hal/mcpwm_ll.h | 37 +++++- .../esp32c6/include/hal/mcpwm_ll.h | 33 +++++- .../esp32h2/include/hal/mcpwm_ll.h | 33 +++++- .../esp32h4/include/hal/mcpwm_ll.h | 47 +++++++- .../esp32p4/include/hal/mcpwm_ll.h | 38 ++++++- .../esp_hal_mcpwm/include/hal/mcpwm_types.h | 11 +- docs/en/api-reference/peripherals/mcpwm.rst | 4 +- .../zh_CN/api-reference/peripherals/mcpwm.rst | 4 +- 12 files changed, 385 insertions(+), 22 deletions(-) diff --git a/components/esp_driver_mcpwm/include/driver/mcpwm_etm.h b/components/esp_driver_mcpwm/include/driver/mcpwm_etm.h index f9ac6e16e9..bef64d51e0 100644 --- a/components/esp_driver_mcpwm/include/driver/mcpwm_etm.h +++ b/components/esp_driver_mcpwm/include/driver/mcpwm_etm.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,6 +23,13 @@ typedef struct { mcpwm_comparator_etm_event_type_t event_type; /*!< MCPWM comparator ETM event type */ } mcpwm_cmpr_etm_event_config_t; +/** + * @brief MCPWM timer ETM event configuration + */ +typedef struct { + mcpwm_timer_etm_event_type_t event_type; /*!< MCPWM timer ETM event type */ +} mcpwm_timer_etm_event_config_t; + /** * @brief Get the ETM event for MCPWM comparator * @@ -38,6 +45,21 @@ typedef struct { */ esp_err_t mcpwm_comparator_new_etm_event(mcpwm_cmpr_handle_t cmpr, const mcpwm_cmpr_etm_event_config_t *config, esp_etm_event_handle_t *out_event); +/** + * @brief Get the ETM event for MCPWM timer + * + * @note The created ETM event object can be deleted later by calling `esp_etm_del_event` + * + * @param[in] timer MCPWM timer, allocated by `mcpwm_new_timer()` + * @param[in] config MCPWM ETM timer 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_FAIL: Get ETM event failed because of other error + */ +esp_err_t mcpwm_timer_new_etm_event(mcpwm_timer_handle_t timer, const mcpwm_timer_etm_event_config_t *config, esp_etm_event_handle_t *out_event); + #ifdef __cplusplus } #endif diff --git a/components/esp_driver_mcpwm/include/driver/mcpwm_timer.h b/components/esp_driver_mcpwm/include/driver/mcpwm_timer.h index 69a8b7a3b6..4a6aeb3216 100644 --- a/components/esp_driver_mcpwm/include/driver/mcpwm_timer.h +++ b/components/esp_driver_mcpwm/include/driver/mcpwm_timer.h @@ -34,7 +34,7 @@ typedef struct { uint32_t resolution_hz; /*!< Counter resolution in Hz The step size of each count tick equals to (1 / resolution_hz) seconds */ mcpwm_timer_count_mode_t count_mode; /*!< Count mode */ - uint32_t period_ticks; /*!< Number of count ticks within a period */ + uint32_t period_ticks; /*!< Number of count ticks within a period. For up-down mode, the timer peak value is half of the period_ticks */ int intr_priority; /*!< MCPWM timer interrupt priority, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */ struct { diff --git a/components/esp_driver_mcpwm/src/mcpwm_etm.c b/components/esp_driver_mcpwm/src/mcpwm_etm.c index bf1fe7e99f..9cd0258ffa 100644 --- a/components/esp_driver_mcpwm/src/mcpwm_etm.c +++ b/components/esp_driver_mcpwm/src/mcpwm_etm.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,7 +13,13 @@ typedef struct { mcpwm_cmpr_handle_t cmpr; } mcpwm_comparator_etm_event_t; -static esp_err_t mcpwm_del_etm_event(esp_etm_event_t *event) +typedef struct { + esp_etm_event_t base; + mcpwm_timer_handle_t timer; + mcpwm_timer_etm_event_type_t event_type; +} mcpwm_timer_etm_event_t; + +static esp_err_t mcpwm_del_comparator_etm_event(esp_etm_event_t *event) { mcpwm_comparator_etm_event_t *etm_event = __containerof(event, mcpwm_comparator_etm_event_t, base); mcpwm_cmpr_handle_t cmpr = etm_event->cmpr; @@ -39,11 +45,27 @@ static esp_err_t mcpwm_del_etm_event(esp_etm_event_t *event) return ESP_OK; } +static esp_err_t mcpwm_del_timer_etm_event(esp_etm_event_t *event) +{ + mcpwm_timer_etm_event_t *etm_event = __containerof(event, mcpwm_timer_etm_event_t, base); + mcpwm_timer_handle_t timer = etm_event->timer; + mcpwm_group_t *group = timer->group; + mcpwm_hal_context_t *hal = &group->hal; + int timer_id = timer->timer_id; + + portENTER_CRITICAL(&group->spinlock); + mcpwm_ll_etm_enable_timer_event(hal->dev, timer_id, etm_event->event_type, false); + portEXIT_CRITICAL(&group->spinlock); + free(etm_event); + return ESP_OK; +} + esp_err_t mcpwm_comparator_new_etm_event(mcpwm_cmpr_handle_t cmpr, const mcpwm_cmpr_etm_event_config_t *config, esp_etm_event_handle_t *out_event) { esp_err_t ret = ESP_OK; mcpwm_comparator_etm_event_t *event = NULL; ESP_RETURN_ON_FALSE(cmpr && config && out_event, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(config->event_type < MCPWM_CMPR_ETM_EVENT_MAX, ESP_ERR_INVALID_ARG, TAG, "invalid event type"); event = heap_caps_calloc(1, sizeof(mcpwm_comparator_etm_event_t), MCPWM_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(event, ESP_ERR_NO_MEM, TAG, "no memory for ETM event"); @@ -78,14 +100,53 @@ esp_err_t mcpwm_comparator_new_etm_event(mcpwm_cmpr_handle_t cmpr, const mcpwm_c event->cmpr = cmpr; event->base.event_id = event_id; event->base.trig_periph = ETM_TRIG_PERIPH_MCPWM; - event->base.del = mcpwm_del_etm_event; + event->base.del = mcpwm_del_comparator_etm_event; *out_event = &event->base; return ESP_OK; err: if (event) { - mcpwm_del_etm_event(&event->base); + mcpwm_del_comparator_etm_event(&event->base); + } + return ret; +} + +esp_err_t mcpwm_timer_new_etm_event(mcpwm_timer_handle_t timer, const mcpwm_timer_etm_event_config_t *config, esp_etm_event_handle_t *out_event) +{ + esp_err_t ret = ESP_OK; + mcpwm_timer_etm_event_t *event = NULL; + ESP_RETURN_ON_FALSE(timer && config && out_event, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(config->event_type < MCPWM_TIMER_ETM_EVENT_MAX, ESP_ERR_INVALID_ARG, TAG, "invalid event type"); + event = heap_caps_calloc(1, sizeof(mcpwm_timer_etm_event_t), MCPWM_MEM_ALLOC_CAPS); + ESP_RETURN_ON_FALSE(event, ESP_ERR_NO_MEM, TAG, "no memory for ETM event"); + + mcpwm_group_t *group = timer->group; + mcpwm_hal_context_t *hal = &group->hal; + int group_id = group->group_id; + int timer_id = timer->timer_id; + uint32_t event_id = 0; + + portENTER_CRITICAL(&group->spinlock); + mcpwm_ll_etm_enable_timer_event(hal->dev, timer_id, config->event_type, true); + portEXIT_CRITICAL(&group->spinlock); + event_id = MCPWM_LL_TIMER_ETM_EVENT_TABLE(group_id, timer_id, config->event_type); + event->event_type = config->event_type; + ESP_GOTO_ON_FALSE(event_id != 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "not supported event type"); + ESP_LOGD(TAG, "MCPWM (%d) timer (%d) event_id (%"PRId32")", group_id, timer_id, event_id); + + // fill the ETM event object + event->timer = timer; + event->base.event_id = event_id; + event->base.trig_periph = ETM_TRIG_PERIPH_MCPWM; + event->base.del = mcpwm_del_timer_etm_event; + + *out_event = &event->base; + return ESP_OK; + +err: + if (event) { + mcpwm_del_timer_etm_event(&event->base); } return ret; } diff --git a/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_etm.c b/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_etm.c index 3a40f9994a..2339ff029c 100644 --- a/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_etm.c +++ b/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_etm.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +9,7 @@ #include "unity.h" #include "unity_test_utils.h" #include "esp_attr.h" +#include "hal/mcpwm_ll.h" #include "driver/gptimer_etm.h" #include "driver/gptimer.h" #include "driver/gpio.h" @@ -18,9 +19,11 @@ TEST_CASE("mcpwm_comparator_etm_event", "[mcpwm][etm]") { // MCPWM cmpra -------------------------------------> ETM channel A ---> GPTimer start // MCPWM cmprb / evt_cmpra (if support evt_cmpr) ---> ETM channel B ---> GPTimer stop + // Use the last MCPWM group (e.g. group_id=1 when MCPWM_LL_GROUP_NUM==2) to test multi-group chips + const int mcpwm_group_id = MCPWM_LL_GET(GROUP_NUM) - 1; mcpwm_timer_config_t timer_config = { - .group_id = 0, + .group_id = mcpwm_group_id, .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT, .resolution_hz = 1 * 1000 * 1000, .count_mode = MCPWM_TIMER_COUNT_MODE_UP, @@ -30,7 +33,7 @@ TEST_CASE("mcpwm_comparator_etm_event", "[mcpwm][etm]") TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer)); mcpwm_operator_config_t operator_config = { - .group_id = 0, + .group_id = mcpwm_group_id, }; mcpwm_oper_handle_t oper = NULL; TEST_ESP_OK(mcpwm_new_operator(&operator_config, &oper)); @@ -151,3 +154,99 @@ TEST_CASE("mcpwm_comparator_etm_event", "[mcpwm][etm]") TEST_ESP_OK(mcpwm_del_operator(oper)); TEST_ESP_OK(mcpwm_del_timer(timer)); } + +TEST_CASE("mcpwm_timer_etm_event", "[mcpwm][etm]") +{ + // MCPWM timer TEP (timer equals peak) ---> ETM channel A ---> GPTimer start + // MCPWM timer TEZ (timer equals zero) ---> ETM channel B ---> GPTimer stop + // Using UP_DOWN count mode, the timer counts: 0 -> peak -> 0 -> peak -> ... + // GPTimer starts at TEP and stops at TEZ, so it measures the time from peak to 0 + // Use the last MCPWM group (e.g. group_id=1 when MCPWM_LL_GROUP_NUM==2) to test multi-group chips + const int mcpwm_group_id = MCPWM_LL_GET(GROUP_NUM) - 1; + + printf("create mcpwm timer\r\n"); + const uint32_t timer_resolution = 1 * 1000 * 1000; // 1MHz, 1 tick = 1us + const uint32_t period_ticks = 10000; // For UP_DOWN mode, peak = period_ticks / 2 = 5000 + mcpwm_timer_config_t timer_config = { + .group_id = mcpwm_group_id, + .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT, + .resolution_hz = timer_resolution, + .count_mode = MCPWM_TIMER_COUNT_MODE_UP_DOWN, + .period_ticks = period_ticks, + }; + mcpwm_timer_handle_t mcpwm_timer = NULL; + TEST_ESP_OK(mcpwm_new_timer(&timer_config, &mcpwm_timer)); + TEST_ESP_OK(mcpwm_timer_enable(mcpwm_timer)); + + printf("create mcpwm timer etm event\r\n"); + esp_etm_event_handle_t mcpwm_timer_event_tez = NULL; + esp_etm_event_handle_t mcpwm_timer_event_tep = NULL; + mcpwm_timer_etm_event_config_t timer_etm_event_config = { + .event_type = MCPWM_TIMER_ETM_EVENT_TEZ, + }; + TEST_ESP_OK(mcpwm_timer_new_etm_event(mcpwm_timer, &timer_etm_event_config, &mcpwm_timer_event_tez)); + timer_etm_event_config.event_type = MCPWM_TIMER_ETM_EVENT_TEP; + TEST_ESP_OK(mcpwm_timer_new_etm_event(mcpwm_timer, &timer_etm_event_config, &mcpwm_timer_event_tep)); + + printf("create gptimer\r\n"); + gptimer_handle_t gptimer = NULL; + gptimer_config_t gptimer_config = { + .clk_src = GPTIMER_CLK_SRC_DEFAULT, + .direction = GPTIMER_COUNT_UP, + .resolution_hz = timer_resolution, // Same resolution as MCPWM timer + }; + TEST_ESP_OK(gptimer_new_timer(&gptimer_config, &gptimer)); + + printf("create gptimer etm task\r\n"); + esp_etm_task_handle_t gptimer_task_start = NULL; + esp_etm_task_handle_t gptimer_task_stop = NULL; + gptimer_etm_task_config_t gptimer_etm_task_conf = { + .task_type = GPTIMER_ETM_TASK_START_COUNT, + }; + TEST_ESP_OK(gptimer_new_etm_task(gptimer, &gptimer_etm_task_conf, &gptimer_task_start)); + gptimer_etm_task_conf.task_type = GPTIMER_ETM_TASK_STOP_COUNT; + TEST_ESP_OK(gptimer_new_etm_task(gptimer, &gptimer_etm_task_conf, &gptimer_task_stop)); + TEST_ESP_OK(gptimer_enable(gptimer)); + + printf("create and connect etm channels\r\n"); + esp_etm_channel_config_t etm_config = {}; + esp_etm_channel_handle_t etm_channel_a = NULL; + esp_etm_channel_handle_t etm_channel_b = NULL; + TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_a)); + TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_b)); + // TEP -> start gptimer, TEZ -> stop gptimer + TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, mcpwm_timer_event_tep, gptimer_task_start)); + TEST_ESP_OK(esp_etm_channel_connect(etm_channel_b, mcpwm_timer_event_tez, gptimer_task_stop)); + TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a)); + TEST_ESP_OK(esp_etm_channel_enable(etm_channel_b)); + + printf("start mcpwm timer and let it run for multiple periods\r\n"); + TEST_ESP_OK(mcpwm_timer_start_stop(mcpwm_timer, MCPWM_TIMER_START_NO_STOP)); + esp_rom_delay_us(100 * 1000); // Let it run for 100ms + TEST_ESP_OK(mcpwm_timer_start_stop(mcpwm_timer, MCPWM_TIMER_STOP_EMPTY)); + + printf("verify gptimer count value\r\n"); + uint64_t gptimer_count = 0; + TEST_ESP_OK(gptimer_get_raw_count(gptimer, &gptimer_count)); + printf("gptimer_count: %"PRIu64"\r\n", gptimer_count); + // In UP_DOWN mode with period_ticks=10000: + // - One full cycle (0->peak->0) takes 10000 ticks + // - Peak value is period_ticks/2 = 5000 + // - GPTimer accumulates: 10 cycles * 5000 ticks = 50000 ticks + const uint32_t expected_count = (100 * 1000 / period_ticks) * (period_ticks / 2); + TEST_ASSERT_UINT_WITHIN(500, expected_count, gptimer_count); + + printf("cleanup\r\n"); + TEST_ESP_OK(gptimer_disable(gptimer)); + TEST_ESP_OK(gptimer_del_timer(gptimer)); + TEST_ESP_OK(esp_etm_channel_disable(etm_channel_a)); + TEST_ESP_OK(esp_etm_channel_disable(etm_channel_b)); + TEST_ESP_OK(esp_etm_del_task(gptimer_task_start)); + TEST_ESP_OK(esp_etm_del_task(gptimer_task_stop)); + TEST_ESP_OK(esp_etm_del_event(mcpwm_timer_event_tez)); + TEST_ESP_OK(esp_etm_del_event(mcpwm_timer_event_tep)); + TEST_ESP_OK(esp_etm_del_channel(etm_channel_a)); + TEST_ESP_OK(esp_etm_del_channel(etm_channel_b)); + TEST_ESP_OK(mcpwm_timer_disable(mcpwm_timer)); + TEST_ESP_OK(mcpwm_del_timer(mcpwm_timer)); +} diff --git a/components/esp_hal_mcpwm/esp32c5/include/hal/mcpwm_ll.h b/components/esp_hal_mcpwm/esp32c5/include/hal/mcpwm_ll.h index 02944ddc62..751601c81d 100644 --- a/components/esp_hal_mcpwm/esp32c5/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32c5/include/hal/mcpwm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ #include #include "soc/soc_caps.h" #include "soc/mcpwm_struct.h" +#include "soc/mcpwm_reg.h" #include "soc/clk_tree_defs.h" #include "soc/pcr_struct.h" #include "hal/mcpwm_types.h" @@ -69,9 +70,16 @@ extern "C" { #define MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) ((uint8_t[]) {0, 1, 2, 3}[(action)]) #define MCPWM_LL_BRAKE_MODE_TO_REG_VAL(mode) ((uint8_t[]) {0, 1}[(mode)]) +// MCPWM ETM timer event table +#define MCPWM_LL_TIMER_ETM_EVENT_TABLE(group, timer_id, event) \ + (uint32_t[1][MCPWM_TIMER_ETM_EVENT_MAX]){{ \ + [MCPWM_TIMER_ETM_EVENT_TEZ] = MCPWM0_EVT_TIMER0_TEZ + timer_id, \ + [MCPWM_TIMER_ETM_EVENT_TEP] = MCPWM0_EVT_TIMER0_TEP + timer_id, \ + }}[group][event] + // MCPWM ETM comparator event table #define MCPWM_LL_ETM_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \ - (uint32_t[2][MCPWM_CMPR_ETM_EVENT_MAX]){ \ + (uint32_t[1][MCPWM_CMPR_ETM_EVENT_MAX]){ \ { \ [MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM0_EVT_OP0_TEA + oper_id + 3 * cmpr_id, \ }, \ @@ -79,7 +87,7 @@ extern "C" { // MCPWM ETM event comparator event table #define MCPWM_LL_ETM_EVENT_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \ - (uint32_t[2][MCPWM_CMPR_ETM_EVENT_MAX]){ \ + (uint32_t[1][MCPWM_CMPR_ETM_EVENT_MAX]){ \ { \ [MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM0_EVT_OP0_TEE1 + oper_id + 3 * cmpr_id, \ }, \ @@ -1699,6 +1707,29 @@ static inline void mcpwm_ll_etm_enable_evt_comparator_event(mcpwm_dev_t *mcpwm, } } +/** + * @brief Enable timer ETM event + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param event_type Timer ETM event type (TEZ or TEP) + * @param en True: enable ETM module, False: disable ETM module + */ +static inline void mcpwm_ll_etm_enable_timer_event(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_etm_event_type_t event_type, bool en) +{ + uint32_t bit_offset; + if (event_type == MCPWM_TIMER_ETM_EVENT_TEZ) { + bit_offset = timer_id + MCPWM_EVT_TIMER0_TEZ_EN_S; + } else { // MCPWM_TIMER_ETM_EVENT_TEP + bit_offset = timer_id + MCPWM_EVT_TIMER0_TEP_EN_S; + } + if (en) { + mcpwm->evt_en.val |= 1 << bit_offset; + } else { + mcpwm->evt_en.val &= ~(1 << bit_offset); + } +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_mcpwm/esp32c6/include/hal/mcpwm_ll.h b/components/esp_hal_mcpwm/esp32c6/include/hal/mcpwm_ll.h index b83037e51e..90b95c5849 100644 --- a/components/esp_hal_mcpwm/esp32c6/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32c6/include/hal/mcpwm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,6 +17,7 @@ #include #include "soc/soc_caps.h" #include "soc/mcpwm_struct.h" +#include "soc/mcpwm_reg.h" #include "soc/clk_tree_defs.h" #include "soc/pcr_struct.h" #include "hal/mcpwm_types.h" @@ -75,6 +76,13 @@ extern "C" { #define MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) ((uint8_t[]) {0, 1, 2, 3}[(action)]) #define MCPWM_LL_BRAKE_MODE_TO_REG_VAL(mode) ((uint8_t[]) {0, 1}[(mode)]) +// MCPWM ETM timer event table +#define MCPWM_LL_TIMER_ETM_EVENT_TABLE(group, timer_id, event) \ + (uint32_t[1][MCPWM_TIMER_ETM_EVENT_MAX]){{ \ + [MCPWM_TIMER_ETM_EVENT_TEZ] = MCPWM_EVT_TIMER0_TEZ + timer_id, \ + [MCPWM_TIMER_ETM_EVENT_TEP] = MCPWM_EVT_TIMER0_TEP + timer_id, \ + }}[group][event] + // MCPWM ETM comparator event table #define MCPWM_LL_ETM_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \ (uint32_t [1][MCPWM_CMPR_ETM_EVENT_MAX]){{ \ @@ -1659,6 +1667,29 @@ static inline void mcpwm_ll_etm_enable_comparator_event(mcpwm_dev_t *mcpwm, int } } +/** + * @brief Enable timer ETM event + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param event_type Timer ETM event type (TEZ or TEP) + * @param en True: enable ETM module, False: disable ETM module + */ +static inline void mcpwm_ll_etm_enable_timer_event(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_etm_event_type_t event_type, bool en) +{ + uint32_t bit_offset; + if (event_type == MCPWM_TIMER_ETM_EVENT_TEZ) { + bit_offset = timer_id + MCPWM_EVT_TIMER0_TEZ_EN_S; + } else { // MCPWM_TIMER_ETM_EVENT_TEP + bit_offset = timer_id + MCPWM_EVT_TIMER0_TEP_EN_S; + } + if (en) { + mcpwm->evt_en.val |= 1 << bit_offset; + } else { + mcpwm->evt_en.val &= ~(1 << bit_offset); + } +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_mcpwm/esp32h2/include/hal/mcpwm_ll.h b/components/esp_hal_mcpwm/esp32h2/include/hal/mcpwm_ll.h index ce536a12e5..cb08533b7f 100644 --- a/components/esp_hal_mcpwm/esp32h2/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32h2/include/hal/mcpwm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ #include #include "soc/soc_caps.h" #include "soc/mcpwm_struct.h" +#include "soc/mcpwm_reg.h" #include "soc/clk_tree_defs.h" #include "soc/pcr_struct.h" #include "hal/mcpwm_types.h" @@ -73,6 +74,13 @@ extern "C" { #define MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) ((uint8_t[]) {0, 1, 2, 3}[(action)]) #define MCPWM_LL_BRAKE_MODE_TO_REG_VAL(mode) ((uint8_t[]) {0, 1}[(mode)]) +// MCPWM ETM timer event table +#define MCPWM_LL_TIMER_ETM_EVENT_TABLE(group, timer_id, event) \ + (uint32_t[1][MCPWM_TIMER_ETM_EVENT_MAX]){{ \ + [MCPWM_TIMER_ETM_EVENT_TEZ] = MCPWM_EVT_TIMER0_TEZ + timer_id, \ + [MCPWM_TIMER_ETM_EVENT_TEP] = MCPWM_EVT_TIMER0_TEP + timer_id, \ + }}[group][event] + // MCPWM ETM comparator event table #define MCPWM_LL_ETM_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \ (uint32_t [1][MCPWM_CMPR_ETM_EVENT_MAX]){{ \ @@ -1657,6 +1665,29 @@ static inline void mcpwm_ll_etm_enable_comparator_event(mcpwm_dev_t *mcpwm, int } } +/** + * @brief Enable timer ETM event + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param event_type Timer ETM event type (TEZ or TEP) + * @param en True: enable ETM module, False: disable ETM module + */ +static inline void mcpwm_ll_etm_enable_timer_event(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_etm_event_type_t event_type, bool en) +{ + uint32_t bit_offset; + if (event_type == MCPWM_TIMER_ETM_EVENT_TEZ) { + bit_offset = timer_id + MCPWM_EVT_TIMER0_TEZ_EN_S; + } else { // MCPWM_TIMER_ETM_EVENT_TEP + bit_offset = timer_id + MCPWM_EVT_TIMER0_TEP_EN_S; + } + if (en) { + mcpwm->evt_en.val |= 1 << bit_offset; + } else { + mcpwm->evt_en.val &= ~(1 << bit_offset); + } +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_mcpwm/esp32h4/include/hal/mcpwm_ll.h b/components/esp_hal_mcpwm/esp32h4/include/hal/mcpwm_ll.h index ec0f1ba5a2..56302c1e13 100644 --- a/components/esp_hal_mcpwm/esp32h4/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32h4/include/hal/mcpwm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ #include #include "soc/soc_caps.h" #include "soc/mcpwm_struct.h" +#include "soc/mcpwm_reg.h" #include "soc/clk_tree_defs.h" #include "soc/pcr_struct.h" #include "hal/mcpwm_types.h" @@ -69,12 +70,28 @@ extern "C" { #define MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) ((uint8_t[]) {0, 1, 2, 3}[(action)]) #define MCPWM_LL_BRAKE_MODE_TO_REG_VAL(mode) ((uint8_t[]) {0, 1}[(mode)]) +// MCPWM ETM timer event table +#define MCPWM_LL_TIMER_ETM_EVENT_TABLE(group, timer_id, event) \ + (uint32_t[2][MCPWM_TIMER_ETM_EVENT_MAX]){ \ + { \ + [MCPWM_TIMER_ETM_EVENT_TEZ] = MCPWM0_EVT_TIMER0_TEZ + timer_id, \ + [MCPWM_TIMER_ETM_EVENT_TEP] = MCPWM0_EVT_TIMER0_TEP + timer_id, \ + }, \ + { \ + [MCPWM_TIMER_ETM_EVENT_TEZ] = MCPWM1_EVT_TIMER0_TEZ + timer_id, \ + [MCPWM_TIMER_ETM_EVENT_TEP] = MCPWM1_EVT_TIMER0_TEP + timer_id, \ + }, \ + }[group][event] + // MCPWM ETM comparator event table #define MCPWM_LL_ETM_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \ (uint32_t[2][MCPWM_CMPR_ETM_EVENT_MAX]){ \ { \ [MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM0_EVT_OP0_TEA + oper_id + 3 * cmpr_id, \ }, \ + { \ + [MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM1_EVT_OP0_TEA + oper_id + 3 * cmpr_id, \ + }, \ }[group][event] // MCPWM ETM event comparator event table @@ -82,7 +99,10 @@ extern "C" { (uint32_t[2][MCPWM_CMPR_ETM_EVENT_MAX]){ \ { \ [MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM0_EVT_OP0_TEE1 + oper_id + 3 * cmpr_id, \ - }, \ + }, \ + { \ + [MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM1_EVT_OP0_TEE1 + oper_id + 3 * cmpr_id, \ + }, \ }[group][event] /** @@ -1717,6 +1737,29 @@ static inline void mcpwm_ll_etm_enable_evt_comparator_event(mcpwm_dev_t *mcpwm, } } +/** + * @brief Enable timer ETM event + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param event_type Timer ETM event type (TEZ or TEP) + * @param en True: enable ETM module, False: disable ETM module + */ +static inline void mcpwm_ll_etm_enable_timer_event(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_etm_event_type_t event_type, bool en) +{ + uint32_t bit_offset; + if (event_type == MCPWM_TIMER_ETM_EVENT_TEZ) { + bit_offset = timer_id + MCPWM_EVT_TIMER0_TEZ_EN_S; + } else { // MCPWM_TIMER_ETM_EVENT_TEP + bit_offset = timer_id + MCPWM_EVT_TIMER0_TEP_EN_S; + } + if (en) { + mcpwm->evt_en.val |= 1 << bit_offset; + } else { + mcpwm->evt_en.val &= ~(1 << bit_offset); + } +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_mcpwm/esp32p4/include/hal/mcpwm_ll.h b/components/esp_hal_mcpwm/esp32p4/include/hal/mcpwm_ll.h index 311ae07d60..b5a6db0e3b 100644 --- a/components/esp_hal_mcpwm/esp32p4/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32p4/include/hal/mcpwm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,7 @@ #include #include "soc/soc_caps.h" #include "soc/mcpwm_struct.h" +#include "soc/mcpwm_reg.h" #include "soc/clk_tree_defs.h" #include "soc/hp_sys_clkrst_struct.h" #include "hal/mcpwm_types.h" @@ -77,6 +78,18 @@ extern "C" { #define MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) ((uint8_t[]) {0, 1, 2, 3}[(action)]) #define MCPWM_LL_BRAKE_MODE_TO_REG_VAL(mode) ((uint8_t[]) {0, 1}[(mode)]) +#define MCPWM_LL_TIMER_ETM_EVENT_TABLE(group, timer_id, event) \ + (uint32_t[2][MCPWM_TIMER_ETM_EVENT_MAX]){ \ + { \ + [MCPWM_TIMER_ETM_EVENT_TEZ] = MCPWM0_EVT_TIMER0_TEZ + timer_id, \ + [MCPWM_TIMER_ETM_EVENT_TEP] = MCPWM0_EVT_TIMER0_TEP + timer_id, \ + }, \ + { \ + [MCPWM_TIMER_ETM_EVENT_TEZ] = MCPWM1_EVT_TIMER0_TEZ + timer_id, \ + [MCPWM_TIMER_ETM_EVENT_TEP] = MCPWM1_EVT_TIMER0_TEP + timer_id, \ + }, \ + }[group][event] + // MCPWM ETM comparator event table #define MCPWM_LL_ETM_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \ (uint32_t[2][MCPWM_CMPR_ETM_EVENT_MAX]){ \ @@ -1764,6 +1777,29 @@ static inline void mcpwm_ll_etm_enable_evt_comparator_event(mcpwm_dev_t *mcpwm, } } +/** + * @brief Enable timer ETM event + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param event_type Timer ETM event type (TEZ or TEP) + * @param en True: enable ETM module, False: disable ETM module + */ +static inline void mcpwm_ll_etm_enable_timer_event(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_etm_event_type_t event_type, bool en) +{ + uint32_t bit_offset; + if (event_type == MCPWM_TIMER_ETM_EVENT_TEZ) { + bit_offset = timer_id + MCPWM_EVT_TIMER0_TEZ_EN_S; // TEZ events start at bit 3 + } else { // MCPWM_TIMER_ETM_EVENT_TEP + bit_offset = timer_id + MCPWM_EVT_TIMER0_TEP_EN_S; // TEP events start at bit 6 + } + if (en) { + mcpwm->evt_en.val |= 1 << bit_offset; + } else { + mcpwm->evt_en.val &= ~(1 << bit_offset); + } +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_mcpwm/include/hal/mcpwm_types.h b/components/esp_hal_mcpwm/include/hal/mcpwm_types.h index 8562f400bb..21acc66581 100644 --- a/components/esp_hal_mcpwm/include/hal/mcpwm_types.h +++ b/components/esp_hal_mcpwm/include/hal/mcpwm_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -105,6 +105,15 @@ typedef enum { MCPWM_CAP_EDGE_NEG, /*!< Capture on the negative edge */ } mcpwm_capture_edge_t; +/** + * @brief MCPWM timer specific events that supported by the ETM module + */ +typedef enum { + MCPWM_TIMER_ETM_EVENT_TEZ, /*!< The timer reaches zero */ + MCPWM_TIMER_ETM_EVENT_TEP, /*!< The timer reaches peak */ + MCPWM_TIMER_ETM_EVENT_MAX, /*!< Maximum number of timer events */ +} mcpwm_timer_etm_event_type_t; + /** * @brief MCPWM comparator specific events that supported by the ETM module */ diff --git a/docs/en/api-reference/peripherals/mcpwm.rst b/docs/en/api-reference/peripherals/mcpwm.rst index 1b82458065..f0a8bbed67 100644 --- a/docs/en/api-reference/peripherals/mcpwm.rst +++ b/docs/en/api-reference/peripherals/mcpwm.rst @@ -960,9 +960,9 @@ If you don't want to process the captured value in the capture event callback fu ETM Event and Task ^^^^^^^^^^^^^^^^^^ - MCPWM comparator is able to generate events that can interact with the :doc:`ETM ` module. The supported events are listed in the :cpp:type:`mcpwm_comparator_etm_event_type_t`. You can call :cpp:func:`mcpwm_comparator_new_etm_event` to get the corresponding ETM event handle. + MCPWM timer and comparator can generate events that can be connected to the :doc:`ETM ` module. The event types for the timer and comparator are listed in :cpp:type:`mcpwm_timer_etm_event_type_t` and :cpp:type:`mcpwm_comparator_etm_event_type_t` respectively. You can get the ETM event handle by calling :cpp:func:`mcpwm_timer_new_etm_event` or :cpp:func:`mcpwm_comparator_new_etm_event`. - For how to connect the event and task to an ETM channel, please refer to the :doc:`ETM ` documentation. + For how to connect the MCPWM events to an ETM channel, please refer to the :doc:`ETM ` documentation. .. _mcpwm-power-management: diff --git a/docs/zh_CN/api-reference/peripherals/mcpwm.rst b/docs/zh_CN/api-reference/peripherals/mcpwm.rst index a5010ba289..9ae072e1ef 100644 --- a/docs/zh_CN/api-reference/peripherals/mcpwm.rst +++ b/docs/zh_CN/api-reference/peripherals/mcpwm.rst @@ -960,9 +960,9 @@ MCPWM 捕获通道支持在信号上检测到有效边沿时发送通知。须 ETM 事件与任务 ^^^^^^^^^^^^^^^^^^ - MCPWM 比较器可以产生事件,这些事件可以连接到 :doc:`ETM ` 模块。:cpp:type:`mcpwm_comparator_etm_event_type_t` 中列出了 MCPWM 比较器能够产生的事件类型。用户可以通过调用 :cpp:func:`mcpwm_comparator_new_etm_event` 来获得相应事件的 ETM event 句柄。 + MCPWM 的定时器和比较器可以产生事件,这些事件可以连接到 :doc:`ETM ` 模块。:cpp:type:`mcpwm_timer_etm_event_type_t` 和 :cpp:type:`mcpwm_comparator_etm_event_type_t` 中分别列出了 MCPWM 定时器和比较器能够产生的事件类型。用户可以通过调用 :cpp:func:`mcpwm_timer_new_etm_event` 或 :cpp:func:`mcpwm_comparator_new_etm_event` 来获得相应事件的 ETM event 句柄。 - 关于如何将 MCPWM 比较器事件连接到 ETM 通道中,请参阅 :doc:`ETM ` 文档。 + 关于如何将 MCPWM 事件连接到 ETM 通道中,请参阅 :doc:`ETM ` 文档。 .. _mcpwm-power-management: