diff --git a/components/driver/deprecated/driver/mcpwm.h b/components/driver/deprecated/driver/mcpwm.h index 7724c62dd1..346a0de73f 100644 --- a/components/driver/deprecated/driver/mcpwm.h +++ b/components/driver/deprecated/driver/mcpwm.h @@ -51,10 +51,10 @@ esp_err_t mcpwm_set_pin(mcpwm_unit_t mcpwm_num, const mcpwm_pin_config_t *mcpwm_ /** * @brief Initialize MCPWM parameters - * @note - * The default resolution configured for MCPWM group and timer are 160M / 16 = 10M and 10M / 10 = 1M - * The default resolution can be changed by calling mcpwm_group_set_resolution() and mcpwm_timer_set_resolution(), - * before calling this function. + * @note The default resolution configured for MCPWM timer is 1M, it can be changed by `mcpwm_timer_set_resolution`. + * @note The default resolution configured for MCPWM group can be different on different esp targets (because of different clock source). + * You can change the group resolution by mcpwm_group_set_resolution() + * @note If you want to change the preset resolution of MCPWM group and timer, please call them before this function. * * @param mcpwm_num set MCPWM unit * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers. @@ -68,11 +68,9 @@ esp_err_t mcpwm_init( mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcp /** * @brief Set resolution of the MCPWM group - * @note - * This will override default resolution of group(=10,000,000). - * This WILL NOT automatically update frequency and duty. Call mcpwm_set_frequency() and mcpwm_set_duty() manually - * to set them back. - * The group resolution must be an integral multiple of timer resolution. + * @note This will override default resolution of MCPWM group. + * @note This WILL NOT automatically update PWM frequency and duty. Please call `mcpwm_set_frequency` and `mcpwm_set_duty` manually to reflect the change. + * @note The group resolution must be an integral multiple of timer resolution. * * @param mcpwm_num set MCPWM unit * @param resolution set expected frequency resolution @@ -85,11 +83,9 @@ esp_err_t mcpwm_group_set_resolution(mcpwm_unit_t mcpwm_num, unsigned long int r /** * @brief Set resolution of each timer - * @note - * This WILL override default resolution of timer(=1,000,000). - * This WILL NOT automatically update frequency and duty. Call mcpwm_set_frequency() and mcpwm_set_duty() manually - * to set them back. - * The group resolution must be an integral multiple of timer resolution. + * @note This will override default resolution of timer(=1,000,000). + * @note This WILL NOT automatically update PWM frequency and duty. Please call `mcpwm_set_frequency` and `mcpwm_set_duty` manually to reflect the change. + * @note The group resolution must be an integral multiple of timer resolution. * * @param mcpwm_num set MCPWM unit * @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers diff --git a/components/driver/deprecated/mcpwm_legacy.c b/components/driver/deprecated/mcpwm_legacy.c index c56806f13c..9562b42f5e 100644 --- a/components/driver/deprecated/mcpwm_legacy.c +++ b/components/driver/deprecated/mcpwm_legacy.c @@ -1,20 +1,17 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include #include "sdkconfig.h" #include "freertos/FreeRTOS.h" -#include "freertos/semphr.h" #include "freertos/task.h" #include "esp_log.h" #include "esp_err.h" #include "esp_check.h" #include "esp_rom_gpio.h" #include "esp_intr_alloc.h" -#include "soc/gpio_periph.h" #include "soc/mcpwm_periph.h" #include "hal/mcpwm_hal.h" #include "hal/gpio_hal.h" @@ -22,6 +19,7 @@ #include "driver/mcpwm_types_legacy.h" #include "driver/gpio.h" #include "esp_private/periph_ctrl.h" +#include "clk_tree.h" #include "esp_private/esp_clk.h" static const char *TAG = "mcpwm(legacy)"; @@ -48,14 +46,20 @@ _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 // 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) +// Note: we can't modify the default MCPWM group resolution once it's determined +// otherwise we may break user's existing code which configures the dead-time based on this resolution, see `mcpwm_deadtime_enable` +#if CONFIG_IDF_TARGET_ESP32H2 +#define MCPWM_DEFAULT_GROUP_CLK_RESOLUTION_HZ (12 * 1000 * 1000) +#else +#define MCPWM_DEFAULT_GROUP_CLK_RESOLUTION_HZ (10 * 1000 * 1000) +#endif -_Static_assert(SOC_MCPWM_OPERATORS_PER_GROUP >= SOC_MCPWM_TIMERS_PER_GROUP, "This driver assumes the timer num equals to the operator num."); -_Static_assert(SOC_MCPWM_COMPARATORS_PER_OPERATOR >= SOC_MCPWM_GENERATORS_PER_OPERATOR, "This driver assumes the generator num equals to the generator num."); -_Static_assert(SOC_MCPWM_GENERATORS_PER_OPERATOR == 2, "This driver assumes the generator num equals to 2."); +// Preset MCPWM Timer clock resolution (1MHz) +#define MCPWM_DEFAULT_TIMER_CLK_RESOLUTION_HZ (1 * 1000 * 1000) + +ESP_STATIC_ASSERT(SOC_MCPWM_OPERATORS_PER_GROUP >= SOC_MCPWM_TIMERS_PER_GROUP, "This driver assumes the timer num equals to the operator num."); +ESP_STATIC_ASSERT(SOC_MCPWM_COMPARATORS_PER_OPERATOR >= SOC_MCPWM_GENERATORS_PER_OPERATOR, "This driver assumes the generator num equals to the generator num."); +ESP_STATIC_ASSERT(SOC_MCPWM_GENERATORS_PER_OPERATOR == 2, "This driver assumes the generator num equals to 2."); #define MCPWM_TIMER_ID_CHECK(mcpwm_num, timer_num) \ do { \ @@ -85,8 +89,8 @@ typedef struct { portMUX_TYPE spinlock; _lock_t mutex_lock; const int group_id; - int group_pre_scale; // starts from 1, not 0. will be subtracted by 1 in ll driver - int timer_pre_scale[SOC_MCPWM_TIMERS_PER_GROUP]; // same as above + int group_resolution_hz; + int timer_resolution_hz[SOC_MCPWM_TIMERS_PER_GROUP]; intr_handle_t mcpwm_intr_handle; // handler for ISR register, one per MCPWM group cap_isr_func_t cap_isr_func[SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER]; // handler for ISR callback, one for each cap ch } mcpwm_context_t; @@ -96,27 +100,13 @@ static mcpwm_context_t context[SOC_MCPWM_GROUPS] = { .hal = {MCPWM_LL_GET_HW(0)}, .spinlock = portMUX_INITIALIZER_UNLOCKED, .group_id = 0, - .group_pre_scale = MCPWM_GROUP_CLK_SRC_HZ / MCPWM_GROUP_CLK_HZ, - .timer_pre_scale = { - [0 ... SOC_MCPWM_TIMERS_PER_GROUP - 1] = - MCPWM_GROUP_CLK_HZ / MCPWM_TIMER_CLK_HZ - }, - .mcpwm_intr_handle = NULL, - .cap_isr_func = {[0 ... SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER - 1] = {NULL, NULL}}, }, #if SOC_MCPWM_GROUPS > 1 [1] = { .hal = {MCPWM_LL_GET_HW(1)}, .spinlock = portMUX_INITIALIZER_UNLOCKED, .group_id = 1, - .group_pre_scale = MCPWM_GROUP_CLK_SRC_HZ / MCPWM_GROUP_CLK_HZ, - .timer_pre_scale = { - [0 ... SOC_MCPWM_TIMERS_PER_GROUP - 1] = - MCPWM_GROUP_CLK_HZ / MCPWM_TIMER_CLK_HZ - }, - .mcpwm_intr_handle = NULL, - .cap_isr_func = {[0 ... SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER - 1] = {NULL, NULL}}, - } + }, #endif }; @@ -215,28 +205,51 @@ esp_err_t mcpwm_stop(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num) return ESP_OK; } -esp_err_t mcpwm_group_set_resolution(mcpwm_unit_t mcpwm_num, unsigned long int resolution) +static inline uint32_t mcpwm_group_get_resolution(mcpwm_unit_t mcpwm_num) +{ + if (context[mcpwm_num].group_resolution_hz == 0) { + context[mcpwm_num].group_resolution_hz = MCPWM_DEFAULT_GROUP_CLK_RESOLUTION_HZ; + } + return context[mcpwm_num].group_resolution_hz; +} + +static inline uint32_t mcpwm_timer_get_resolution(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num) +{ + if (context[mcpwm_num].timer_resolution_hz[timer_num] == 0) { + context[mcpwm_num].timer_resolution_hz[timer_num] = MCPWM_DEFAULT_TIMER_CLK_RESOLUTION_HZ; + } + return context[mcpwm_num].timer_resolution_hz[timer_num]; +} + +esp_err_t mcpwm_group_set_resolution(mcpwm_unit_t mcpwm_num, uint32_t resolution) { mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; - int pre_scale_temp = MCPWM_GROUP_CLK_SRC_HZ / resolution; + uint32_t clk_src_hz = 0; + clk_tree_src_get_freq_hz(MCPWM_TIMER_CLK_SRC_DEFAULT, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_hz); + + int pre_scale_temp = clk_src_hz / resolution; ESP_RETURN_ON_FALSE(pre_scale_temp >= 1, ESP_ERR_INVALID_ARG, TAG, "invalid resolution"); - context[mcpwm_num].group_pre_scale = pre_scale_temp; + context[mcpwm_num].group_resolution_hz = clk_src_hz / pre_scale_temp; + mcpwm_critical_enter(mcpwm_num); - mcpwm_ll_group_set_clock_prescale(hal->dev, context[mcpwm_num].group_pre_scale); + mcpwm_ll_group_set_clock_prescale(hal->dev, pre_scale_temp); mcpwm_critical_exit(mcpwm_num); return ESP_OK; } -esp_err_t mcpwm_timer_set_resolution(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, unsigned long int resolution) +esp_err_t mcpwm_timer_set_resolution(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, uint32_t resolution) { MCPWM_TIMER_CHECK(mcpwm_num, timer_num); mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; - int pre_scale_temp = MCPWM_GROUP_CLK_SRC_HZ / context[mcpwm_num].group_pre_scale / resolution; + uint32_t group_resolution = mcpwm_group_get_resolution(mcpwm_num); + + int pre_scale_temp = group_resolution / resolution; ESP_RETURN_ON_FALSE(pre_scale_temp >= 1, ESP_ERR_INVALID_ARG, TAG, "invalid resolution"); - context[mcpwm_num].timer_pre_scale[timer_num] = pre_scale_temp; + context[mcpwm_num].timer_resolution_hz[timer_num] = context[mcpwm_num].group_resolution_hz / pre_scale_temp; + mcpwm_critical_enter(mcpwm_num); - mcpwm_ll_timer_set_clock_prescale(hal->dev, timer_num, context[mcpwm_num].timer_pre_scale[timer_num]); + mcpwm_ll_timer_set_clock_prescale(hal->dev, timer_num, pre_scale_temp); mcpwm_critical_exit(mcpwm_num); return ESP_OK; } @@ -252,10 +265,8 @@ esp_err_t mcpwm_set_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, u mcpwm_ll_timer_update_period_at_once(hal->dev, timer_num); uint32_t previous_peak = mcpwm_ll_timer_get_peak(hal->dev, timer_num, false); - int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev); - unsigned long int real_timer_clk_hz = - MCPWM_GROUP_CLK_SRC_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num); - uint32_t new_peak = real_timer_clk_hz / frequency; + uint32_t timer_resolution = mcpwm_timer_get_resolution(mcpwm_num, timer_num); + uint32_t new_peak = timer_resolution / frequency; mcpwm_ll_timer_set_peak(hal->dev, timer_num, new_peak, false); // keep the duty cycle unchanged float scale = ((float)new_peak) / previous_peak; @@ -300,11 +311,9 @@ esp_err_t mcpwm_set_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, 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); // to avid multiplication overflow, use uint64_t here - uint64_t real_timer_clk_hz = - MCPWM_GROUP_CLK_SRC_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num); - uint64_t compare_val = real_timer_clk_hz * duty_in_us / 1000000; + uint64_t timer_resolution = mcpwm_timer_get_resolution(mcpwm_num, timer_num); + uint64_t compare_val = timer_resolution * duty_in_us / 1000000; mcpwm_ll_operator_set_compare_value(hal->dev, op, cmp, (uint32_t)compare_val); mcpwm_ll_operator_enable_update_compare_on_tez(hal->dev, op, cmp, true); mcpwm_ll_operator_enable_update_compare_on_tep(hal->dev, op, cmp, true); @@ -405,17 +414,21 @@ esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpw }; mcpwm_hal_init(hal, &config); + uint32_t clk_src_hz = 0; + clk_tree_src_get_freq_hz(MCPWM_TIMER_CLK_SRC_DEFAULT, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_hz); + uint32_t group_resolution = mcpwm_group_get_resolution(mcpwm_num); + uint32_t timer_resolution = mcpwm_timer_get_resolution(mcpwm_num, timer_num); + uint32_t group_pre_scale = clk_src_hz / group_resolution; + uint32_t timer_pre_scale = group_resolution / timer_resolution; + 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_group_set_clock_prescale(hal->dev, group_pre_scale); + mcpwm_ll_timer_set_clock_prescale(hal->dev, timer_num, timer_pre_scale); mcpwm_ll_timer_set_count_mode(hal->dev, timer_num, mcpwm_conf->counter_mode); mcpwm_ll_timer_update_period_at_once(hal->dev, timer_num); - int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev); - unsigned long int real_timer_clk_hz = - MCPWM_GROUP_CLK_SRC_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num); - mcpwm_ll_timer_set_peak(hal->dev, timer_num, real_timer_clk_hz / mcpwm_conf->frequency, false); + mcpwm_ll_timer_set_peak(hal->dev, timer_num, timer_resolution / mcpwm_conf->frequency, false); mcpwm_ll_operator_connect_timer(hal->dev, timer_num, timer_num); //the driver currently always use the timer x for operator x mcpwm_critical_exit(mcpwm_num); @@ -434,13 +447,13 @@ uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num) ESP_LOGE(TAG, "Invalid MCPWM timer instance"); return 0; } + + uint32_t timer_resolution = mcpwm_timer_get_resolution(mcpwm_num, timer_num); + 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); - unsigned long int real_timer_clk_hz = - MCPWM_GROUP_CLK_SRC_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num); uint32_t peak = mcpwm_ll_timer_get_peak(hal->dev, timer_num, false); - uint32_t freq = real_timer_clk_hz / peak; + uint32_t freq = timer_resolution / peak; mcpwm_critical_exit(mcpwm_num); return freq; } @@ -466,14 +479,14 @@ uint32_t mcpwm_get_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, m ESP_LOGE(TAG, "Invalid MCPWM generator instance"); return 0; } + + uint32_t timer_resolution = mcpwm_timer_get_resolution(mcpwm_num, timer_num); + //the driver currently always use the timer x for operator x const int op = timer_num; 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); - unsigned long int real_timer_clk_hz = - MCPWM_GROUP_CLK_SRC_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num); - uint32_t duty = mcpwm_ll_operator_get_compare_value(hal->dev, op, gen) * (1000000.0 / real_timer_clk_hz); + uint32_t duty = mcpwm_ll_operator_get_compare_value(hal->dev, op, gen) * (1000000.0 / timer_resolution); mcpwm_critical_exit(mcpwm_num); return duty; } @@ -797,10 +810,16 @@ esp_err_t mcpwm_capture_enable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_cha .group_id = mcpwm_num }; mcpwm_hal_init(hal, &init_config); + + uint32_t clk_src_hz = 0; + clk_tree_src_get_freq_hz(MCPWM_TIMER_CLK_SRC_DEFAULT, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_hz); + uint32_t group_resolution = mcpwm_group_get_resolution(mcpwm_num); + uint32_t group_pre_scale = clk_src_hz / group_resolution; + 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_group_set_clock_prescale(hal->dev, group_pre_scale); mcpwm_ll_capture_enable_timer(hal->dev, true); mcpwm_ll_capture_enable_channel(hal->dev, cap_channel, true); mcpwm_ll_capture_enable_negedge(hal->dev, cap_channel, cap_conf->cap_edge & MCPWM_NEG_EDGE); @@ -879,7 +898,7 @@ uint32_t mcpwm_capture_get_resolution(mcpwm_unit_t mcpwm_num) return 0; } #if SOC_MCPWM_CAPTURE_CLK_FROM_GROUP - return MCPWM_GROUP_CLK_SRC_HZ / context[mcpwm_num].group_pre_scale; + return mcpwm_group_get_resolution(mcpwm_num); #else return esp_clk_apb_freq(); #endif diff --git a/components/driver/mcpwm/mcpwm_com.c b/components/driver/mcpwm/mcpwm_com.c index bec5514a79..248f1194e0 100644 --- a/components/driver/mcpwm/mcpwm_com.c +++ b/components/driver/mcpwm/mcpwm_com.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,8 +14,8 @@ #endif #include "esp_log.h" #include "esp_check.h" +#include "clk_tree.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" @@ -115,29 +115,14 @@ esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, soc_module_clk_t clk_s "group clock conflict, already is %d but attempt to %d", group->clk_src, clk_src); if (do_clock_init) { - // [clk_tree] ToDo: replace the following switch-case table by clock_tree APIs - switch (clk_src) { -#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 - ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, group->pm_lock_name, &group->pm_lock); - ESP_RETURN_ON_ERROR(ret, TAG, "create ESP_PM_APB_FREQ_MAX lock failed"); - 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 + ESP_RETURN_ON_ERROR(clk_tree_src_get_freq_hz(clk_src, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &periph_src_clk_hz), TAG, "get clock source freq failed"); -#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; - } +#if CONFIG_PM_ENABLE + sprintf(group->pm_lock_name, "mcpwm_%d", group->group_id); // e.g. mcpwm_0 + ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, group->pm_lock_name, &group->pm_lock); + ESP_RETURN_ON_ERROR(ret, TAG, "create pm lock failed"); + ESP_LOGD(TAG, "install NO_LIGHT_SLEEP lock for MCPWM group(%d)", group->group_id); +#endif // CONFIG_PM_ENABLE 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); diff --git a/components/driver/test_apps/legacy_mcpwm_driver/README.md b/components/driver/test_apps/legacy_mcpwm_driver/README.md index 7e3b67329a..79d69249a9 100644 --- a/components/driver/test_apps/legacy_mcpwm_driver/README.md +++ b/components/driver/test_apps/legacy_mcpwm_driver/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C6 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | 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 b2bc2e2e9c..9792f76513 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 @@ -25,9 +25,13 @@ #define TEST_SYNC_GPIO_2 (19) #define TEST_CAP_GPIO (21) -#define MCPWM_GROUP_CLK_SRC_HZ 160000000 -#define MCPWM_TEST_GROUP_CLK_HZ (MCPWM_GROUP_CLK_SRC_HZ / 16) -#define MCPWM_TEST_TIMER_CLK_HZ (MCPWM_TEST_GROUP_CLK_HZ / 10) +// MCPWM default resolution +#if CONFIG_IDF_TARGET_ESP32H2 +#define MCPWM_TEST_GROUP_CLK_HZ (12 * 1000 * 1000) +#else +#define MCPWM_TEST_GROUP_CLK_HZ (10 * 1000 * 1000) +#endif +#define MCPWM_TEST_TIMER_CLK_HZ (1 * 1000 * 1000) const static mcpwm_io_signals_t pwma[] = {MCPWM0A, MCPWM1A, MCPWM2A}; const static mcpwm_io_signals_t pwmb[] = {MCPWM0B, MCPWM1B, MCPWM2B}; diff --git a/components/driver/test_apps/legacy_mcpwm_driver/pytest_legacy_mcpwm.py b/components/driver/test_apps/legacy_mcpwm_driver/pytest_legacy_mcpwm.py index e2ed1b1d4b..a5a72ebff6 100644 --- a/components/driver/test_apps/legacy_mcpwm_driver/pytest_legacy_mcpwm.py +++ b/components/driver/test_apps/legacy_mcpwm_driver/pytest_legacy_mcpwm.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 import pytest @@ -8,6 +8,7 @@ from pytest_embedded import Dut @pytest.mark.esp32 @pytest.mark.esp32s3 @pytest.mark.esp32c6 +@pytest.mark.esp32h2 @pytest.mark.generic @pytest.mark.parametrize( 'config', diff --git a/components/driver/test_apps/mcpwm/README.md b/components/driver/test_apps/mcpwm/README.md index 7e3b67329a..79d69249a9 100644 --- a/components/driver/test_apps/mcpwm/README.md +++ b/components/driver/test_apps/mcpwm/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C6 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/mcpwm/pytest_mcpwm.py b/components/driver/test_apps/mcpwm/pytest_mcpwm.py index 427d6d062c..e658c90ba1 100644 --- a/components/driver/test_apps/mcpwm/pytest_mcpwm.py +++ b/components/driver/test_apps/mcpwm/pytest_mcpwm.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 import pytest @@ -8,6 +8,7 @@ from pytest_embedded import Dut @pytest.mark.esp32 @pytest.mark.esp32s3 @pytest.mark.esp32c6 +@pytest.mark.esp32h2 @pytest.mark.generic @pytest.mark.parametrize( 'config', diff --git a/components/hal/esp32h2/include/hal/clk_gate_ll.h b/components/hal/esp32h2/include/hal/clk_gate_ll.h index 2022c9f861..9f3c55fcd4 100644 --- a/components/hal/esp32h2/include/hal/clk_gate_ll.h +++ b/components/hal/esp32h2/include/hal/clk_gate_ll.h @@ -53,6 +53,8 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph) return PCR_TWAI0_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_TWAI0_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_TWAI0_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: @@ -263,6 +269,8 @@ static uint32_t periph_ll_get_rst_en_reg(periph_module_t periph) return PCR_TWAI0_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/esp32h2/include/hal/mcpwm_ll.h b/components/hal/esp32h2/include/hal/mcpwm_ll.h new file mode 100644 index 0000000000..1023d11531 --- /dev/null +++ b/components/hal/esp32h2/include/hal/mcpwm_ll.h @@ -0,0 +1,1647 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 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 + ******************************************************************************/ + +#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_XTAL: + PCR.pwm_clk_conf.pwm_clkm_sel = 0; + break; + case SOC_MOD_CLK_PLL_F96M: + 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/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index 7d015b5064..57589b58dd 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -439,10 +439,6 @@ 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/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index ccabb3b234..0d08f68818 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -229,7 +229,6 @@ #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/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index c7781b8e8d..fd189cf615 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -659,14 +659,6 @@ 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_RSA_MAX_BIT_LEN int default 3072 diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index d1dd2a4cd9..63d4af49c6 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -280,8 +280,6 @@ #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-5359 (Copy from esp32c3, need check) /*--------------------------- RSA CAPS ---------------------------------------*/ diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index af214b680b..51aac11cad 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/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_GPTIMER_SUPPORTED bool default y @@ -507,14 +511,6 @@ 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/esp32h2/include/soc/periph_defs.h b/components/soc/esp32h2/include/soc/periph_defs.h index df6eef2c74..167ef1bf8f 100644 --- a/components/soc/esp32h2/include/soc/periph_defs.h +++ b/components/soc/esp32h2/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 @@ -93,7 +94,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, ETS_PCNT_INTR_SOURCE, ETS_PARL_IO_TX_INTR_SOURCE, ETS_PARL_IO_RX_INTR_SOURCE, diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 73f6d15a5b..4c93e5689d 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -30,7 +30,7 @@ #define SOC_GDMA_SUPPORTED 1 #define SOC_ASYNC_MEMCPY_SUPPORTED 1 #define SOC_PCNT_SUPPORTED 1 -// #define SOC_MCPWM_SUPPORTED 1 // TODO: IDF-6237 +#define SOC_MCPWM_SUPPORTED 1 // #define SOC_TWAI_SUPPORTED 1 // TODO: IDF-6217 // #define SOC_BT_SUPPORTED 1 // TODO: IDF-6416 // #define SOC_IEEE802154_SUPPORTED 1 // TODO: IDF-6577 @@ -235,7 +235,6 @@ #define SOC_RMT_SUPPORT_XTAL 1 /*!< Support set XTAL clock as the RMT clock source */ // #define SOC_RMT_SUPPORT_RC_FAST 1 /*!< Support set RC_FAST as the RMT clock source */ -// TODO: IDF-6237 /*-------------------------- 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 @@ -249,9 +248,7 @@ #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 +#define SOC_MCPWM_CAPTURE_CLK_FROM_GROUP (1) ///< Capture timer shares clock with other PWM timers // TODO: IDF-6267 (Copy from esp32c6, need check) /*-------------------------- RTC CAPS --------------------------------------*/ diff --git a/components/soc/esp32h2/ld/esp32h2.peripherals.ld b/components/soc/esp32h2/ld/esp32h2.peripherals.ld index 0167d1583c..8e74e69474 100644 --- a/components/soc/esp32h2/ld/esp32h2.peripherals.ld +++ b/components/soc/esp32h2/ld/esp32h2.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 ( PVT_MONITOR = 0x60019000 ); diff --git a/components/soc/esp32h2/mcpwm_periph.c b/components/soc/esp32h2/mcpwm_periph.c new file mode 100644 index 0000000000..f8806c57f1 --- /dev/null +++ b/components/soc/esp32h2/mcpwm_periph.c @@ -0,0 +1,83 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 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 f145a7e9ec..eb79851262 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -535,10 +535,6 @@ 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/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index a0af8c3e9d..57810f03bb 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -219,7 +219,6 @@ #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/esp32h2.txt b/docs/docs_not_updated/esp32h2.txt index 6a16efd423..e25c498fc2 100644 --- a/docs/docs_not_updated/esp32h2.txt +++ b/docs/docs_not_updated/esp32h2.txt @@ -81,7 +81,6 @@ api-reference/peripherals/etm api-reference/peripherals/i2s api-reference/peripherals/touch_element api-reference/peripherals/lcd -api-reference/peripherals/mcpwm api-reference/peripherals/secure_element api-reference/peripherals/temp_sensor api-reference/peripherals/spi_features diff --git a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/README.md b/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/README.md index a6bcc2cefe..f8630be000 100644 --- a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/README.md +++ b/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C6 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | # MCPWM Brushed DC Motor Example (See the README.md file in the upper level 'examples' directory for more information about examples.) diff --git a/examples/peripherals/mcpwm/mcpwm_bldc_hall_control/README.md b/examples/peripherals/mcpwm/mcpwm_bldc_hall_control/README.md index e7f4bd21df..13563662fd 100644 --- a/examples/peripherals/mcpwm/mcpwm_bldc_hall_control/README.md +++ b/examples/peripherals/mcpwm/mcpwm_bldc_hall_control/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C6 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | # MCPWM BLDC Motor Control with HALL Sensor Example diff --git a/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/README.md b/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/README.md index 8bbd7ab14d..e0ad00fedd 100644 --- a/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/README.md +++ b/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C6 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | # HC-SR04 Example based on MCPWM Capture diff --git a/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/pytest_hc_sr04.py b/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/pytest_hc_sr04.py index f87ab4b197..04b2edacbb 100644 --- a/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/pytest_hc_sr04.py +++ b/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/pytest_hc_sr04.py @@ -8,6 +8,7 @@ from pytest_embedded import Dut @pytest.mark.esp32 @pytest.mark.esp32s3 @pytest.mark.esp32c6 +@pytest.mark.esp32h2 @pytest.mark.generic def test_hc_sr04_example(dut: Dut) -> None: dut.expect_exact('example: Install capture timer') diff --git a/examples/peripherals/mcpwm/mcpwm_servo_control/README.md b/examples/peripherals/mcpwm/mcpwm_servo_control/README.md index 3ccd34c3c4..4a00a144bd 100644 --- a/examples/peripherals/mcpwm/mcpwm_servo_control/README.md +++ b/examples/peripherals/mcpwm/mcpwm_servo_control/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C6 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | # MCPWM RC Servo Control Example (See the README.md file in the upper level 'examples' directory for more information about examples.) diff --git a/examples/peripherals/mcpwm/mcpwm_servo_control/pytest_servo_mg996r.py b/examples/peripherals/mcpwm/mcpwm_servo_control/pytest_servo_mg996r.py index fc33d1125f..c73914e90a 100644 --- a/examples/peripherals/mcpwm/mcpwm_servo_control/pytest_servo_mg996r.py +++ b/examples/peripherals/mcpwm/mcpwm_servo_control/pytest_servo_mg996r.py @@ -8,6 +8,7 @@ from pytest_embedded import Dut @pytest.mark.esp32 @pytest.mark.esp32s3 @pytest.mark.esp32c6 +@pytest.mark.esp32h2 @pytest.mark.generic def test_servo_mg996r_example(dut: Dut) -> None: dut.expect_exact('example: Create timer and operator') diff --git a/examples/peripherals/mcpwm/mcpwm_sync/README.md b/examples/peripherals/mcpwm/mcpwm_sync/README.md index b70e00515f..656f9b1557 100644 --- a/examples/peripherals/mcpwm/mcpwm_sync/README.md +++ b/examples/peripherals/mcpwm/mcpwm_sync/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C6 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | # MCPWM Sync Example diff --git a/examples/peripherals/mcpwm/mcpwm_sync/pytest_mcpwm_sync.py b/examples/peripherals/mcpwm/mcpwm_sync/pytest_mcpwm_sync.py index 6bf09fa2c9..8d4e13baf2 100644 --- a/examples/peripherals/mcpwm/mcpwm_sync/pytest_mcpwm_sync.py +++ b/examples/peripherals/mcpwm/mcpwm_sync/pytest_mcpwm_sync.py @@ -8,6 +8,7 @@ from pytest_embedded import Dut @pytest.mark.esp32 @pytest.mark.esp32s3 @pytest.mark.esp32c6 +@pytest.mark.esp32h2 @pytest.mark.generic @pytest.mark.parametrize('config', [ pytest.param('gpio', marks=[pytest.mark.esp32, pytest.mark.esp32s3]), diff --git a/examples/peripherals/rmt/dshot_esc/main/dshot_esc_example_main.c b/examples/peripherals/rmt/dshot_esc/main/dshot_esc_example_main.c index 7277cca447..56dc1e9513 100644 --- a/examples/peripherals/rmt/dshot_esc/main/dshot_esc_example_main.c +++ b/examples/peripherals/rmt/dshot_esc/main/dshot_esc_example_main.c @@ -10,7 +10,11 @@ #include "driver/rmt_tx.h" #include "dshot_esc_encoder.h" +#if CONFIG_IDF_TARGET_ESP32H2 +#define DSHOT_ESC_RESOLUTION_HZ 32000000 // 32MHz resolution, DSHot protocol needs a relative high resolution +#else #define DSHOT_ESC_RESOLUTION_HZ 40000000 // 40MHz resolution, DSHot protocol needs a relative high resolution +#endif #define DSHOT_ESC_GPIO_NUM 0 static const char *TAG = "example";