From de5fb9f070e359eee78e27c17da834baed4e6c12 Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 19 Mar 2024 15:51:15 +0800 Subject: [PATCH] feat(mcpwm): driver support on esp32-c5 --- components/driver/deprecated/mcpwm_legacy.c | 19 +- .../main/test_legacy_mcpwm.c | 14 +- components/esp_driver_mcpwm/src/mcpwm_com.c | 4 +- .../test_apps/mcpwm/main/CMakeLists.txt | 6 +- .../test_apps/mcpwm}/main/test_mcpwm_etm.c | 6 +- .../test_apps/etm/main/CMakeLists.txt | 4 - components/hal/esp32/include/hal/mcpwm_ll.h | 27 +- components/hal/esp32c5/include/hal/mcpwm_ll.h | 1730 +++++++++++++++++ components/hal/esp32c6/include/hal/mcpwm_ll.h | 29 +- components/hal/esp32h2/include/hal/mcpwm_ll.h | 29 +- components/hal/esp32p4/include/hal/mcpwm_ll.h | 39 +- components/hal/esp32s3/include/hal/mcpwm_ll.h | 27 +- .../mp/include/soc/Kconfig.soc_caps.in | 60 + .../esp32c5/mp/include/soc/clk_tree_defs.h | 18 +- .../soc/esp32c5/mp/include/soc/mcpwm_reg.h | 6 +- .../soc/esp32c5/mp/include/soc/mcpwm_struct.h | 267 +-- .../soc/esp32c5/mp/include/soc/soc_caps.h | 31 +- .../soc/esp32c5/mp/ld/esp32c5.peripherals.ld | 2 +- components/soc/esp32c5/mp/mcpwm_periph.c | 83 + docs/docs_not_updated/esp32c5.txt | 1 - docs/en/api-reference/peripherals/mcpwm.rst | 2 +- .../zh_CN/api-reference/peripherals/mcpwm.rst | 2 +- .../mcpwm/mcpwm_servo_control/README.md | 2 +- 23 files changed, 2053 insertions(+), 355 deletions(-) rename components/{esp_hw_support/test_apps/etm => esp_driver_mcpwm/test_apps/mcpwm}/main/test_mcpwm_etm.c (94%) create mode 100644 components/hal/esp32c5/include/hal/mcpwm_ll.h create mode 100644 components/soc/esp32c5/mp/mcpwm_periph.c diff --git a/components/driver/deprecated/mcpwm_legacy.c b/components/driver/deprecated/mcpwm_legacy.c index b2efec86f1..974402f949 100644 --- a/components/driver/deprecated/mcpwm_legacy.c +++ b/components/driver/deprecated/mcpwm_legacy.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,14 +13,16 @@ #include "esp_rom_gpio.h" #include "esp_intr_alloc.h" #include "soc/mcpwm_periph.h" +#include "soc/io_mux_reg.h" #include "hal/mcpwm_hal.h" #include "hal/gpio_hal.h" #include "hal/mcpwm_ll.h" #include "driver/mcpwm_types_legacy.h" #include "driver/gpio.h" #include "esp_private/periph_ctrl.h" -#include "esp_clk_tree.h" +#include "esp_private/gpio.h" #include "esp_private/esp_clk.h" +#include "esp_clk_tree.h" static const char *TAG = "mcpwm(legacy)"; @@ -204,7 +206,7 @@ esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal, int capture_id = io_signal - MCPWM_CAP_0; esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].captures[capture_id].cap_sig, 0); } - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO); + gpio_func_sel(gpio_num, PIN_FUNC_GPIO); return ESP_OK; } @@ -268,7 +270,6 @@ static inline uint32_t mcpwm_timer_get_resolution(mcpwm_unit_t mcpwm_num, mcpwm_ esp_err_t mcpwm_group_set_resolution(mcpwm_unit_t mcpwm_num, uint32_t resolution) { mcpwm_module_enable(mcpwm_num); - mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; uint32_t clk_src_hz = 0; esp_clk_tree_src_get_freq_hz(MCPWM_TIMER_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_hz); @@ -277,7 +278,7 @@ esp_err_t mcpwm_group_set_resolution(mcpwm_unit_t mcpwm_num, uint32_t resolution context[mcpwm_num].group_resolution_hz = clk_src_hz / pre_scale_temp; MCPWM_CLOCK_SRC_ATOMIC() { - mcpwm_ll_group_set_clock_prescale(hal->dev, pre_scale_temp); + mcpwm_ll_group_set_clock_prescale(mcpwm_num, pre_scale_temp); } return ESP_OK; } @@ -467,8 +468,8 @@ esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpw uint32_t timer_pre_scale = group_resolution / timer_resolution; MCPWM_CLOCK_SRC_ATOMIC() { - mcpwm_ll_group_set_clock_source(hal->dev, (soc_module_clk_t)MCPWM_CAPTURE_CLK_SRC_DEFAULT); - mcpwm_ll_group_set_clock_prescale(hal->dev, group_pre_scale); + mcpwm_ll_group_set_clock_source(mcpwm_num, (soc_module_clk_t)MCPWM_CAPTURE_CLK_SRC_DEFAULT); + mcpwm_ll_group_set_clock_prescale(mcpwm_num, group_pre_scale); } mcpwm_critical_enter(mcpwm_num); @@ -864,8 +865,8 @@ esp_err_t mcpwm_capture_enable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_cha uint32_t group_pre_scale = clk_src_hz / group_resolution; MCPWM_CLOCK_SRC_ATOMIC() { - mcpwm_ll_group_set_clock_source(hal->dev, (soc_module_clk_t)MCPWM_CAPTURE_CLK_SRC_DEFAULT); - mcpwm_ll_group_set_clock_prescale(hal->dev, group_pre_scale); + mcpwm_ll_group_set_clock_source(mcpwm_num, (soc_module_clk_t)MCPWM_CAPTURE_CLK_SRC_DEFAULT); + mcpwm_ll_group_set_clock_prescale(mcpwm_num, group_pre_scale); } mcpwm_critical_enter(mcpwm_num); diff --git a/components/driver/test_apps/legacy_mcpwm_driver/main/test_legacy_mcpwm.c b/components/driver/test_apps/legacy_mcpwm_driver/main/test_legacy_mcpwm.c index bd3cccc6cb..1526620f7c 100644 --- a/components/driver/test_apps/legacy_mcpwm_driver/main/test_legacy_mcpwm.c +++ b/components/driver/test_apps/legacy_mcpwm_driver/main/test_legacy_mcpwm.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,7 +12,9 @@ #include "hal/gpio_hal.h" #include "esp_rom_gpio.h" #include "esp_private/esp_clk.h" +#include "esp_private/gpio.h" #include "soc/mcpwm_periph.h" +#include "soc/io_mux_reg.h" #include "driver/pulse_cnt.h" #include "driver/mcpwm.h" #include "driver/gpio.h" @@ -61,10 +63,12 @@ const static mcpwm_io_signals_t sync_io_sig_array[] = {MCPWM_SYNC_0, MCPWM_SYNC_ const static mcpwm_capture_signal_t cap_sig_array[] = {MCPWM_SELECT_CAP0, MCPWM_SELECT_CAP1, MCPWM_SELECT_CAP2}; const static mcpwm_io_signals_t cap_io_sig_array[] = {MCPWM_CAP_0, MCPWM_CAP_1, MCPWM_CAP_2}; +#if SOC_PCNT_SUPPORTED static pcnt_unit_handle_t pcnt_unit_a; static pcnt_channel_handle_t pcnt_chan_a; static pcnt_unit_handle_t pcnt_unit_b; static pcnt_channel_handle_t pcnt_chan_b; +#endif // This GPIO init function is almost the same to public API `mcpwm_gpio_init()`, except that // this function will configure all MCPWM GPIOs into output and input capable @@ -93,7 +97,7 @@ static esp_err_t test_mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t int capture_id = io_signal - MCPWM_CAP_0; esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].captures[capture_id].cap_sig, 0); } - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO); + gpio_func_sel(gpio_num, PIN_FUNC_GPIO); return ESP_OK; } @@ -119,6 +123,7 @@ static void mcpwm_setup_testbench(mcpwm_unit_t group, mcpwm_timer_t timer, uint3 TEST_ESP_OK(mcpwm_init(group, timer, &pwm_config)); } +#if SOC_PCNT_SUPPORTED static void pcnt_setup_testbench(void) { // PWMA <--> PCNT UNIT0 @@ -173,6 +178,7 @@ static uint32_t pcnt_get_pulse_number(pcnt_unit_handle_t pwm_pcnt_unit, int capt printf("count value: %d\r\n", count_value); return (uint32_t)count_value; } +#endif // SOC_PCNT_SUPPORTED static void mcpwm_timer_duty_test(mcpwm_unit_t unit, mcpwm_timer_t timer, unsigned long int group_resolution, unsigned long int timer_resolution) { @@ -210,6 +216,7 @@ TEST_CASE("MCPWM duty test", "[mcpwm]") // ------------------------------------------------------------------------------------- +#if SOC_PCNT_SUPPORTED static void mcpwm_start_stop_test(mcpwm_unit_t unit, mcpwm_timer_t timer) { uint32_t pulse_number = 0; @@ -244,6 +251,7 @@ TEST_CASE("MCPWM start and stop test", "[mcpwm]") } } } +#endif // SOC_PCNT_SUPPORTED // ------------------------------------------------------------------------------------- @@ -276,6 +284,7 @@ TEST_CASE("MCPWM deadtime test", "[mcpwm]") } // ------------------------------------------------------------------------------------- +#if SOC_PCNT_SUPPORTED #define TEST_CARRIER_FREQ 250000 static void mcpwm_carrier_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_carrier_out_ivt_t invert_or_not, uint8_t period, uint8_t duty, uint8_t os_width) @@ -315,6 +324,7 @@ TEST_CASE("MCPWM carrier test", "[mcpwm]") } } } +#endif // SOC_PCNT_SUPPORTED // ------------------------------------------------------------------------------------- diff --git a/components/esp_driver_mcpwm/src/mcpwm_com.c b/components/esp_driver_mcpwm/src/mcpwm_com.c index d5fc5a9561..60b5443b0f 100644 --- a/components/esp_driver_mcpwm/src/mcpwm_com.c +++ b/components/esp_driver_mcpwm/src/mcpwm_com.c @@ -173,7 +173,7 @@ esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, soc_module_clk_t clk_s #endif // CONFIG_PM_ENABLE MCPWM_CLOCK_SRC_ATOMIC() { - mcpwm_ll_group_set_clock_source(group->hal.dev, clk_src); + mcpwm_ll_group_set_clock_source(group->group_id, clk_src); } } return ret; @@ -232,7 +232,7 @@ esp_err_t mcpwm_set_prescale(mcpwm_group_t *group, uint32_t expect_module_resolu group->prescale = group_prescale; group->resolution_hz = group_resolution_hz; MCPWM_CLOCK_SRC_ATOMIC() { - mcpwm_ll_group_set_clock_prescale(group->hal.dev, group_prescale); + mcpwm_ll_group_set_clock_prescale(group_id, group_prescale); } } else { prescale_conflict = (group->prescale != group_prescale); diff --git a/components/esp_driver_mcpwm/test_apps/mcpwm/main/CMakeLists.txt b/components/esp_driver_mcpwm/test_apps/mcpwm/main/CMakeLists.txt index 119892a0b4..d4f59e540d 100644 --- a/components/esp_driver_mcpwm/test_apps/mcpwm/main/CMakeLists.txt +++ b/components/esp_driver_mcpwm/test_apps/mcpwm/main/CMakeLists.txt @@ -13,8 +13,12 @@ if(CONFIG_MCPWM_ISR_IRAM_SAFE) list(APPEND srcs "test_mcpwm_iram.c") endif() +if(CONFIG_SOC_ETM_SUPPORTED AND CONFIG_SOC_MCPWM_SUPPORT_ETM) + list(APPEND srcs "test_mcpwm_etm.c") +endif() + # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} - PRIV_REQUIRES unity esp_driver_mcpwm esp_driver_gpio + PRIV_REQUIRES unity esp_driver_mcpwm esp_driver_gpio esp_driver_gptimer WHOLE_ARCHIVE) diff --git a/components/esp_hw_support/test_apps/etm/main/test_mcpwm_etm.c b/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_etm.c similarity index 94% rename from components/esp_hw_support/test_apps/etm/main/test_mcpwm_etm.c rename to components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_etm.c index 5eb9fd472b..3a40f9994a 100644 --- a/components/esp_hw_support/test_apps/etm/main/test_mcpwm_etm.c +++ b/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_etm.c @@ -14,7 +14,7 @@ #include "driver/gpio.h" #include "driver/mcpwm_prelude.h" -TEST_CASE("mcpwm_comparator_etm_event", "[etm]") +TEST_CASE("mcpwm_comparator_etm_event", "[mcpwm][etm]") { // MCPWM cmpra -------------------------------------> ETM channel A ---> GPTimer start // MCPWM cmprb / evt_cmpra (if support evt_cmpr) ---> ETM channel B ---> GPTimer stop @@ -58,9 +58,9 @@ TEST_CASE("mcpwm_comparator_etm_event", "[etm]") }; TEST_ESP_OK(mcpwm_new_generator(oper, &generator_config, &generator)); TEST_ESP_OK(mcpwm_generator_set_action_on_compare_event(generator, - MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, comparator_a, MCPWM_GEN_ACTION_HIGH))); + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, comparator_a, MCPWM_GEN_ACTION_HIGH))); TEST_ESP_OK(mcpwm_generator_set_action_on_compare_event(generator, - MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, comparator_b, MCPWM_GEN_ACTION_LOW))); + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, comparator_b, MCPWM_GEN_ACTION_LOW))); // allocate etm channels printf("allocate etm channels\r\n"); diff --git a/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt b/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt index e9207be15a..3e09a61352 100644 --- a/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt @@ -13,10 +13,6 @@ if(CONFIG_SOC_SYSTIMER_SUPPORT_ETM) list(APPEND srcs "test_systimer_etm.c") endif() -if(CONFIG_SOC_MCPWM_SUPPORT_ETM) - list(APPEND srcs "test_mcpwm_etm.c") -endif() - if(CONFIG_SOC_ANA_CMPR_SUPPORT_ETM AND CONFIG_SOC_TIMER_SUPPORT_ETM) # Analog Comparator event test relies on GPTIMER task list(APPEND srcs "test_ana_cmpr_etm.c") diff --git a/components/hal/esp32/include/hal/mcpwm_ll.h b/components/hal/esp32/include/hal/mcpwm_ll.h index 4c23fd1014..3aef65d877 100644 --- a/components/hal/esp32/include/hal/mcpwm_ll.h +++ b/components/hal/esp32/include/hal/mcpwm_ll.h @@ -112,7 +112,7 @@ static inline void mcpwm_ll_reset_register(int group_id) #define mcpwm_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; mcpwm_ll_reset_register(__VA_ARGS__) /** - * @brief Enable MCPWM module clock + * @brief Enable MCPWM function clock * * @note Not support to enable/disable the peripheral clock * @@ -128,25 +128,26 @@ static inline void mcpwm_ll_group_enable_clock(int group_id, bool en) /** * @brief Set the clock source for MCPWM * - * @param mcpwm Peripheral instance address + * @param group_id Group ID * @param clk_src Clock source for the MCPWM peripheral */ -static inline void mcpwm_ll_group_set_clock_source(mcpwm_dev_t *mcpwm, mcpwm_timer_clock_source_t clk_src) +static inline void mcpwm_ll_group_set_clock_source(int group_id, mcpwm_timer_clock_source_t clk_src) { - (void)mcpwm; + (void)group_id; (void)clk_src; } /** * @brief Set the MCPWM group clock prescale * - * @param mcpwm Peripheral instance address + * @param group_id Group ID * @param pre_scale Prescale value */ -static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int prescale) +static inline void mcpwm_ll_group_set_clock_prescale(int group_id, int prescale) { // group clock: PWM_clk = CLK_160M / (prescale) HAL_ASSERT(prescale <= 256 && prescale > 0); + mcpwm_dev_t *mcpwm = MCPWM_LL_GET_HW(group_id); HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->clk_cfg, clk_prescale, prescale - 1); } @@ -220,7 +221,7 @@ static inline uint32_t mcpwm_ll_intr_get_status(mcpwm_dev_t *mcpwm) * @brief Clear MCPWM interrupt status by mask * * @param mcpwm Peripheral instance address - * @param mask Interupt status mask + * @param mask Interrupt status mask */ __attribute__((always_inline)) static inline void mcpwm_ll_intr_clear_status(mcpwm_dev_t *mcpwm, uint32_t mask) @@ -1620,18 +1621,6 @@ static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static inline uint32_t mcpwm_ll_group_get_clock_prescale(mcpwm_dev_t *mcpwm) -{ - return HAL_FORCE_READ_U32_REG_FIELD(mcpwm->clk_cfg, clk_prescale) + 1; -} - -static inline uint32_t mcpwm_ll_timer_get_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id) -{ - mcpwm_timer_cfg0_reg_t cfg0; - cfg0.val = mcpwm->timer[timer_id].timer_cfg0.val; - return cfg0.timer_prescale + 1; -} - static inline uint32_t mcpwm_ll_timer_get_peak(mcpwm_dev_t *mcpwm, int timer_id, bool symmetric) { return HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period) + (symmetric ? 0 : 1); diff --git a/components/hal/esp32c5/include/hal/mcpwm_ll.h b/components/hal/esp32c5/include/hal/mcpwm_ll.h new file mode 100644 index 0000000000..b1ba7b1362 --- /dev/null +++ b/components/hal/esp32c5/include/hal/mcpwm_ll.h @@ -0,0 +1,1730 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "soc/soc_caps.h" +#include "soc/mcpwm_struct.h" +#include "soc/clk_tree_defs.h" +#include "soc/pcr_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 + +// Get MCPWM group register base address +#define MCPWM_LL_GET_HW(ID) (((ID) == 0) ? &MCPWM0 : NULL) + +// 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)]) + +// MCPWM ETM comparator event table +#define MCPWM_LL_ETM_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \ + (uint32_t[2][MCPWM_CMPR_ETM_EVENT_MAX]){ \ + { \ + [MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM0_EVT_OP0_TEA + oper_id + 3 * cmpr_id, \ + }, \ + }[group][event] + +// MCPWM ETM event comparator event table +#define MCPWM_LL_ETM_EVENT_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \ + (uint32_t[2][MCPWM_CMPR_ETM_EVENT_MAX]){ \ + { \ + [MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM0_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) +{ + (void)group_id; // only support MCPWM0 + PCR.pwm_conf.pwm_clk_en = enable; +} + +/** + * @brief Reset the MCPWM module + * + * @param group_id Group ID + */ +static inline void mcpwm_ll_reset_register(int group_id) +{ + (void)group_id; // only support MCPWM0 + PCR.pwm_conf.pwm_rst_en = 1; + PCR.pwm_conf.pwm_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) +{ + (void)group_id; // only support MCPWM0 + PCR.pwm_clk_conf.pwm_clkm_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) +{ + (void)group_id; // only support MCPWM0 + uint8_t clk_id = 0; + switch (clk_src) { + case SOC_MOD_CLK_XTAL: + clk_id = 0; + break; + case SOC_MOD_CLK_RC_FAST: + clk_id = 1; + break; + case SOC_MOD_CLK_PLL_F160M: + clk_id = 2; + break; + default: + HAL_ASSERT(false); + break; + } + PCR.pwm_clk_conf.pwm_clkm_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) +{ + (void)group_id; // only support MCPWM0 + // group clock: PWM_clk = source_clock / (prescale) + HAL_ASSERT(prescale <= 256 && prescale > 0); + HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.pwm_clk_conf, pwm_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].timer_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].timer_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].timer_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].timer_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].timer_cfg0.timern_period_upmethod |= 0x01; + } else { + mcpwm->timer[timer_id].timer_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].timer_cfg0.timern_period_upmethod |= 0x02; + } else { + mcpwm->timer[timer_id].timer_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].timer_cfg1.timern_mod = 0; + break; + case MCPWM_TIMER_COUNT_MODE_UP: + mcpwm->timer[timer_id].timer_cfg1.timern_mod = 1; + break; + case MCPWM_TIMER_COUNT_MODE_DOWN: + mcpwm->timer[timer_id].timer_cfg1.timern_mod = 2; + break; + case MCPWM_TIMER_COUNT_MODE_UP_DOWN: + mcpwm->timer[timer_id].timer_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].timer_cfg1.timern_start = 0; + break; + case MCPWM_TIMER_STOP_FULL: + mcpwm->timer[timer_id].timer_cfg1.timern_start = 1; + break; + case MCPWM_TIMER_START_NO_STOP: + mcpwm->timer[timer_id].timer_cfg1.timern_start = 2; + break; + case MCPWM_TIMER_START_STOP_EMPTY: + mcpwm->timer[timer_id].timer_cfg1.timern_start = 3; + break; + case MCPWM_TIMER_START_STOP_FULL: + mcpwm->timer[timer_id].timer_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].timer_cfg1.timern_mod == 0) { + return HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_status, timern_value); + } + if (mcpwm->timer[timer_id].timer_status.timern_direction) { // down direction + return (HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_status, timern_value) + 1) % + (HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timern_period) + 1); + } + // up direction + return (HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_status, timern_value) + + HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timern_period)) % + (HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_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].timer_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].timer_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].timer_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].timer_sync.timern_synco_sel = 1; + break; + case MCPWM_TIMER_EVENT_FULL: + mcpwm->timer[timer_id].timer_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].timer_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].timer_sync.timern_sync_sw = ~mcpwm->timer[timer_id].timer_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].timer_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].timer_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) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->operators[operator_id].timestamp[compare_id], 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)); + } +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static inline uint32_t mcpwm_ll_timer_get_peak(mcpwm_dev_t *mcpwm, int timer_id, bool symmetric) +{ + return HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timern_period) + (symmetric ? 0 : 1); +} + +static inline mcpwm_timer_count_mode_t mcpwm_ll_timer_get_count_mode(mcpwm_dev_t *mcpwm, int timer_id) +{ + switch (mcpwm->timer[timer_id].timer_cfg1.timern_mod) { + case 1: + return MCPWM_TIMER_COUNT_MODE_UP; + case 2: + return MCPWM_TIMER_COUNT_MODE_DOWN; + case 3: + return MCPWM_TIMER_COUNT_MODE_UP_DOWN; + case 0: + default: + return MCPWM_TIMER_COUNT_MODE_PAUSE; + } +} + +static inline uint32_t mcpwm_ll_operator_get_compare_value(mcpwm_dev_t *mcpwm, int operator_id, int compare_id) +{ + return HAL_FORCE_READ_U32_REG_FIELD(mcpwm->operators[operator_id].timestamp[compare_id], cmprn); +} + +__attribute__((always_inline)) +static inline uint32_t mcpwm_ll_intr_get_capture_status(mcpwm_dev_t *mcpwm) +{ + return (mcpwm->int_st.val >> 27) & 0x07; +} + +__attribute__((always_inline)) +static inline void mcpwm_ll_intr_clear_capture_status(mcpwm_dev_t *mcpwm, uint32_t capture_mask) +{ + mcpwm->int_clr.val = (capture_mask & 0x07) << 27; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32c6/include/hal/mcpwm_ll.h b/components/hal/esp32c6/include/hal/mcpwm_ll.h index 2efa55adc6..c535e64116 100644 --- a/components/hal/esp32c6/include/hal/mcpwm_ll.h +++ b/components/hal/esp32c6/include/hal/mcpwm_ll.h @@ -101,7 +101,7 @@ static inline void mcpwm_ll_reset_register(int group_id) } /** - * @brief Enable MCPWM module clock + * @brief Enable MCPWM function clock * * @param group_id Group ID * @param en true to enable, false to disable @@ -115,12 +115,12 @@ static inline void mcpwm_ll_group_enable_clock(int group_id, bool en) /** * @brief Set the clock source for MCPWM * - * @param mcpwm Peripheral instance address + * @param group_id Group ID * @param clk_src Clock source for the MCPWM peripheral */ -static inline void mcpwm_ll_group_set_clock_source(mcpwm_dev_t *mcpwm, soc_module_clk_t clk_src) +static inline void mcpwm_ll_group_set_clock_source(int group_id, soc_module_clk_t clk_src) { - (void)mcpwm; // only one MCPWM instance + (void)group_id; switch (clk_src) { case SOC_MOD_CLK_PLL_F160M: PCR.pwm_clk_conf.pwm_clkm_sel = 1; @@ -137,12 +137,12 @@ static inline void mcpwm_ll_group_set_clock_source(mcpwm_dev_t *mcpwm, soc_modul /** * @brief Set the MCPWM group clock prescale * - * @param mcpwm Peripheral instance address + * @param group_id Group ID * @param prescale Prescale value */ -static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int prescale) +static inline void mcpwm_ll_group_set_clock_prescale(int group_id, int prescale) { - (void)mcpwm; // only one MCPWM instance + (void)group_id; // group clock: PWM_clk = source_clock / (prescale) HAL_ASSERT(prescale <= 256 && prescale > 0); HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.pwm_clk_conf, pwm_div_num, prescale - 1); @@ -218,7 +218,7 @@ static inline uint32_t mcpwm_ll_intr_get_status(mcpwm_dev_t *mcpwm) * @brief Clear MCPWM interrupt status by mask * * @param mcpwm Peripheral instance address - * @param mask Interupt status mask + * @param mask Interrupt status mask */ __attribute__((always_inline)) static inline void mcpwm_ll_intr_clear_status(mcpwm_dev_t *mcpwm, uint32_t mask) @@ -1649,19 +1649,6 @@ static inline void mcpwm_ll_etm_enable_comparator_event(mcpwm_dev_t *mcpwm, int /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static inline uint32_t mcpwm_ll_group_get_clock_prescale(mcpwm_dev_t *mcpwm) -{ - (void)mcpwm; // only one MCPWM instance - return HAL_FORCE_READ_U32_REG_FIELD(PCR.pwm_clk_conf, pwm_div_num) + 1; -} - -static inline uint32_t mcpwm_ll_timer_get_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id) -{ - mcpwm_timer_cfg0_reg_t cfg0; - cfg0.val = mcpwm->timer[timer_id].timer_cfg0.val; - return cfg0.timer_prescale + 1; -} - static inline uint32_t mcpwm_ll_timer_get_peak(mcpwm_dev_t *mcpwm, int timer_id, bool symmetric) { return HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period) + (symmetric ? 0 : 1); diff --git a/components/hal/esp32h2/include/hal/mcpwm_ll.h b/components/hal/esp32h2/include/hal/mcpwm_ll.h index abcb9327fa..b78b503a5e 100644 --- a/components/hal/esp32h2/include/hal/mcpwm_ll.h +++ b/components/hal/esp32h2/include/hal/mcpwm_ll.h @@ -99,7 +99,7 @@ static inline void mcpwm_ll_reset_register(int group_id) } /** - * @brief Enable MCPWM module clock + * @brief Enable MCPWM function clock * * @param group_id Group ID * @param en true to enable, false to disable @@ -113,12 +113,12 @@ static inline void mcpwm_ll_group_enable_clock(int group_id, bool en) /** * @brief Set the clock source for MCPWM * - * @param mcpwm Peripheral instance address + * @param group_id Group ID * @param clk_src Clock source for the MCPWM peripheral */ -static inline void mcpwm_ll_group_set_clock_source(mcpwm_dev_t *mcpwm, soc_module_clk_t clk_src) +static inline void mcpwm_ll_group_set_clock_source(int group_id, soc_module_clk_t clk_src) { - (void)mcpwm; // only one MCPWM instance + (void)group_id; switch (clk_src) { case SOC_MOD_CLK_XTAL: PCR.pwm_clk_conf.pwm_clkm_sel = 0; @@ -135,12 +135,12 @@ static inline void mcpwm_ll_group_set_clock_source(mcpwm_dev_t *mcpwm, soc_modul /** * @brief Set the MCPWM group clock prescale * - * @param mcpwm Peripheral instance address + * @param group_id Group ID * @param prescale Prescale value */ -static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int prescale) +static inline void mcpwm_ll_group_set_clock_prescale(int group_id, int prescale) { - (void)mcpwm; // only one MCPWM instance + (void)group_id; // group clock: PWM_clk = source_clock / (prescale) HAL_ASSERT(prescale <= 256 && prescale > 0); HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.pwm_clk_conf, pwm_div_num, prescale - 1); @@ -216,7 +216,7 @@ static inline uint32_t mcpwm_ll_intr_get_status(mcpwm_dev_t *mcpwm) * @brief Clear MCPWM interrupt status by mask * * @param mcpwm Peripheral instance address - * @param mask Interupt status mask + * @param mask Interrupt status mask */ __attribute__((always_inline)) static inline void mcpwm_ll_intr_clear_status(mcpwm_dev_t *mcpwm, uint32_t mask) @@ -1647,19 +1647,6 @@ static inline void mcpwm_ll_etm_enable_comparator_event(mcpwm_dev_t *mcpwm, int /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static inline uint32_t mcpwm_ll_group_get_clock_prescale(mcpwm_dev_t *mcpwm) -{ - (void)mcpwm; // only one MCPWM instance - return HAL_FORCE_READ_U32_REG_FIELD(PCR.pwm_clk_conf, pwm_div_num) + 1; -} - -static inline uint32_t mcpwm_ll_timer_get_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id) -{ - mcpwm_timer_cfg0_reg_t cfg0; - cfg0.val = mcpwm->timer[timer_id].timer_cfg0.val; - return cfg0.timer_prescale + 1; -} - static inline uint32_t mcpwm_ll_timer_get_peak(mcpwm_dev_t *mcpwm, int timer_id, bool symmetric) { return HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period) + (symmetric ? 0 : 1); diff --git a/components/hal/esp32p4/include/hal/mcpwm_ll.h b/components/hal/esp32p4/include/hal/mcpwm_ll.h index 957d56b010..4031c06070 100644 --- a/components/hal/esp32p4/include/hal/mcpwm_ll.h +++ b/components/hal/esp32p4/include/hal/mcpwm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ #pragma once #include +#include #include "soc/soc_caps.h" #include "soc/mcpwm_struct.h" #include "soc/clk_tree_defs.h" @@ -22,7 +23,6 @@ #include "hal/mcpwm_types.h" #include "hal/misc.h" #include "hal/assert.h" -#include #include "soc/soc_etm_source.h" #ifdef __cplusplus @@ -133,7 +133,7 @@ static inline void mcpwm_ll_reset_register(int group_id) #define mcpwm_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; mcpwm_ll_reset_register(__VA_ARGS__) /** - * @brief Enable MCPWM module clock + * @brief Enable MCPWM function clock * * @param group_id Group ID * @param en true to enable, false to disable @@ -154,10 +154,10 @@ static inline void mcpwm_ll_group_enable_clock(int group_id, bool en) /** * @brief Set the clock source for MCPWM * - * @param mcpwm Peripheral instance address + * @param group_id Group ID * @param clk_src Clock source for the MCPWM peripheral */ -static inline void mcpwm_ll_group_set_clock_source(mcpwm_dev_t *mcpwm, soc_module_clk_t clk_src) +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) { @@ -174,9 +174,9 @@ static inline void mcpwm_ll_group_set_clock_source(mcpwm_dev_t *mcpwm, soc_modul HAL_ASSERT(false); break; } - if (mcpwm == &MCPWM0) { + if (group_id == 0) { HP_SYS_CLKRST.peri_clk_ctrl20.reg_mcpwm0_clk_src_sel = clk_id; - } else if (mcpwm == &MCPWM1) { + } else if (group_id == 1) { HP_SYS_CLKRST.peri_clk_ctrl20.reg_mcpwm1_clk_src_sel = clk_id; } } @@ -188,16 +188,16 @@ static inline void mcpwm_ll_group_set_clock_source(mcpwm_dev_t *mcpwm, soc_modul /** * @brief Set the MCPWM group clock prescale * - * @param mcpwm Peripheral instance address + * @param group_id Group ID * @param prescale Prescale value */ -static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int prescale) +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 (mcpwm == &MCPWM0) { + if (group_id == 0) { HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl20, reg_mcpwm0_clk_div_num, prescale - 1); - } else if (mcpwm == &MCPWM1) { + } else if (group_id == 1) { HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl20, reg_mcpwm1_clk_div_num, prescale - 1); } } @@ -1738,23 +1738,6 @@ static inline void mcpwm_ll_etm_enable_evt_comparator_event(mcpwm_dev_t *mcpwm, /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static inline uint32_t mcpwm_ll_group_get_clock_prescale(mcpwm_dev_t *mcpwm) -{ - if (mcpwm == &MCPWM0) { - return HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl20, reg_mcpwm0_clk_div_num) + 1; - } else if (mcpwm == &MCPWM1) { - return HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl20, reg_mcpwm1_clk_div_num) + 1; - } - return 0; -} - -static inline uint32_t mcpwm_ll_timer_get_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id) -{ - mcpwm_timer_cfg0_reg_t cfg0; - cfg0.val = mcpwm->timer[timer_id].timer_cfg0.val; - return cfg0.timer_prescale + 1; -} - static inline uint32_t mcpwm_ll_timer_get_peak(mcpwm_dev_t *mcpwm, int timer_id, bool symmetric) { return HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period) + (symmetric ? 0 : 1); diff --git a/components/hal/esp32s3/include/hal/mcpwm_ll.h b/components/hal/esp32s3/include/hal/mcpwm_ll.h index 9c0a434162..bebf87589f 100644 --- a/components/hal/esp32s3/include/hal/mcpwm_ll.h +++ b/components/hal/esp32s3/include/hal/mcpwm_ll.h @@ -108,7 +108,7 @@ static inline void mcpwm_ll_reset_register(int group_id) #define mcpwm_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; mcpwm_ll_reset_register(__VA_ARGS__) /** - * @brief Enable MCPWM module clock + * @brief Enable MCPWM function clock * * @note Not support to enable/disable the peripheral clock * @@ -124,25 +124,26 @@ static inline void mcpwm_ll_group_enable_clock(int group_id, bool en) /** * @brief Set the clock source for MCPWM * - * @param mcpwm Peripheral instance address + * @param group_id Group ID * @param clk_src Clock source for the MCPWM peripheral */ -static inline void mcpwm_ll_group_set_clock_source(mcpwm_dev_t *mcpwm, mcpwm_timer_clock_source_t clk_src) +static inline void mcpwm_ll_group_set_clock_source(int group_id, mcpwm_timer_clock_source_t clk_src) { - (void)mcpwm; + (void)group_id; (void)clk_src; } /** * @brief Set the MCPWM group clock prescale * - * @param mcpwm Peripheral instance address + * @param group_id Group ID * @param prescale Prescale value */ -static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int prescale) +static inline void mcpwm_ll_group_set_clock_prescale(int group_id, int prescale) { // group clock: PWM_clk = CLK_160M / (prescale) HAL_ASSERT(prescale <= 256 && prescale > 0); + mcpwm_dev_t *mcpwm = MCPWM_LL_GET_HW(group_id); HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->clk_cfg, clk_prescale, prescale - 1); } @@ -216,7 +217,7 @@ static inline uint32_t mcpwm_ll_intr_get_status(mcpwm_dev_t *mcpwm) * @brief Clear MCPWM interrupt status by mask * * @param mcpwm Peripheral instance address - * @param mask Interupt status mask + * @param mask Interrupt status mask */ __attribute__((always_inline)) static inline void mcpwm_ll_intr_clear_status(mcpwm_dev_t *mcpwm, uint32_t mask) @@ -1628,18 +1629,6 @@ static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel /////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static inline uint32_t mcpwm_ll_group_get_clock_prescale(mcpwm_dev_t *mcpwm) -{ - return HAL_FORCE_READ_U32_REG_FIELD(mcpwm->clk_cfg, clk_prescale) + 1; -} - -static inline uint32_t mcpwm_ll_timer_get_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id) -{ - mcpwm_timer_cfg0_reg_t cfg0; - cfg0.val = mcpwm->timer[timer_id].timer_cfg0.val; - return cfg0.timer_prescale + 1; -} - static inline uint32_t mcpwm_ll_timer_get_peak(mcpwm_dev_t *mcpwm, int timer_id, bool symmetric) { return HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period) + (symmetric ? 0 : 1); diff --git a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in index f979c3a8f5..859f88ba7e 100644 --- a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in @@ -23,6 +23,10 @@ config SOC_PCNT_SUPPORTED bool default y +config SOC_MCPWM_SUPPORTED + bool + default y + config SOC_ASYNC_MEMCPY_SUPPORTED bool default y @@ -375,6 +379,62 @@ config SOC_RMT_SUPPORT_XTAL bool default y +config SOC_MCPWM_GROUPS + int + default 1 + +config SOC_MCPWM_TIMERS_PER_GROUP + int + default 3 + +config SOC_MCPWM_OPERATORS_PER_GROUP + int + default 3 + +config SOC_MCPWM_COMPARATORS_PER_OPERATOR + int + default 2 + +config SOC_MCPWM_GENERATORS_PER_OPERATOR + int + default 2 + +config SOC_MCPWM_EVENT_COMPARATORS_PER_OPERATOR + int + default 2 + +config SOC_MCPWM_TRIGGERS_PER_OPERATOR + int + default 2 + +config SOC_MCPWM_GPIO_FAULTS_PER_GROUP + int + default 3 + +config SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP + bool + default y + +config SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER + int + default 3 + +config SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP + int + default 3 + +config SOC_MCPWM_SWSYNC_CAN_PROPAGATE + bool + default y + +config SOC_MCPWM_SUPPORT_EVENT_COMPARATOR + bool + default y + +config SOC_MCPWM_CAPTURE_CLK_FROM_GROUP + bool + default y + config SOC_MPI_MEM_BLOCKS_NUM int default 4 diff --git a/components/soc/esp32c5/mp/include/soc/clk_tree_defs.h b/components/soc/esp32c5/mp/include/soc/clk_tree_defs.h index eb04727cf8..022c9796d3 100644 --- a/components/soc/esp32c5/mp/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c5/mp/include/soc/clk_tree_defs.h @@ -276,10 +276,14 @@ typedef enum { // TODO: [ESP32C5] IDF-8633 (inherit from C6) /** * @brief Type of MCPWM timer clock source */ -typedef enum { // TODO: [ESP32C5] IDF-8709 (inherit from C6) +typedef enum { MCPWM_TIMER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ MCPWM_TIMER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ +#if SOC_CLK_TREE_SUPPORTED MCPWM_TIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */ +#else + MCPWM_TIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default clock choice */ +#endif } soc_periph_mcpwm_timer_clk_src_t; /** @@ -290,10 +294,14 @@ typedef enum { // TODO: [ESP32C5] IDF-8709 (inherit from C6) /** * @brief Type of MCPWM capture clock source */ -typedef enum { // TODO: [ESP32C5] IDF-8709 (inherit from C6) +typedef enum { MCPWM_CAPTURE_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ MCPWM_CAPTURE_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ +#if SOC_CLK_TREE_SUPPORTED MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */ +#else + MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default clock choice */ +#endif } soc_periph_mcpwm_capture_clk_src_t; /** @@ -304,10 +312,14 @@ typedef enum { // TODO: [ESP32C5] IDF-8709 (inherit from C6) /** * @brief Type of MCPWM carrier clock source */ -typedef enum { // TODO: [ESP32C5] IDF-8709 (inherit from C6) +typedef enum { MCPWM_CARRIER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ MCPWM_CARRIER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ +#if SOC_CLK_TREE_SUPPORTED MCPWM_CARRIER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */ +#else + MCPWM_CARRIER_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default clock choice */ +#endif } soc_periph_mcpwm_carrier_clk_src_t; ///////////////////////////////////////////////////// I2S ////////////////////////////////////////////////////////////// diff --git a/components/soc/esp32c5/mp/include/soc/mcpwm_reg.h b/components/soc/esp32c5/mp/include/soc/mcpwm_reg.h index 63257f2fc3..4c08912741 100644 --- a/components/soc/esp32c5/mp/include/soc/mcpwm_reg.h +++ b/components/soc/esp32c5/mp/include/soc/mcpwm_reg.h @@ -2764,7 +2764,7 @@ extern "C" { #define MCPWM_CAP0_MODE_V 0x00000003U #define MCPWM_CAP0_MODE_S 1 /** MCPWM_CAP0_PRESCALE : R/W; bitpos: [10:3]; default: 0; - * Configures prescale value on possitive edge of CAP0. Prescale value = + * Configures prescale value on positive edge of CAP0. Prescale value = * PWM_CAP0_PRESCALE + 1 */ #define MCPWM_CAP0_PRESCALE 0x000000FFU @@ -2809,7 +2809,7 @@ extern "C" { #define MCPWM_CAP1_MODE_V 0x00000003U #define MCPWM_CAP1_MODE_S 1 /** MCPWM_CAP1_PRESCALE : R/W; bitpos: [10:3]; default: 0; - * Configures prescale value on possitive edge of CAP1. Prescale value = + * Configures prescale value on positive edge of CAP1. Prescale value = * PWM_CAP1_PRESCALE + 1 */ #define MCPWM_CAP1_PRESCALE 0x000000FFU @@ -2854,7 +2854,7 @@ extern "C" { #define MCPWM_CAP2_MODE_V 0x00000003U #define MCPWM_CAP2_MODE_S 1 /** MCPWM_CAP2_PRESCALE : R/W; bitpos: [10:3]; default: 0; - * Configures prescale value on possitive edge of CAP2. Prescale value = + * Configures prescale value on positive edge of CAP2. Prescale value = * PWM_CAP2_PRESCALE + 1 */ #define MCPWM_CAP2_PRESCALE 0x000000FFU diff --git a/components/soc/esp32c5/mp/include/soc/mcpwm_struct.h b/components/soc/esp32c5/mp/include/soc/mcpwm_struct.h index e75f05c314..8a3816691c 100644 --- a/components/soc/esp32c5/mp/include/soc/mcpwm_struct.h +++ b/components/soc/esp32c5/mp/include/soc/mcpwm_struct.h @@ -210,33 +210,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 */ 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 @@ -314,145 +300,75 @@ typedef union { uint32_t val; } mcpwm_genn_force_reg_t; -/** Type of genn_a register +/** Type of genn register * PWMn output signal A actions configuration register */ typedef union { struct { - /** genn_a_utez : R/W; bitpos: [1:0]; default: 0; + /** genn_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; + uint32_t genn_utez:2; + /** genn_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; + uint32_t genn_utep:2; + /** genn_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; + uint32_t genn_utea:2; + /** genn_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; + uint32_t genn_uteb:2; + /** genn_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; + uint32_t genn_ut0:2; + /** genn_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; + uint32_t genn_ut1:2; + /** genn_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; + uint32_t genn_dtez:2; + /** genn_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; + uint32_t genn_dtep:2; + /** genn_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; + uint32_t genn_dtea:2; + /** genn_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; + uint32_t genn_dteb:2; + /** genn_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; + uint32_t genn_dt0:2; + /** genn_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 genn_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 - */ -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 - */ - 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_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_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_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_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_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_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_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_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_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_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_b_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 @@ -810,7 +726,7 @@ typedef union { */ uint32_t capn_mode:2; /** capn_prescale : R/W; bitpos: [10:3]; default: 0; - * Configures prescale value on possitive edge of CAPn. Prescale value = + * Configures prescale value on positive edge of CAPn. Prescale value = * PWM_CAPn_PRESCALE + 1 */ uint32_t capn_prescale:8; @@ -1191,33 +1107,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 + * Generatorn timer stamp value register */ typedef union { struct { - /** opn_tstmp_e1 : R/W; bitpos: [15:0]; default: 0; + /** opn_tstmp_e : R/W; bitpos: [15:0]; default: 0; * Configures generatorn timer stamp E1 value register */ - 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 @@ -1234,7 +1136,6 @@ typedef union { uint32_t val; } mcpwm_clk_reg_t; - /** Group: Status register */ /** Type of timern_status register * PWM timern status register. @@ -1309,7 +1210,6 @@ typedef union { uint32_t val; } mcpwm_cap_status_reg_t; - /** Group: Interrupt register */ /** Type of int_ena register * Interrupt enable register @@ -1903,7 +1803,6 @@ typedef union { uint32_t val; } mcpwm_int_clr_reg_t; - /** Group: Version register */ /** Type of version register * Version register. @@ -1919,65 +1818,38 @@ typedef union { uint32_t val; } mcpwm_version_reg_t; +typedef struct { + volatile mcpwm_timern_cfg0_reg_t timer_cfg0; + volatile mcpwm_timern_cfg1_reg_t timer_cfg1; + volatile mcpwm_timern_sync_reg_t timer_sync; + volatile mcpwm_timern_status_reg_t timer_status; +} mcpwm_timer_regs_t; typedef struct { + 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 mcpwm_dev_t { volatile mcpwm_clk_cfg_reg_t clk_cfg; - 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_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; @@ -1992,17 +1864,12 @@ 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; } mcpwm_dev_t; -extern mcpwm_dev_t MCPWM; +extern mcpwm_dev_t MCPWM0; #ifndef __cplusplus _Static_assert(sizeof(mcpwm_dev_t) == 0x14c, "Invalid size of mcpwm_dev_t structure"); diff --git a/components/soc/esp32c5/mp/include/soc/soc_caps.h b/components/soc/esp32c5/mp/include/soc/soc_caps.h index f732abb49c..b1c41d30e3 100644 --- a/components/soc/esp32c5/mp/include/soc/soc_caps.h +++ b/components/soc/esp32c5/mp/include/soc/soc_caps.h @@ -24,7 +24,7 @@ #define SOC_AHB_GDMA_SUPPORTED 1 #define SOC_GPTIMER_SUPPORTED 1 #define SOC_PCNT_SUPPORTED 1 -// #define SOC_MCPWM_SUPPORTED 1 // TODO: [ESP32C5] IDF-8709 +#define SOC_MCPWM_SUPPORTED 1 // #define SOC_TWAI_SUPPORTED 1 // TODO: [ESP32C5] IDF-8691 // #define SOC_ETM_SUPPORTED 1 // TODO: [ESP32C5] IDF-8693 // #define SOC_PARLIO_SUPPORTED 1 // TODO: [ESP32C5] IDF-8685, IDF-8686 @@ -324,19 +324,21 @@ // #define SOC_RMT_SUPPORT_RC_FAST 1 /*!< Support set RC_FAST as the RMT clock source */ /*-------------------------- MCPWM CAPS --------------------------------------*/ -// #define SOC_MCPWM_GROUPS (1U) ///< 1 MCPWM groups on the chip (i.e., the number of independent MCPWM peripherals) -// #define SOC_MCPWM_TIMERS_PER_GROUP (3) ///< The number of timers that each group has -// #define SOC_MCPWM_OPERATORS_PER_GROUP (3) ///< The number of operators that each group has -// #define SOC_MCPWM_COMPARATORS_PER_OPERATOR (2) ///< The number of comparators that each operator has -// #define SOC_MCPWM_GENERATORS_PER_OPERATOR (2) ///< The number of generators that each operator has -// #define SOC_MCPWM_TRIGGERS_PER_OPERATOR (2) ///< The number of triggers that each operator has -// #define SOC_MCPWM_GPIO_FAULTS_PER_GROUP (3) ///< The number of fault signal detectors that each group has -// #define SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP (1) ///< The number of capture timers that each group has -// #define SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER (3) ///< The number of capture channels that each capture timer has -// #define SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP (3) ///< The number of GPIO synchros that each group has -// #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_CAPTURE_CLK_FROM_GROUP (1) ///< Capture timer shares clock with other PWM timers +#define SOC_MCPWM_GROUPS 1U ///< 1 MCPWM groups on the chip (i.e., the number of independent MCPWM peripherals) +#define SOC_MCPWM_TIMERS_PER_GROUP 3 ///< The number of timers that each group has +#define SOC_MCPWM_OPERATORS_PER_GROUP 3 ///< The number of operators that each group has +#define SOC_MCPWM_COMPARATORS_PER_OPERATOR 2 ///< The number of comparators that each operator has +#define SOC_MCPWM_GENERATORS_PER_OPERATOR 2 ///< The number of generators that each operator has +#define SOC_MCPWM_EVENT_COMPARATORS_PER_OPERATOR 2 ///< The number of event comparators that each operator has +#define SOC_MCPWM_TRIGGERS_PER_OPERATOR 2 ///< The number of triggers that each operator has +#define SOC_MCPWM_GPIO_FAULTS_PER_GROUP 3 ///< The number of fault signal detectors that each group has +#define SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP 1 ///< The number of capture timers that each group has +#define SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER 3 ///< The number of capture channels that each capture timer has +#define SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP 3 ///< The number of GPIO synchros that each group has +#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 /*------------------------ USB SERIAL JTAG CAPS ------------------------------*/ // #define SOC_USB_SERIAL_JTAG_SUPPORT_LIGHT_SLEEP (1) /*!< Support to maintain minimum usb communication during light sleep */ // TODO: IDF-6395 @@ -530,7 +532,6 @@ /* macro redefine for pass esp_wifi headers md5sum check */ // #define MAC_SUPPORT_PMU_MODEM_STATE SOC_PM_SUPPORT_PMU_MODEM_STATE - // #define SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY (1) /*!