From a7cd298f0293b2514be69c9c931185cd35060432 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Wed, 11 Feb 2026 11:22:16 +0800 Subject: [PATCH 1/3] fix(mcpwm): fixed several errors on mcpwm --- components/esp_driver_mcpwm/src/mcpwm_etm.c | 2 +- .../esp32c5/include/hal/mcpwm_ll.h | 2 +- .../esp_hal_mcpwm/esp32c5/mcpwm_periph.c | 2 +- .../esp32c6/include/hal/mcpwm_ll.h | 3 +- .../esp_hal_mcpwm/esp32c6/mcpwm_periph.c | 2 +- .../esp32h2/include/hal/mcpwm_ll.h | 3 +- .../esp_hal_mcpwm/esp32h2/mcpwm_periph.c | 2 +- .../esp32h21/include/hal/mcpwm_ll.h | 6 +++- .../esp_hal_mcpwm/esp32h21/mcpwm_periph.c | 2 +- .../esp32h4/include/hal/mcpwm_ll.h | 2 +- .../esp_hal_mcpwm/esp32h4/mcpwm_periph.c | 34 +++++++++++++++++-- .../esp32p4/include/hal/mcpwm_ll.h | 3 +- .../esp_hal_mcpwm/esp32p4/mcpwm_periph.c | 2 +- components/soc/esp32c5/include/soc/soc.h | 1 - .../soc/esp32c5/register/soc/mcpwm_reg.h | 2 ++ components/soc/esp32c6/include/soc/soc.h | 1 - .../soc/esp32c6/register/soc/mcpwm_reg.h | 2 ++ .../soc/esp32h21/include/soc/clk_tree_defs.h | 11 +++--- components/soc/esp32p4/include/soc/soc.h | 1 - .../esp32p4/register/hw_ver1/soc/mcpwm_reg.h | 2 ++ .../esp32p4/register/hw_ver3/soc/mcpwm_reg.h | 2 ++ 21 files changed, 65 insertions(+), 22 deletions(-) diff --git a/components/esp_driver_mcpwm/src/mcpwm_etm.c b/components/esp_driver_mcpwm/src/mcpwm_etm.c index 9cd0258ffa..a25d2cde14 100644 --- a/components/esp_driver_mcpwm/src/mcpwm_etm.c +++ b/components/esp_driver_mcpwm/src/mcpwm_etm.c @@ -130,7 +130,7 @@ esp_err_t mcpwm_timer_new_etm_event(mcpwm_timer_handle_t timer, const mcpwm_time 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_id = MCPWM_LL_ETM_TIMER_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); 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 753d53aba4..c91c431da8 100644 --- a/components/esp_hal_mcpwm/esp32c5/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32c5/include/hal/mcpwm_ll.h @@ -71,7 +71,7 @@ extern "C" { #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) \ +#define MCPWM_LL_ETM_TIMER_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, \ diff --git a/components/esp_hal_mcpwm/esp32c5/mcpwm_periph.c b/components/esp_hal_mcpwm/esp32c5/mcpwm_periph.c index 50969c5be8..0b93feefa5 100644 --- a/components/esp_hal_mcpwm/esp32c5/mcpwm_periph.c +++ b/components/esp_hal_mcpwm/esp32c5/mcpwm_periph.c @@ -84,7 +84,7 @@ const soc_mcpwm_signal_desc_t soc_mcpwm_signals[1] = { /** * MCPWM Registers to be saved during sleep retention - * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG, MCPWM_TIMER0_CFG1_REG + * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG * - Operator Configuration registers, e.g.: MCPWM_OPERATOR_TIMERSEL_REG * |- Generator Configuration registers, e.g.: MCPWM_GEN0_STMP_CFG_REG, MCPWM_GEN0_TSTMP_A_REG, MCPWM_GEN0_TSTMP_B_REG, MCPWM_GEN0_CFG0_REG, MCPWM_GEN0_FORCE_REG, MCPWM_GEN0_A_REG, MCPWM_GEN0_B_REG * |- Dead Time Configuration registers, e.g.: MCPWM_DT0_CFG_REG, MCPWM_DT0_FED_CFG_REG, MCPWM_DT0_RED_CFG_REG 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 5c55bbf225..2fdaf2f4c3 100644 --- a/components/esp_hal_mcpwm/esp32c6/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32c6/include/hal/mcpwm_ll.h @@ -71,7 +71,8 @@ extern "C" { #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) \ +// MCPWM ETM timer event table +#define MCPWM_LL_ETM_TIMER_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, \ diff --git a/components/esp_hal_mcpwm/esp32c6/mcpwm_periph.c b/components/esp_hal_mcpwm/esp32c6/mcpwm_periph.c index 23946365c5..7075283d1b 100644 --- a/components/esp_hal_mcpwm/esp32c6/mcpwm_periph.c +++ b/components/esp_hal_mcpwm/esp32c6/mcpwm_periph.c @@ -83,7 +83,7 @@ const soc_mcpwm_signal_desc_t soc_mcpwm_signals[1] = { /** * MCPWM Registers to be saved during sleep retention - * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG, MCPWM_TIMER0_CFG1_REG + * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG * - Operator Configuration registers, e.g.: MCPWM_OPERATOR_TIMERSEL_REG * |- Generator Configuration registers, e.g.: MCPWM_GEN0_STMP_CFG_REG, MCPWM_GEN0_TSTMP_A_REG, MCPWM_GEN0_TSTMP_B_REG, MCPWM_GEN0_CFG0_REG, MCPWM_GEN0_FORCE_REG, MCPWM_GEN0_A_REG, MCPWM_GEN0_B_REG * |- Dead Time Configuration registers, e.g.: MCPWM_DT0_CFG_REG, MCPWM_DT0_FED_CFG_REG, MCPWM_DT0_RED_CFG_REG 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 51db488afc..26d1cd18a6 100644 --- a/components/esp_hal_mcpwm/esp32h2/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32h2/include/hal/mcpwm_ll.h @@ -69,7 +69,8 @@ extern "C" { #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) \ +// MCPWM ETM timer event table +#define MCPWM_LL_ETM_TIMER_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, \ diff --git a/components/esp_hal_mcpwm/esp32h2/mcpwm_periph.c b/components/esp_hal_mcpwm/esp32h2/mcpwm_periph.c index 4f4feb5190..4d2752c18c 100644 --- a/components/esp_hal_mcpwm/esp32h2/mcpwm_periph.c +++ b/components/esp_hal_mcpwm/esp32h2/mcpwm_periph.c @@ -82,7 +82,7 @@ const soc_mcpwm_signal_desc_t soc_mcpwm_signals[1] = { /** * MCPWM Registers to be saved during sleep retention - * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG, MCPWM_TIMER0_CFG1_REG + * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG * - Operator Configuration registers, e.g.: MCPWM_OPERATOR_TIMERSEL_REG * |- Generator Configuration registers, e.g.: MCPWM_GEN0_STMP_CFG_REG, MCPWM_GEN0_TSTMP_A_REG, MCPWM_GEN0_TSTMP_B_REG, MCPWM_GEN0_CFG0_REG, MCPWM_GEN0_FORCE_REG, MCPWM_GEN0_A_REG, MCPWM_GEN0_B_REG * |- Dead Time Configuration registers, e.g.: MCPWM_DT0_CFG_REG, MCPWM_DT0_FED_CFG_REG, MCPWM_DT0_RED_CFG_REG diff --git a/components/esp_hal_mcpwm/esp32h21/include/hal/mcpwm_ll.h b/components/esp_hal_mcpwm/esp32h21/include/hal/mcpwm_ll.h index ba5772a5aa..a11d74f149 100644 --- a/components/esp_hal_mcpwm/esp32h21/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32h21/include/hal/mcpwm_ll.h @@ -69,7 +69,8 @@ extern "C" { #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) \ +// MCPWM ETM timer event table +#define MCPWM_LL_ETM_TIMER_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, \ @@ -140,6 +141,9 @@ static inline void mcpwm_ll_group_set_clock_source(int group_id, soc_module_clk_ case SOC_MOD_CLK_XTAL: PCR.pwm_clk_conf.pwm_clkm_sel = 0; break; + case SOC_MOD_CLK_RC_FAST: + PCR.pwm_clk_conf.pwm_clkm_sel = 1; + break; case SOC_MOD_CLK_PLL_F96M: PCR.pwm_clk_conf.pwm_clkm_sel = 2; break; diff --git a/components/esp_hal_mcpwm/esp32h21/mcpwm_periph.c b/components/esp_hal_mcpwm/esp32h21/mcpwm_periph.c index bc8154d933..df73fd37a8 100644 --- a/components/esp_hal_mcpwm/esp32h21/mcpwm_periph.c +++ b/components/esp_hal_mcpwm/esp32h21/mcpwm_periph.c @@ -82,7 +82,7 @@ const soc_mcpwm_signal_desc_t soc_mcpwm_signals[1] = { /** * MCPWM Registers to be saved during sleep retention - * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG, MCPWM_TIMER0_CFG1_REG + * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG * - Operator Configuration registers, e.g.: MCPWM_OPERATOR_TIMERSEL_REG * |- Generator Configuration registers, e.g.: MCPWM_GEN0_STMP_CFG_REG, MCPWM_GEN0_TSTMP_A_REG, MCPWM_GEN0_TSTMP_B_REG, MCPWM_GEN0_CFG0_REG, MCPWM_GEN0_FORCE_REG, MCPWM_GEN0_A_REG, MCPWM_GEN0_B_REG * |- Dead Time Configuration registers, e.g.: MCPWM_DT0_CFG_REG, MCPWM_DT0_FED_CFG_REG, MCPWM_DT0_RED_CFG_REG 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 94edcfb612..276ae0d192 100644 --- a/components/esp_hal_mcpwm/esp32h4/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32h4/include/hal/mcpwm_ll.h @@ -71,7 +71,7 @@ extern "C" { #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) \ +#define MCPWM_LL_ETM_TIMER_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, \ diff --git a/components/esp_hal_mcpwm/esp32h4/mcpwm_periph.c b/components/esp_hal_mcpwm/esp32h4/mcpwm_periph.c index b5afae1d3d..073f6393cb 100644 --- a/components/esp_hal_mcpwm/esp32h4/mcpwm_periph.c +++ b/components/esp_hal_mcpwm/esp32h4/mcpwm_periph.c @@ -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 */ @@ -150,9 +150,10 @@ const soc_mcpwm_signal_desc_t soc_mcpwm_signals[2] = { } }; +#if SOC_MCPWM_SUPPORT_SLEEP_RETENTION /** * MCPWM Registers to be saved during sleep retention - * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG, MCPWM_TIMER0_CFG1_REG,MCPWM_TIMER0_SYNC_REG + * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG,MCPWM_TIMER0_SYNC_REG * - Operator Configuration registers, e.g.: MCPWM_OPERATOR_TIMERSEL_REG * |- Generator Configuration registers, e.g.: MCPWM_GEN0_STMP_CFG_REG, MCPWM_GEN0_TSTMP_A_REG, MCPWM_GEN0_TSTMP_B_REG, MCPWM_GEN0_CFG0_REG, MCPWM_GEN0_FORCE_REG, MCPWM_GEN0_A_REG, MCPWM_GEN0_B_REG * |- Dead Time Configuration registers, e.g.: MCPWM_DT0_CFG_REG, MCPWM_DT0_FED_CFG_REG, MCPWM_DT0_RED_CFG_REG @@ -168,6 +169,8 @@ const soc_mcpwm_signal_desc_t soc_mcpwm_signals[2] = { #define MCPWM_RETENTION_REGS_BASE(i) DR_REG_MCPWM_BASE(i) static const uint32_t mcpwm_regs_map[4] = {0xf7fff777, 0x3f7ffdff, 0xff8c, 0x0}; static const regdma_entries_config_t mcpwm0_regdma_entries[] = { + // backup stage: save configuration registers + // restore stage: restore the configuration registers [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_MCPWM_LINK(0x00), MCPWM_RETENTION_REGS_BASE(0), MCPWM_RETENTION_REGS_BASE(0), @@ -176,8 +179,21 @@ static const regdma_entries_config_t mcpwm0_regdma_entries[] = { mcpwm_regs_map[2], mcpwm_regs_map[3]), .owner = ENTRY(0) | ENTRY(2), }, + // restore stage: trigger a forced update of all active registers + [1] = { + .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x01), + MCPWM_UPDATE_CFG_REG(0), MCPWM_GLOBAL_FORCE_UP, MCPWM_GLOBAL_FORCE_UP_M, 1, 0), + .owner = ENTRY(0) | ENTRY(2), + }, + [2] = { + .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x02), + MCPWM_UPDATE_CFG_REG(0), 0, MCPWM_GLOBAL_FORCE_UP_M, 1, 0), + .owner = ENTRY(0) | ENTRY(2), + }, }; static const regdma_entries_config_t mcpwm1_regdma_entries[] = { + // backup stage: save configuration registers + // restore stage: restore the configuration registers [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_MCPWM_LINK(0x00), MCPWM_RETENTION_REGS_BASE(1), MCPWM_RETENTION_REGS_BASE(1), @@ -186,6 +202,17 @@ static const regdma_entries_config_t mcpwm1_regdma_entries[] = { mcpwm_regs_map[2], mcpwm_regs_map[3]), .owner = ENTRY(0) | ENTRY(2), }, + // restore stage: trigger a forced update of all active registers + [1] = { + .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x01), + MCPWM_UPDATE_CFG_REG(1), MCPWM_GLOBAL_FORCE_UP, MCPWM_GLOBAL_FORCE_UP_M, 1, 0), + .owner = ENTRY(0) | ENTRY(2), + }, + [2] = { + .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x02), + MCPWM_UPDATE_CFG_REG(1), 0, MCPWM_GLOBAL_FORCE_UP_M, 1, 0), + .owner = ENTRY(0) | ENTRY(2), + }, }; const mcpwm_reg_retention_info_t mcpwm_reg_retention_info[2] = { @@ -195,8 +222,9 @@ const mcpwm_reg_retention_info_t mcpwm_reg_retention_info[2] = { .retention_module = SLEEP_RETENTION_MODULE_MCPWM0 }, [1] = { - .regdma_entry_array = mcpwm0_regdma_entries, + .regdma_entry_array = mcpwm1_regdma_entries, .array_size = ARRAY_SIZE(mcpwm1_regdma_entries), .retention_module = SLEEP_RETENTION_MODULE_MCPWM1 }, }; +#endif // SOC_MCPWM_SUPPORT_SLEEP_RETENTION 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 5471f4a439..1365ed8feb 100644 --- a/components/esp_hal_mcpwm/esp32p4/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32p4/include/hal/mcpwm_ll.h @@ -72,7 +72,8 @@ 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) \ +// MCPWM ETM timer event table +#define MCPWM_LL_ETM_TIMER_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, \ diff --git a/components/esp_hal_mcpwm/esp32p4/mcpwm_periph.c b/components/esp_hal_mcpwm/esp32p4/mcpwm_periph.c index edaa2aa7d1..c76f1c1b29 100644 --- a/components/esp_hal_mcpwm/esp32p4/mcpwm_periph.c +++ b/components/esp_hal_mcpwm/esp32p4/mcpwm_periph.c @@ -153,7 +153,7 @@ const soc_mcpwm_signal_desc_t soc_mcpwm_signals[2] = { #if SOC_MCPWM_SUPPORT_SLEEP_RETENTION /** * MCPWM Registers to be saved during sleep retention - * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG, MCPWM_TIMER0_CFG1_REG + * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG * - Operator Configuration registers, e.g.: MCPWM_OPERATOR_TIMERSEL_REG * |- Generator Configuration registers, e.g.: MCPWM_GEN0_STMP_CFG_REG, MCPWM_GEN0_TSTMP_A_REG, MCPWM_GEN0_TSTMP_B_REG, MCPWM_GEN0_CFG0_REG, MCPWM_GEN0_FORCE_REG, MCPWM_GEN0_A_REG, MCPWM_GEN0_B_REG * |- Dead Time Configuration registers, e.g.: MCPWM_DT0_CFG_REG, MCPWM_DT0_FED_CFG_REG, MCPWM_DT0_RED_CFG_REG diff --git a/components/soc/esp32c5/include/soc/soc.h b/components/soc/esp32c5/include/soc/soc.h index 1417ae2646..5aa0babd50 100644 --- a/components/soc/esp32c5/include/soc/soc.h +++ b/components/soc/esp32c5/include/soc/soc.h @@ -21,7 +21,6 @@ #define REG_TIMG_BASE(i) (DR_REG_TIMERG0_BASE + (i) * 0x1000) // TIMERG0 and TIMERG1 #define REG_SPI_MEM_BASE(i) (DR_REG_SPIMEM0_BASE + (i) * 0x1000) // SPIMEM0 and SPIMEM1 #define REG_I2C_BASE(i) (DR_REG_I2C_BASE) // only one I2C on C5 -#define REG_MCPWM_BASE(i) (DR_REG_MCPWM_BASE) // only one MCPWM on C5 #define REG_TWAI_BASE(i) (DR_REG_TWAI0_BASE + (i) * 0x2000) // TWAI0 and TWAI1 //Registers Operation {{ diff --git a/components/soc/esp32c5/register/soc/mcpwm_reg.h b/components/soc/esp32c5/register/soc/mcpwm_reg.h index 52779d2d3a..cf564afccd 100644 --- a/components/soc/esp32c5/register/soc/mcpwm_reg.h +++ b/components/soc/esp32c5/register/soc/mcpwm_reg.h @@ -11,6 +11,8 @@ extern "C" { #endif +#define REG_MCPWM_BASE(i) (DR_REG_MCPWM_BASE) + /** MCPWM_CLK_CFG_REG register * PWM clock prescaler register. */ diff --git a/components/soc/esp32c6/include/soc/soc.h b/components/soc/esp32c6/include/soc/soc.h index 11e9e4fc09..2dc76dc8f5 100644 --- a/components/soc/esp32c6/include/soc/soc.h +++ b/components/soc/esp32c6/include/soc/soc.h @@ -24,7 +24,6 @@ #define REG_SPI_MEM_BASE(i) (DR_REG_SPI0_BASE + (i) * 0x1000) // SPIMEM0 and SPIMEM1 #define REG_SPI_BASE(i) (((i)==2) ? (DR_REG_SPI2_BASE) : (0)) // only one GPSPI on C6 #define REG_I2C_BASE(i) (DR_REG_I2C_EXT_BASE) // only one I2C on C6 -#define REG_MCPWM_BASE(i) (DR_REG_MCPWM_BASE) // only one MCPWM on C6 #define REG_TWAI_BASE(i) (DR_REG_TWAI0_BASE + (i) * 0x2000) // TWAI0 and TWAI1 //Registers Operation {{ diff --git a/components/soc/esp32c6/register/soc/mcpwm_reg.h b/components/soc/esp32c6/register/soc/mcpwm_reg.h index 067be4ed37..a29389dc91 100644 --- a/components/soc/esp32c6/register/soc/mcpwm_reg.h +++ b/components/soc/esp32c6/register/soc/mcpwm_reg.h @@ -11,6 +11,8 @@ extern "C" { #endif +#define REG_MCPWM_BASE(i) (DR_REG_MCPWM_BASE) + /** MCPWM_CLK_CFG_REG register * PWM clock prescaler register. */ diff --git a/components/soc/esp32h21/include/soc/clk_tree_defs.h b/components/soc/esp32h21/include/soc/clk_tree_defs.h index 609c175b52..cdd7fb5352 100644 --- a/components/soc/esp32h21/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h21/include/soc/clk_tree_defs.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -282,13 +282,14 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of MCPWM Timer */ -#define SOC_MCPWM_TIMER_CLKS {SOC_MOD_CLK_PLL_F96M, SOC_MOD_CLK_XTAL} +#define SOC_MCPWM_TIMER_CLKS {SOC_MOD_CLK_PLL_F96M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL} /** * @brief Type of MCPWM timer clock source */ typedef enum { MCPWM_TIMER_CLK_SRC_PLL96M = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_F96M as the source clock */ + MCPWM_TIMER_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ MCPWM_TIMER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ MCPWM_TIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_F96M as the default clock choice */ } soc_periph_mcpwm_timer_clk_src_t; @@ -296,13 +297,14 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of MCPWM Capture Timer */ -#define SOC_MCPWM_CAPTURE_CLKS {SOC_MOD_CLK_PLL_F96M, SOC_MOD_CLK_XTAL} +#define SOC_MCPWM_CAPTURE_CLKS {SOC_MOD_CLK_PLL_F96M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL} /** * @brief Type of MCPWM capture clock source */ typedef enum { MCPWM_CAPTURE_CLK_SRC_PLL96M = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_F96M as the source clock */ + MCPWM_CAPTURE_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ MCPWM_CAPTURE_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_F96M as the default clock choice */ } soc_periph_mcpwm_capture_clk_src_t; @@ -310,13 +312,14 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of MCPWM Carrier */ -#define SOC_MCPWM_CARRIER_CLKS {SOC_MOD_CLK_PLL_F96M, SOC_MOD_CLK_XTAL} +#define SOC_MCPWM_CARRIER_CLKS {SOC_MOD_CLK_PLL_F96M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL} /** * @brief Type of MCPWM carrier clock source */ typedef enum { MCPWM_CARRIER_CLK_SRC_PLL96M = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_F96M as the source clock */ + MCPWM_CARRIER_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ MCPWM_CARRIER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ MCPWM_CARRIER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_F96M as the default clock choice */ } soc_periph_mcpwm_carrier_clk_src_t; diff --git a/components/soc/esp32p4/include/soc/soc.h b/components/soc/esp32p4/include/soc/soc.h index f0bdfeb578..d5e09e1171 100644 --- a/components/soc/esp32p4/include/soc/soc.h +++ b/components/soc/esp32p4/include/soc/soc.h @@ -22,7 +22,6 @@ #define REG_SPI_MEM_BASE(i) (DR_REG_FLASH_SPI0_BASE + (i) * 0x1000) // SPIMEM0 and SPIMEM1 #define REG_SPI_BASE(i) (((i)>=2) ? (DR_REG_SPI2_BASE + (i-2) * 0x1000) : (0)) // GPSPI2 and GPSPI3 #define REG_I2C_BASE(i) (DR_REG_I2C0_BASE + (i) * 0x1000) -#define REG_MCPWM_BASE(i) (DR_REG_MCPWM_BASE + (i) * 0x1000) #define REG_TWAI_BASE(i) (DR_REG_TWAI0_BASE + (i) * 0x1000) // TWAI0 and TWAI1 //Registers Operation {{ diff --git a/components/soc/esp32p4/register/hw_ver1/soc/mcpwm_reg.h b/components/soc/esp32p4/register/hw_ver1/soc/mcpwm_reg.h index ccce33b5d4..c050efddb4 100644 --- a/components/soc/esp32p4/register/hw_ver1/soc/mcpwm_reg.h +++ b/components/soc/esp32p4/register/hw_ver1/soc/mcpwm_reg.h @@ -11,6 +11,8 @@ extern "C" { #endif +#define REG_MCPWM_BASE(i) (DR_REG_MCPWM_BASE + (i) * 0x1000) + /** MCPWM_CLK_CFG_REG register * PWM clock prescaler register. */ diff --git a/components/soc/esp32p4/register/hw_ver3/soc/mcpwm_reg.h b/components/soc/esp32p4/register/hw_ver3/soc/mcpwm_reg.h index 06dd8c1fbc..e6f0d46a91 100644 --- a/components/soc/esp32p4/register/hw_ver3/soc/mcpwm_reg.h +++ b/components/soc/esp32p4/register/hw_ver3/soc/mcpwm_reg.h @@ -11,6 +11,8 @@ extern "C" { #endif +#define REG_MCPWM_BASE(i) (DR_REG_MCPWM_BASE + (i) * 0x1000) + /** MCPWM_CLK_CFG_REG register * PWM clock prescaler register. */ From 675aa0695c67a6ecb0704480a63e13682dd4b480 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Thu, 12 Feb 2026 16:46:07 +0800 Subject: [PATCH 2/3] feat(mcpwm): support mcpwm on esp32s31 - Remove duplicate 'MCPWM ETM timer event table' comment (esp32h2, esp32c6, esp32h21) - esp32s31 clk_tree_defs: add PLL20M enum for MCPWM timer/capture/carrier to match SOC_MCPWM_*_CLKS Made-with: Cursor --- .../test_apps/mcpwm/README.md | 4 +- .../test_apps/mcpwm/main/test_mcpwm_gen.c | 26 +- .../esp32c6/include/hal/mcpwm_ll.h | 1 - .../esp32h2/include/hal/mcpwm_ll.h | 1 - .../esp32h21/include/hal/mcpwm_ll.h | 1 - .../esp32s31/include/hal/mcpwm_ll.h | 1782 +++++++++++++++++ .../esp_hal_mcpwm/esp32s31/mcpwm_periph.c | 355 ++++ .../esp32s31/include/soc/Kconfig.soc_caps.in | 20 + .../soc/esp32s31/include/soc/clk_tree_defs.h | 47 + .../soc/esp32s31/include/soc/soc_caps.h | 9 +- .../soc/esp32s31/register/soc/mcpwm_reg.h | 3 + .../soc/esp32s31/register/soc/mcpwm_struct.h | 454 ++--- docs/en/api-reference/peripherals/mcpwm.rst | 8 +- .../zh_CN/api-reference/peripherals/mcpwm.rst | 9 +- .../mcpwm/mcpwm_bldc_hall_control/README.md | 4 +- .../mcpwm/mcpwm_capture_hc_sr04/README.md | 4 +- .../mcpwm/mcpwm_foc_svpwm_open_loop/README.md | 4 +- .../mcpwm/mcpwm_servo_control/README.md | 4 +- .../peripherals/mcpwm/mcpwm_sync/README.md | 4 +- 19 files changed, 2362 insertions(+), 378 deletions(-) create mode 100644 components/esp_hal_mcpwm/esp32s31/include/hal/mcpwm_ll.h create mode 100644 components/esp_hal_mcpwm/esp32s31/mcpwm_periph.c diff --git a/components/esp_driver_mcpwm/test_apps/mcpwm/README.md b/components/esp_driver_mcpwm/test_apps/mcpwm/README.md index 9917b63055..9344e709c6 100644 --- a/components/esp_driver_mcpwm/test_apps/mcpwm/README.md +++ b/components/esp_driver_mcpwm/test_apps/mcpwm/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | --------- | diff --git a/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_gen.c b/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_gen.c index c9bf433fde..df27ec03b3 100644 --- a/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_gen.c +++ b/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_gen.c @@ -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 */ @@ -417,18 +417,18 @@ static void mcpwm_gen_action_test_template(uint32_t timer_resolution, uint32_t p } TEST_ESP_OK(mcpwm_timer_disable(timer)); - TEST_ESP_OK(mcpwm_del_generator(generator_a)); - TEST_ESP_OK(mcpwm_del_generator(generator_b)); - TEST_ESP_OK(mcpwm_del_comparator(comparator_a)); - TEST_ESP_OK(mcpwm_del_comparator(comparator_b)); - TEST_ESP_OK(mcpwm_del_operator(oper)); - TEST_ESP_OK(mcpwm_del_timer(timer)); TEST_ESP_OK(mcpwm_capture_channel_disable(cap_channel_a)); TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel_a)); TEST_ESP_OK(mcpwm_capture_channel_disable(cap_channel_b)); TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel_b)); TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer)); TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer)); + TEST_ESP_OK(mcpwm_del_generator(generator_a)); + TEST_ESP_OK(mcpwm_del_generator(generator_b)); + TEST_ESP_OK(mcpwm_del_comparator(comparator_a)); + TEST_ESP_OK(mcpwm_del_comparator(comparator_b)); + TEST_ESP_OK(mcpwm_del_operator(oper)); + TEST_ESP_OK(mcpwm_del_timer(timer)); } static void single_edge_active_high(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) @@ -651,18 +651,18 @@ static void mcpwm_deadtime_test_template(uint32_t timer_resolution, uint32_t per ret_capb[1] = cap_value_b[1] * 1000 / clk_src_res; TEST_ESP_OK(mcpwm_timer_disable(timer)); - TEST_ESP_OK(mcpwm_del_generator(generator_a)); - TEST_ESP_OK(mcpwm_del_generator(generator_b)); - TEST_ESP_OK(mcpwm_del_comparator(comparator_a)); - TEST_ESP_OK(mcpwm_del_comparator(comparator_b)); - TEST_ESP_OK(mcpwm_del_operator(oper)); - TEST_ESP_OK(mcpwm_del_timer(timer)); TEST_ESP_OK(mcpwm_capture_channel_disable(cap_channel_a)); TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel_a)); TEST_ESP_OK(mcpwm_capture_channel_disable(cap_channel_b)); TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel_b)); TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer)); TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer)); + TEST_ESP_OK(mcpwm_del_generator(generator_a)); + TEST_ESP_OK(mcpwm_del_generator(generator_b)); + TEST_ESP_OK(mcpwm_del_comparator(comparator_a)); + TEST_ESP_OK(mcpwm_del_comparator(comparator_b)); + TEST_ESP_OK(mcpwm_del_operator(oper)); + TEST_ESP_OK(mcpwm_del_timer(timer)); } static void ahc_set_generator_actions(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) 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 2fdaf2f4c3..000d5f1124 100644 --- a/components/esp_hal_mcpwm/esp32c6/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32c6/include/hal/mcpwm_ll.h @@ -70,7 +70,6 @@ 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 // MCPWM ETM timer event table #define MCPWM_LL_ETM_TIMER_EVENT_TABLE(group, timer_id, event) \ (uint32_t[1][MCPWM_TIMER_ETM_EVENT_MAX]){{ \ 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 26d1cd18a6..dabc8fc77c 100644 --- a/components/esp_hal_mcpwm/esp32h2/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32h2/include/hal/mcpwm_ll.h @@ -68,7 +68,6 @@ 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 // MCPWM ETM timer event table #define MCPWM_LL_ETM_TIMER_EVENT_TABLE(group, timer_id, event) \ (uint32_t[1][MCPWM_TIMER_ETM_EVENT_MAX]){{ \ diff --git a/components/esp_hal_mcpwm/esp32h21/include/hal/mcpwm_ll.h b/components/esp_hal_mcpwm/esp32h21/include/hal/mcpwm_ll.h index a11d74f149..fdff8ad65b 100644 --- a/components/esp_hal_mcpwm/esp32h21/include/hal/mcpwm_ll.h +++ b/components/esp_hal_mcpwm/esp32h21/include/hal/mcpwm_ll.h @@ -68,7 +68,6 @@ 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 // MCPWM ETM timer event table #define MCPWM_LL_ETM_TIMER_EVENT_TABLE(group, timer_id, event) \ (uint32_t[1][MCPWM_TIMER_ETM_EVENT_MAX]){{ \ diff --git a/components/esp_hal_mcpwm/esp32s31/include/hal/mcpwm_ll.h b/components/esp_hal_mcpwm/esp32s31/include/hal/mcpwm_ll.h new file mode 100644 index 0000000000..1189b5b934 --- /dev/null +++ b/components/esp_hal_mcpwm/esp32s31/include/hal/mcpwm_ll.h @@ -0,0 +1,1782 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for ESP32-S31 MCPWM register operations + +#pragma once + +#include +#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" +#include "hal/misc.h" +#include "hal/assert.h" +#include "soc/soc_etm_source.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// MCPWM LL get macro +#define MCPWM_LL_GET(attr) (MCPWM_LL_ ## attr) + +// Get MCPWM group register base address +#define MCPWM_LL_GET_HW(ID) (((ID) == 0) ? &MCPWM0 : ((ID) == 1) ? &MCPWM1 : ((ID) == 2) ? &MCPWM2 : &MCPWM3) + +// MCPWM capabilities +#define MCPWM_LL_GROUP_NUM (4) ///< 4 MCPWM groups on the chip (i.e., the number of independent MCPWM peripherals) +#define MCPWM_LL_TIMERS_PER_GROUP (3) ///< The number of timers that each group has +#define MCPWM_LL_OPERATORS_PER_GROUP (3) ///< The number of operators that each group has +#define MCPWM_LL_COMPARATORS_PER_OPERATOR (2) ///< The number of comparators that each operator has +#define MCPWM_LL_EVENT_COMPARATORS_PER_OPERATOR (2) ///< The number of event comparators that each operator has +#define MCPWM_LL_GENERATORS_PER_OPERATOR (2) ///< The number of generators that each operator has +#define MCPWM_LL_TRIGGERS_PER_OPERATOR (2) ///< The number of triggers that each operator has +#define MCPWM_LL_GPIO_FAULTS_PER_GROUP (3) ///< The number of fault signal detectors that each group has +#define MCPWM_LL_CAPTURE_TIMERS_PER_GROUP (1) ///< The number of capture timers that each group has +#define MCPWM_LL_CAPTURE_CHANNELS_PER_TIMER (3) ///< The number of capture channels that each capture timer has +#define MCPWM_LL_GPIO_SYNCHROS_PER_GROUP (3) ///< The number of GPIO synchros that each group has + +// MCPWM interrupt event mask +#define MCPWM_LL_EVENT_TIMER_STOP(timer) (1 << (timer)) +#define MCPWM_LL_EVENT_TIMER_EMPTY(timer) (1 << ((timer) + 3)) +#define MCPWM_LL_EVENT_TIMER_FULL(timer) (1 << ((timer) + 6)) +#define MCPWM_LL_EVENT_TIMER_MASK(timer) (MCPWM_LL_EVENT_TIMER_STOP(timer) | MCPWM_LL_EVENT_TIMER_EMPTY(timer) | MCPWM_LL_EVENT_TIMER_FULL(timer)) +#define MCPWM_LL_EVENT_FAULT_ENTER(fault) (1 << ((fault) + 9)) +#define MCPWM_LL_EVENT_FAULT_EXIT(fault) (1 << ((fault) + 12)) +#define MCPWM_LL_EVENT_FAULT_MASK(fault) (MCPWM_LL_EVENT_FAULT_ENTER(fault) | MCPWM_LL_EVENT_FAULT_EXIT(fault)) +#define MCPWM_LL_EVENT_CMP_EQUAL(oper, cmp) (1 << ((oper) + (cmp) * 3 + 15)) +#define MCPWM_LL_EVENT_OPER_BRAKE_CBC(oper) (1 << ((oper) + 21)) +#define MCPWM_LL_EVENT_OPER_BRAKE_OST(oper) (1 << ((oper) + 24)) +#define MCPWM_LL_EVENT_OPER_MASK(oper) (MCPWM_LL_EVENT_OPER_BRAKE_CBC(oper) | MCPWM_LL_EVENT_OPER_BRAKE_OST(oper)) +#define MCPWM_LL_EVENT_CAPTURE(cap) (1 << ((cap) + 27)) + +// Maximum values due to limited register bit width +#define MCPWM_LL_MAX_GROUP_PRESCALE 256 +#define MCPWM_LL_MAX_TIMER_PRESCALE 256 +#define MCPWM_LL_MAX_CARRIER_PRESCALE 16 +#define MCPWM_LL_MAX_CARRIER_ONESHOT 16 +#define MCPWM_LL_MAX_CAPTURE_PRESCALE 256 +#define MCPWM_LL_MAX_CAPTURE_TIMER_PRESCALE 1 +#define MCPWM_LL_MAX_DEAD_DELAY 65536 +#define MCPWM_LL_MAX_COUNT_VALUE 65536 + +// translate the HAL types into register values +#define MCPWM_LL_TIMER_EVENT_TO_REG_VAL(event) ((uint8_t[]) {0, 1}[(event)]) +#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_ETM_TIMER_EVENT_TABLE(group, timer_id, event) \ + (uint32_t[4][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 }, \ + { [MCPWM_TIMER_ETM_EVENT_TEZ] = MCPWM2_EVT_TIMER0_TEZ + timer_id, [MCPWM_TIMER_ETM_EVENT_TEP] = MCPWM2_EVT_TIMER0_TEP + timer_id }, \ + { [MCPWM_TIMER_ETM_EVENT_TEZ] = MCPWM3_EVT_TIMER0_TEZ + timer_id, [MCPWM_TIMER_ETM_EVENT_TEP] = MCPWM3_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[4][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 }, \ + { [MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM2_EVT_OP0_TEA + oper_id + 3 * cmpr_id }, \ + { [MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM3_EVT_OP0_TEA + oper_id + 3 * cmpr_id }, \ + }[group][event] + +// MCPWM ETM event comparator event table +#define MCPWM_LL_ETM_EVENT_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \ + (uint32_t[4][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 },\ + { [MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM2_EVT_OP0_TEE1 + oper_id + 3 * cmpr_id },\ + { [MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM3_EVT_OP0_TEE1 + oper_id + 3 * cmpr_id },\ + }[group][event] + +/** + * @brief The dead time module's clock source + */ +typedef enum { + MCPWM_LL_DEADTIME_CLK_SRC_GROUP, + MCPWM_LL_DEADTIME_CLK_SRC_TIMER, +} mcpwm_ll_deadtime_clock_src_t; + +////////////////////////////////////////MCPWM Group Specific//////////////////////////////////////////////////////////// + +/** + * @brief Enable the bus clock for MCPWM module + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void mcpwm_ll_enable_bus_clock(int group_id, bool enable) +{ + if (group_id == 0) { + HP_SYS_CLKRST.mcpwm0_ctrl0.reg_mcpwm0_apb_clk_en = enable; + } else if (group_id == 1) { + HP_SYS_CLKRST.mcpwm1_ctrl0.reg_mcpwm1_apb_clk_en = enable; + } else if (group_id == 2) { + HP_SYS_CLKRST.mcpwm2_ctrl0.reg_mcpwm2_apb_clk_en = enable; + } else { + HP_SYS_CLKRST.mcpwm3_ctrl0.reg_mcpwm3_apb_clk_en = enable; + } +} + +/** + * @brief Reset the MCPWM module + * + * @param group_id Group ID + */ +static inline void mcpwm_ll_reset_register(int group_id) +{ + if (group_id == 0) { + HP_SYS_CLKRST.mcpwm0_ctrl0.reg_mcpwm0_rst_en = 1; + HP_SYS_CLKRST.mcpwm0_ctrl0.reg_mcpwm0_rst_en = 0; + } else if (group_id == 1) { + HP_SYS_CLKRST.mcpwm1_ctrl0.reg_mcpwm1_rst_en = 1; + HP_SYS_CLKRST.mcpwm1_ctrl0.reg_mcpwm1_rst_en = 0; + } else if (group_id == 2) { + HP_SYS_CLKRST.mcpwm2_ctrl0.reg_mcpwm2_rst_en = 1; + HP_SYS_CLKRST.mcpwm2_ctrl0.reg_mcpwm2_rst_en = 0; + } else { + HP_SYS_CLKRST.mcpwm3_ctrl0.reg_mcpwm3_rst_en = 1; + HP_SYS_CLKRST.mcpwm3_ctrl0.reg_mcpwm3_rst_en = 0; + } +} + +/** + * @brief Enable MCPWM function clock + * + * @param group_id Group ID + * @param en true to enable, false to disable + */ +static inline void mcpwm_ll_group_enable_clock(int group_id, bool en) +{ + if (group_id == 0) { + HP_SYS_CLKRST.mcpwm0_ctrl0.reg_mcpwm0_clk_en = en; + } else if (group_id == 1) { + HP_SYS_CLKRST.mcpwm1_ctrl0.reg_mcpwm1_clk_en = en; + } else if (group_id == 2) { + HP_SYS_CLKRST.mcpwm2_ctrl0.reg_mcpwm2_clk_en = en; + } else { + HP_SYS_CLKRST.mcpwm3_ctrl0.reg_mcpwm3_clk_en = en; + } +} + +/** + * @brief Set the clock source for MCPWM + * + * @param group_id Group ID + * @param clk_src Clock source for the MCPWM peripheral + */ +static inline void mcpwm_ll_group_set_clock_source(int group_id, soc_module_clk_t clk_src) +{ + uint8_t clk_id = 0; + switch (clk_src) { + case SOC_MOD_CLK_XTAL: + clk_id = 0; + break; + case SOC_MOD_CLK_PLL_F20M: + clk_id = 1; + break; + case SOC_MOD_CLK_PLL_F160M: + clk_id = 2; + break; + default: + HAL_ASSERT(false); + break; + } + if (group_id == 0) { + HP_SYS_CLKRST.mcpwm0_ctrl0.reg_mcpwm0_clk_src_sel = clk_id; + } else if (group_id == 1) { + HP_SYS_CLKRST.mcpwm1_ctrl0.reg_mcpwm1_clk_src_sel = clk_id; + } else if (group_id == 2) { + HP_SYS_CLKRST.mcpwm2_ctrl0.reg_mcpwm2_clk_src_sel = clk_id; + } else { + HP_SYS_CLKRST.mcpwm3_ctrl0.reg_mcpwm3_clk_src_sel = clk_id; + } +} + +/** + * @brief Set the MCPWM group clock prescale + * + * @param group_id Group ID + * @param prescale Prescale value + */ +static inline void mcpwm_ll_group_set_clock_prescale(int group_id, int prescale) +{ + // group clock: PWM_clk = source_clock / (prescale) + HAL_ASSERT(prescale <= 256 && prescale > 0); + if (group_id == 0) { + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.mcpwm0_ctrl0, reg_mcpwm0_clk_div_num, prescale - 1); + } else if (group_id == 1) { + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.mcpwm1_ctrl0, reg_mcpwm1_clk_div_num, prescale - 1); + } else if (group_id == 2) { + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.mcpwm2_ctrl0, reg_mcpwm2_clk_div_num, prescale - 1); + } else { + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.mcpwm3_ctrl0, reg_mcpwm3_clk_div_num, prescale - 1); + } +} + +/** + * @brief Enable update MCPWM active registers from shadow registers + * + * @param mcpwm Peripheral instance address + */ +static inline void mcpwm_ll_group_enable_shadow_mode(mcpwm_dev_t *mcpwm) +{ + mcpwm->update_cfg.global_up_en = 1; + mcpwm->update_cfg.op0_up_en = 1; + mcpwm->update_cfg.op1_up_en = 1; + mcpwm->update_cfg.op2_up_en = 1; +} + +/** + * @brief Flush shadow registers to active registers + * + * @param mcpwm Peripheral instance address + */ +static inline void mcpwm_ll_group_flush_shadow(mcpwm_dev_t *mcpwm) +{ + // a toggle can trigger a forced update of all active registers in MCPWM, i.e. shadow->active + mcpwm->update_cfg.global_force_up = 1; + mcpwm->update_cfg.global_force_up = 0; +} + +//////////////////////////////////////////Interrupt Specific//////////////////////////////////////////////////////////// + +/** + * @brief Get interrupt status register address + * + * @param mcpwm Peripheral instance address + * @return Register address + */ +static inline volatile void *mcpwm_ll_intr_get_status_reg(mcpwm_dev_t *mcpwm) +{ + return &mcpwm->int_st; +} + +/** + * @brief Enable MCPWM interrupt for specific event mask + * + * @param mcpwm Peripheral instance address + * @param mask Event mask + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_intr_enable(mcpwm_dev_t *mcpwm, uint32_t mask, bool enable) +{ + if (enable) { + mcpwm->int_ena.val |= mask; + } else { + mcpwm->int_ena.val &= ~mask; + } +} + +/** + * @brief Get MCPWM interrupt status + * + * @param mcpwm Peripheral instance address + * @return Interrupt status + */ +__attribute__((always_inline)) +static inline uint32_t mcpwm_ll_intr_get_status(mcpwm_dev_t *mcpwm) +{ + return mcpwm->int_st.val; +} + +/** + * @brief Clear MCPWM interrupt status by mask + * + * @param mcpwm Peripheral instance address + * @param mask Interrupt status mask + */ +__attribute__((always_inline)) +static inline void mcpwm_ll_intr_clear_status(mcpwm_dev_t *mcpwm, uint32_t mask) +{ + mcpwm->int_clr.val = mask; +} + +////////////////////////////////////////MCPWM Timer Specific//////////////////////////////////////////////////////////// + +/** + * @brief Set MCPWM timer prescale + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param prescale Prescale value + */ +static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id, uint32_t prescale) +{ + HAL_ASSERT(prescale <= 256 && prescale > 0); + HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timern_cfg0, timern_prescale, prescale - 1); +} + +/** + * @brief Set peak value for MCPWM timer + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param peak Peak value + * @param symmetric True to set symmetric peak value, False to set asymmetric peak value + */ +__attribute__((always_inline)) +static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric) +{ + if (!symmetric) { // in asymmetric mode, period = [0,peak-1] + HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timern_cfg0, timern_period, peak - 1); + } else { // in symmetric mode, period = [0,peak-1] + [peak,1] + HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timern_cfg0, timern_period, peak); + } +} + +/** + * @brief Update MCPWM period immediately + * @note When period value is updated in the shadow register, it will be flushed to active register immediately. + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + */ +static inline void mcpwm_ll_timer_update_period_at_once(mcpwm_dev_t *mcpwm, int timer_id) +{ + mcpwm->timer[timer_id].timern_cfg0.timern_period_upmethod = 0; +} + +/** + * @brief Enable to update MCPWM period upon TEZ event + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_timer_enable_update_period_on_tez(mcpwm_dev_t *mcpwm, int timer_id, bool enable) +{ + if (enable) { + mcpwm->timer[timer_id].timern_cfg0.timern_period_upmethod |= 0x01; + } else { + mcpwm->timer[timer_id].timern_cfg0.timern_period_upmethod &= ~0x01; + } +} + +/** + * @brief Enable to update MCPWM period upon sync event + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_timer_enable_update_period_on_sync(mcpwm_dev_t *mcpwm, int timer_id, bool enable) +{ + if (enable) { + mcpwm->timer[timer_id].timern_cfg0.timern_period_upmethod |= 0x02; + } else { + mcpwm->timer[timer_id].timern_cfg0.timern_period_upmethod &= ~0x02; + } +} + +/** + * @brief Set MCPWM timer count mode + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param mode Timer count mode + */ +static inline void mcpwm_ll_timer_set_count_mode(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_count_mode_t mode) +{ + switch (mode) { + case MCPWM_TIMER_COUNT_MODE_PAUSE: + mcpwm->timer[timer_id].timern_cfg1.timern_mod = 0; + break; + case MCPWM_TIMER_COUNT_MODE_UP: + mcpwm->timer[timer_id].timern_cfg1.timern_mod = 1; + break; + case MCPWM_TIMER_COUNT_MODE_DOWN: + mcpwm->timer[timer_id].timern_cfg1.timern_mod = 2; + break; + case MCPWM_TIMER_COUNT_MODE_UP_DOWN: + mcpwm->timer[timer_id].timern_cfg1.timern_mod = 3; + break; + default: + HAL_ASSERT(false); + break; + } +} + +/** + * @brief Execute MCPWM timer start/stop command + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param cmd Timer start/stop command + */ +static inline void mcpwm_ll_timer_set_start_stop_command(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_start_stop_cmd_t cmd) +{ + switch (cmd) { + case MCPWM_TIMER_STOP_EMPTY: + mcpwm->timer[timer_id].timern_cfg1.timern_start = 0; + break; + case MCPWM_TIMER_STOP_FULL: + mcpwm->timer[timer_id].timern_cfg1.timern_start = 1; + break; + case MCPWM_TIMER_START_NO_STOP: + mcpwm->timer[timer_id].timern_cfg1.timern_start = 2; + break; + case MCPWM_TIMER_START_STOP_EMPTY: + mcpwm->timer[timer_id].timern_cfg1.timern_start = 3; + break; + case MCPWM_TIMER_START_STOP_FULL: + mcpwm->timer[timer_id].timern_cfg1.timern_start = 4; + break; + default: + HAL_ASSERT(false); + break; + } +} + +/** + * @brief Get timer count value + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @return Timer count value + */ +__attribute__((always_inline)) +static inline uint32_t mcpwm_ll_timer_get_count_value(mcpwm_dev_t *mcpwm, int timer_id) +{ + // status.value saves the "next count value", so need an extra round up here to get the current count value according to count mode + // timer is paused + if (mcpwm->timer[timer_id].timern_cfg1.timern_mod == 0) { + return HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timern_status, timern_value); + } + if (mcpwm->timer[timer_id].timern_status.timern_direction) { // down direction + return (HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timern_status, timern_value) + 1) % + (HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timern_cfg0, timern_period) + 1); + } + // up direction + return (HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timern_status, timern_value) + + HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timern_cfg0, timern_period)) % + (HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timern_cfg0, timern_period) + 1); +} + +/** + * @brief Get timer count direction + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @return Timer count direction + */ +__attribute__((always_inline)) +static inline mcpwm_timer_direction_t mcpwm_ll_timer_get_count_direction(mcpwm_dev_t *mcpwm, int timer_id) +{ + return mcpwm->timer[timer_id].timern_status.timern_direction ? MCPWM_TIMER_DIRECTION_DOWN : MCPWM_TIMER_DIRECTION_UP; +} + +/** + * @brief Enable sync input for timer + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_timer_enable_sync_input(mcpwm_dev_t *mcpwm, int timer_id, bool enable) +{ + mcpwm->timer[timer_id].timern_sync.timern_synci_en = enable; +} + +/** + * @brief Use the input sync signal as the output sync signal (i.e. propagate the input sync signal) + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + */ +static inline void mcpwm_ll_timer_propagate_input_sync(mcpwm_dev_t *mcpwm, int timer_id) +{ + // sync_out is selected to sync_in + mcpwm->timer[timer_id].timern_sync.timern_synco_sel = 0; +} + +/** + * @brief Set the sync output signal to one of the timer event + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param event Timer event + */ +static inline void mcpwm_ll_timer_sync_out_on_timer_event(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_event_t event) +{ + switch (event) { + case MCPWM_TIMER_EVENT_EMPTY: + mcpwm->timer[timer_id].timern_sync.timern_synco_sel = 1; + break; + case MCPWM_TIMER_EVENT_FULL: + mcpwm->timer[timer_id].timern_sync.timern_synco_sel = 2; + break; + default: + HAL_ASSERT(false); + break; + } +} + +/** + * @brief Disable sync output for MCPWM timer + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + */ +static inline void mcpwm_ll_timer_disable_sync_out(mcpwm_dev_t *mcpwm, int timer_id) +{ + // sync_out will always be zero + mcpwm->timer[timer_id].timern_sync.timern_synco_sel = 3; +} + +/** + * @brief Trigger MCPWM timer software sync event + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + */ +static inline void mcpwm_ll_timer_trigger_soft_sync(mcpwm_dev_t *mcpwm, int timer_id) +{ + mcpwm->timer[timer_id].timern_sync.timern_sync_sw = ~mcpwm->timer[timer_id].timern_sync.timern_sync_sw; +} + +/** + * @brief Set sync count value for MCPWM timer + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param phase_value Sync phase value + */ +static inline void mcpwm_ll_timer_set_sync_phase_value(mcpwm_dev_t *mcpwm, int timer_id, uint32_t phase_value) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timern_sync, timern_phase, phase_value); +} + +/** + * @brief Set sync phase direction for MCPWM timer + * + * @param mcpwm Peripheral instance address + * @param timer_id Timer ID, index from 0 to 2 + * @param direction Sync phase direction + */ +static inline void mcpwm_ll_timer_set_sync_phase_direction(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_direction_t direction) +{ + mcpwm->timer[timer_id].timern_sync.timern_phase_direction = direction; +} + +/** + * @brief Select which GPIO sync input to use + * + * @param mcpwm Peripheral instance address + * @param timer Timer ID, index from 0 to 2 + * @param gpio_sync_id GPIO sync ID, index from 0 to 2 + */ +static inline void mcpwm_ll_timer_set_gpio_sync_input(mcpwm_dev_t *mcpwm, int timer, int gpio_sync_id) +{ + mcpwm->timer_synci_cfg.val &= ~(0x07 << (timer * 3)); + mcpwm->timer_synci_cfg.val |= (gpio_sync_id + 4) << (timer * 3); +} + +/** + * @brief Select which timer sync input to use + * + * @param mcpwm Peripheral instance address + * @param timer Timer ID, index from 0 to 2 + * @param timer_sync_id Timer sync ID, index from 0 to 2 + */ +static inline void mcpwm_ll_timer_set_timer_sync_input(mcpwm_dev_t *mcpwm, int timer, int timer_sync_id) +{ + mcpwm->timer_synci_cfg.val &= ~(0x07 << (timer * 3)); + mcpwm->timer_synci_cfg.val |= (timer_sync_id + 1) << (timer * 3); +} + +/** + * @brief Clear timer sync input selection + * + * @param mcpwm Peripheral instance address + * @param timer Timer ID, index from 0 to 2 + */ +static inline void mcpwm_ll_timer_clear_sync_input(mcpwm_dev_t *mcpwm, int timer) +{ + // no sync input is selected, but software sync can still work + mcpwm->timer_synci_cfg.val &= ~(0x07 << (timer * 3)); +} + +/** + * @brief Invert the GPIO sync input signal + * + * @param mcpwm Peripheral instance address + * @param sync_id GPIO sync ID, index from 0 to 2 + * @param invert True to invert, False to not invert + */ +static inline void mcpwm_ll_invert_gpio_sync_input(mcpwm_dev_t *mcpwm, int sync_id, bool invert) +{ + if (invert) { + mcpwm->timer_synci_cfg.val |= 1 << (sync_id + 9); + } else { + mcpwm->timer_synci_cfg.val &= ~(1 << (sync_id + 9)); + } +} + +////////////////////////////////////////MCPWM Operator Specific///////////////////////////////////////////////////////// + +/** + * @brief Flush operator shadow registers to active registers + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + */ +static inline void mcpwm_ll_operator_flush_shadow(mcpwm_dev_t *mcpwm, int operator_id) +{ + mcpwm->update_cfg.val ^= (1 << (2 * operator_id + 3)); +} + +/** + * @brief Connect operator and timer by ID + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param timer_id Timer ID, index from 0 to 2 + */ +static inline void mcpwm_ll_operator_connect_timer(mcpwm_dev_t *mcpwm, int operator_id, int timer_id) +{ + mcpwm->operator_timersel.val &= ~(0x03 << (2 * operator_id)); + mcpwm->operator_timersel.val |= (timer_id << (2 * operator_id)); +} + +/** + * @brief Update the compare value immediately + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param compare_id Compare ID, index from 0 to 1 + */ +static inline void mcpwm_ll_operator_update_compare_at_once(mcpwm_dev_t *mcpwm, int operator_id, int compare_id) +{ + mcpwm->operators[operator_id].gen_stmp_cfg.val &= ~(0x0F << (4 * compare_id)); +} + +/** + * @brief Enable to update the compare value upon TEZ event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param compare_id Compare ID, index from 0 to 1 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_operator_enable_update_compare_on_tez(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].gen_stmp_cfg.val |= (1 << 0) << (4 * compare_id); + } else { + mcpwm->operators[operator_id].gen_stmp_cfg.val &= ~((1 << 0) << (4 * compare_id)); + } +} + +/** + * @brief Enable to update the compare value upon TEP event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param compare_id Compare ID, index from 0 to 1 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_operator_enable_update_compare_on_tep(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].gen_stmp_cfg.val |= (1 << 1) << (4 * compare_id); + } else { + mcpwm->operators[operator_id].gen_stmp_cfg.val &= ~((1 << 1) << (4 * compare_id)); + } +} + +/** + * @brief Enable to update the compare value upon sync event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param compare_id Compare ID, index from 0 to 1 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_operator_enable_update_compare_on_sync(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].gen_stmp_cfg.val |= (1 << 2) << (4 * compare_id); + } else { + mcpwm->operators[operator_id].gen_stmp_cfg.val &= ~((1 << 2) << (4 * compare_id)); + } +} + +/** + * @brief Stop updating the compare value + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param compare_id Compare ID, index from 0 to 1 + * @param stop_or_not True to stop, False to not stop + */ +static inline void mcpwm_ll_operator_stop_update_compare(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, bool stop_or_not) +{ + if (stop_or_not) { + mcpwm->operators[operator_id].gen_stmp_cfg.val |= (1 << 3) << (4 * compare_id); + } else { + mcpwm->operators[operator_id].gen_stmp_cfg.val &= ~((1 << 3) << (4 * compare_id)); + } +} + +/** + * @brief Set compare value for comparator + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param compare_id Compare ID, index from 0 to 1 + * @param compare_value Compare value + */ +__attribute__((always_inline)) +static inline void mcpwm_ll_operator_set_compare_value(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, uint32_t compare_value) +{ + if (compare_id == 0) { + HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->operators[operator_id].timestamp[0], cmprn, compare_value); + } else { + HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->operators[operator_id].timestamp[1], cmprn, compare_value); + } +} + +/** + * @brief Set equal value for operator event comparator + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param event_cmpr_id Event Comparator ID, index from 0 to 1 + * @param compare_value Compare value + */ +__attribute__((always_inline)) +static inline void mcpwm_ll_operator_set_event_compare_value(mcpwm_dev_t *mcpwm, int operator_id, int event_cmpr_id, uint32_t compare_value) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->operators_timestamp[operator_id].timestamp[event_cmpr_id], opn_tstmp_e, compare_value); +} + +/** + * @brief Update operator actions immediately + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + */ +static inline void mcpwm_ll_operator_update_action_at_once(mcpwm_dev_t *mcpwm, int operator_id) +{ + mcpwm->operators[operator_id].gen_cfg0.genn_cfg_upmethod = 0; +} + +/** + * @brief Enable update actions on TEZ event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_operator_enable_update_action_on_tez(mcpwm_dev_t *mcpwm, int operator_id, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].gen_cfg0.genn_cfg_upmethod |= 1 << 0; + } else { + mcpwm->operators[operator_id].gen_cfg0.genn_cfg_upmethod &= ~(1 << 0); + } +} + +/** + * @brief Enable update actions on TEP event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_operator_enable_update_action_on_tep(mcpwm_dev_t *mcpwm, int operator_id, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].gen_cfg0.genn_cfg_upmethod |= 1 << 1; + } else { + mcpwm->operators[operator_id].gen_cfg0.genn_cfg_upmethod &= ~(1 << 1); + } +} + +/** + * @brief Enable update actions on sync event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_operator_enable_update_action_on_sync(mcpwm_dev_t *mcpwm, int operator_id, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].gen_cfg0.genn_cfg_upmethod |= 1 << 2; + } else { + mcpwm->operators[operator_id].gen_cfg0.genn_cfg_upmethod &= ~(1 << 2); + } +} + +/** + * @brief Stop updating actions + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param stop_or_not True to stop, False to not stop + */ +static inline void mcpwm_ll_operator_stop_update_action(mcpwm_dev_t *mcpwm, int operator_id, bool stop_or_not) +{ + if (stop_or_not) { + mcpwm->operators[operator_id].gen_cfg0.genn_cfg_upmethod |= 1 << 3; + } else { + mcpwm->operators[operator_id].gen_cfg0.genn_cfg_upmethod &= ~(1 << 3); + } +} + +/** + * @brief Set trigger from GPIO (reuse the fault GPIO) + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param trig_id Trigger ID, index from 0 to 1 + * @param fault_gpio_id Fault GPIO ID, index from 0 to 3 + */ +static inline void mcpwm_ll_operator_set_trigger_from_gpio_fault(mcpwm_dev_t *mcpwm, int operator_id, int trig_id, int fault_gpio_id) +{ + mcpwm->operators[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id)); + mcpwm->operators[operator_id].gen_cfg0.val |= (fault_gpio_id << (4 + 3 * trig_id)); +} + +/** + * @brief Set trigger from sync event (when the timer/gpio/soft taken the sync signal) + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param trig_id Trigger ID, index from 0 to 1 + */ +static inline void mcpwm_ll_operator_set_trigger_from_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id) +{ + // the timer here is not selectable, must be the one connected with the operator + mcpwm->operators[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id)); + mcpwm->operators[operator_id].gen_cfg0.val |= (3 << (4 + 3 * trig_id)); +} + +////////////////////////////////////////MCPWM Generator Specific//////////////////////////////////////////////////////// + +/** + * @brief Reset actions for the generator + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param generator_id Generator ID, index from 0 to 1 + */ +static inline void mcpwm_ll_generator_reset_actions(mcpwm_dev_t *mcpwm, int operator_id, int generator_id) +{ + mcpwm->operators[operator_id].generator[generator_id].val = 0; +} + +/** + * @brief Set generator action on timer event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param generator_id Generator ID, index from 0 to 1 + * @param direction Timer direction + * @param event Timer event + * @param action Action to set + */ +static inline void mcpwm_ll_generator_set_action_on_timer_event(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, + mcpwm_timer_direction_t direction, mcpwm_timer_event_t event, mcpwm_generator_action_t action) +{ + // empty: 0, full: 1 + if (direction == MCPWM_TIMER_DIRECTION_UP) { // utez, utep + mcpwm->operators[operator_id].generator[generator_id].val &= ~(0x03 << (MCPWM_LL_TIMER_EVENT_TO_REG_VAL(event) * 2)); + mcpwm->operators[operator_id].generator[generator_id].val |= MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) << (MCPWM_LL_TIMER_EVENT_TO_REG_VAL(event) * 2); + } else if (direction == MCPWM_TIMER_DIRECTION_DOWN) { // dtez, dtep + mcpwm->operators[operator_id].generator[generator_id].val &= ~(0x03 << (MCPWM_LL_TIMER_EVENT_TO_REG_VAL(event) * 2 + 12)); + mcpwm->operators[operator_id].generator[generator_id].val |= MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) << (MCPWM_LL_TIMER_EVENT_TO_REG_VAL(event) * 2 + 12); + } +} + +/** + * @brief Set generator action on compare event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param generator_id Generator ID, index from 0 to 1 + * @param direction Timer direction + * @param comp_id Compare ID, index from 0 to 1 + * @param action Action to set + */ +static inline void mcpwm_ll_generator_set_action_on_compare_event(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, + mcpwm_timer_direction_t direction, int cmp_id, int action) +{ + if (direction == MCPWM_TIMER_DIRECTION_UP) { // utea, uteb + mcpwm->operators[operator_id].generator[generator_id].val &= ~(0x03 << (cmp_id * 2 + 4)); + mcpwm->operators[operator_id].generator[generator_id].val |= MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) << (cmp_id * 2 + 4); + } else if (direction == MCPWM_TIMER_DIRECTION_DOWN) { // dtea, dteb + mcpwm->operators[operator_id].generator[generator_id].val &= ~(0x03 << (cmp_id * 2 + 16)); + mcpwm->operators[operator_id].generator[generator_id].val |= MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) << (cmp_id * 2 + 16); + } +} + +/** + * @brief Set generator action on trigger event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param generator_id Generator ID, index from 0 to 1 + * @param direction Timer direction + * @param trig_id Trigger ID, index from 0 to 1 + * @param action Action to set + */ +static inline void mcpwm_ll_generator_set_action_on_trigger_event(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, + mcpwm_timer_direction_t direction, int trig_id, int action) +{ + if (direction == MCPWM_TIMER_DIRECTION_UP) { // ut0, ut1 + mcpwm->operators[operator_id].generator[generator_id].val &= ~(0x03 << (trig_id * 2 + 8)); + mcpwm->operators[operator_id].generator[generator_id].val |= MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) << (trig_id * 2 + 8); + } else if (direction == MCPWM_TIMER_DIRECTION_DOWN) { // dt0, dt1 + mcpwm->operators[operator_id].generator[generator_id].val &= ~(0x03 << (trig_id * 2 + 20)); + mcpwm->operators[operator_id].generator[generator_id].val |= MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) << (trig_id * 2 + 20); + } +} + +/** + * @brief Set generator action on brake event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param generator_id Generator ID, index from 0 to 1 + * @param direction Timer direction + * @param brake_mode Brake mode + * @param action Action to set + */ +static inline void mcpwm_ll_generator_set_action_on_brake_event(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, + mcpwm_timer_direction_t direction, mcpwm_operator_brake_mode_t brake_mode, int action) +{ + // the following bit operation is highly depend on the register bit layout. + // the priority comes: generator ID > brake mode > direction + if (direction == MCPWM_TIMER_DIRECTION_UP) { + mcpwm->operators[operator_id].fh_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * MCPWM_LL_BRAKE_MODE_TO_REG_VAL(brake_mode) + 2)); + mcpwm->operators[operator_id].fh_cfg0.val |= MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) << (8 + 8 * generator_id + 4 * MCPWM_LL_BRAKE_MODE_TO_REG_VAL(brake_mode) + 2); + } else if (direction == MCPWM_TIMER_DIRECTION_DOWN) { + mcpwm->operators[operator_id].fh_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * MCPWM_LL_BRAKE_MODE_TO_REG_VAL(brake_mode))); + mcpwm->operators[operator_id].fh_cfg0.val |= MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) << (8 + 8 * generator_id + 4 * MCPWM_LL_BRAKE_MODE_TO_REG_VAL(brake_mode)); + } +} + +/** + * @brief Trigger non-continue forced action for generator + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param generator_id Generator ID, index from 0 to 1 + */ +static inline void mcpwm_ll_gen_trigger_noncontinue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id) +{ + if (generator_id == 0) { + mcpwm->operators[operator_id].gen_force.genn_a_nciforce = ~mcpwm->operators[operator_id].gen_force.genn_a_nciforce; + } else { + mcpwm->operators[operator_id].gen_force.genn_b_nciforce = ~mcpwm->operators[operator_id].gen_force.genn_b_nciforce; + } +} + +/** + * @brief Disable continue forced action for generator + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param generator_id Generator ID, index from 0 to 1 + */ +static inline void mcpwm_ll_gen_disable_continue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id) +{ + mcpwm->operators[operator_id].gen_force.genn_cntuforce_upmethod = 0; // update force method immediately + if (generator_id == 0) { + mcpwm->operators[operator_id].gen_force.genn_a_cntuforce_mode = 0; + } else { + mcpwm->operators[operator_id].gen_force.genn_b_cntuforce_mode = 0; + } +} + +/** + * @brief Disable non-continue forced action for generator + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param generator_id Generator ID, index from 0 to 1 + */ +static inline void mcpwm_ll_gen_disable_noncontinue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id) +{ + if (generator_id == 0) { + mcpwm->operators[operator_id].gen_force.genn_a_nciforce_mode = 0; + } else { + mcpwm->operators[operator_id].gen_force.genn_b_nciforce_mode = 0; + } +} + +/** + * @brief Set continue force level for generator + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param generator_id Generator ID, index from 0 to 1 + * @param level Force level to set + */ +static inline void mcpwm_ll_gen_set_continue_force_level(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int level) +{ + mcpwm->operators[operator_id].gen_force.genn_cntuforce_upmethod = 0; // update force method immediately + if (generator_id == 0) { + mcpwm->operators[operator_id].gen_force.genn_a_cntuforce_mode = level + 1; + } else { + mcpwm->operators[operator_id].gen_force.genn_b_cntuforce_mode = level + 1; + } +} + +/** + * @brief Set non-continue force level for generator + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param generator_id Generator ID, index from 0 to 1 + * @param level Force level to set + */ +static inline void mcpwm_ll_gen_set_noncontinue_force_level(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int level) +{ + if (generator_id == 0) { + mcpwm->operators[operator_id].gen_force.genn_a_nciforce_mode = level + 1; + } else { + mcpwm->operators[operator_id].gen_force.genn_b_nciforce_mode = level + 1; + } +} + +////////////////////////////////////////MCPWM Dead Time Specific//////////////////////////////////////////////////////// + +/** + * @brief Set clock source for dead time submodule + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param src Clock source for dead time submodule + */ +static inline void mcpwm_ll_operator_set_deadtime_clock_src(mcpwm_dev_t *mcpwm, int operator_id, mcpwm_ll_deadtime_clock_src_t src) +{ + switch (src) { + case MCPWM_LL_DEADTIME_CLK_SRC_GROUP: + mcpwm->operators[operator_id].dt_cfg.dbn_clk_sel = 0; + break; + case MCPWM_LL_DEADTIME_CLK_SRC_TIMER: + mcpwm->operators[operator_id].dt_cfg.dbn_clk_sel = 1; + break; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Select the generator for RED block + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param generator Generator ID, index from 0 to 1 + */ +static inline void mcpwm_ll_deadtime_red_select_generator(mcpwm_dev_t *mcpwm, int operator_id, int generator) +{ + mcpwm->operators[operator_id].dt_cfg.dbn_red_insel = generator; +} + +/** + * @brief Select the generator for FED block + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param generator Generator ID, index from 0 to 1 + */ +static inline void mcpwm_ll_deadtime_fed_select_generator(mcpwm_dev_t *mcpwm, int operator_id, int generator) +{ + mcpwm->operators[operator_id].dt_cfg.dbn_fed_insel = generator; +} + +/** + * @brief Set which path to bypass in the deadtime submodule + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param path Path to bypass, index from 0 to 1 + * @param bypass True to bypass, False to not bypass + */ +static inline void mcpwm_ll_deadtime_bypass_path(mcpwm_dev_t *mcpwm, int operator_id, int path, bool bypass) +{ + if (bypass) { + mcpwm->operators[operator_id].dt_cfg.val |= 1 << (path + 15); + } else { + mcpwm->operators[operator_id].dt_cfg.val &= ~(1 << (path + 15)); + } +} + +/** + * @brief Invert the output path + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param path Path to invert, index from 0 to 1 + * @param invert True to invert, False to not invert + */ +static inline void mcpwm_ll_deadtime_invert_outpath(mcpwm_dev_t *mcpwm, int operator_id, int path, bool invert) +{ + if (invert) { + mcpwm->operators[operator_id].dt_cfg.val |= 1 << (path + 13); + } else { + mcpwm->operators[operator_id].dt_cfg.val &= ~(1 << (path + 13)); + } +} + +/** + * @brief Swap the output path + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param path Path to swap, index from 0 to 1 + * @param swap True to swap, False to not swap + */ +static inline void mcpwm_ll_deadtime_swap_out_path(mcpwm_dev_t *mcpwm, int operator_id, int path, bool swap) +{ + if (swap) { + mcpwm->operators[operator_id].dt_cfg.val |= 1 << (path + 9); + } else { + mcpwm->operators[operator_id].dt_cfg.val &= ~(1 << (path + 9)); + } +} + +/** + * @brief Enable the DEB block + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_deadtime_enable_deb(mcpwm_dev_t *mcpwm, int operator_id, bool enable) +{ + mcpwm->operators[operator_id].dt_cfg.dbn_deb_mode = enable; +} + +/** + * @brief Get the deadtime switch topology + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @return Dead time submodule's switch topology, each bit represents one switch on/off status + */ +static inline uint32_t mcpwm_ll_deadtime_get_switch_topology(mcpwm_dev_t *mcpwm, int operator_id) +{ + return (mcpwm->operators[operator_id].dt_cfg.dbn_deb_mode << 8) | (mcpwm->operators[operator_id].dt_cfg.dbn_b_outswap << 7) | + (mcpwm->operators[operator_id].dt_cfg.dbn_a_outswap << 6) | (mcpwm->operators[operator_id].dt_cfg.dbn_fed_insel << 5) | + (mcpwm->operators[operator_id].dt_cfg.dbn_red_insel << 4) | (mcpwm->operators[operator_id].dt_cfg.dbn_fed_outinvert << 3) | + (mcpwm->operators[operator_id].dt_cfg.dbn_red_outinvert << 2) | (mcpwm->operators[operator_id].dt_cfg.dbn_a_outbypass << 1) | + (mcpwm->operators[operator_id].dt_cfg.dbn_b_outbypass << 0); +} + +/** + * @brief Set falling edge delay duration + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param fed Delay duration, in deadtime submodule's clock cycles + */ +static inline void mcpwm_ll_deadtime_set_falling_delay(mcpwm_dev_t *mcpwm, int operator_id, uint32_t fed) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->operators[operator_id].dt_fed_cfg, dbn_fed, fed - 1); +} + +/** + * @brief Set rising edge delay duration + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param red Delay duration, in deadtime submodule's clock cycles + */ +static inline void mcpwm_ll_deadtime_set_rising_delay(mcpwm_dev_t *mcpwm, int operator_id, uint32_t red) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->operators[operator_id].dt_red_cfg, dbn_red, red - 1); +} + +/** + * @brief Update deadtime immediately + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + */ +static inline void mcpwm_ll_deadtime_update_delay_at_once(mcpwm_dev_t *mcpwm, int operator_id) +{ + mcpwm->operators[operator_id].dt_cfg.dbn_fed_upmethod = 0; + mcpwm->operators[operator_id].dt_cfg.dbn_red_upmethod = 0; +} + +/** + * @brief Enable to update deadtime on TEZ event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_deadtime_enable_update_delay_on_tez(mcpwm_dev_t *mcpwm, int operator_id, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].dt_cfg.dbn_fed_upmethod |= 1 << 0; + mcpwm->operators[operator_id].dt_cfg.dbn_red_upmethod |= 1 << 0; + } else { + mcpwm->operators[operator_id].dt_cfg.dbn_fed_upmethod &= ~(1 << 0); + mcpwm->operators[operator_id].dt_cfg.dbn_red_upmethod &= ~(1 << 0); + } +} + +/** + * @brief Enable to update deadtime on TEP event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_deadtime_enable_update_delay_on_tep(mcpwm_dev_t *mcpwm, int operator_id, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].dt_cfg.dbn_fed_upmethod |= 1 << 1; + mcpwm->operators[operator_id].dt_cfg.dbn_red_upmethod |= 1 << 1; + } else { + mcpwm->operators[operator_id].dt_cfg.dbn_fed_upmethod &= ~(1 << 1); + mcpwm->operators[operator_id].dt_cfg.dbn_red_upmethod &= ~(1 << 1); + } +} + +/** + * @brief Enable to update deadtime on sync event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_deadtime_enable_update_delay_on_sync(mcpwm_dev_t *mcpwm, int operator_id, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].dt_cfg.dbn_fed_upmethod |= 1 << 2; + mcpwm->operators[operator_id].dt_cfg.dbn_red_upmethod |= 1 << 2; + } else { + mcpwm->operators[operator_id].dt_cfg.dbn_fed_upmethod &= ~(1 << 2); + mcpwm->operators[operator_id].dt_cfg.dbn_red_upmethod &= ~(1 << 2); + } +} + +/** + * @brief Stop updating deadtime + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param stop_or_not True to stop, False to continue + */ +static inline void mcpwm_ll_deadtime_stop_update_delay(mcpwm_dev_t *mcpwm, int operator_id, bool stop_or_not) +{ + if (stop_or_not) { + mcpwm->operators[operator_id].dt_cfg.dbn_fed_upmethod |= 1 << 3; + mcpwm->operators[operator_id].dt_cfg.dbn_red_upmethod |= 1 << 3; + } else { + mcpwm->operators[operator_id].dt_cfg.dbn_fed_upmethod &= ~(1 << 3); + mcpwm->operators[operator_id].dt_cfg.dbn_red_upmethod &= ~(1 << 3); + } +} + +////////////////////////////////////////MCPWM Carrier Specific////////////////////////////////////////////////////////// + +/** + * @brief Enable carrier for MCPWM operator + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_carrier_enable(mcpwm_dev_t *mcpwm, int operator_id, bool enable) +{ + mcpwm->operators[operator_id].carrier_cfg.choppern_en = enable; +} + +/** + * @brief Set prescale for MCPWM carrier source clock + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param prescale Prescale value + */ +static inline void mcpwm_ll_carrier_set_prescale(mcpwm_dev_t *mcpwm, int operator_id, uint8_t prescale) +{ + HAL_ASSERT(prescale > 0 && prescale <= 16); + mcpwm->operators[operator_id].carrier_cfg.choppern_prescale = prescale - 1; +} + +/** + * @brief Set duty cycle of MCPWM carrier + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param carrier_duty Duty cycle value + */ +static inline void mcpwm_ll_carrier_set_duty(mcpwm_dev_t *mcpwm, int operator_id, uint8_t carrier_duty) +{ + mcpwm->operators[operator_id].carrier_cfg.choppern_duty = carrier_duty; +} + +/** + * @brief Invert the signal after the carrier is applied + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param invert True to invert, False to not invert + */ +static inline void mcpwm_ll_carrier_out_invert(mcpwm_dev_t *mcpwm, int operator_id, bool invert) +{ + mcpwm->operators[operator_id].carrier_cfg.choppern_out_invert = invert; +} + +/** + * @brief Invert the signal before applying the carrier + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param invert True to invert, False to not invert + */ +static inline void mcpwm_ll_carrier_in_invert(mcpwm_dev_t *mcpwm, int operator_id, bool invert) +{ + mcpwm->operators[operator_id].carrier_cfg.choppern_in_invert = invert; +} + +/** + * @brief Set the first pulse width of the carrier + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param pulse_width Pulse width + */ +static inline void mcpwm_ll_carrier_set_first_pulse_width(mcpwm_dev_t *mcpwm, int operator_id, uint8_t pulse_width) +{ + HAL_ASSERT(pulse_width >= 1); + mcpwm->operators[operator_id].carrier_cfg.choppern_oshtwth = pulse_width - 1; +} + +////////////////////////////////////////MCPWM Fault Specific//////////////////////////////////////////////////////////// + +/** + * @brief Enable GPIO fault detection + * + * @param mcpwm Peripheral instance address + * @param fault_sig GPIO fault ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_fault_enable_detection(mcpwm_dev_t *mcpwm, int fault_sig, bool enable) +{ + if (enable) { + mcpwm->fault_detect.val |= 1 << fault_sig; + } else { + mcpwm->fault_detect.val &= ~(1 << fault_sig); + } +} + +/** + * @brief Set fault polarity (i.e. which level is treated as an active fault) + * + * @param mcpwm Peripheral instance address + * @param fault_sig GPIO fault ID, index from 0 to 2 + * @param level Active level, 0 for low, 1 for high + */ +static inline void mcpwm_ll_fault_set_active_level(mcpwm_dev_t *mcpwm, int fault_sig, bool level) +{ + if (level) { + mcpwm->fault_detect.val |= 1 << (fault_sig + 3); + } else { + mcpwm->fault_detect.val &= ~(1 << (fault_sig + 3)); + } +} + +/** + * @brief Clear the OST brake + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + */ +static inline void mcpwm_ll_brake_clear_ost(mcpwm_dev_t *mcpwm, int operator_id) +{ + // a posedge can clear the ost fault status + mcpwm->operators[operator_id].fh_cfg1.tzn_clr_ost = 0; + mcpwm->operators[operator_id].fh_cfg1.tzn_clr_ost = 1; +} + +/** + * @brief Enable the OST brake + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param fault_sig GPIO fault ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_brake_enable_oneshot_mode(mcpwm_dev_t *mcpwm, int operator_id, int fault_sig, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].fh_cfg0.val |= (1 << (7 - fault_sig)); + } else { + mcpwm->operators[operator_id].fh_cfg0.val &= ~(1 << (7 - fault_sig)); + } +} + +/** + * @brief Enable the CBC brake + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param fault_sig GPIO fault ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_brake_enable_cbc_mode(mcpwm_dev_t *mcpwm, int operator_id, int fault_sig, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].fh_cfg0.val |= (enable << (3 - fault_sig)); + } else { + mcpwm->operators[operator_id].fh_cfg0.val &= ~(1 << (3 - fault_sig)); + } +} + +/** + * @brief Enable refresh the CBC brake on TEZ event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_brake_enable_cbc_refresh_on_tez(mcpwm_dev_t *mcpwm, int operator_id, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].fh_cfg1.val |= 1 << 1; + } else { + mcpwm->operators[operator_id].fh_cfg1.val &= ~(1 << 1); + } +} + +/** + * @brief Enable refresh the CBC brake on TEP event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_fault_enable_cbc_refresh_on_tep(mcpwm_dev_t *mcpwm, int operator_id, bool enable) +{ + if (enable) { + mcpwm->operators[operator_id].fh_cfg1.val |= 1 << 2; + } else { + mcpwm->operators[operator_id].fh_cfg1.val &= ~(1 << 2); + } +} + +/** + * @brief Enable software CBC brake + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_brake_enable_soft_cbc(mcpwm_dev_t *mcpwm, int operator_id, bool enable) +{ + mcpwm->operators[operator_id].fh_cfg0.tzn_sw_cbc = enable; +} + +/** + * @brief Enable software OST brake + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_brake_enable_soft_ost(mcpwm_dev_t *mcpwm, int operator_id, bool enable) +{ + mcpwm->operators[operator_id].fh_cfg0.tzn_sw_ost = enable; +} + +/** + * @brief Trigger software CBC brake for once + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + */ +static inline void mcpwm_ll_brake_trigger_soft_cbc(mcpwm_dev_t *mcpwm, int operator_id) +{ + mcpwm->operators[operator_id].fh_cfg1.tzn_force_cbc = ~mcpwm->operators[operator_id].fh_cfg1.tzn_force_cbc; +} + +/** + * @brief Trigger software OST brake for once + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + */ +static inline void mcpwm_ll_brake_trigger_soft_ost(mcpwm_dev_t *mcpwm, int operator_id) +{ + mcpwm->operators[operator_id].fh_cfg1.tzn_force_ost = ~mcpwm->operators[operator_id].fh_cfg1.tzn_force_ost; +} + +/** + * @brief Whether the OST brake is still active + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @return True if active, False if not + */ +static inline bool mcpwm_ll_ost_brake_active(mcpwm_dev_t *mcpwm, int operator_id) +{ + return mcpwm->operators[operator_id].fh_status.tzn_ost_on; +} + +/** + * @brief Whether the CBC brake is still active + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @return True if active, False if not + */ +static inline bool mcpwm_ll_cbc_brake_active(mcpwm_dev_t *mcpwm, int operator_id) +{ + return mcpwm->operators[operator_id].fh_status.tzn_cbc_on; +} + +////////////////////////////////////////MCPWM Capture Specific////////////////////////////////////////////////////////// + +/** + * @brief Enable capture timer + * + * @param mcpwm Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_capture_enable_timer(mcpwm_dev_t *mcpwm, bool enable) +{ + mcpwm->cap_timer_cfg.cap_timer_en = enable; +} + +/** + * @brief Enable capture channel + * + * @param mcpwm Peripheral instance address + * @param channel Channel ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_capture_enable_channel(mcpwm_dev_t *mcpwm, int channel, bool enable) +{ + mcpwm->cap_chn_cfg[channel].capn_en = enable; +} + +/** + * @brief Set sync phase for capture timer + * + * @param mcpwm Peripheral instance address + * @param phase_value Phase value + */ +static inline void mcpwm_ll_capture_set_sync_phase_value(mcpwm_dev_t *mcpwm, uint32_t phase_value) +{ + mcpwm->cap_timer_phase.cap_phase = phase_value; +} + +/** + * @brief Enable sync for capture timer + * + * @param mcpwm Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_capture_enable_timer_sync(mcpwm_dev_t *mcpwm, bool enable) +{ + mcpwm->cap_timer_cfg.cap_synci_en = enable; +} + +/** + * @brief Set the timer sync source for MCPWM capture timer + * + * @param mcpwm Peripheral instance address + * @param sync_out_timer MCPWM Timer ID, index from 0 to 2 + */ +static inline void mcpwm_ll_capture_set_timer_sync(mcpwm_dev_t *mcpwm, int sync_out_timer) +{ + mcpwm->cap_timer_cfg.cap_synci_sel = sync_out_timer + 1; +} + +/** + * @brief Set the GPIO sync source for MCPWM capture timer + * + * @param mcpwm Peripheral instance address + * @param gpio_sync GPIO sync ID, index from 0 to 2 + */ +static inline void mcpwm_ll_capture_set_gpio_sync(mcpwm_dev_t *mcpwm, int gpio_sync) +{ + mcpwm->cap_timer_cfg.cap_synci_sel = gpio_sync + 4; +} + +/** + * @brief Trigger a software sync for capture timer + * + * @param mcpwm Peripheral instance address + */ +static inline void mcpwm_ll_capture_trigger_sw_sync(mcpwm_dev_t *mcpwm) +{ + mcpwm->cap_timer_cfg.cap_sync_sw = 1; // auto clear +} + +/** + * @brief Enable capture on positive edge + * + * @param mcpwm Peripheral instance address + * @param channel Channel ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_capture_enable_posedge(mcpwm_dev_t *mcpwm, int channel, bool enable) +{ + if (enable) { + mcpwm->cap_chn_cfg[channel].val |= 1 << 2; + } else { + mcpwm->cap_chn_cfg[channel].val &= ~(1 << 2); + } +} + +/** + * @brief Enable capture on negative edge + * + * @param mcpwm Peripheral instance address + * @param channel Channel ID, index from 0 to 2 + * @param enable True to enable, False to disable + */ +static inline void mcpwm_ll_capture_enable_negedge(mcpwm_dev_t *mcpwm, int channel, bool enable) +{ + if (enable) { + mcpwm->cap_chn_cfg[channel].val |= 1 << 1; + } else { + mcpwm->cap_chn_cfg[channel].val &= ~(1 << 1); + } +} + +/** + * @brief Invert the capture input signal + * + * @param mcpwm Peripheral instance address + * @param channel Channel ID, index from 0 to 2 + * @param invert True to invert, False to not invert + */ +static inline void mcpwm_ll_invert_input(mcpwm_dev_t *mcpwm, int channel, bool invert) +{ + mcpwm->cap_chn_cfg[channel].capn_in_invert = invert; +} + +/** + * @brief Trigger the software capture for once + * + * @param mcpwm Peripheral instance address + * @param channel Channel ID, index from 0 to 2 + */ +static inline void mcpwm_ll_trigger_soft_capture(mcpwm_dev_t *mcpwm, int channel) +{ + mcpwm->cap_chn_cfg[channel].capn_sw = 1; // auto clear +} + +/** + * @brief Get the captured value + * + * @param mcpwm Peripheral instance address + * @param channel Channel ID, index from 0 to 2 + * @return Captured value + */ +__attribute__((always_inline)) +static inline uint32_t mcpwm_ll_capture_get_value(mcpwm_dev_t *mcpwm, int channel) +{ + return mcpwm->cap_chn[channel].capn_value; +} + +/** + * @brief Get the captured edge + * + * @param mcpwm Peripheral instance address + * @param channel Channel ID, index from 0 to 2 + * @return Captured edge + */ +__attribute__((always_inline)) +static inline mcpwm_capture_edge_t mcpwm_ll_capture_get_edge(mcpwm_dev_t *mcpwm, int channel) +{ + return mcpwm->cap_status.val & (1 << channel) ? MCPWM_CAP_EDGE_NEG : MCPWM_CAP_EDGE_POS; +} + +/** + * @brief Set the prescale of the input capture signal + * + * @param mcpwm Peripheral instance address + * @param channel Channel ID, index from 0 to 2 + * @param prescale Prescale value + */ +static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel, uint32_t prescale) +{ + HAL_ASSERT(prescale > 0); + HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale - 1); +} + +//////////////////////////////////////////MCPWM ETM Specific//////////////////////////////////////////////////////////// + +/** + * @brief Enable comparator ETM event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param cmpr_id Comparator ID, index from 0 to 2 + * @param en True: enable ETM module, False: disable ETM module + */ +static inline void mcpwm_ll_etm_enable_comparator_event(mcpwm_dev_t *mcpwm, int operator_id, int cmpr_id, bool en) +{ + if (en) { + mcpwm->evt_en.val |= 1 << (operator_id + 3 * cmpr_id + 9); + } else { + mcpwm->evt_en.val &= ~(1 << (operator_id + 3 * cmpr_id + 9)); + } +} + +/** + * @brief Enable event_comparator ETM event + * + * @param mcpwm Peripheral instance address + * @param operator_id Operator ID, index from 0 to 2 + * @param evt_cmpr_id Event comparator ID, index from 0 to 2 + * @param en True: enable ETM module, False: disable ETM module + */ +static inline void mcpwm_ll_etm_enable_evt_comparator_event(mcpwm_dev_t *mcpwm, int operator_id, int evt_cmpr_id, bool en) +{ + if (en) { + mcpwm->evt_en2.val |= 1 << (operator_id + 3 * evt_cmpr_id); + } else { + mcpwm->evt_en2.val &= ~(1 << (operator_id + 3 * evt_cmpr_id)); + } +} + +/** + * @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/esp32s31/mcpwm_periph.c b/components/esp_hal_mcpwm/esp32s31/mcpwm_periph.c new file mode 100644 index 0000000000..93b2366e43 --- /dev/null +++ b/components/esp_hal_mcpwm/esp32s31/mcpwm_periph.c @@ -0,0 +1,355 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc.h" +#include "hal/mcpwm_periph.h" +#include "soc/mcpwm_reg.h" +#include "soc/gpio_sig_map.h" + +const soc_mcpwm_signal_desc_t soc_mcpwm_signals[4] = { + { + .module_name = "MCPWM0", + .irq_id = ETS_PWM0_INTR_SOURCE, + .operators = { + [0] = { + .generators = { + [0] = { + .pwm_sig = PWM0_CH0_A_PAD_OUT_IDX + }, + [1] = { + .pwm_sig = PWM0_CH0_B_PAD_OUT_IDX + } + } + }, + [1] = { + .generators = { + [0] = { + .pwm_sig = PWM0_CH1_A_PAD_OUT_IDX + }, + [1] = { + .pwm_sig = PWM0_CH1_B_PAD_OUT_IDX + } + } + }, + [2] = { + .generators = { + [0] = { + .pwm_sig = PWM0_CH2_A_PAD_OUT_IDX + }, + [1] = { + .pwm_sig = PWM0_CH2_B_PAD_OUT_IDX + } + } + } + }, + .gpio_faults = { + [0] = { + .fault_sig = PWM0_F0_PAD_IN_IDX + }, + [1] = { + .fault_sig = PWM0_F1_PAD_IN_IDX + }, + [2] = { + .fault_sig = PWM0_F2_PAD_IN_IDX + } + }, + .captures = { + [0] = { + .cap_sig = PWM0_CAP0_PAD_IN_IDX + }, + [1] = { + .cap_sig = PWM0_CAP1_PAD_IN_IDX + }, + [2] = { + .cap_sig = PWM0_CAP2_PAD_IN_IDX + } + }, + .gpio_synchros = { + [0] = { + .sync_sig = PWM0_SYNC0_PAD_IN_IDX + }, + [1] = { + .sync_sig = PWM0_SYNC1_PAD_IN_IDX + }, + [2] = { + .sync_sig = PWM0_SYNC2_PAD_IN_IDX + } + } + }, + { + .module_name = "MCPWM1", + .irq_id = ETS_PWM1_INTR_SOURCE, + .operators = { + [0] = { + .generators = { + [0] = { + .pwm_sig = PWM1_CH0_A_PAD_OUT_IDX + }, + [1] = { + .pwm_sig = PWM1_CH0_B_PAD_OUT_IDX + } + } + }, + [1] = { + .generators = { + [0] = { + .pwm_sig = PWM1_CH1_A_PAD_OUT_IDX + }, + [1] = { + .pwm_sig = PWM1_CH1_B_PAD_OUT_IDX + } + } + }, + [2] = { + .generators = { + [0] = { + .pwm_sig = PWM1_CH2_A_PAD_OUT_IDX + }, + [1] = { + .pwm_sig = PWM1_CH2_B_PAD_OUT_IDX + } + } + } + }, + .gpio_faults = { + [0] = { + .fault_sig = PWM1_F0_PAD_IN_IDX + }, + [1] = { + .fault_sig = PWM1_F1_PAD_IN_IDX + }, + [2] = { + .fault_sig = PWM1_F2_PAD_IN_IDX + } + }, + .captures = { + [0] = { + .cap_sig = PWM1_CAP0_PAD_IN_IDX + }, + [1] = { + .cap_sig = PWM1_CAP1_PAD_IN_IDX + }, + [2] = { + .cap_sig = PWM1_CAP2_PAD_IN_IDX + } + }, + .gpio_synchros = { + [0] = { + .sync_sig = PWM1_SYNC0_PAD_IN_IDX + }, + [1] = { + .sync_sig = PWM1_SYNC1_PAD_IN_IDX + }, + [2] = { + .sync_sig = PWM1_SYNC2_PAD_IN_IDX + } + } + }, + { + .module_name = "MCPWM2", + .irq_id = ETS_PWM2_INTR_SOURCE, + .operators = { + [0] = { + .generators = { + [0] = { + .pwm_sig = PWM2_CH0_A_PAD_OUT_IDX + }, + [1] = { + .pwm_sig = PWM2_CH0_B_PAD_OUT_IDX + } + } + }, + [1] = { + .generators = { + [0] = { + .pwm_sig = PWM2_CH1_A_PAD_OUT_IDX + }, + [1] = { + .pwm_sig = PWM2_CH1_B_PAD_OUT_IDX + } + } + }, + [2] = { + .generators = { + [0] = { + .pwm_sig = PWM2_CH2_A_PAD_OUT_IDX + }, + [1] = { + .pwm_sig = PWM2_CH2_B_PAD_OUT_IDX + } + } + } + }, + .gpio_faults = { + [0] = { + .fault_sig = PWM2_F0_PAD_IN_IDX + }, + [1] = { + .fault_sig = PWM2_F1_PAD_IN_IDX + }, + [2] = { + .fault_sig = PWM2_F2_PAD_IN_IDX + } + }, + .captures = { + [0] = { + .cap_sig = PWM2_CAP0_PAD_IN_IDX + }, + [1] = { + .cap_sig = PWM2_CAP1_PAD_IN_IDX + }, + [2] = { + .cap_sig = PWM2_CAP2_PAD_IN_IDX + } + }, + .gpio_synchros = { + [0] = { + .sync_sig = PWM2_SYNC0_PAD_IN_IDX + }, + [1] = { + .sync_sig = PWM2_SYNC1_PAD_IN_IDX + }, + [2] = { + .sync_sig = PWM2_SYNC2_PAD_IN_IDX + } + } + }, + { + .module_name = "MCPWM3", + .irq_id = ETS_PWM3_INTR_SOURCE, + .operators = { + [0] = { + .generators = { + [0] = { + .pwm_sig = PWM3_CH0_A_PAD_OUT_IDX + }, + [1] = { + .pwm_sig = PWM3_CH0_B_PAD_OUT_IDX + } + } + }, + [1] = { + .generators = { + [0] = { + .pwm_sig = PWM3_CH1_A_PAD_OUT_IDX + }, + [1] = { + .pwm_sig = PWM3_CH1_B_PAD_OUT_IDX + } + } + }, + [2] = { + .generators = { + [0] = { + .pwm_sig = PWM3_CH2_A_PAD_OUT_IDX + }, + [1] = { + .pwm_sig = PWM3_CH2_B_PAD_OUT_IDX + } + } + } + }, + .gpio_faults = { + [0] = { + .fault_sig = PWM3_F0_PAD_IN_IDX + }, + [1] = { + .fault_sig = PWM3_F1_PAD_IN_IDX + }, + [2] = { + .fault_sig = PWM3_F2_PAD_IN_IDX + } + }, + .captures = { + [0] = { + .cap_sig = PWM3_CAP0_PAD_IN_IDX + }, + [1] = { + .cap_sig = PWM3_CAP1_PAD_IN_IDX + }, + [2] = { + .cap_sig = PWM3_CAP2_PAD_IN_IDX + } + }, + .gpio_synchros = { + [0] = { + .sync_sig = PWM3_SYNC0_PAD_IN_IDX + }, + [1] = { + .sync_sig = PWM3_SYNC1_PAD_IN_IDX + }, + [2] = { + .sync_sig = PWM3_SYNC2_PAD_IN_IDX + } + } + } +}; + +#if SOC_MCPWM_SUPPORT_SLEEP_RETENTION +/** + * MCPWM Registers to be saved during sleep retention + * - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG, MCPWM_TIMER0_CFG2_REG, MCPWM_TIMER0_CFG3_REG + * - Operator Configuration registers, e.g.: MCPWM_OPERATOR_TIMERSEL_REG + * |- Generator Configuration registers, e.g.: MCPWM_GEN0_STMP_CFG_REG, MCPWM_GEN0_TSTMP_A_REG, MCPWM_GEN0_TSTMP_B_REG, MCPWM_GEN0_CFG0_REG, MCPWM_GEN0_FORCE_REG, MCPWM_GEN0_A_REG, MCPWM_GEN0_B_REG + * |- Dead Time Configuration registers, e.g.: MCPWM_DT0_CFG_REG, MCPWM_DT0_FED_CFG_REG, MCPWM_DT0_RED_CFG_REG + * |- Carrier Configuration registers, e.g.: MCPWM_CARRIER0_CFG_REG + * └- Fault Handle Configuration registers, e.g.: MCPWM_FAULT_DETECT_REG, MCPWM_FH0_CFG0_REG, MCPWM_FH0_CFG1_REG + * - Capture Timer Configuration registers, e.g.: MCPWM_CAP_TIMER_CFG_REG, MCPWM_CAP_TIMER_PHASE_REG, MCPWM_CAP_CH0_CFG_REG, MCPWM_CAP_CH1_CFG_REG, MCPWM_CAP_CH2_CFG_REG + * - Interrupt enable registers, e.g.: MCPWM_INT_ENA_REG + * - ETM Configurations, e.g.: MCPWM_EVT_EN_REG, MCPWM_TASK_EN_REG + * - Misc Configurations, e.g.: MCPWM_UPDATE_CFG_REG +*/ +#define MCPWM_RETENTION_REGS_CNT 73 +#define MCPWM_RETENTION_REGS_BASE(i) REG_MCPWM_BASE(i) +static const uint32_t mcpwm_regs_map[4] = {0xf7fff777, 0x3f7ffdff, 0x1f8ff8c, 0x0}; +#define MCPWM_SLEEP_RETENTION_ENTRIES(mcpwm_port) { \ + /* backup stage: save configuration registers \ + restore stage: restore the configuration registers */ \ + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \ + REGDMA_MCPWM_LINK(0x00), \ + MCPWM_RETENTION_REGS_BASE(mcpwm_port), \ + MCPWM_RETENTION_REGS_BASE(mcpwm_port), \ + MCPWM_RETENTION_REGS_CNT, 0, 0, \ + mcpwm_regs_map[0], mcpwm_regs_map[1], \ + mcpwm_regs_map[2], mcpwm_regs_map[3]), \ + .owner = ENTRY(0)}, \ + /* restore stage: trigger a forced update of all active registers*/ \ + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x01), \ + MCPWM_UPDATE_CFG_REG(mcpwm_port), MCPWM_GLOBAL_FORCE_UP, MCPWM_GLOBAL_FORCE_UP_M, 1, 0), \ + .owner = ENTRY(0) }, \ + [2] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x02), \ + MCPWM_UPDATE_CFG_REG(mcpwm_port), 0, MCPWM_GLOBAL_FORCE_UP_M, 1, 0), \ + .owner = ENTRY(0) }, \ +}; + +static const regdma_entries_config_t mcpwm0_regs_retention[] = MCPWM_SLEEP_RETENTION_ENTRIES(0); +static const regdma_entries_config_t mcpwm1_regs_retention[] = MCPWM_SLEEP_RETENTION_ENTRIES(1); +static const regdma_entries_config_t mcpwm2_regs_retention[] = MCPWM_SLEEP_RETENTION_ENTRIES(2); +static const regdma_entries_config_t mcpwm3_regs_retention[] = MCPWM_SLEEP_RETENTION_ENTRIES(3); + +const mcpwm_reg_retention_info_t mcpwm_reg_retention_info[4] = { + [0] = { + .regdma_entry_array = mcpwm0_regs_retention, + .array_size = ARRAY_SIZE(mcpwm0_regs_retention), + .retention_module = SLEEP_RETENTION_MODULE_MCPWM0 + }, + [1] = { + .regdma_entry_array = mcpwm1_regs_retention, + .array_size = ARRAY_SIZE(mcpwm1_regs_retention), + .retention_module = SLEEP_RETENTION_MODULE_MCPWM1 + }, + [2] = { + .regdma_entry_array = mcpwm2_regs_retention, + .array_size = ARRAY_SIZE(mcpwm2_regs_retention), + .retention_module = SLEEP_RETENTION_MODULE_MCPWM2 + }, + [3] = { + .regdma_entry_array = mcpwm3_regs_retention, + .array_size = ARRAY_SIZE(mcpwm3_regs_retention), + .retention_module = SLEEP_RETENTION_MODULE_MCPWM3 + }, +}; +#endif //SOC_MCPWM_SUPPORT_SLEEP_RETENTION diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 9ce4168e5e..03cf2bb788 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -31,6 +31,10 @@ config SOC_GPTIMER_SUPPORTED bool default y +config SOC_MCPWM_SUPPORTED + bool + default y + config SOC_ASYNC_MEMCPY_SUPPORTED bool default y @@ -526,3 +530,19 @@ config SOC_LP_TIMER_BIT_WIDTH_HI config SOC_RTC_TIMER_V3 bool default y + +config SOC_MCPWM_SWSYNC_CAN_PROPAGATE + bool + default y + +config SOC_MCPWM_SUPPORT_ETM + bool + default y + +config SOC_MCPWM_SUPPORT_EVENT_COMPARATOR + bool + default y + +config SOC_MCPWM_CAPTURE_CLK_FROM_GROUP + bool + default y diff --git a/components/soc/esp32s31/include/soc/clk_tree_defs.h b/components/soc/esp32s31/include/soc/clk_tree_defs.h index a0915003d3..d5fcb1f2b8 100644 --- a/components/soc/esp32s31/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s31/include/soc/clk_tree_defs.h @@ -317,6 +317,53 @@ typedef enum { SDM_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M clock as the default clock choice */ } soc_periph_sdm_clk_src_t; +//////////////////////////////////////////////////MCPWM///////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of MCPWM Timer + */ +#define SOC_MCPWM_TIMER_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_PLL_F160M} + +/** + * @brief Type of MCPWM timer clock source + */ +typedef enum { + MCPWM_TIMER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + MCPWM_TIMER_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ + MCPWM_TIMER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ + MCPWM_TIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default choice */ +} soc_periph_mcpwm_timer_clk_src_t; + +/** + * @brief Array initializer for all supported clock sources of MCPWM Capture Timer + */ +#define SOC_MCPWM_CAPTURE_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_PLL_F160M} + +/** + * @brief Type of MCPWM capture clock source + */ +typedef enum { + MCPWM_CAPTURE_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + MCPWM_CAPTURE_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ + MCPWM_CAPTURE_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ + MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default choice */ +} soc_periph_mcpwm_capture_clk_src_t; + +/** + * @brief Array initializer for all supported clock sources of MCPWM Carrier + */ +#define SOC_MCPWM_CARRIER_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_PLL_F20M, SOC_MOD_CLK_PLL_F160M} + +/** + * @brief Type of MCPWM carrier clock source + */ +typedef enum { + MCPWM_CARRIER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + MCPWM_CARRIER_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ + MCPWM_CARRIER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ + MCPWM_CARRIER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default choice */ +} soc_periph_mcpwm_carrier_clk_src_t; + //////////////////////////////////////////////CLOCK OUTPUT/////////////////////////////////////////////////////////// typedef enum { CLKOUT_SIG_MPLL = 0, /*!< MPLL is from 40MHz XTAL oscillator frequency multipliers */ diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index de70ef109b..57bb7e9cc6 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -39,7 +39,7 @@ // #define SOC_LCDCAM_CAM_SUPPORTED 1 // TODO: [ESP32S31] IDF-14722 // #define SOC_LCDCAM_I80_LCD_SUPPORTED 1 // TODO: [ESP32S31] IDF-14722 // #define SOC_LCDCAM_RGB_LCD_SUPPORTED 1 // TODO: [ESP32S31] IDF-14722 -// #define SOC_MCPWM_SUPPORTED 1 // TODO: [ESP32S31] IDF-14756 +#define SOC_MCPWM_SUPPORTED 1 // #define SOC_TWAI_SUPPORTED 1 // TODO: [ESP32S31] IDF-14719 // #define SOC_ETM_SUPPORTED 1 // TODO: [ESP32S31] IDF-14724 // #define SOC_PARLIO_SUPPORTED 1 // TODO: [ESP32S31] IDF-14711 @@ -325,3 +325,10 @@ #define SOC_LP_TIMER_BIT_WIDTH_LO 32 // Bit width of lp_timer low part #define SOC_LP_TIMER_BIT_WIDTH_HI 16 // Bit width of lp_timer high part #define SOC_RTC_TIMER_V3 1 + +/*-------------------------- MCPWM CAPS --------------------------------------*/ +#define SOC_MCPWM_SWSYNC_CAN_PROPAGATE (1) ///< Software sync event can be routed to its output +#define SOC_MCPWM_SUPPORT_ETM (1) ///< Support ETM (Event Task Matrix) +#define SOC_MCPWM_SUPPORT_EVENT_COMPARATOR (1) ///< Support event comparator (based on ETM) +#define SOC_MCPWM_CAPTURE_CLK_FROM_GROUP (1) ///< Capture timer shares clock with other PWM timers +// #define SOC_MCPWM_SUPPORT_SLEEP_RETENTION (1) ///< Support back up registers before sleep diff --git a/components/soc/esp32s31/register/soc/mcpwm_reg.h b/components/soc/esp32s31/register/soc/mcpwm_reg.h index 24274001f7..64b829a58b 100644 --- a/components/soc/esp32s31/register/soc/mcpwm_reg.h +++ b/components/soc/esp32s31/register/soc/mcpwm_reg.h @@ -7,6 +7,9 @@ #include #include "soc/soc.h" + +#define REG_MCPWM_BASE(i) (DR_REG_MCPWM0_BASE + (i) * 0x1000) + #ifdef __cplusplus extern "C" { #endif diff --git a/components/soc/esp32s31/register/soc/mcpwm_struct.h b/components/soc/esp32s31/register/soc/mcpwm_struct.h index f71d3c07f8..73a5999f17 100644 --- a/components/soc/esp32s31/register/soc/mcpwm_struct.h +++ b/components/soc/esp32s31/register/soc/mcpwm_struct.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 OR MIT */ @@ -242,33 +242,19 @@ typedef union { uint32_t val; } mcpwm_genn_stmp_cfg_reg_t; -/** Type of genn_tstmp_a register - * Generatorn time stamp A's shadow register +/** Type of genn_tstmp register + * Generatorn time stamp shadow register (unified type for array access) */ typedef union { struct { - /** cmprn_a : R/W; bitpos: [15:0]; default: 0; - * Configures the value of PWM generator n time stamp A's shadow register. + /** cmprn : R/W; bitpos: [15:0]; default: 0; + * Configures the value of PWM generator n time stamp shadow register. */ - uint32_t cmprn_a:16; + uint32_t cmprn:16; uint32_t reserved_16:16; }; uint32_t val; -} mcpwm_genn_tstmp_a_reg_t; - -/** Type of genn_tstmp_b register - * Generatorn time stamp B's shadow register - */ -typedef union { - struct { - /** cmprn_b : R/W; bitpos: [15:0]; default: 0; - * Configures the value of PWM generator n time stamp B's shadow register. - */ - uint32_t cmprn_b:16; - uint32_t reserved_16:16; - }; - uint32_t val; -} mcpwm_genn_tstmp_b_reg_t; +} mcpwm_genn_tstmp_reg_t; /** Type of genn_cfg0 register * Generatorn fault event T0 and T1 configuration register @@ -371,217 +357,76 @@ typedef union { uint32_t val; } mcpwm_genn_force_reg_t; -/** Type of genn_a register - * PWMn output signal A actions configuration register - */ -typedef union { - struct { - /** genn_a_utez : R/W; bitpos: [1:0]; default: 0; - * Configures action on PWMn A triggered by event TEZ when timer increasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle - */ - uint32_t genn_a_utez:2; - /** genn_a_utep : R/W; bitpos: [3:2]; default: 0; - * Configures action on PWMn A triggered by event TEP when timer increasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle - */ - uint32_t genn_a_utep:2; - /** genn_a_utea : R/W; bitpos: [5:4]; default: 0; - * Configures action on PWMn A triggered by event TEA when timer increasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle - */ - uint32_t genn_a_utea:2; - /** genn_a_uteb : R/W; bitpos: [7:6]; default: 0; - * Configures action on PWMn A triggered by event TEB when timer increasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle - */ - uint32_t genn_a_uteb:2; - /** genn_a_ut0 : R/W; bitpos: [9:8]; default: 0; - * Configures action on PWMn A triggered by event_t0 when timer increasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle - */ - uint32_t genn_a_ut0:2; - /** genn_a_ut1 : R/W; bitpos: [11:10]; default: 0; - * Configures action on PWMn A triggered by event_t1 when timer increasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle - */ - uint32_t genn_a_ut1:2; - /** genn_a_dtez : R/W; bitpos: [13:12]; default: 0; - * Configures action on PWMn A triggered by event TEZ when timer decreasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle - */ - uint32_t genn_a_dtez:2; - /** genn_a_dtep : R/W; bitpos: [15:14]; default: 0; - * Configures action on PWMn A triggered by event TEP when timer decreasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle - */ - uint32_t genn_a_dtep:2; - /** genn_a_dtea : R/W; bitpos: [17:16]; default: 0; - * Configures action on PWMn A triggered by event TEA when timer decreasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle - */ - uint32_t genn_a_dtea:2; - /** genn_a_dteb : R/W; bitpos: [19:18]; default: 0; - * Configures action on PWMn A triggered by event TEB when timer decreasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle - */ - uint32_t genn_a_dteb:2; - /** genn_a_dt0 : R/W; bitpos: [21:20]; default: 0; - * Configures action on PWMn A triggered by event_t0 when timer decreasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle - */ - uint32_t genn_a_dt0:2; - /** genn_a_dt1 : R/W; bitpos: [23:22]; default: 0; - * Configures action on PWMn A triggered by event_t1 when timer decreasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle - */ - uint32_t genn_a_dt1:2; - uint32_t reserved_24:8; - }; - uint32_t val; -} mcpwm_genn_a_reg_t; -/** Type of genn_b register - * PWMn output signal B actions configuration register +/** Type of genn register + * PWMn output signal actions configuration register (unified type for array access) */ typedef union { struct { - /** genn_b_utez : R/W; bitpos: [1:0]; default: 0; - * Configures action on PWMn B triggered by event TEZ when timer increasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle + /** genn_utez : R/W; bitpos: [1:0]; default: 0; + * Configures action on PWMn triggered by event TEZ when timer increasing. + * 0: No change, 1: Low, 2: High, 3: Toggle */ - uint32_t genn_b_utez:2; - /** genn_b_utep : R/W; bitpos: [3:2]; default: 0; - * Configures action on PWMn B triggered by event TEP when timer increasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle + uint32_t genn_utez:2; + /** genn_utep : R/W; bitpos: [3:2]; default: 0; + * Configures action on PWMn triggered by event TEP when timer increasing. + * 0: No change, 1: Low, 2: High, 3: Toggle */ - uint32_t genn_b_utep:2; - /** genn_b_utea : R/W; bitpos: [5:4]; default: 0; - * Configures action on PWMn B triggered by event TEA when timer increasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle + uint32_t genn_utep:2; + /** genn_utea : R/W; bitpos: [5:4]; default: 0; + * Configures action on PWMn triggered by event TEA when timer increasing. + * 0: No change, 1: Low, 2: High, 3: Toggle */ - uint32_t genn_b_utea:2; - /** genn_b_uteb : R/W; bitpos: [7:6]; default: 0; - * Configures action on PWMn B triggered by event TEB when timer increasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle + uint32_t genn_utea:2; + /** genn_uteb : R/W; bitpos: [7:6]; default: 0; + * Configures action on PWMn triggered by event TEB when timer increasing. + * 0: No change, 1: Low, 2: High, 3: Toggle */ - uint32_t genn_b_uteb:2; - /** genn_b_ut0 : R/W; bitpos: [9:8]; default: 0; - * Configures action on PWMn B triggered by event_t0 when timer increasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle + uint32_t genn_uteb:2; + /** genn_ut0 : R/W; bitpos: [9:8]; default: 0; + * Configures action on PWMn triggered by event_t0 when timer increasing. + * 0: No change, 1: Low, 2: High, 3: Toggle */ - uint32_t genn_b_ut0:2; - /** genn_b_ut1 : R/W; bitpos: [11:10]; default: 0; - * Configures action on PWMn B triggered by event_t1 when timer increasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle + uint32_t genn_ut0:2; + /** genn_ut1 : R/W; bitpos: [11:10]; default: 0; + * Configures action on PWMn triggered by event_t1 when timer increasing. + * 0: No change, 1: Low, 2: High, 3: Toggle */ - uint32_t genn_b_ut1:2; - /** genn_b_dtez : R/W; bitpos: [13:12]; default: 0; - * Configures action on PWMn B triggered by event TEZ when timer decreasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle + uint32_t genn_ut1:2; + /** genn_dtez : R/W; bitpos: [13:12]; default: 0; + * Configures action on PWMn triggered by event TEZ when timer decreasing. + * 0: No change, 1: Low, 2: High, 3: Toggle */ - uint32_t genn_b_dtez:2; - /** genn_b_dtep : R/W; bitpos: [15:14]; default: 0; - * Configures action on PWMn B triggered by event TEP when timer decreasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle + uint32_t genn_dtez:2; + /** genn_dtep : R/W; bitpos: [15:14]; default: 0; + * Configures action on PWMn triggered by event TEP when timer decreasing. + * 0: No change, 1: Low, 2: High, 3: Toggle */ - uint32_t genn_b_dtep:2; - /** genn_b_dtea : R/W; bitpos: [17:16]; default: 0; - * Configures action on PWMn B triggered by event TEA when timer decreasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle + uint32_t genn_dtep:2; + /** genn_dtea : R/W; bitpos: [17:16]; default: 0; + * Configures action on PWMn triggered by event TEA when timer decreasing. + * 0: No change, 1: Low, 2: High, 3: Toggle */ - uint32_t genn_b_dtea:2; - /** genn_b_dteb : R/W; bitpos: [19:18]; default: 0; - * Configures action on PWMn B triggered by event TEB when timer decreasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle + uint32_t genn_dtea:2; + /** genn_dteb : R/W; bitpos: [19:18]; default: 0; + * Configures action on PWMn triggered by event TEB when timer decreasing. + * 0: No change, 1: Low, 2: High, 3: Toggle */ - uint32_t genn_b_dteb:2; - /** genn_b_dt0 : R/W; bitpos: [21:20]; default: 0; - * Configures action on PWMn B triggered by event_t0 when timer decreasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle + uint32_t genn_dteb:2; + /** genn_dt0 : R/W; bitpos: [21:20]; default: 0; + * Configures action on PWMn triggered by event_t0 when timer decreasing. + * 0: No change, 1: Low, 2: High, 3: Toggle */ - uint32_t genn_b_dt0:2; - /** genn_b_dt1 : R/W; bitpos: [23:22]; default: 0; - * Configures action on PWMn B triggered by event_t1 when timer decreasing. - * 0: No change - * 1: Low - * 2: High - * 3: Toggle + uint32_t genn_dt0:2; + /** genn_dt1 : R/W; bitpos: [23:22]; default: 0; + * Configures action on PWMn triggered by event_t1 when timer decreasing. + * 0: No change, 1: Low, 2: High, 3: Toggle */ - uint32_t genn_b_dt1:2; + uint32_t genn_dt1:2; uint32_t reserved_24:8; }; uint32_t val; -} mcpwm_genn_b_reg_t; +} mcpwm_genn_reg_t; /** Type of dtn_cfg register * Dead time configuration register @@ -1570,33 +1415,19 @@ typedef union { uint32_t val; } mcpwm_evt_en2_reg_t; -/** Type of opn_tstmp_e1 register - * Generatorn timer stamp E1 value register +/** Type of opn_tstmp register + * Operator timestamp register (unified type for array access) */ typedef union { struct { - /** opn_tstmp_e1 : R/W; bitpos: [15:0]; default: 0; - * Configures generatorn timer stamp E1 value register + /** opn_tstmp_e : R/W; bitpos: [15:0]; default: 0; + * Configures the value of PWM operator timestamp. */ - uint32_t opn_tstmp_e1:16; + uint32_t opn_tstmp_e:16; uint32_t reserved_16:16; }; uint32_t val; -} mcpwm_opn_tstmp_e1_reg_t; - -/** Type of opn_tstmp_e2 register - * Generatorn timer stamp E2 value register - */ -typedef union { - struct { - /** opn_tstmp_e2 : R/W; bitpos: [15:0]; default: 0; - * Configures generatorn timer stamp E2 value register - */ - uint32_t opn_tstmp_e2:16; - uint32_t reserved_16:16; - }; - uint32_t val; -} mcpwm_opn_tstmp_e2_reg_t; +} mcpwm_opn_tstmp_reg_t; /** Type of clk register * Global configuration register @@ -1614,65 +1445,35 @@ typedef union { uint32_t val; } mcpwm_clk_reg_t; -/** Type of timern_cfg2 register - * PWM timern timestamp a configuration register. +/** Type of timer_tstmp_cfg register + * PWM timern timestamp a configuration register. (unified type for array access) */ typedef union { struct { - /** timern_a : R/W; bitpos: [15:0]; default: 255; - * Configures the timestamp a shadow of PWM timern + /** timern_tstmp : R/W; bitpos: [15:0]; default: 255; + * Configures the timestamp shadow of PWM timern */ - uint32_t timern_a:16; - /** timern_a_upmethod : R/W; bitpos: [17:16]; default: 0; - * Configures the update method for active register of PWM timern timestamp a. + uint32_t timern_tstmp:16; + /** timern_upmethod : R/W; bitpos: [17:16]; default: 0; + * Configures the update method for active register of PWM timern timestamp. * 0: Immediate * 1: TEZ * 2: Sync * 3: TEZ or sync * TEZ here and below means timer equal zero event */ - uint32_t timern_a_upmethod:2; - /** timern_a_dir : R/W; bitpos: [18]; default: 0; - * Configures the direction of the timer when timern value equal a value for event + uint32_t timern_upmethod:2; + /** timern_dir : R/W; bitpos: [18]; default: 0; + * Configures the direction of the timer when timern value equal value for event * trigger. * 0: up * 1: down */ - uint32_t timern_a_dir:1; + uint32_t timern_dir:1; uint32_t reserved_19:13; }; uint32_t val; -} mcpwm_timern_cfg2_reg_t; - -/** Type of timern_cfg3 register - * PWM timern timestamp b configuration register. - */ -typedef union { - struct { - /** timern_b : R/W; bitpos: [15:0]; default: 255; - * Configures the timestamp b shadow of PWM timern - */ - uint32_t timern_b:16; - /** timern_b_upmethod : R/W; bitpos: [17:16]; default: 0; - * Configures the update method for active register of PWM timern timestamp b. - * 0: Immediate - * 1: TEZ - * 2: Sync - * 3: TEZ or sync - * TEZ here and below means timer equal zero event - */ - uint32_t timern_b_upmethod:2; - /** timern_b_dir : R/W; bitpos: [18]; default: 0; - * Configures the direction of the timer when timern value equal b value for event - * trigger. - * 0: up - * 1: down - */ - uint32_t timern_b_dir:1; - uint32_t reserved_19:13; - }; - uint32_t val; -} mcpwm_timern_cfg3_reg_t; +} mcpwm_timern_tstmp_cfg_reg_t; /** Group: Status register */ @@ -2369,64 +2170,41 @@ typedef union { uint32_t val; } mcpwm_version_reg_t; +typedef struct { + volatile mcpwm_timern_cfg0_reg_t timern_cfg0; + volatile mcpwm_timern_cfg1_reg_t timern_cfg1; + volatile mcpwm_timern_sync_reg_t timern_sync; + volatile mcpwm_timern_status_reg_t timern_status; +} mcpwm_timer_regs_t; typedef struct { - volatile mcpwm_timern_cfg0_reg_t timer0_cfg0; - volatile mcpwm_timern_cfg1_reg_t timer0_cfg1; - volatile mcpwm_timern_sync_reg_t timer0_sync; - volatile mcpwm_timern_status_reg_t timer0_status; - volatile mcpwm_timern_cfg0_reg_t timer1_cfg0; - volatile mcpwm_timern_cfg1_reg_t timer1_cfg1; - volatile mcpwm_timern_sync_reg_t timer1_sync; - volatile mcpwm_timern_status_reg_t timer1_status; - volatile mcpwm_timern_cfg0_reg_t timer2_cfg0; - volatile mcpwm_timern_cfg1_reg_t timer2_cfg1; - volatile mcpwm_timern_sync_reg_t timer2_sync; - volatile mcpwm_timern_status_reg_t timer2_status; + volatile mcpwm_genn_stmp_cfg_reg_t gen_stmp_cfg; + volatile mcpwm_genn_tstmp_reg_t timestamp[2]; + volatile mcpwm_genn_cfg0_reg_t gen_cfg0; + volatile mcpwm_genn_force_reg_t gen_force; + volatile mcpwm_genn_reg_t generator[2]; + volatile mcpwm_dtn_cfg_reg_t dt_cfg; + volatile mcpwm_dtn_fed_cfg_reg_t dt_fed_cfg; + volatile mcpwm_dtn_red_cfg_reg_t dt_red_cfg; + volatile mcpwm_carriern_cfg_reg_t carrier_cfg; + volatile mcpwm_fhn_cfg0_reg_t fh_cfg0; + volatile mcpwm_fhn_cfg1_reg_t fh_cfg1; + volatile mcpwm_fhn_status_reg_t fh_status; +} mcpwm_operator_reg_t; + +typedef struct { + volatile mcpwm_opn_tstmp_reg_t timestamp[2]; +} mcpwm_operator_tstmp_reg_t; + +typedef struct { + volatile mcpwm_timern_tstmp_cfg_reg_t timer_tstmp_cfg[2]; +} mcpwm_timer_tstmp_reg_t; + +typedef struct mcpwm_dev_t { + volatile mcpwm_timer_regs_t timer[3]; volatile mcpwm_timer_synci_cfg_reg_t timer_synci_cfg; volatile mcpwm_operator_timersel_reg_t operator_timersel; - volatile mcpwm_genn_stmp_cfg_reg_t gen0_stmp_cfg; - volatile mcpwm_genn_tstmp_a_reg_t gen0_tstmp_a; - volatile mcpwm_genn_tstmp_b_reg_t gen0_tstmp_b; - volatile mcpwm_genn_cfg0_reg_t gen0_cfg0; - volatile mcpwm_genn_force_reg_t gen0_force; - volatile mcpwm_genn_a_reg_t gen0_a; - volatile mcpwm_genn_b_reg_t gen0_b; - volatile mcpwm_dtn_cfg_reg_t dt0_cfg; - volatile mcpwm_dtn_fed_cfg_reg_t dt0_fed_cfg; - volatile mcpwm_dtn_red_cfg_reg_t dt0_red_cfg; - volatile mcpwm_carriern_cfg_reg_t carrier0_cfg; - volatile mcpwm_fhn_cfg0_reg_t fh0_cfg0; - volatile mcpwm_fhn_cfg1_reg_t fh0_cfg1; - volatile mcpwm_fhn_status_reg_t fh0_status; - volatile mcpwm_genn_stmp_cfg_reg_t gen1_stmp_cfg; - volatile mcpwm_genn_tstmp_a_reg_t gen1_tstmp_a; - volatile mcpwm_genn_tstmp_b_reg_t gen1_tstmp_b; - volatile mcpwm_genn_cfg0_reg_t gen1_cfg0; - volatile mcpwm_genn_force_reg_t gen1_force; - volatile mcpwm_genn_a_reg_t gen1_a; - volatile mcpwm_genn_b_reg_t gen1_b; - volatile mcpwm_dtn_cfg_reg_t dt1_cfg; - volatile mcpwm_dtn_fed_cfg_reg_t dt1_fed_cfg; - volatile mcpwm_dtn_red_cfg_reg_t dt1_red_cfg; - volatile mcpwm_carriern_cfg_reg_t carrier1_cfg; - volatile mcpwm_fhn_cfg0_reg_t fh1_cfg0; - volatile mcpwm_fhn_cfg1_reg_t fh1_cfg1; - volatile mcpwm_fhn_status_reg_t fh1_status; - volatile mcpwm_genn_stmp_cfg_reg_t gen2_stmp_cfg; - volatile mcpwm_genn_tstmp_a_reg_t gen2_tstmp_a; - volatile mcpwm_genn_tstmp_b_reg_t gen2_tstmp_b; - volatile mcpwm_genn_cfg0_reg_t gen2_cfg0; - volatile mcpwm_genn_force_reg_t gen2_force; - volatile mcpwm_genn_a_reg_t gen2_a; - volatile mcpwm_genn_b_reg_t gen2_b; - volatile mcpwm_dtn_cfg_reg_t dt2_cfg; - volatile mcpwm_dtn_fed_cfg_reg_t dt2_fed_cfg; - volatile mcpwm_dtn_red_cfg_reg_t dt2_red_cfg; - volatile mcpwm_carriern_cfg_reg_t carrier2_cfg; - volatile mcpwm_fhn_cfg0_reg_t fh2_cfg0; - volatile mcpwm_fhn_cfg1_reg_t fh2_cfg1; - volatile mcpwm_fhn_status_reg_t fh2_status; + volatile mcpwm_operator_reg_t operators[3]; volatile mcpwm_fault_detect_reg_t fault_detect; volatile mcpwm_cap_timer_cfg_reg_t cap_timer_cfg; volatile mcpwm_cap_timer_phase_reg_t cap_timer_phase; @@ -2441,23 +2219,17 @@ typedef struct { volatile mcpwm_evt_en_reg_t evt_en; volatile mcpwm_task_en_reg_t task_en; volatile mcpwm_evt_en2_reg_t evt_en2; - volatile mcpwm_opn_tstmp_e1_reg_t op0_tstmp_e1; - volatile mcpwm_opn_tstmp_e2_reg_t op0_tstmp_e2; - volatile mcpwm_opn_tstmp_e1_reg_t op1_tstmp_e1; - volatile mcpwm_opn_tstmp_e2_reg_t op1_tstmp_e2; - volatile mcpwm_opn_tstmp_e1_reg_t op2_tstmp_e1; - volatile mcpwm_opn_tstmp_e2_reg_t op2_tstmp_e2; + volatile mcpwm_operator_tstmp_reg_t operators_timestamp[3]; volatile mcpwm_clk_reg_t clk; volatile mcpwm_version_reg_t version; uint32_t reserved_148; - volatile mcpwm_timern_cfg2_reg_t timer0_cfg2; - volatile mcpwm_timern_cfg3_reg_t timer0_cfg3; - volatile mcpwm_timern_cfg2_reg_t timer1_cfg2; - volatile mcpwm_timern_cfg3_reg_t timer1_cfg3; - volatile mcpwm_timern_cfg2_reg_t timer2_cfg2; - volatile mcpwm_timern_cfg3_reg_t timer2_cfg3; + volatile mcpwm_timer_tstmp_reg_t timers_timestamp[3]; } mcpwm_dev_t; +extern mcpwm_dev_t MCPWM0; +extern mcpwm_dev_t MCPWM1; +extern mcpwm_dev_t MCPWM2; +extern mcpwm_dev_t MCPWM3; #ifndef __cplusplus _Static_assert(sizeof(mcpwm_dev_t) == 0x164, "Invalid size of mcpwm_dev_t structure"); diff --git a/docs/en/api-reference/peripherals/mcpwm.rst b/docs/en/api-reference/peripherals/mcpwm.rst index 371aad6cc3..6850a1bcd7 100644 --- a/docs/en/api-reference/peripherals/mcpwm.rst +++ b/docs/en/api-reference/peripherals/mcpwm.rst @@ -48,7 +48,7 @@ Description of the MCPWM functionality is divided into the following sections: - :ref:`mcpwm-generator-force-actions` - describes how to control the generator output level asynchronously in a forceful way. - :ref:`mcpwm-synchronization` - describes how to synchronize the MCPWM timers and get a fixed phase difference between the generated PWM signals. - :ref:`mcpwm-capture` - describes how to use the MCPWM capture module to measure the pulse width of a signal. - :SOC_MCPWM_SUPPORT_ETM: - :ref:`mcpwm-etm-event-and-task` - describes what the events and tasks can be connected to the ETM channel. + :SOC_MCPWM_SUPPORT_ETM and SOC_ETM_SUPPORTED: - :ref:`mcpwm-etm-event-and-task` - describes what the events and tasks can be connected to the ETM channel. - :ref:`mcpwm-power-management` - describes how different source clocks affects power consumption. - :ref:`mcpwm-resolution-config` - describes the resolution configuration rules for the MCPWM submodule. - :ref:`mcpwm-iram-safe` - describes tips on how to make the RMT interrupt work better along with a disabled cache. @@ -121,7 +121,7 @@ The :cpp:func:`mcpwm_new_comparator` will return a pointer to the allocated comp On the contrary, calling the :cpp:func:`mcpwm_del_comparator` function will free the allocated comparator object. -.. only:: SOC_MCPWM_SUPPORT_EVENT_COMPARATOR and SOC_MCPWM_SUPPORT_ETM +.. only:: SOC_MCPWM_SUPPORT_EVENT_COMPARATOR and SOC_MCPWM_SUPPORT_ETM and SOC_ETM_SUPPORTED There's another kind of comparator called "Event Comparator", which **can not** control the final PWM directly but only generates the ETM events at a configurable time stamp. You can allocate an event comparator by calling the :cpp:func:`mcpwm_new_event_comparator` function. This function will return the same handle type as :cpp:func:`mcpwm_new_comparator`, but with a different configuration structure :cpp:type:`mcpwm_event_comparator_config_t`. For more information, please refer to :ref:`mcpwm-etm-event-and-task`. @@ -953,7 +953,7 @@ Get the Last Captured Value If you don't want to process the captured value in the capture event callback function, but want to process it in other places, you can call :cpp:func:`mcpwm_capture_get_latched_value` to get the last captured value. -.. only:: SOC_MCPWM_SUPPORT_ETM +.. only:: SOC_MCPWM_SUPPORT_ETM and SOC_ETM_SUPPORTED .. _mcpwm-etm-event-and-task: @@ -966,7 +966,7 @@ If you don't want to process the captured value in the capture event callback fu .. _mcpwm-power-management: -.. only:: not SOC_MCPWM_SUPPORT_ETM +.. only:: not (SOC_MCPWM_SUPPORT_ETM and SOC_ETM_SUPPORTED) .. _mcpwm-power-management: diff --git a/docs/zh_CN/api-reference/peripherals/mcpwm.rst b/docs/zh_CN/api-reference/peripherals/mcpwm.rst index 11f9ae7d30..e2edf3fb07 100644 --- a/docs/zh_CN/api-reference/peripherals/mcpwm.rst +++ b/docs/zh_CN/api-reference/peripherals/mcpwm.rst @@ -48,7 +48,7 @@ MCPWM 外设是一个多功能 PWM 生成器,集成多个子模块,在电力 - :ref:`mcpwm-generator-force-actions` - 介绍如何强制异步控制生成器的输出水平。 - :ref:`mcpwm-synchronization` - 介绍如何同步 MCPWM 定时器,并确保生成的最终输出 PWM 信号具有固定的相位差。 - :ref:`mcpwm-capture` - 介绍如何使用 MCPWM 捕获模块测量信号脉宽。 - :SOC_MCPWM_SUPPORT_ETM: - :ref:`mcpwm-etm-event-and-task` - MCPWM 提供了哪些事件和任务可以连接到 ETM 通道上。 + :SOC_MCPWM_SUPPORT_ETM and SOC_ETM_SUPPORTED: - :ref:`mcpwm-etm-event-and-task` - MCPWM 提供了哪些事件和任务可以连接到 ETM 通道上。 - :ref:`mcpwm-power-management` - 介绍不同的时钟源对功耗的影响。 - :ref:`mcpwm-resolution-config` - 介绍 MCPWM 子模块的分辨率配置规则。 - :ref:`mcpwm-iram-safe` - 介绍如何协调 RMT 中断与禁用缓存。 @@ -121,7 +121,7 @@ MCPWM 比较器 反之,调用 :cpp:func:`mcpwm_del_comparator` 函数将释放已分配的比较器。 -.. only:: SOC_MCPWM_SUPPORT_EVENT_COMPARATOR and SOC_MCPWM_SUPPORT_ETM +.. only:: SOC_MCPWM_SUPPORT_EVENT_COMPARATOR and SOC_MCPWM_SUPPORT_ETM and SOC_ETM_SUPPORTED MCPWM 中还有另外一种比较器 —— “事件比较器”,它不能直接控制 PWM 的输出,只能用来产生 EMT 子系统中使用到的事件。事件比较器能够设置的阈值也是可配的。调用 :cpp:func:`mcpwm_new_event_comparator` 函数可以申请一个事件比较器,该函数返回的句柄类型和 :cpp:func:`mcpwm_new_comparator` 函数一样,但是需要的配置结构体是不同的。事件比较器的配置位于 :cpp:type:`mcpwm_event_comparator_config_t`。更多相关内容请参阅 :ref:`mcpwm-etm-event-and-task`。 @@ -953,7 +953,7 @@ MCPWM 捕获通道支持在信号上检测到有效边沿时发送通知。须 如果不想在捕获事件回调函数中处理捕获值,而是想在其他地方处理,可以调用 :cpp:func:`mcpwm_capture_get_latched_value` 获得上一次锁存的捕获值。 -.. only:: SOC_MCPWM_SUPPORT_ETM +.. only:: SOC_MCPWM_SUPPORT_ETM and SOC_ETM_SUPPORTED .. _mcpwm-etm-event-and-task: @@ -962,11 +962,12 @@ MCPWM 捕获通道支持在信号上检测到有效边沿时发送通知。须 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-power-management: -.. only:: not SOC_MCPWM_SUPPORT_ETM +.. only:: not (SOC_MCPWM_SUPPORT_ETM and SOC_ETM_SUPPORTED) .. _mcpwm-power-management: diff --git a/examples/peripherals/mcpwm/mcpwm_bldc_hall_control/README.md b/examples/peripherals/mcpwm/mcpwm_bldc_hall_control/README.md index ad8367ebb7..20a1c03454 100644 --- a/examples/peripherals/mcpwm/mcpwm_bldc_hall_control/README.md +++ b/examples/peripherals/mcpwm/mcpwm_bldc_hall_control/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | --------- | # MCPWM BLDC Motor Control with HALL Sensor Example diff --git a/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/README.md b/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/README.md index 40ff93752f..d51a07bb21 100644 --- a/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/README.md +++ b/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | --------- | # HC-SR04 Example based on MCPWM Capture diff --git a/examples/peripherals/mcpwm/mcpwm_foc_svpwm_open_loop/README.md b/examples/peripherals/mcpwm/mcpwm_foc_svpwm_open_loop/README.md index 38a22b5087..75e158f202 100644 --- a/examples/peripherals/mcpwm/mcpwm_foc_svpwm_open_loop/README.md +++ b/examples/peripherals/mcpwm/mcpwm_foc_svpwm_open_loop/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | --------- | # MCPWM FOC SVPWM Generation Open Loop Example diff --git a/examples/peripherals/mcpwm/mcpwm_servo_control/README.md b/examples/peripherals/mcpwm/mcpwm_servo_control/README.md index ea7152b9a9..5820eab55c 100644 --- a/examples/peripherals/mcpwm/mcpwm_servo_control/README.md +++ b/examples/peripherals/mcpwm/mcpwm_servo_control/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | --------- | # MCPWM RC Servo Control Example (See the README.md file in the upper level 'examples' directory for more information about examples.) diff --git a/examples/peripherals/mcpwm/mcpwm_sync/README.md b/examples/peripherals/mcpwm/mcpwm_sync/README.md index 606099a2bc..fc0473befe 100644 --- a/examples/peripherals/mcpwm/mcpwm_sync/README.md +++ b/examples/peripherals/mcpwm/mcpwm_sync/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | --------- | # MCPWM Sync Example From b8cfb155a2d9ee6b12ae6dd61fdddbb236d3546b Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Thu, 5 Mar 2026 10:18:45 +0800 Subject: [PATCH 3/3] test(mcpwm): involve all mcpwm groups for critical tests --- .../test_apps/mcpwm/main/test_mcpwm_gen.c | 323 +++++++++--------- 1 file changed, 169 insertions(+), 154 deletions(-) diff --git a/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_gen.c b/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_gen.c index df27ec03b3..24cacd5cd6 100644 --- a/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_gen.c +++ b/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_gen.c @@ -231,63 +231,68 @@ TEST_CASE("mcpwm_generator_action_on_timer_event", "[mcpwm]") }; TEST_ESP_OK(gpio_config(&gen_gpio_conf)); - printf("create timer and operator\r\n"); - mcpwm_timer_config_t timer_config = { - .group_id = 0, - .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT, - .resolution_hz = 1000000, - .count_mode = MCPWM_TIMER_COUNT_MODE_UP, - .period_ticks = 1000, - }; - mcpwm_timer_handle_t timer = NULL; - TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer)); - TEST_ESP_OK(mcpwm_timer_enable(timer)); + for (int group_id = 0; group_id < MCPWM_LL_GET(GROUP_NUM); group_id++) { + printf("test MCPWM group %d/%d\r\n", group_id, MCPWM_LL_GET(GROUP_NUM)); - mcpwm_operator_config_t oper_config = { - .group_id = 0, - }; - mcpwm_oper_handle_t oper = NULL; - TEST_ESP_OK(mcpwm_new_operator(&oper_config, &oper)); + printf("create timer and operator\r\n"); + mcpwm_timer_config_t timer_config = { + .group_id = group_id, + .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT, + .resolution_hz = 1000000, + .count_mode = MCPWM_TIMER_COUNT_MODE_UP, + .period_ticks = 1000, + }; + mcpwm_timer_handle_t timer = NULL; + TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer)); + TEST_ESP_OK(mcpwm_timer_enable(timer)); - printf("connect timer and operator\r\n"); - TEST_ESP_OK(mcpwm_operator_connect_timer(oper, timer)); + mcpwm_operator_config_t oper_config = { + .group_id = group_id, + }; + mcpwm_oper_handle_t oper = NULL; + TEST_ESP_OK(mcpwm_new_operator(&oper_config, &oper)); - printf("create generator\r\n"); - mcpwm_generator_config_t gen_config = { - .gen_gpio_num = generator_gpio, - }; - mcpwm_gen_handle_t gen = NULL; - TEST_ESP_OK(mcpwm_new_generator(oper, &gen_config, &gen)); + printf("connect timer and operator\r\n"); + TEST_ESP_OK(mcpwm_operator_connect_timer(oper, timer)); - printf("set generator to output high on timer full\r\n"); - TEST_ESP_OK(mcpwm_generator_set_action_on_timer_event(gen, - MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_HIGH))); - TEST_ESP_OK(mcpwm_generator_set_action_on_timer_event(gen, - MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_KEEP))); - printf("start timer\r\n"); - TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP)); - vTaskDelay(pdMS_TO_TICKS(100)); - printf("stop timer on full\r\n"); - TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_FULL)); - TEST_ASSERT_EQUAL(1, gpio_get_level(generator_gpio)); + printf("create generator\r\n"); + mcpwm_generator_config_t gen_config = { + .gen_gpio_num = generator_gpio, + }; + mcpwm_gen_handle_t gen = NULL; + TEST_ESP_OK(mcpwm_new_generator(oper, &gen_config, &gen)); - printf("set generator to output low on timer full\r\n"); - TEST_ESP_OK(mcpwm_generator_set_action_on_timer_event(gen, - MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_LOW))); - TEST_ESP_OK(mcpwm_generator_set_action_on_timer_event(gen, - MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_KEEP))); - printf("start timer\r\n"); - TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP)); - vTaskDelay(pdMS_TO_TICKS(100)); - printf("stop timer on full\r\n"); - TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_FULL)); - TEST_ASSERT_EQUAL(0, gpio_get_level(generator_gpio)); + printf("set generator to output high on timer full\r\n"); + TEST_ESP_OK(mcpwm_generator_set_action_on_timer_event(gen, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_HIGH))); + TEST_ESP_OK(mcpwm_generator_set_action_on_timer_event(gen, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_KEEP))); + printf("start timer\r\n"); + TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP)); + vTaskDelay(pdMS_TO_TICKS(100)); + printf("stop timer on full\r\n"); + TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_FULL)); + TEST_ASSERT_EQUAL(1, gpio_get_level(generator_gpio)); + + printf("set generator to output low on timer full\r\n"); + TEST_ESP_OK(mcpwm_generator_set_action_on_timer_event(gen, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_LOW))); + TEST_ESP_OK(mcpwm_generator_set_action_on_timer_event(gen, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_KEEP))); + printf("start timer\r\n"); + TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP)); + vTaskDelay(pdMS_TO_TICKS(100)); + printf("stop timer on full\r\n"); + TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_FULL)); + TEST_ASSERT_EQUAL(0, gpio_get_level(generator_gpio)); + + printf("delete timer, operator, generator for group %d\r\n", group_id); + TEST_ESP_OK(mcpwm_timer_disable(timer)); + TEST_ESP_OK(mcpwm_del_generator(gen)); + TEST_ESP_OK(mcpwm_del_operator(oper)); + TEST_ESP_OK(mcpwm_del_timer(timer)); + } - printf("delete timer, operator, generator\r\n"); - TEST_ESP_OK(mcpwm_timer_disable(timer)); - TEST_ESP_OK(mcpwm_del_generator(gen)); - TEST_ESP_OK(mcpwm_del_operator(oper)); - TEST_ESP_OK(mcpwm_del_timer(timer)); TEST_ESP_OK(gpio_reset_pin(generator_gpio)); } @@ -305,12 +310,12 @@ static bool test_capture_callback(mcpwm_cap_channel_handle_t cap_channel, const typedef void (*set_gen_actions_cb_t)(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb); -static void mcpwm_gen_action_test_template(uint32_t timer_resolution, uint32_t period, mcpwm_timer_count_mode_t count_mode, +static void mcpwm_gen_action_test_template(int group_id, uint32_t timer_resolution, uint32_t period, mcpwm_timer_count_mode_t count_mode, uint32_t cmpa, uint32_t cmpb, int gpioa, int gpiob, set_gen_actions_cb_t set_generator_actions, uint32_t *ret_capa, uint32_t *ret_capb) { mcpwm_timer_config_t timer_config = { - .group_id = 0, + .group_id = group_id, .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT, .count_mode = count_mode, .resolution_hz = timer_resolution, @@ -320,7 +325,7 @@ static void mcpwm_gen_action_test_template(uint32_t timer_resolution, uint32_t p TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer)); mcpwm_operator_config_t operator_config = { - .group_id = 0, + .group_id = group_id, }; mcpwm_oper_handle_t oper = NULL; TEST_ESP_OK(mcpwm_new_operator(&operator_config, &oper)); @@ -355,7 +360,7 @@ static void mcpwm_gen_action_test_template(uint32_t timer_resolution, uint32_t p esp_clk_tree_src_get_freq_hz(MCPWM_CAPTURE_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz); mcpwm_capture_timer_config_t cap_timer_config = { .clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT, - .group_id = 0, + .group_id = group_id, .resolution_hz = clk_src_freq_hz, }; TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timer)); @@ -504,47 +509,52 @@ static void dual_edge_complementary(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t TEST_CASE("mcpwm_generator_action_on_compare_event", "[mcpwm]") { uint32_t capa, capb; - printf("[Asymmetric, SingleEdge, ActiveHigh]\r\n"); - // PWMA: high = [1->350], low = [351->499,0] - // PWMB: high = [1->200], low = [201->499,0] - mcpwm_gen_action_test_template(1000000, 500, MCPWM_TIMER_COUNT_MODE_UP, 350, 200, TEST_PWMA_GPIO, TEST_PWMB_GPIO, single_edge_active_high, &capa, &capb); - TEST_ASSERT_UINT_WITHIN(2, 150, capa); - TEST_ASSERT_UINT_WITHIN(2, 300, capb); - printf("[Asymmetric, SingleEdge, ActiveLow]\r\n"); - // PWMA: low = [0->300], high = [301->499] - // PWMB: low = [0->150], high = [151->499] - mcpwm_gen_action_test_template(1000000, 500, MCPWM_TIMER_COUNT_MODE_UP, 300, 150, TEST_PWMA_GPIO, TEST_PWMB_GPIO, single_edge_active_low, &capa, &capb); - TEST_ASSERT_UINT_WITHIN(2, 200, capa); - TEST_ASSERT_UINT_WITHIN(2, 350, capb); + for (int group_id = 0; group_id < MCPWM_LL_GET(GROUP_NUM); group_id++) { + printf("test MCPWM group %d/%d\r\n", group_id, MCPWM_LL_GET(GROUP_NUM)); - printf("[Asymmetric, PulsePlacement]\r\n"); - // PWMA: low = [0->200], high = [201->400], low = [401->599] - // PWMB: high = [0->599], low = [0->599] - mcpwm_gen_action_test_template(1000000, 600, MCPWM_TIMER_COUNT_MODE_UP, 200, 400, TEST_PWMA_GPIO, TEST_PWMB_GPIO, pulse_placement, &capa, &capb); - TEST_ASSERT_UINT_WITHIN(2, 200, capa); - TEST_ASSERT_UINT_WITHIN(2, 600, capb); + printf("[Asymmetric, SingleEdge, ActiveHigh]\r\n"); + // PWMA: high = [1->350], low = [351->499,0] + // PWMB: high = [1->200], low = [201->499,0] + mcpwm_gen_action_test_template(group_id, 1000000, 500, MCPWM_TIMER_COUNT_MODE_UP, 350, 200, TEST_PWMA_GPIO, TEST_PWMB_GPIO, single_edge_active_high, &capa, &capb); + TEST_ASSERT_UINT_WITHIN(2, 150, capa); + TEST_ASSERT_UINT_WITHIN(2, 300, capb); - printf("[Asymmetric, DualEdge, ActiveLow]\r\n"); - // PWMA: low = [0->250], high = [251->599, 600->450], low = [451->1] - // PWMB: low = [0->599], low = [600->1] - mcpwm_gen_action_test_template(1000000, 1200, MCPWM_TIMER_COUNT_MODE_UP_DOWN, 250, 450, TEST_PWMA_GPIO, TEST_PWMB_GPIO, dual_edge_active_low_asym, &capa, &capb); - TEST_ASSERT_UINT_WITHIN(2, 500, capa); - TEST_ASSERT_UINT_WITHIN(2, 600, capb); + printf("[Asymmetric, SingleEdge, ActiveLow]\r\n"); + // PWMA: low = [0->300], high = [301->499] + // PWMB: low = [0->150], high = [151->499] + mcpwm_gen_action_test_template(group_id, 1000000, 500, MCPWM_TIMER_COUNT_MODE_UP, 300, 150, TEST_PWMA_GPIO, TEST_PWMB_GPIO, single_edge_active_low, &capa, &capb); + TEST_ASSERT_UINT_WITHIN(2, 200, capa); + TEST_ASSERT_UINT_WITHIN(2, 350, capb); - printf("[Symmetric, DualEdge, ActiveLow]\r\n"); - // PWMA: low = [0->400], high = [401->599, 600->400], low = [399->1] - // PWMB: low = [0->500], high = [501->599, 600->500], low = [499->1] - mcpwm_gen_action_test_template(1000000, 1200, MCPWM_TIMER_COUNT_MODE_UP_DOWN, 400, 500, TEST_PWMA_GPIO, TEST_PWMB_GPIO, dual_edge_active_low_sym, &capa, &capb); - TEST_ASSERT_UINT_WITHIN(2, 400, capa); - TEST_ASSERT_UINT_WITHIN(2, 200, capb); + printf("[Asymmetric, PulsePlacement]\r\n"); + // PWMA: low = [0->200], high = [201->400], low = [401->599] + // PWMB: high = [0->599], low = [0->599] + mcpwm_gen_action_test_template(group_id, 1000000, 600, MCPWM_TIMER_COUNT_MODE_UP, 200, 400, TEST_PWMA_GPIO, TEST_PWMB_GPIO, pulse_placement, &capa, &capb); + TEST_ASSERT_UINT_WITHIN(2, 200, capa); + TEST_ASSERT_UINT_WITHIN(2, 600, capb); - printf("[Symmetric, DualEdge, Complementary]\r\n"); - // PWMA: low = [0->350], high = [351->599, 600->350], low = [349->1] - // PWMB: low = [0->400], high = [401->599, 600->400], low = [399->1] - mcpwm_gen_action_test_template(1000000, 1200, MCPWM_TIMER_COUNT_MODE_UP_DOWN, 350, 400, TEST_PWMA_GPIO, TEST_PWMB_GPIO, dual_edge_complementary, &capa, &capb); - TEST_ASSERT_UINT_WITHIN(2, 500, capa); - TEST_ASSERT_UINT_WITHIN(2, 400, capb); + printf("[Asymmetric, DualEdge, ActiveLow]\r\n"); + // PWMA: low = [0->250], high = [251->599, 600->450], low = [451->1] + // PWMB: low = [0->599], low = [600->1] + mcpwm_gen_action_test_template(group_id, 1000000, 1200, MCPWM_TIMER_COUNT_MODE_UP_DOWN, 250, 450, TEST_PWMA_GPIO, TEST_PWMB_GPIO, dual_edge_active_low_asym, &capa, &capb); + TEST_ASSERT_UINT_WITHIN(2, 500, capa); + TEST_ASSERT_UINT_WITHIN(2, 600, capb); + + printf("[Symmetric, DualEdge, ActiveLow]\r\n"); + // PWMA: low = [0->400], high = [401->599, 600->400], low = [399->1] + // PWMB: low = [0->500], high = [501->599, 600->500], low = [499->1] + mcpwm_gen_action_test_template(group_id, 1000000, 1200, MCPWM_TIMER_COUNT_MODE_UP_DOWN, 400, 500, TEST_PWMA_GPIO, TEST_PWMB_GPIO, dual_edge_active_low_sym, &capa, &capb); + TEST_ASSERT_UINT_WITHIN(2, 400, capa); + TEST_ASSERT_UINT_WITHIN(2, 200, capb); + + printf("[Symmetric, DualEdge, Complementary]\r\n"); + // PWMA: low = [0->350], high = [351->599, 600->350], low = [349->1] + // PWMB: low = [0->400], high = [401->599, 600->400], low = [399->1] + mcpwm_gen_action_test_template(group_id, 1000000, 1200, MCPWM_TIMER_COUNT_MODE_UP_DOWN, 350, 400, TEST_PWMA_GPIO, TEST_PWMB_GPIO, dual_edge_complementary, &capa, &capb); + TEST_ASSERT_UINT_WITHIN(2, 500, capa); + TEST_ASSERT_UINT_WITHIN(2, 400, capb); + } } typedef void (*set_dead_time_cb_t)(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb); @@ -897,77 +907,82 @@ TEST_CASE("mcpwm_duty_empty_full", "[mcpwm]") }; TEST_ESP_OK(gpio_config(&gen_gpio_conf)); - mcpwm_timer_handle_t timer; - mcpwm_oper_handle_t oper; - mcpwm_cmpr_handle_t comparator; - mcpwm_gen_handle_t gen; + for (int group_id = 0; group_id < MCPWM_LL_GET(GROUP_NUM); group_id++) { + printf("test MCPWM group %d/%d\r\n", group_id, MCPWM_LL_GET(GROUP_NUM)); - mcpwm_timer_config_t timer_config = { - .group_id = 0, - .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT, - .resolution_hz = 1 * 1000 * 1000, - .period_ticks = 50, // 50us <-> 20KHz - .count_mode = MCPWM_TIMER_COUNT_MODE_UP, - }; - mcpwm_operator_config_t operator_config = { - .group_id = 0, - }; - mcpwm_comparator_config_t comparator_config = { - .flags.update_cmp_on_tep = true, - .flags.update_cmp_on_tez = true, - }; - printf("install timer, operator and comparator\r\n"); - TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer)); - TEST_ESP_OK(mcpwm_new_operator(&operator_config, &oper)); - TEST_ESP_OK(mcpwm_new_comparator(oper, &comparator_config, &comparator)); + mcpwm_timer_handle_t timer = NULL; + mcpwm_oper_handle_t oper = NULL; + mcpwm_cmpr_handle_t comparator = NULL; + mcpwm_gen_handle_t gen = NULL; - printf("connect MCPWM timer and operators\r\n"); - TEST_ESP_OK(mcpwm_operator_connect_timer(oper, timer)); - TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator, 0)); + mcpwm_timer_config_t timer_config = { + .group_id = group_id, + .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT, + .resolution_hz = 1 * 1000 * 1000, + .period_ticks = 50, // 50us <-> 20KHz + .count_mode = MCPWM_TIMER_COUNT_MODE_UP, + }; + mcpwm_operator_config_t operator_config = { + .group_id = group_id, + }; + mcpwm_comparator_config_t comparator_config = { + .flags.update_cmp_on_tep = true, + .flags.update_cmp_on_tez = true, + }; + printf("install timer, operator and comparator\r\n"); + TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer)); + TEST_ESP_OK(mcpwm_new_operator(&operator_config, &oper)); + TEST_ESP_OK(mcpwm_new_comparator(oper, &comparator_config, &comparator)); - printf("install MCPWM generator\r\n"); - mcpwm_generator_config_t gen_config = { - .gen_gpio_num = gen_gpio_num, - }; - TEST_ESP_OK(mcpwm_new_generator(oper, &gen_config, &gen)); + printf("connect MCPWM timer and operators\r\n"); + TEST_ESP_OK(mcpwm_operator_connect_timer(oper, timer)); + TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator, 0)); - printf("set generator actions on timer and compare events\r\n"); - TEST_ESP_OK(mcpwm_generator_set_action_on_timer_event(gen, - MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); - TEST_ESP_OK(mcpwm_generator_set_action_on_compare_event(gen, - MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, comparator, MCPWM_GEN_ACTION_LOW))); + printf("install MCPWM generator\r\n"); + mcpwm_generator_config_t gen_config = { + .gen_gpio_num = gen_gpio_num, + }; + TEST_ESP_OK(mcpwm_new_generator(oper, &gen_config, &gen)); - printf("start timer\r\n"); - TEST_ESP_OK(mcpwm_timer_enable(timer)); - TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP)); + printf("set generator actions on timer and compare events\r\n"); + TEST_ESP_OK(mcpwm_generator_set_action_on_timer_event(gen, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + TEST_ESP_OK(mcpwm_generator_set_action_on_compare_event(gen, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, comparator, MCPWM_GEN_ACTION_LOW))); - // check if the output is a const low level - for (int i = 0; i < 100; i++) { - TEST_ASSERT_EQUAL(0, gpio_get_level(gen_gpio_num)); - esp_rom_delay_us(1); + printf("start timer\r\n"); + TEST_ESP_OK(mcpwm_timer_enable(timer)); + TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP)); + + // check if the output is a const low level + for (int i = 0; i < 100; i++) { + TEST_ASSERT_EQUAL(0, gpio_get_level(gen_gpio_num)); + esp_rom_delay_us(1); + } + + // set the compare equals to the period + TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator, 50)); + vTaskDelay(pdMS_TO_TICKS(10)); + // so the output should be a const high level + for (int i = 0; i < 100; i++) { + TEST_ASSERT_EQUAL(1, gpio_get_level(gen_gpio_num)); + esp_rom_delay_us(1); + } + + TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator, 49)); + vTaskDelay(pdMS_TO_TICKS(100)); + TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator, 1)); + vTaskDelay(pdMS_TO_TICKS(100)); + + printf("uninstall timer, operator and comparator for group %d\r\n", group_id); + TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY)); + TEST_ESP_OK(mcpwm_timer_disable(timer)); + TEST_ESP_OK(mcpwm_del_generator(gen)); + TEST_ESP_OK(mcpwm_del_comparator(comparator)); + TEST_ESP_OK(mcpwm_del_operator(oper)); + TEST_ESP_OK(mcpwm_del_timer(timer)); } - // set the compare equals to the period - TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator, 50)); - vTaskDelay(pdMS_TO_TICKS(10)); - // so the output should be a const high level - for (int i = 0; i < 100; i++) { - TEST_ASSERT_EQUAL(1, gpio_get_level(gen_gpio_num)); - esp_rom_delay_us(1); - } - - TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator, 49)); - vTaskDelay(pdMS_TO_TICKS(100)); - TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator, 1)); - vTaskDelay(pdMS_TO_TICKS(100)); - - printf("uninstall timer, operator and comparator\r\n"); - TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY)); - TEST_ESP_OK(mcpwm_timer_disable(timer)); - TEST_ESP_OK(mcpwm_del_generator(gen)); - TEST_ESP_OK(mcpwm_del_comparator(comparator)); - TEST_ESP_OK(mcpwm_del_operator(oper)); - TEST_ESP_OK(mcpwm_del_timer(timer)); TEST_ESP_OK(gpio_reset_pin(gen_gpio_num)); }