morris пре 3 година
родитељ
комит
f997b81242
26 измењених фајлова са 2031 додато и 57 уклоњено
  1. 46 38
      components/driver/deprecated/driver/mcpwm.h
  2. 19 1
      components/driver/deprecated/mcpwm_legacy.c
  3. 11 4
      components/driver/mcpwm/mcpwm_cap.c
  4. 15 2
      components/driver/mcpwm/mcpwm_com.c
  5. 3 3
      components/driver/mcpwm/mcpwm_private.h
  6. 1 1
      components/driver/mcpwm/mcpwm_timer.c
  7. 3 3
      components/driver/test_apps/legacy_mcpwm_driver/main/test_legacy_mcpwm.c
  8. 4 0
      components/driver/test_apps/mcpwm/main/test_mcpwm_oper.c
  9. 26 0
      components/hal/esp32/include/hal/mcpwm_ll.h
  10. 8 0
      components/hal/esp32c6/include/hal/clk_gate_ll.h
  11. 1649 0
      components/hal/esp32c6/include/hal/mcpwm_ll.h
  12. 26 0
      components/hal/esp32s3/include/hal/mcpwm_ll.h
  13. 4 0
      components/soc/esp32/include/soc/Kconfig.soc_caps.in
  14. 1 1
      components/soc/esp32/include/soc/clk_tree_defs.h
  15. 1 0
      components/soc/esp32/include/soc/soc_caps.h
  16. 1 0
      components/soc/esp32c6/CMakeLists.txt
  17. 64 0
      components/soc/esp32c6/include/soc/Kconfig.soc_caps.in
  18. 38 0
      components/soc/esp32c6/include/soc/clk_tree_defs.h
  19. 1 1
      components/soc/esp32c6/include/soc/mcpwm_struct.h
  20. 2 1
      components/soc/esp32c6/include/soc/periph_defs.h
  21. 18 0
      components/soc/esp32c6/include/soc/soc_caps.h
  22. 1 1
      components/soc/esp32c6/ld/esp32c6.peripherals.ld
  23. 83 0
      components/soc/esp32c6/mcpwm_periph.c
  24. 4 0
      components/soc/esp32s3/include/soc/Kconfig.soc_caps.in
  25. 1 1
      components/soc/esp32s3/include/soc/clk_tree_defs.h
  26. 1 0
      components/soc/esp32s3/include/soc/soc_caps.h

+ 46 - 38
components/driver/deprecated/driver/mcpwm.h

@@ -24,7 +24,7 @@ extern "C" {
  *
  * @note This function initializes one gpio at a time.
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param io_signal set MCPWM signals, each MCPWM unit has 6 output(MCPWMXA, MCPWMXB) and 9 input(SYNC_X, FAULT_X, CAP_X)
  *                  'X' is timer_num(0-2)
  * @param gpio_num set this to configure gpio for MCPWM, if you want to use gpio16, gpio_num = 16
@@ -40,7 +40,7 @@ esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal,
  *
  * @note This function initialize a group of MCPWM GPIOs at a time.
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param mcpwm_pin MCPWM pin structure
  *
  * @return
@@ -56,7 +56,7 @@ esp_err_t mcpwm_set_pin(mcpwm_unit_t mcpwm_num, const mcpwm_pin_config_t *mcpwm_
  *        The default resolution can be changed by calling mcpwm_group_set_resolution() and mcpwm_timer_set_resolution(),
  *        before calling this function.
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers.
  * @param mcpwm_conf configure structure mcpwm_config_t
  *
@@ -74,7 +74,7 @@ esp_err_t mcpwm_init( mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcp
  *        to set them back.
  *        The group resolution must be an integral multiple of timer resolution.
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param resolution set expected frequency resolution
  *
  * @return
@@ -91,7 +91,7 @@ esp_err_t mcpwm_group_set_resolution(mcpwm_unit_t mcpwm_num, unsigned long int r
  *        to set them back.
  *        The group resolution must be an integral multiple of timer resolution.
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param resolution set expected frequency resolution
  *
@@ -104,7 +104,7 @@ esp_err_t mcpwm_timer_set_resolution(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer
 /**
  * @brief Set frequency(in Hz) of MCPWM timer
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param frequency set the frequency in Hz of each timer
  *
@@ -117,7 +117,7 @@ esp_err_t mcpwm_set_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, u
 /**
  * @brief Set duty cycle of each operator(MCPWMXA/MCPWMXB)
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param gen set the generator(MCPWMXA/MCPWMXB), 'X' is operator number selected
  * @param duty set duty cycle in %(i.e for 62.3% duty cycle, duty = 62.3) of each operator
@@ -131,7 +131,7 @@ esp_err_t mcpwm_set_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_
 /**
  * @brief Set duty cycle of each operator(MCPWMXA/MCPWMXB) in us
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param gen set the generator(MCPWMXA/MCPWMXB), 'x' is operator number selected
  * @param duty_in_us set duty value in microseconds of each operator
@@ -147,7 +147,7 @@ esp_err_t mcpwm_set_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
  * @note
  *        Call this function every time after mcpwm_set_signal_high or mcpwm_set_signal_low to resume with previously set duty cycle
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param gen set the generator(MCPWMXA/MCPWMXB), 'x' is operator number selected
  * @param duty_type set active low or active high duty type
@@ -161,7 +161,7 @@ esp_err_t mcpwm_set_duty_type(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, m
 /**
  * @brief Get frequency of timer
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  *
  * @return
@@ -172,7 +172,7 @@ uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
 /**
  * @brief Get duty cycle of each operator
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param gen set the generator(MCPWMXA/MCPWMXB), 'x' is operator number selected
  *
@@ -184,7 +184,7 @@ float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_oper
 /**
  * @brief Get duty cycle of each operator in us
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param gen set the generator(MCPWMXA/MCPWMXB), 'x' is operator number selected
  *
@@ -196,7 +196,7 @@ uint32_t mcpwm_get_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, m
 /**
  * @brief Use this function to set MCPWM signal high
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param gen set the operator(MCPWMXA/MCPWMXB), 'x' is timer number selected
  *
@@ -210,7 +210,7 @@ esp_err_t mcpwm_set_signal_high(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
 /**
  * @brief Use this function to set MCPWM signal low
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param gen set the operator(MCPWMXA/MCPWMXB), 'x' is timer number selected
  *
@@ -224,7 +224,7 @@ esp_err_t mcpwm_set_signal_low(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
 /**
  * @brief Start MCPWM signal on timer 'x'
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  *
  * @return
@@ -236,7 +236,7 @@ esp_err_t mcpwm_start(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
 /**
  * @brief Start MCPWM signal on timer 'x'
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  *
  * @return
@@ -248,7 +248,7 @@ esp_err_t mcpwm_stop(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
 /**
  * @brief  Initialize carrier configuration
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param carrier_conf configure structure mcpwm_carrier_config_t
  *
@@ -261,7 +261,7 @@ esp_err_t mcpwm_carrier_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, co
 /**
  * @brief Enable MCPWM carrier submodule, for respective timer
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  *
  * @return
@@ -273,7 +273,7 @@ esp_err_t mcpwm_carrier_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
 /**
  * @brief Disable MCPWM carrier submodule, for respective timer
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  *
  * @return
@@ -285,7 +285,7 @@ esp_err_t mcpwm_carrier_disable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
 /**
  * @brief Set period of carrier
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param carrier_period set the carrier period of each timer, carrier period = (carrier_period + 1)*800ns
  *                    (carrier_period <= 15)
@@ -299,7 +299,7 @@ esp_err_t mcpwm_carrier_set_period(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_n
 /**
  * @brief Set duty_cycle of carrier
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param carrier_duty set duty_cycle of carrier , carrier duty cycle = carrier_duty*12.5%
  *                  (chop_duty <= 7)
@@ -315,7 +315,7 @@ esp_err_t mcpwm_carrier_set_duty_cycle(mcpwm_unit_t mcpwm_num, mcpwm_timer_t tim
  *
  * @note The carrier oneshot pulse can't disabled.
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param pulse_width set pulse width of first pulse in oneshot mode, width = (carrier period)*(pulse_width +1)
  *                    (pulse_width <= 15)
@@ -329,7 +329,7 @@ esp_err_t mcpwm_carrier_oneshot_mode_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_
 /**
  * @brief Enable or disable carrier output inversion
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param carrier_ivt_mode enable or disable carrier output inversion
  *
@@ -343,7 +343,7 @@ esp_err_t mcpwm_carrier_output_invert(mcpwm_unit_t mcpwm_num, mcpwm_timer_t time
 /**
  * @brief Enable and initialize deadtime for each MCPWM timer
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param dt_mode set deadtime mode
  * @param red set rising edge delay = (red + 1) * MCPWM Group Resolution (default to 100ns, can be changed by `mcpwm_group_set_resolution`)
@@ -359,7 +359,7 @@ esp_err_t mcpwm_deadtime_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
 /**
  * @brief Disable deadtime on MCPWM timer
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  *
  * @return
@@ -371,7 +371,7 @@ esp_err_t mcpwm_deadtime_disable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num
 /**
  * @brief Initialize fault submodule, currently low level triggering is not supported
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param intput_level set fault signal level, which will cause fault to occur
  * @param fault_sig set the fault pin, which needs to be enabled
  *
@@ -386,7 +386,7 @@ esp_err_t mcpwm_fault_init(mcpwm_unit_t mcpwm_num, mcpwm_fault_input_level_t int
  * @note
  *        currently low level triggering is not supported
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param fault_sig set the fault pin, which needs to be enabled for oneshot mode
  * @param action_on_pwmxa action to be taken on MCPWMXA when fault occurs, either no change or high or low or toggle
@@ -404,7 +404,7 @@ esp_err_t mcpwm_fault_set_oneshot_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t tim
  * @note
  *        currently low level triggering is not supported
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param fault_sig set the fault pin, which needs to be enabled for cyc mode
  * @param action_on_pwmxa action to be taken on MCPWMXA when fault occurs, either no change or high or low or toggle
@@ -420,7 +420,7 @@ esp_err_t mcpwm_fault_set_cyc_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_n
 /**
  * @brief Disable fault signal
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param fault_sig fault pin, which needs to be disabled
  *
  * @return
@@ -432,7 +432,7 @@ esp_err_t mcpwm_fault_deinit(mcpwm_unit_t mcpwm_num, mcpwm_fault_signal_t fault_
 /**
  * @brief Enable capture channel
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param cap_channel capture channel, which needs to be enabled
  * @param cap_conf capture channel configuration
  *
@@ -445,7 +445,7 @@ esp_err_t mcpwm_capture_enable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_cha
 /**
  * @brief Disable capture channel
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param cap_channel capture channel, which needs to be disabled
  *
  * @return
@@ -457,7 +457,7 @@ esp_err_t mcpwm_capture_disable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_ch
 /**
  * @brief Get capture value
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param cap_sig capture channel on which value is to be measured
  *
  * @return
@@ -465,10 +465,18 @@ esp_err_t mcpwm_capture_disable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_ch
  */
 uint32_t mcpwm_capture_signal_get_value(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig);
 
+/**
+ * @brief Get capture timer's resolution
+ *
+ * @param mcpwm_num set MCPWM unit
+ * @return Capture timer's resolution
+ */
+uint32_t mcpwm_capture_get_resolution(mcpwm_unit_t mcpwm_num);
+
 /**
  * @brief Get edge of capture signal
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param cap_sig capture channel of whose edge is to be determined
  *
  * @return
@@ -479,7 +487,7 @@ uint32_t mcpwm_capture_signal_get_edge(mcpwm_unit_t mcpwm_num, mcpwm_capture_sig
 /**
  * @brief Initialize sync submodule and sets the signal that will cause the timer be loaded with pre-defined value
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param sync_conf sync configuration on this timer
  *
@@ -492,7 +500,7 @@ esp_err_t mcpwm_sync_configure(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
 /**
  * @brief Disable sync submodule on given timer
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  *
  * @return
@@ -505,7 +513,7 @@ esp_err_t mcpwm_sync_disable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
  * @brief Set sync output on given timer
  *        Configures what event triggers MCPWM timer to output a sync signal.
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  * @param trigger set the trigger that will cause the timer to generate a software sync signal.
  *                Specifically, `MCPWM_SWSYNC_SOURCE_DISABLED` will disable the timer from generating sync signal.
@@ -518,7 +526,7 @@ esp_err_t mcpwm_set_timer_sync_output(mcpwm_unit_t mcpwm_num, mcpwm_timer_t time
 /**
  * @brief Trigger a software sync event and sends it to a specific timer.
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
  *
  * @note This software sync event will have the same effect as hw one, except that:
@@ -534,7 +542,7 @@ esp_err_t mcpwm_timer_trigger_soft_sync(mcpwm_unit_t mcpwm_num, mcpwm_timer_t ti
 /**
  * @brief Set external GPIO sync input inverter
  *
- * @param mcpwm_num set MCPWM unit(0-1)
+ * @param mcpwm_num set MCPWM unit
  * @param sync_sig set sync signal of MCPWM, only supports GPIO sync signal
  * @param invert whether GPIO sync source input is inverted (to get negative edge trigger)
  *

+ 19 - 1
components/driver/deprecated/mcpwm_legacy.c

@@ -22,6 +22,7 @@
 #include "driver/mcpwm_types_legacy.h"
 #include "driver/gpio.h"
 #include "esp_private/periph_ctrl.h"
+#include "esp_private/esp_clk.h"
 
 static const char *TAG = "mcpwm(legacy)";
 
@@ -47,7 +48,7 @@ _Static_assert(MCPWM_UNIT_MAX == SOC_MCPWM_GROUPS, "MCPWM unit number not equal
 #define MCPWM_INTR_FLAG  0
 #endif
 
-#define MCPWM_GROUP_CLK_SRC_HZ 160000000
+#define MCPWM_GROUP_CLK_SRC_HZ 160000000 // MCPWM clock source is fixed to `MCPWM_CAPTURE_CLK_SRC_PLL160M`
 #define MCPWM_GROUP_CLK_PRESCALE (16)
 #define MCPWM_GROUP_CLK_HZ (MCPWM_GROUP_CLK_SRC_HZ / MCPWM_GROUP_CLK_PRESCALE)
 #define MCPWM_TIMER_CLK_HZ (MCPWM_GROUP_CLK_HZ / 10)
@@ -405,6 +406,8 @@ esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpw
     mcpwm_hal_init(hal, &config);
 
     mcpwm_critical_enter(mcpwm_num);
+    mcpwm_ll_group_enable_clock(hal->dev, true);
+    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, context[mcpwm_num].group_pre_scale);
     mcpwm_ll_timer_set_clock_prescale(hal->dev, timer_num, context[mcpwm_num].timer_pre_scale[timer_num]);
     mcpwm_ll_timer_set_count_mode(hal->dev, timer_num, mcpwm_conf->counter_mode);
@@ -795,6 +798,8 @@ esp_err_t mcpwm_capture_enable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_cha
     };
     mcpwm_hal_init(hal, &init_config);
     mcpwm_critical_enter(mcpwm_num);
+    mcpwm_ll_group_enable_clock(hal->dev, true);
+    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, context[mcpwm_num].group_pre_scale);
     mcpwm_ll_capture_enable_timer(hal->dev, true);
     mcpwm_ll_capture_enable_channel(hal->dev, cap_channel, true);
@@ -867,6 +872,19 @@ uint32_t MCPWM_ISR_ATTR mcpwm_capture_signal_get_value(mcpwm_unit_t mcpwm_num, m
     return mcpwm_ll_capture_get_value(hal->dev, cap_sig);
 }
 
+uint32_t mcpwm_capture_get_resolution(mcpwm_unit_t mcpwm_num)
+{
+    if (mcpwm_num >= MCPWM_UNIT_MAX) {
+        ESP_LOGE(TAG, "Invalid MCPWM instance");
+        return 0;
+    }
+#if SOC_MCPWM_CAPTURE_CLK_FROM_GROUP
+    return MCPWM_GROUP_CLK_SRC_HZ / context[mcpwm_num].group_pre_scale;
+#else
+    return esp_clk_apb_freq();
+#endif
+}
+
 uint32_t MCPWM_ISR_ATTR mcpwm_capture_signal_get_edge(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig)
 {
     if (mcpwm_num >= MCPWM_UNIT_MAX && cap_sig >= SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER) {

+ 11 - 4
components/driver/mcpwm/mcpwm_cap.c

@@ -92,6 +92,16 @@ esp_err_t mcpwm_new_capture_timer(const mcpwm_capture_timer_config_t *config, mc
     cap_timer = heap_caps_calloc(1, sizeof(mcpwm_cap_timer_t), MCPWM_MEM_ALLOC_CAPS);
     ESP_GOTO_ON_FALSE(cap_timer, ESP_ERR_NO_MEM, err, TAG, "no mem for capture timer");
 
+    ESP_GOTO_ON_ERROR(mcpwm_cap_timer_register_to_group(cap_timer, config->group_id), err, TAG, "register timer failed");
+    mcpwm_group_t *group = cap_timer->group;
+    int group_id = group->group_id;
+
+#if SOC_MCPWM_CAPTURE_CLK_FROM_GROUP
+    // capture timer clock source is same as the MCPWM group
+    ESP_GOTO_ON_ERROR(mcpwm_select_periph_clock(group, (soc_module_clk_t)config->clk_src), err, TAG, "set group clock failed");
+    cap_timer->resolution_hz = group->resolution_hz;
+#else
+    // capture timer has independent clock source selection
     switch (config->clk_src) {
     case MCPWM_CAPTURE_CLK_SRC_APB:
         cap_timer->resolution_hz = esp_clk_apb_freq();
@@ -103,10 +113,7 @@ esp_err_t mcpwm_new_capture_timer(const mcpwm_capture_timer_config_t *config, mc
     default:
         ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid clock source:%d", config->clk_src);
     }
-
-    ESP_GOTO_ON_ERROR(mcpwm_cap_timer_register_to_group(cap_timer, config->group_id), err, TAG, "register timer failed");
-    mcpwm_group_t *group = cap_timer->group;
-    int group_id = group->group_id;
+#endif
 
     // fill in other capture timer specific members
     cap_timer->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;

+ 15 - 2
components/driver/mcpwm/mcpwm_com.c

@@ -15,6 +15,7 @@
 #include "esp_log.h"
 #include "esp_check.h"
 #include "esp_private/periph_ctrl.h"
+#include "esp_private/esp_clk.h"
 #include "soc/mcpwm_periph.h"
 #include "hal/mcpwm_ll.h"
 #include "mcpwm_private.h"
@@ -55,6 +56,7 @@ mcpwm_group_t *mcpwm_acquire_group_handle(int group_id)
             // disable all interrupts and clear pending status
             mcpwm_ll_intr_enable(hal->dev, UINT32_MAX, false);
             mcpwm_ll_intr_clear_status(hal->dev, UINT32_MAX);
+            mcpwm_ll_group_enable_clock(hal->dev, true);
         }
     } else { // group already install
         group = s_platform.groups[group_id];
@@ -81,6 +83,7 @@ void mcpwm_release_group_handle(mcpwm_group_t *group)
     if (s_platform.group_ref_counts[group_id] == 0) {
         do_deinitialize = true;
         s_platform.groups[group_id] = NULL; // deregister from platfrom
+        mcpwm_ll_group_enable_clock(group->hal.dev, false);
         // hal layer deinitialize
         mcpwm_hal_deinit(&group->hal);
         periph_module_disable(mcpwm_periph_signals.groups[group_id].module);
@@ -93,7 +96,7 @@ void mcpwm_release_group_handle(mcpwm_group_t *group)
     }
 }
 
-esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, mcpwm_timer_clock_source_t clk_src)
+esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, soc_module_clk_t clk_src)
 {
     esp_err_t ret = ESP_OK;
     uint32_t periph_src_clk_hz = 0;
@@ -114,7 +117,8 @@ esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, mcpwm_timer_clock_sour
     if (do_clock_init) {
         // [clk_tree] ToDo: replace the following switch-case table by clock_tree APIs
         switch (clk_src) {
-        case MCPWM_TIMER_CLK_SRC_DEFAULT:
+#if SOC_MCPWM_CLK_SUPPORT_PLL160M
+        case SOC_MOD_CLK_PLL_F160M:
             periph_src_clk_hz = 160000000;
 #if CONFIG_PM_ENABLE
             sprintf(group->pm_lock_name, "mcpwm_%d", group->group_id); // e.g. mcpwm_0
@@ -123,10 +127,19 @@ esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, mcpwm_timer_clock_sour
             ESP_LOGD(TAG, "install ESP_PM_APB_FREQ_MAX lock for MCPWM group(%d)", group->group_id);
 #endif // CONFIG_PM_ENABLE
             break;
+#endif // SOC_MCPWM_CLK_SUPPORT_PLL160M
+
+#if SOC_MCPWM_CLK_SUPPORT_XTAL
+        case SOC_MOD_CLK_XTAL:
+            periph_src_clk_hz = esp_clk_xtal_freq();
+            break;
+#endif // SOC_MCPWM_CLK_SUPPORT_XTAL
         default:
             ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "clock source %d is not supported", clk_src);
             break;
         }
+
+        mcpwm_ll_group_set_clock_source(group->hal.dev, clk_src);
         mcpwm_ll_group_set_clock_prescale(group->hal.dev, MCPWM_PERIPH_CLOCK_PRE_SCALE);
         group->resolution_hz = periph_src_clk_hz / MCPWM_PERIPH_CLOCK_PRE_SCALE;
         ESP_LOGD(TAG, "group (%d) clock resolution:%"PRIu32"Hz", group->group_id, group->resolution_hz);

+ 3 - 3
components/driver/mcpwm/mcpwm_private.h

@@ -57,8 +57,8 @@ struct mcpwm_group_t {
     mcpwm_hal_context_t hal; // HAL instance is at group level
     portMUX_TYPE spinlock;   // group level spinlock
     uint32_t resolution_hz;  // MCPWM group clock resolution
-    esp_pm_lock_handle_t pm_lock;       // power management lock
-    mcpwm_timer_clock_source_t clk_src; // source clock
+    esp_pm_lock_handle_t pm_lock; // power management lock
+    soc_module_clk_t clk_src; // peripheral source clock
     mcpwm_cap_timer_t *cap_timer; // mcpwm capture timers
     mcpwm_timer_t *timers[SOC_MCPWM_TIMERS_PER_GROUP]; // mcpwm timer array
     mcpwm_oper_t *operators[SOC_MCPWM_OPERATORS_PER_GROUP]; // mcpwm operator array
@@ -220,7 +220,7 @@ struct mcpwm_cap_channel_t {
 
 mcpwm_group_t *mcpwm_acquire_group_handle(int group_id);
 void mcpwm_release_group_handle(mcpwm_group_t *group);
-esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, mcpwm_timer_clock_source_t clk_src);
+esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, soc_module_clk_t clk_src);
 
 #ifdef __cplusplus
 }

+ 1 - 1
components/driver/mcpwm/mcpwm_timer.c

@@ -101,7 +101,7 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle
     mcpwm_hal_context_t *hal = &group->hal;
     int timer_id = timer->timer_id;
     // select the clock source
-    ESP_GOTO_ON_ERROR(mcpwm_select_periph_clock(group, config->clk_src), err, TAG, "set group clock failed");
+    ESP_GOTO_ON_ERROR(mcpwm_select_periph_clock(group, (soc_module_clk_t)config->clk_src), err, TAG, "set group clock failed");
     // reset the timer to a determined state
     mcpwm_hal_timer_reset(hal, timer_id);
     // set timer resolution

+ 3 - 3
components/driver/test_apps/legacy_mcpwm_driver/main/test_legacy_mcpwm.c

@@ -487,7 +487,7 @@ static void mcpwm_swsync_test(mcpwm_unit_t unit)
 
     vTaskDelay(pdMS_TO_TICKS(100));
 
-    uint32_t delta_timestamp_us = (cap_timestamp[2] - cap_timestamp[1]) * 1000000 / esp_clk_apb_freq();
+    uint32_t delta_timestamp_us = (cap_timestamp[2] - cap_timestamp[1]) * 1000000 / mcpwm_capture_get_resolution(unit);
     uint32_t expected_phase_us = 1000000 / mcpwm_get_frequency(unit, MCPWM_TIMER_0) * test_sync_phase / 1000;
     // accept +-2 error
     TEST_ASSERT_UINT32_WITHIN(2, expected_phase_us, delta_timestamp_us);
@@ -552,8 +552,8 @@ static void mcpwm_capture_test(mcpwm_unit_t unit, mcpwm_capture_signal_t cap_cha
     gpio_set_level(TEST_CAP_GPIO, 1);
     TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(40)));
     uint32_t cap_val1 = mcpwm_capture_signal_get_value(unit, cap_chan);
-    // capture clock source is APB (80MHz), 100ms means 8000000 ticks
-    TEST_ASSERT_UINT_WITHIN(100000, 8000000, cap_val1 - cap_val0);
+    uint32_t delta = mcpwm_capture_get_resolution(unit) / (cap_val1 - cap_val0);
+    TEST_ASSERT_UINT_WITHIN(2, 10, delta);
 
     TEST_ESP_OK(mcpwm_capture_disable_channel(unit, cap_channel));
 }

+ 4 - 0
components/driver/test_apps/mcpwm/main/test_mcpwm_oper.c

@@ -48,7 +48,11 @@ TEST_CASE("mcpwm_operator_install_uninstall", "[mcpwm]")
             TEST_ESP_OK(mcpwm_operator_connect_timer(operators[k++], timers[i]));
         }
     }
+
+#if SOC_MCPWM_GROUPS > 1
     TEST_ESP_ERR(ESP_ERR_INVALID_ARG, mcpwm_operator_connect_timer(operators[0], timers[1]));
+#endif
+
     printf("uninstall operators and timers\r\n");
     for (int i = 0; i < total_operators; i++) {
         TEST_ESP_OK(mcpwm_del_operator(operators[i]));

+ 26 - 0
components/hal/esp32/include/hal/mcpwm_ll.h

@@ -63,6 +63,32 @@ typedef enum {
 
 ////////////////////////////////////////MCPWM Group Specific////////////////////////////////////////////////////////////
 
+/**
+ * @brief Set the clock source for MCPWM
+ *
+ * @param mcpwm Peripheral instance address
+ * @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)
+{
+    (void)mcpwm;
+    (void)clk_src;
+}
+
+/**
+ * @brief Enable MCPWM module clock
+ *
+ * @note Not support to enable/disable the peripheral clock
+ *
+ * @param mcpwm Peripheral instance address
+ * @param en true to enable, false to disable
+ */
+static inline void mcpwm_ll_group_enable_clock(mcpwm_dev_t *mcpwm, bool en)
+{
+    (void)mcpwm; // only one MCPWM instance
+    (void)en;
+}
+
 /**
  * @brief Set the MCPWM group clock prescale
  *

+ 8 - 0
components/hal/esp32c6/include/hal/clk_gate_ll.h

@@ -54,6 +54,8 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
             return PCR_TWAI1_CLK_EN;
         case PERIPH_GDMA_MODULE:
             return PCR_GDMA_CLK_EN;
+        case PERIPH_MCPWM0_MODULE:
+            return PCR_PWM_CLK_EN;
         case PERIPH_AES_MODULE:
             return PCR_AES_CLK_EN;
         case PERIPH_SHA_MODULE:
@@ -120,6 +122,8 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
             return PCR_TWAI1_RST_EN;
         case PERIPH_GDMA_MODULE:
             return PCR_GDMA_RST_EN;
+        case PERIPH_MCPWM0_MODULE:
+            return PCR_PWM_RST_EN;
         case PERIPH_AES_MODULE:
         if (enable == true) {
             // Clear reset on digital signature, otherwise AES unit is held in reset also.
@@ -210,6 +214,8 @@ static uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
             return PCR_TWAI1_CONF_REG;
         case PERIPH_GDMA_MODULE:
             return PCR_GDMA_CONF_REG;
+        case PERIPH_MCPWM0_MODULE:
+            return PCR_PWM_CONF_REG;
         case PERIPH_AES_MODULE:
             return PCR_AES_CONF_REG;
         case PERIPH_SHA_MODULE:
@@ -262,6 +268,8 @@ static uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
             return PCR_TWAI1_CONF_REG;
         case PERIPH_GDMA_MODULE:
             return PCR_GDMA_CONF_REG;
+        case PERIPH_MCPWM0_MODULE:
+            return PCR_PWM_CONF_REG;
         case PERIPH_AES_MODULE:
             return PCR_AES_CONF_REG;
         case PERIPH_SHA_MODULE:

+ 1649 - 0
components/hal/esp32c6/include/hal/mcpwm_ll.h

@@ -0,0 +1,1649 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/*******************************************************************************
+ * NOTICE
+ * The hal is not public api, don't use in application code.
+ * See readme.md in hal/include/hal/readme.md
+ ******************************************************************************/
+
+// The LL layer for ESP32-C6 MCPWM register operations
+
+#pragma once
+
+#include <stdbool.h>
+#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"
+
+#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_CARRIER_ONESHOT         16
+#define MCPWM_LL_MAX_CAPTURE_PRESCALE        256
+#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)])
+
+/**
+ * @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 Set the clock source for MCPWM
+ *
+ * @param mcpwm Peripheral instance address
+ * @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)
+{
+    (void)mcpwm; // only one MCPWM instance
+    switch (clk_src) {
+    case SOC_MOD_CLK_PLL_F160M:
+        PCR.pwm_clk_conf.pwm_clkm_sel = 1;
+        break;
+    case SOC_MOD_CLK_XTAL:
+        PCR.pwm_clk_conf.pwm_clkm_sel = 2;
+        break;
+    default:
+        HAL_ASSERT(false);
+        break;
+    }
+}
+
+/**
+ * @brief Enable MCPWM module clock
+ *
+ * @param mcpwm Peripheral instance address
+ * @param en true to enable, false to disable
+ */
+static inline void mcpwm_ll_group_enable_clock(mcpwm_dev_t *mcpwm, bool en)
+{
+    (void)mcpwm; // only one MCPWM instance
+    PCR.pwm_clk_conf.pwm_clkm_en = en;
+}
+
+/**
+ * @brief Set the MCPWM group clock prescale
+ *
+ * @param mcpwm Peripheral instance address
+ * @param pre_scale Prescale value
+ */
+static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int pre_scale)
+{
+    (void)mcpwm; // only one MCPWM instance
+    // group clock: PWM_clk = source_clock / (prescale + 1)
+    HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.pwm_clk_conf, pwm_div_num, pre_scale - 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 Interupt 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, timer_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
+ */
+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_ASSERT(peak > 0 && peak <= MCPWM_LL_MAX_COUNT_VALUE);
+        HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak - 1);
+    } else { // in symmetric mode, period = [0,peak-1] + [peak,1]
+        HAL_ASSERT(peak < MCPWM_LL_MAX_COUNT_VALUE);
+        HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_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.timer_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.timer_period_upmethod |= 0x01;
+    } else {
+        mcpwm->timer[timer_id].timer_cfg0.timer_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.timer_period_upmethod |= 0x02;
+    } else {
+        mcpwm->timer[timer_id].timer_cfg0.timer_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.timer_mod = 0;
+        break;
+    case MCPWM_TIMER_COUNT_MODE_UP:
+        mcpwm->timer[timer_id].timer_cfg1.timer_mod = 1;
+        break;
+    case MCPWM_TIMER_COUNT_MODE_DOWN:
+        mcpwm->timer[timer_id].timer_cfg1.timer_mod = 2;
+        break;
+    case MCPWM_TIMER_COUNT_MODE_UP_DOWN:
+        mcpwm->timer[timer_id].timer_cfg1.timer_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.timer_start = 0;
+        break;
+    case MCPWM_TIMER_STOP_FULL:
+        mcpwm->timer[timer_id].timer_cfg1.timer_start = 1;
+        break;
+    case MCPWM_TIMER_START_NO_STOP:
+        mcpwm->timer[timer_id].timer_cfg1.timer_start = 2;
+        break;
+    case MCPWM_TIMER_START_STOP_EMPTY:
+        mcpwm->timer[timer_id].timer_cfg1.timer_start = 3;
+        break;
+    case MCPWM_TIMER_START_STOP_FULL:
+        mcpwm->timer[timer_id].timer_cfg1.timer_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.timer_mod == 0) {
+        return HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_status, timer_value);
+    }
+    if (mcpwm->timer[timer_id].timer_status.timer_direction) { // down direction
+        return (HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_status, timer_value) + 1) %
+               (HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period) + 1);
+    }
+    // up direction
+    return (HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_status, timer_value) +
+            HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period)) %
+           (HAL_FORCE_READ_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_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.timer_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.timer_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.timer_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.timer_synco_sel = 1;
+        break;
+    case MCPWM_TIMER_EVENT_FULL:
+        mcpwm->timer[timer_id].timer_sync.timer_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.timer_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.timer_sync_sw = ~mcpwm->timer[timer_id].timer_sync.timer_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, timer_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.timer_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], cmpr, 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.gen_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.gen_cfg_upmethod |= 1 << 0;
+    } else {
+        mcpwm->operators[operator_id].gen_cfg0.gen_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.gen_cfg_upmethod |= 1 << 1;
+    } else {
+        mcpwm->operators[operator_id].gen_cfg0.gen_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.gen_cfg_upmethod |= 1 << 2;
+    } else {
+        mcpwm->operators[operator_id].gen_cfg0.gen_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.gen_cfg_upmethod |= 1 << 3;
+    } else {
+        mcpwm->operators[operator_id].gen_cfg0.gen_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(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 timer sync event (when the timer 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_timer_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.gen_a_nciforce = ~mcpwm->operators[operator_id].gen_force.gen_a_nciforce;
+    } else {
+        mcpwm->operators[operator_id].gen_force.gen_b_nciforce = ~mcpwm->operators[operator_id].gen_force.gen_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.gen_cntuforce_upmethod = 0; // update force method immediately
+    if (generator_id == 0) {
+        mcpwm->operators[operator_id].gen_force.gen_a_cntuforce_mode = 0;
+    } else {
+        mcpwm->operators[operator_id].gen_force.gen_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.gen_a_nciforce_mode = 0;
+    } else {
+        mcpwm->operators[operator_id].gen_force.gen_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.gen_cntuforce_upmethod = 0; // update force method immediately
+    if (generator_id == 0) {
+        mcpwm->operators[operator_id].gen_force.gen_a_cntuforce_mode = level + 1;
+    } else {
+        mcpwm->operators[operator_id].gen_force.gen_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.gen_a_nciforce_mode = level + 1;
+    } else {
+        mcpwm->operators[operator_id].gen_force.gen_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.db_clk_sel = 0;
+        break;
+    case MCPWM_LL_DEADTIME_CLK_SRC_TIMER:
+        mcpwm->operators[operator_id].dt_cfg.db_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.db_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.db_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.db_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.db_deb_mode << 8) | (mcpwm->operators[operator_id].dt_cfg.db_b_outswap << 7) |
+           (mcpwm->operators[operator_id].dt_cfg.db_a_outswap << 6) | (mcpwm->operators[operator_id].dt_cfg.db_fed_insel << 5) |
+           (mcpwm->operators[operator_id].dt_cfg.db_red_insel << 4) | (mcpwm->operators[operator_id].dt_cfg.db_fed_outinvert << 3) |
+           (mcpwm->operators[operator_id].dt_cfg.db_red_outinvert << 2) | (mcpwm->operators[operator_id].dt_cfg.db_a_outbypass << 1) |
+           (mcpwm->operators[operator_id].dt_cfg.db_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, db_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, db_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.db_fed_upmethod = 0;
+    mcpwm->operators[operator_id].dt_cfg.db_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.db_fed_upmethod |= 1 << 0;
+        mcpwm->operators[operator_id].dt_cfg.db_red_upmethod |= 1 << 0;
+    } else {
+        mcpwm->operators[operator_id].dt_cfg.db_fed_upmethod &= ~(1 << 0);
+        mcpwm->operators[operator_id].dt_cfg.db_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.db_fed_upmethod |= 1 << 1;
+        mcpwm->operators[operator_id].dt_cfg.db_red_upmethod |= 1 << 1;
+    } else {
+        mcpwm->operators[operator_id].dt_cfg.db_fed_upmethod &= ~(1 << 1);
+        mcpwm->operators[operator_id].dt_cfg.db_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.db_fed_upmethod |= 1 << 2;
+        mcpwm->operators[operator_id].dt_cfg.db_red_upmethod |= 1 << 2;
+    } else {
+        mcpwm->operators[operator_id].dt_cfg.db_fed_upmethod &= ~(1 << 2);
+        mcpwm->operators[operator_id].dt_cfg.db_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.db_fed_upmethod |= 1 << 3;
+        mcpwm->operators[operator_id].dt_cfg.db_red_upmethod |= 1 << 3;
+    } else {
+        mcpwm->operators[operator_id].dt_cfg.db_fed_upmethod &= ~(1 << 3);
+        mcpwm->operators[operator_id].dt_cfg.db_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.chopper_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.chopper_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.chopper_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.chopper_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.chopper_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.chopper_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.tz_clr_ost = 0;
+    mcpwm->operators[operator_id].fh_cfg1.tz_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.tz_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.tz_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.tz_force_cbc = ~mcpwm->operators[operator_id].fh_cfg1.tz_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.tz_force_ost = ~mcpwm->operators[operator_id].fh_cfg1.tz_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.tz_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.tz_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);
+}
+
+//////////////////////////////////////////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_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 = mcpwm->timer[timer_id].timer_cfg0;
+    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);
+}
+
+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.timer_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], cmpr);
+}
+
+__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

+ 26 - 0
components/hal/esp32s3/include/hal/mcpwm_ll.h

@@ -63,6 +63,32 @@ typedef enum {
 
 ////////////////////////////////////////MCPWM Group Specific////////////////////////////////////////////////////////////
 
+/**
+ * @brief Set the clock source for MCPWM
+ *
+ * @param mcpwm Peripheral instance address
+ * @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)
+{
+    (void)mcpwm;
+    (void)clk_src;
+}
+
+/**
+ * @brief Enable MCPWM module clock
+ *
+ * @note Not support to enable/disable the peripheral clock
+ *
+ * @param mcpwm Peripheral instance address
+ * @param en true to enable, false to disable
+ */
+static inline void mcpwm_ll_group_enable_clock(mcpwm_dev_t *mcpwm, bool en)
+{
+    (void)mcpwm; // only one MCPWM instance
+    (void)en;
+}
+
 /**
  * @brief Set the MCPWM group clock prescale
  *

+ 4 - 0
components/soc/esp32/include/soc/Kconfig.soc_caps.in

@@ -431,6 +431,10 @@ config SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP
     int
     default 3
 
+config SOC_MCPWM_CLK_SUPPORT_PLL160M
+    bool
+    default y
+
 config SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED
     bool
     default n

+ 1 - 1
components/soc/esp32/include/soc/clk_tree_defs.h

@@ -228,7 +228,7 @@ typedef enum {
  */
 typedef enum {
     MCPWM_CAPTURE_CLK_SRC_APB = SOC_MOD_CLK_APB,     /*!< Select APB as the source clock */
-    MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< SElect APB as the default clock choice */
+    MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default clock choice */
 } soc_periph_mcpwm_capture_clk_src_t;
 
 ///////////////////////////////////////////////////I2S//////////////////////////////////////////////////////////////////

+ 1 - 0
components/soc/esp32/include/soc/soc_caps.h

@@ -229,6 +229,7 @@
 #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_CLK_SUPPORT_PLL160M        (1)    ///< Support PLL160M as clock source
 
 /*-------------------------- MPU CAPS ----------------------------------------*/
 //TODO: correct the caller and remove unsupported lines

+ 1 - 0
components/soc/esp32c6/CMakeLists.txt

@@ -8,6 +8,7 @@ set(srcs
     "spi_periph.c"
     "ledc_periph.c"
     "pcnt_periph.c"
+    "mcpwm_periph.c"
     "rmt_periph.c"
     "i2s_periph.c"
     "i2c_periph.c"

+ 64 - 0
components/soc/esp32c6/include/soc/Kconfig.soc_caps.in

@@ -15,6 +15,10 @@ config SOC_PCNT_SUPPORTED
     bool
     default y
 
+config SOC_MCPWM_SUPPORTED
+    bool
+    default y
+
 config SOC_BT_SUPPORTED
     bool
     default y
@@ -435,6 +439,66 @@ config SOC_RMT_SUPPORT_APB
     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_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_ETM
+    bool
+    default y
+
+config SOC_MCPWM_CAPTURE_CLK_FROM_GROUP
+    bool
+    default y
+
+config SOC_MCPWM_CLK_SUPPORT_PLL160M
+    bool
+    default y
+
+config SOC_MCPWM_CLK_SUPPORT_XTAL
+    bool
+    default y
+
 config SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH
     int
     default 128

+ 38 - 0
components/soc/esp32c6/include/soc/clk_tree_defs.h

@@ -219,6 +219,44 @@ typedef enum {
     UART_SCLK_DEFAULT = SOC_MOD_CLK_APB, /*!< UART source clock default choice is APB */
 } soc_periph_uart_clk_src_legacy_t;
 
+//////////////////////////////////////////////////MCPWM/////////////////////////////////////////////////////////////////
+
+/**
+ * @brief Array initializer for all supported clock sources of MCPWM Timer
+ */
+#define SOC_MCPWM_TIMER_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL}
+
+/**
+ * @brief Type of MCPWM timer clock source
+ */
+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 CONFIG_IDF_ENV_FPGA
+    MCPWM_TIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL,      /*!< Select XTAL as the default clock choice */
+#else
+    MCPWM_TIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */
+#endif
+} soc_periph_mcpwm_timer_clk_src_t;
+
+/**
+ * @brief Array initializer for all supported clock sources of MCPWM Capture Timer
+ */
+#define SOC_MCPWM_CAPTURE_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL}
+
+/**
+ * @brief Type of MCPWM capture clock source
+ */
+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 CONFIG_IDF_ENV_FPGA
+    MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL,      /*!< Select XTAL as the default clock choice */
+#else
+    MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */
+#endif
+} soc_periph_mcpwm_capture_clk_src_t;
+
 ///////////////////////////////////////////////////// I2S //////////////////////////////////////////////////////////////
 
 /**

+ 1 - 1
components/soc/esp32c6/include/soc/mcpwm_struct.h

@@ -1683,7 +1683,7 @@ typedef struct mcpwm_dev_t {
     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) == 0x130, "Invalid size of mcpwm_dev_t structure");

+ 2 - 1
components/soc/esp32c6/include/soc/periph_defs.h

@@ -38,6 +38,7 @@ typedef enum {
     PERIPH_HMAC_MODULE,
     PERIPH_DS_MODULE,
     PERIPH_GDMA_MODULE,
+    PERIPH_MCPWM0_MODULE,
     PERIPH_SYSTIMER_MODULE,
     PERIPH_SARADC_MODULE,
     PERIPH_MODULE_MAX
@@ -105,7 +106,7 @@ typedef enum {
     ETS_SYSTIMER_TARGET1_EDGE_INTR_SOURCE,      /**< interrupt of system timer 1, EDGE*/
     ETS_SYSTIMER_TARGET2_EDGE_INTR_SOURCE,      /**< interrupt of system timer 2, EDGE*/
     ETS_APB_ADC_INTR_SOURCE,                    /**< interrupt of APB ADC, LEVEL*/
-    ETS_PWM_INTR_SOURCE,
+    ETS_MCPWM0_INTR_SOURCE,                     /**< interrupt of MCPWM0, LEVEL*/
     ETS_PCNT_INTR_SOURCE,
     ETS_PARL_IO_INTR_SOURCE,
     ETS_SLC0_INTR_SOURCE,

+ 18 - 0
components/soc/esp32c6/include/soc/soc_caps.h

@@ -29,6 +29,7 @@
 #define SOC_DEDICATED_GPIO_SUPPORTED    1
 #define SOC_GDMA_SUPPORTED              1
 #define SOC_PCNT_SUPPORTED              1
+#define SOC_MCPWM_SUPPORTED             1
 // #define SOC_TWAI_SUPPORTED              1 // TODO: IDF-5313
 #define SOC_BT_SUPPORTED                1
 #define SOC_ASYNC_MEMCPY_SUPPORTED      1
@@ -235,6 +236,23 @@
 #define SOC_RMT_SUPPORT_XTAL                  1  /*!< Support set XTAL clock as the RMT clock source */
 #define SOC_RMT_SUPPORT_APB                   1  /*!< Support set APB 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_CLK_SUPPORT_PLL160M        (1)    ///< Support PLL160M as clock source
+#define SOC_MCPWM_CLK_SUPPORT_XTAL           (1)    ///< Support XTAL as clock source
+
 // TODO: IDF-5348 (Copy from esp32c3, need check)
 /*-------------------------- RTC CAPS --------------------------------------*/
 #define SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH       (128)

+ 1 - 1
components/soc/esp32c6/ld/esp32c6.peripherals.ld

@@ -27,7 +27,7 @@ PROVIDE ( INTMTX        = 0x60010000 );
 PROVIDE ( ATOMIC_LOCKER = 0x60011000 );
 PROVIDE ( PCNT          = 0x60012000 );
 PROVIDE ( SOC_ETM       = 0x60013000 );
-PROVIDE ( MCPWM         = 0x60014000 );
+PROVIDE ( MCPWM0        = 0x60014000 );
 PROVIDE ( PARL_IO       = 0x60015000 );
 PROVIDE ( HINF          = 0x60016000 );
 PROVIDE ( SLC           = 0x60017000 );

+ 83 - 0
components/soc/esp32c6/mcpwm_periph.c

@@ -0,0 +1,83 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "soc/soc.h"
+#include "soc/mcpwm_periph.h"
+#include "soc/gpio_sig_map.h"
+
+const mcpwm_signal_conn_t mcpwm_periph_signals = {
+    .groups = {
+        [0] = {
+            .module = PERIPH_MCPWM0_MODULE,
+            .irq_id = ETS_MCPWM0_INTR_SOURCE,
+            .operators = {
+                [0] = {
+                    .generators = {
+                        [0] = {
+                            .pwm_sig = PWM0_OUT0A_IDX
+                        },
+                        [1] = {
+                            .pwm_sig = PWM0_OUT0B_IDX
+                        }
+                    }
+                },
+                [1] = {
+                    .generators = {
+                        [0] = {
+                            .pwm_sig = PWM0_OUT1A_IDX
+                        },
+                        [1] = {
+                            .pwm_sig = PWM0_OUT1B_IDX
+                        }
+                    }
+                },
+                [2] = {
+                    .generators = {
+                        [0] = {
+                            .pwm_sig = PWM0_OUT2A_IDX
+                        },
+                        [1] = {
+                            .pwm_sig = PWM0_OUT2B_IDX
+                        }
+                    }
+                }
+            },
+            .gpio_faults = {
+                [0] = {
+                    .fault_sig = PWM0_F0_IN_IDX
+                },
+                [1] = {
+                    .fault_sig = PWM0_F1_IN_IDX
+                },
+                [2] = {
+                    .fault_sig = PWM0_F2_IN_IDX
+                }
+            },
+            .captures = {
+                [0] = {
+                    .cap_sig = PWM0_CAP0_IN_IDX
+                },
+                [1] = {
+                    .cap_sig = PWM0_CAP1_IN_IDX
+                },
+                [2] = {
+                    .cap_sig = PWM0_CAP2_IN_IDX
+                }
+            },
+            .gpio_synchros = {
+                [0] = {
+                    .sync_sig = PWM0_SYNC0_IN_IDX
+                },
+                [1] = {
+                    .sync_sig = PWM0_SYNC1_IN_IDX
+                },
+                [2] = {
+                    .sync_sig = PWM0_SYNC2_IN_IDX
+                }
+            }
+        },
+    }
+};

+ 4 - 0
components/soc/esp32s3/include/soc/Kconfig.soc_caps.in

@@ -507,6 +507,10 @@ config SOC_MCPWM_SWSYNC_CAN_PROPAGATE
     bool
     default y
 
+config SOC_MCPWM_CLK_SUPPORT_PLL160M
+    bool
+    default y
+
 config SOC_PCNT_GROUPS
     int
     default 1

+ 1 - 1
components/soc/esp32s3/include/soc/clk_tree_defs.h

@@ -244,7 +244,7 @@ typedef enum {
  */
 typedef enum {
     MCPWM_CAPTURE_CLK_SRC_APB = SOC_MOD_CLK_APB,     /*!< Select APB as the source clock */
-    MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< SElect APB as the default clock choice */
+    MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default clock choice */
 } soc_periph_mcpwm_capture_clk_src_t;
 
 ///////////////////////////////////////////////////// I2S //////////////////////////////////////////////////////////////

+ 1 - 0
components/soc/esp32s3/include/soc/soc_caps.h

@@ -207,6 +207,7 @@
 #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_CLK_SUPPORT_PLL160M        (1)    ///< Support PLL160M as clock source
 
 /*-------------------------- MPU CAPS ----------------------------------------*/
 #include "mpu_caps.h"