diff --git a/components/driver/deprecated/driver/mcpwm.h b/components/driver/deprecated/driver/mcpwm.h index b39532295e..7724c62dd1 100644 --- a/components/driver/deprecated/driver/mcpwm.h +++ b/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,21 +465,29 @@ 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 - * Capture signal edge: 1 - positive edge, 2 - negtive edge + * Capture signal edge: 1 - positive edge, 2 - negative edge, 0 - Invalid */ uint32_t mcpwm_capture_signal_get_edge(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_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) * diff --git a/components/driver/deprecated/mcpwm_legacy.c b/components/driver/deprecated/mcpwm_legacy.c index 2e2bb402a9..c39e049a02 100644 --- a/components/driver/deprecated/mcpwm_legacy.c +++ b/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); @@ -427,7 +430,10 @@ esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpw uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num) { - MCPWM_TIMER_CHECK(mcpwm_num, timer_num); + if (mcpwm_num >= MCPWM_UNIT_MAX || timer_num >= MCPWM_TIMER_MAX) { + ESP_LOGE(TAG, "Invalid MCPWM timer instance"); + return 0; + } mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; mcpwm_critical_enter(mcpwm_num); int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev); @@ -441,9 +447,12 @@ uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num) float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen) { + if (mcpwm_num >= MCPWM_UNIT_MAX || timer_num >= MCPWM_TIMER_MAX || gen >= MCPWM_GEN_MAX) { + ESP_LOGE(TAG, "Invalid MCPWM generator instance"); + return 0; + } //the driver currently always use the timer x for operator x const int op = timer_num; - MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen); mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; mcpwm_critical_enter(mcpwm_num); float duty = 100.0 * mcpwm_ll_operator_get_compare_value(hal->dev, op, gen) / mcpwm_ll_timer_get_peak(hal->dev, timer_num, false); @@ -453,9 +462,12 @@ float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_gene uint32_t mcpwm_get_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t gen) { + if (mcpwm_num >= MCPWM_UNIT_MAX || timer_num >= MCPWM_TIMER_MAX || gen >= MCPWM_GEN_MAX) { + ESP_LOGE(TAG, "Invalid MCPWM generator instance"); + return 0; + } //the driver currently always use the timer x for operator x const int op = timer_num; - MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen); mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; mcpwm_critical_enter(mcpwm_num); int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev); @@ -786,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); @@ -851,16 +865,31 @@ esp_err_t mcpwm_capture_disable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_ch uint32_t MCPWM_ISR_ATTR mcpwm_capture_signal_get_value(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig) { - ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR); - ESP_RETURN_ON_FALSE(cap_sig < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER, ESP_ERR_INVALID_ARG, TAG, MCPWM_CAPTURE_ERROR); + if (mcpwm_num >= MCPWM_UNIT_MAX && cap_sig >= SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER) { + return 0; + } mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; 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) { - ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR); - ESP_RETURN_ON_FALSE(cap_sig < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER, ESP_ERR_INVALID_ARG, TAG, MCPWM_CAPTURE_ERROR); + if (mcpwm_num >= MCPWM_UNIT_MAX && cap_sig >= SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER) { + return 0; + } mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; return mcpwm_ll_capture_get_edge(hal->dev, cap_sig) == MCPWM_CAP_EDGE_NEG ? 2 : 1; } diff --git a/components/driver/include/driver/mcpwm_cap.h b/components/driver/include/driver/mcpwm_cap.h index d40ef2fd1a..f1bb030720 100644 --- a/components/driver/include/driver/mcpwm_cap.h +++ b/components/driver/include/driver/mcpwm_cap.h @@ -94,6 +94,18 @@ esp_err_t mcpwm_capture_timer_start(mcpwm_cap_timer_handle_t cap_timer); */ esp_err_t mcpwm_capture_timer_stop(mcpwm_cap_timer_handle_t cap_timer); +/** + * @brief Get MCPWM capture timer resolution, in Hz + * + * @param[in] cap_timer MCPWM capture timer, allocated by `mcpwm_new_capture_timer()` + * @param[out] out_resolution Returned capture timer resolution, in Hz + * @return + * - ESP_OK: Get capture timer resolution successfully + * - ESP_ERR_INVALID_ARG: Get capture timer resolution failed because of invalid argument + * - ESP_FAIL: Get capture timer resolution failed because of other error + */ +esp_err_t mcpwm_capture_timer_get_resolution(mcpwm_cap_timer_handle_t cap_timer, uint32_t *out_resolution); + /** * @brief MCPWM Capture timer sync phase configuration */ diff --git a/components/driver/mcpwm/mcpwm_cap.c b/components/driver/mcpwm/mcpwm_cap.c index ef6e3b2c2a..32a3fb1da1 100644 --- a/components/driver/mcpwm/mcpwm_cap.c +++ b/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; @@ -185,6 +192,13 @@ esp_err_t mcpwm_capture_timer_stop(mcpwm_cap_timer_handle_t cap_timer) return ESP_OK; } +esp_err_t mcpwm_capture_timer_get_resolution(mcpwm_cap_timer_handle_t cap_timer, uint32_t *out_resolution) +{ + ESP_RETURN_ON_FALSE(cap_timer && out_resolution, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + *out_resolution = cap_timer->resolution_hz; + return ESP_OK; +} + static esp_err_t mcpwm_capture_channel_register_to_timer(mcpwm_cap_channel_t *cap_channel, mcpwm_cap_timer_t *cap_timer) { int cap_chan_id = -1; diff --git a/components/driver/mcpwm/mcpwm_com.c b/components/driver/mcpwm/mcpwm_com.c index fb9975d650..bec5514a79 100644 --- a/components/driver/mcpwm/mcpwm_com.c +++ b/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); diff --git a/components/driver/mcpwm/mcpwm_private.h b/components/driver/mcpwm/mcpwm_private.h index 912b0a9c92..826f0b4976 100644 --- a/components/driver/mcpwm/mcpwm_private.h +++ b/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 } diff --git a/components/driver/mcpwm/mcpwm_timer.c b/components/driver/mcpwm/mcpwm_timer.c index 6d516a9256..084b75ca62 100644 --- a/components/driver/mcpwm/mcpwm_timer.c +++ b/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 diff --git a/components/driver/test_apps/legacy_mcpwm_driver/main/test_legacy_mcpwm.c b/components/driver/test_apps/legacy_mcpwm_driver/main/test_legacy_mcpwm.c index 72a41a7bc8..b2bc2e2e9c 100644 --- a/components/driver/test_apps/legacy_mcpwm_driver/main/test_legacy_mcpwm.c +++ b/components/driver/test_apps/legacy_mcpwm_driver/main/test_legacy_mcpwm.c @@ -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)); } diff --git a/components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c b/components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c index 911f2e8dcc..7da9603480 100644 --- a/components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c +++ b/components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c @@ -74,7 +74,7 @@ TEST_CASE("mcpwm_capture_ext_gpio", "[mcpwm]") printf("install mcpwm capture timer\r\n"); mcpwm_cap_timer_handle_t cap_timer = NULL; mcpwm_capture_timer_config_t cap_timer_config = { - .clk_src = MCPWM_CAPTURE_CLK_SRC_APB, + .clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT, .group_id = 0, }; TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timer)); @@ -115,8 +115,8 @@ TEST_CASE("mcpwm_capture_ext_gpio", "[mcpwm]") gpio_set_level(cap_gpio, 0); vTaskDelay(pdMS_TO_TICKS(100)); printf("capture value: Pos=%"PRIu32", Neg=%"PRIu32"\r\n", cap_value[0], cap_value[1]); - // Capture timer is clocked from APB by default - uint32_t clk_src_res = esp_clk_apb_freq(); + uint32_t clk_src_res; + mcpwm_capture_timer_get_resolution(cap_timer, &clk_src_res); TEST_ASSERT_UINT_WITHIN(100000, clk_src_res / 10, cap_value[1] - cap_value[0]); printf("uninstall capture channel and timer\r\n"); @@ -183,8 +183,8 @@ TEST_CASE("mcpwm_capture_software_catch", "[mcpwm]") TEST_ASSERT_EQUAL(2, test_callback_data.cap_data_index); uint32_t delta = test_callback_data.cap_data[1] - test_callback_data.cap_data[0]; esp_rom_printf("duration=%u ticks\r\n", delta); - // Capture timer is clocked from APB by default - uint32_t clk_src_res = esp_clk_apb_freq(); + uint32_t clk_src_res; + mcpwm_capture_timer_get_resolution(cap_timer, &clk_src_res); TEST_ASSERT_UINT_WITHIN(80000, clk_src_res / 100, delta); printf("uninstall capture channel and timer\r\n"); diff --git a/components/driver/test_apps/mcpwm/main/test_mcpwm_oper.c b/components/driver/test_apps/mcpwm/main/test_mcpwm_oper.c index 455cf910bd..bbd6e25aa3 100644 --- a/components/driver/test_apps/mcpwm/main/test_mcpwm_oper.c +++ b/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])); diff --git a/components/hal/esp32/include/hal/mcpwm_ll.h b/components/hal/esp32/include/hal/mcpwm_ll.h index 4eba4eb6df..5192d7291d 100644 --- a/components/hal/esp32/include/hal/mcpwm_ll.h +++ b/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 * diff --git a/components/hal/esp32c6/include/hal/clk_gate_ll.h b/components/hal/esp32c6/include/hal/clk_gate_ll.h index 50fb6b6795..92df457681 100644 --- a/components/hal/esp32c6/include/hal/clk_gate_ll.h +++ b/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: diff --git a/components/hal/esp32c6/include/hal/mcpwm_ll.h b/components/hal/esp32c6/include/hal/mcpwm_ll.h new file mode 100644 index 0000000000..3a94ff3cfb --- /dev/null +++ b/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 +#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 diff --git a/components/hal/esp32s3/include/hal/mcpwm_ll.h b/components/hal/esp32s3/include/hal/mcpwm_ll.h index 10e2cc1f63..0111b62261 100644 --- a/components/hal/esp32s3/include/hal/mcpwm_ll.h +++ b/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 * diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index d17400cf5e..f60df47bda 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/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 diff --git a/components/soc/esp32/include/soc/clk_tree_defs.h b/components/soc/esp32/include/soc/clk_tree_defs.h index 9e2541bd6e..50bb125926 100644 --- a/components/soc/esp32/include/soc/clk_tree_defs.h +++ b/components/soc/esp32/include/soc/clk_tree_defs.h @@ -108,6 +108,7 @@ typedef enum { // For digital domain: peripherals, WIFI, BLE SOC_MOD_CLK_APB, /*!< APB_CLK is highly dependent on the CPU_CLK source */ SOC_MOD_CLK_PLL_D2, /*!< PLL_D2_CLK is derived from PLL, it has a fixed divider of 2 */ + SOC_MOD_CLK_PLL_F160M, /*!< PLL_F160M_CLK is derived from PLL, and has a fixed frequency of 160MHz */ SOC_MOD_CLK_XTAL32K, /*!< XTAL32K_CLK comes from the external 32kHz crystal, passing a clock gating to the peripherals */ SOC_MOD_CLK_RC_FAST, /*!< RC_FAST_CLK comes from the internal 8MHz rc oscillator, passing a clock gating to the peripherals */ SOC_MOD_CLK_RC_FAST_D256, /*!< RC_FAST_D256_CLK comes from the internal 8MHz rc oscillator, divided by 256, and passing a clock gating to the peripherals */ @@ -207,14 +208,14 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of MCPWM Timer */ -#define SOC_MCPWM_TIMER_CLKS {SOC_MOD_CLK_PLL_D2} +#define SOC_MCPWM_TIMER_CLKS {SOC_MOD_CLK_PLL_F160M} /** * @brief Type of MCPWM timer clock source */ typedef enum { - MCPWM_TIMER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_D2, /*!< Select PLL_D2 (160MHz) as the source clock */ - MCPWM_TIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_D2, /*!< Select PLL_D2 as the default clock choice */ + MCPWM_TIMER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ + MCPWM_TIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */ } soc_periph_mcpwm_timer_clk_src_t; /** @@ -227,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////////////////////////////////////////////////////////////////// diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index d783231fdd..7571eecc21 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/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 diff --git a/components/soc/esp32c6/CMakeLists.txt b/components/soc/esp32c6/CMakeLists.txt index 762518d93f..0eb7ac39a9 100644 --- a/components/soc/esp32c6/CMakeLists.txt +++ b/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" diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 2f41d6692e..1493ebdc05 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/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 diff --git a/components/soc/esp32c6/include/soc/clk_tree_defs.h b/components/soc/esp32c6/include/soc/clk_tree_defs.h index 1343a8cddd..7a983ecf8c 100644 --- a/components/soc/esp32c6/include/soc/clk_tree_defs.h +++ b/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 ////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32c6/include/soc/mcpwm_struct.h b/components/soc/esp32c6/include/soc/mcpwm_struct.h index 2d98b4e26e..1a91a623f6 100644 --- a/components/soc/esp32c6/include/soc/mcpwm_struct.h +++ b/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"); diff --git a/components/soc/esp32c6/include/soc/periph_defs.h b/components/soc/esp32c6/include/soc/periph_defs.h index 2360268684..c839f304b3 100644 --- a/components/soc/esp32c6/include/soc/periph_defs.h +++ b/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, diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index d32ecce6df..d87ad897c0 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/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) diff --git a/components/soc/esp32c6/ld/esp32c6.peripherals.ld b/components/soc/esp32c6/ld/esp32c6.peripherals.ld index 55f47792d2..49596bfb5b 100644 --- a/components/soc/esp32c6/ld/esp32c6.peripherals.ld +++ b/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 ); diff --git a/components/soc/esp32c6/mcpwm_periph.c b/components/soc/esp32c6/mcpwm_periph.c new file mode 100644 index 0000000000..25e1b86cc1 --- /dev/null +++ b/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 + } + } + }, + } +}; diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index a75fb3d1c9..9aabb07562 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/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 diff --git a/components/soc/esp32s3/include/soc/clk_tree_defs.h b/components/soc/esp32s3/include/soc/clk_tree_defs.h index 7b96225a53..ee74280f90 100644 --- a/components/soc/esp32s3/include/soc/clk_tree_defs.h +++ b/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 ////////////////////////////////////////////////////////////// diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 1341c78a57..8e7997bab9 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/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" diff --git a/docs/docs_not_updated/esp32c6.txt b/docs/docs_not_updated/esp32c6.txt index 3942c37633..fc21b2bcc8 100644 --- a/docs/docs_not_updated/esp32c6.txt +++ b/docs/docs_not_updated/esp32c6.txt @@ -127,7 +127,6 @@ api-reference/peripherals/gptimer api-reference/peripherals/pcnt api-reference/peripherals/touch_element api-reference/peripherals/lcd -api-reference/peripherals/mcpwm api-reference/peripherals/secure_element api-reference/peripherals/ledc api-reference/peripherals/temp_sensor diff --git a/docs/en/api-reference/peripherals/mcpwm.rst b/docs/en/api-reference/peripherals/mcpwm.rst index 017d934ac1..30b24bb9c7 100644 --- a/docs/en/api-reference/peripherals/mcpwm.rst +++ b/docs/en/api-reference/peripherals/mcpwm.rst @@ -806,7 +806,7 @@ The MCPWM capture channel can inform the user when there's a valid edge detected - :cpp:member:`mcpwm_capture_event_callbacks_t::on_cap` sets callback function for the capture channel when a valid edge is detected. -The callback function will provide event specific data of type :cpp:type:`mcpwm_capture_event_data_t`, so that you can get the edge of the capture signal in :cpp:member:`mcpwm_capture_event_data_t::cap_edge` and the count value of that moment in :cpp:member:`mcpwm_capture_event_data_t::cap_value`. +The callback function will provide event specific data of type :cpp:type:`mcpwm_capture_event_data_t`, so that you can get the edge of the capture signal in :cpp:member:`mcpwm_capture_event_data_t::cap_edge` and the count value of that moment in :cpp:member:`mcpwm_capture_event_data_t::cap_value`. To convert the capture count into timestamp, you need to know the resolution of the capture timer by calling :cpp:func:`mcpwm_capture_timer_get_resolution`. The callback function is called within the ISR context, so is should **not** attempt to block (e.g., make sure that only FreeRTOS APIs with ``ISR`` suffix is called within the function).