diff --git a/components/driver/mcpwm/include/driver/mcpwm_gen.h b/components/driver/mcpwm/include/driver/mcpwm_gen.h index 91d46ce70245..1924c83b6808 100644 --- a/components/driver/mcpwm/include/driver/mcpwm_gen.h +++ b/components/driver/mcpwm/include/driver/mcpwm_gen.h @@ -205,6 +205,62 @@ esp_err_t mcpwm_generator_set_action_on_brake_event(mcpwm_gen_handle_t generator */ esp_err_t mcpwm_generator_set_actions_on_brake_event(mcpwm_gen_handle_t generator, mcpwm_gen_brake_event_action_t ev_act, ...); +/** + * @brief Generator action on specific fault event + */ +typedef struct { + mcpwm_timer_direction_t direction; /*!< Timer direction */ + mcpwm_fault_handle_t fault; /*!< Which fault as the trigger. Only support GPIO fault */ + mcpwm_generator_action_t action; /*!< Generator action should perform */ +} mcpwm_gen_fault_event_action_t; + +/** + * @brief Help macros to construct a mcpwm_gen_fault_event_action_t entry + */ +#define MCPWM_GEN_FAULT_EVENT_ACTION(dir, flt, act) \ + (mcpwm_gen_fault_event_action_t) { .direction = dir, .fault = flt, .action = act } + +/** + * @brief Set generator action on MCPWM Fault event + * + * @param[in] generator MCPWM generator handle, allocated by `mcpwm_new_generator()` + * @param[in] ev_act MCPWM trigger event action, can be constructed by `MCPWM_GEN_FAULT_EVENT_ACTION` helper macro + * @return + * - ESP_OK: Set generator action successfully + * - ESP_ERR_INVALID_ARG: Set generator action failed because of invalid argument + * - ESP_FAIL: Set generator action failed because of other error + */ +esp_err_t mcpwm_generator_set_action_on_fault_event(mcpwm_gen_handle_t generator, mcpwm_gen_fault_event_action_t ev_act); + +/** + * @brief Generator action on specific sync event + */ +typedef struct { + mcpwm_timer_direction_t direction; /*!< Timer direction */ + mcpwm_sync_handle_t sync; /*!< Which sync as the trigger*/ + mcpwm_generator_action_t action; /*!< Generator action should perform */ +} mcpwm_gen_sync_event_action_t; + +/** + * @brief Help macros to construct a mcpwm_gen_sync_event_action_t entry + */ +#define MCPWM_GEN_SYNC_EVENT_ACTION(dir, syn, act) \ + (mcpwm_gen_sync_event_action_t) { .direction = dir, .sync = syn, .action = act } + +/** + * @brief Set generator action on MCPWM Sync event + * + * @note The trigger only support one sync action, regardless of the kinds. Should not call this function more than once. + * + * @param[in] generator MCPWM generator handle, allocated by `mcpwm_new_generator()` + * @param[in] ev_act MCPWM trigger event action, can be constructed by `MCPWM_GEN_SYNC_EVENT_ACTION` helper macro + * @return + * - ESP_OK: Set generator action successfully + * - ESP_ERR_INVALID_ARG: Set generator action failed because of invalid argument + * - ESP_FAIL: Set generator action failed because of other error + */ +esp_err_t mcpwm_generator_set_action_on_sync_event(mcpwm_gen_handle_t generator, mcpwm_gen_sync_event_action_t ev_act); + /** * @brief MCPWM dead time configuration structure */ diff --git a/components/driver/mcpwm/mcpwm_gen.c b/components/driver/mcpwm/mcpwm_gen.c index 6c2e049d52b7..47db3f176f44 100644 --- a/components/driver/mcpwm/mcpwm_gen.c +++ b/components/driver/mcpwm/mcpwm_gen.c @@ -258,6 +258,60 @@ esp_err_t mcpwm_generator_set_actions_on_brake_event(mcpwm_gen_handle_t gen, mcp return ESP_OK; } +esp_err_t mcpwm_generator_set_action_on_fault_event(mcpwm_gen_handle_t gen, mcpwm_gen_fault_event_action_t ev_act) +{ + ESP_RETURN_ON_FALSE(gen, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + mcpwm_fault_t *fault = ev_act.fault; + ESP_RETURN_ON_FALSE(fault->type == MCPWM_FAULT_TYPE_GPIO, ESP_ERR_NOT_SUPPORTED, TAG, "not supported fault type"); + mcpwm_oper_t *oper = gen->oper; + mcpwm_group_t *group = oper->group; + // check the remained triggers + int trigger_id = -1; + portENTER_CRITICAL(&oper->spinlock); + for (int i = 0; i < SOC_MCPWM_TRIGGERS_PER_OPERATOR; i++) { + if (oper->triggers[i] == MCPWM_TRIGGER_NO_ASSIGN) { + trigger_id = i; + oper->triggers[i] = MCPWM_TRIGGER_GPIO_FAULT; + break; + } + } + portEXIT_CRITICAL(&oper->spinlock); + ESP_RETURN_ON_FALSE(trigger_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free trigger in operator (%d,%d)", group->group_id, oper->oper_id); + mcpwm_gpio_fault_t *gpio_fault = __containerof(fault, mcpwm_gpio_fault_t, base); + mcpwm_ll_operator_set_trigger_from_gpio_fault(group->hal.dev, oper->oper_id, trigger_id, gpio_fault->fault_id); + mcpwm_ll_generator_set_action_on_trigger_event(group->hal.dev, oper->oper_id, gen->gen_id, + ev_act.direction, trigger_id, ev_act.action); + return ESP_OK; +} + +esp_err_t mcpwm_generator_set_action_on_sync_event(mcpwm_gen_handle_t gen, mcpwm_gen_sync_event_action_t ev_act) +{ + ESP_RETURN_ON_FALSE(gen, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + mcpwm_oper_t *oper = gen->oper; + mcpwm_group_t *group = oper->group; + // check the remained triggers + int trigger_id = -1; + int trigger_sync_used = 0; + portENTER_CRITICAL(&oper->spinlock); + for (int i = 0; i < SOC_MCPWM_TRIGGERS_PER_OPERATOR; i++) { + if (oper->triggers[i] == MCPWM_TRIGGER_SYNC_EVENT) { + trigger_sync_used = 1; + break; + } else if (oper->triggers[i] == MCPWM_TRIGGER_NO_ASSIGN) { + trigger_id = i; + oper->triggers[i] = MCPWM_TRIGGER_SYNC_EVENT; + break; + } + } + portEXIT_CRITICAL(&oper->spinlock); + ESP_RETURN_ON_FALSE(!trigger_sync_used, ESP_ERR_INVALID_STATE, TAG, "only one sync supported"); + ESP_RETURN_ON_FALSE(trigger_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free trigger in operator (%d,%d)", group->group_id, oper->oper_id); + mcpwm_ll_operator_set_trigger_from_sync(group->hal.dev, oper->oper_id, trigger_id); + mcpwm_ll_generator_set_action_on_trigger_event(group->hal.dev, oper->oper_id, gen->gen_id, + ev_act.direction, trigger_id, ev_act.action); + return ESP_OK; +} + esp_err_t mcpwm_generator_set_dead_time(mcpwm_gen_handle_t in_generator, mcpwm_gen_handle_t out_generator, const mcpwm_dead_time_config_t *config) { ESP_RETURN_ON_FALSE(in_generator && out_generator && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); diff --git a/components/driver/mcpwm/mcpwm_private.h b/components/driver/mcpwm/mcpwm_private.h index e5e13a9b5c05..c91666be6073 100644 --- a/components/driver/mcpwm/mcpwm_private.h +++ b/components/driver/mcpwm/mcpwm_private.h @@ -90,6 +90,12 @@ struct mcpwm_timer_t { void *user_data; // user data which would be passed to the timer callbacks }; +typedef enum { + MCPWM_TRIGGER_NO_ASSIGN, //default trigger source + MCPWM_TRIGGER_GPIO_FAULT, //trigger assigned to gpio fault + MCPWM_TRIGGER_SYNC_EVENT, //trigger assigned to sync event +} mcpwm_trigger_source_t; + struct mcpwm_oper_t { int oper_id; // operator ID, index from 0 mcpwm_group_t *group; // which group the timer belongs to @@ -98,6 +104,7 @@ struct mcpwm_oper_t { intr_handle_t intr; // interrupt handle mcpwm_gen_t *generators[SOC_MCPWM_GENERATORS_PER_OPERATOR]; // mcpwm generator array mcpwm_cmpr_t *comparators[SOC_MCPWM_COMPARATORS_PER_OPERATOR]; // mcpwm comparator array + mcpwm_trigger_source_t triggers[SOC_MCPWM_TRIGGERS_PER_OPERATOR]; // mcpwm trigger array, can be either a fault or a sync mcpwm_soft_fault_t *soft_fault; // mcpwm software fault mcpwm_operator_brake_mode_t brake_mode_on_soft_fault; // brake mode on software triggered fault mcpwm_operator_brake_mode_t brake_mode_on_gpio_fault[SOC_MCPWM_GPIO_FAULTS_PER_GROUP]; // brake mode on GPIO triggered faults diff --git a/components/driver/test_apps/mcpwm/main/test_mcpwm_gen.c b/components/driver/test_apps/mcpwm/main/test_mcpwm_gen.c index 668773224a57..9fefc911f311 100644 --- a/components/driver/test_apps/mcpwm/main/test_mcpwm_gen.c +++ b/components/driver/test_apps/mcpwm/main/test_mcpwm_gen.c @@ -11,6 +11,8 @@ #include "driver/mcpwm_oper.h" #include "driver/mcpwm_cmpr.h" #include "driver/mcpwm_gen.h" +#include "driver/mcpwm_fault.h" +#include "driver/mcpwm_sync.h" #include "driver/gpio.h" TEST_CASE("mcpwm_generator_install_uninstall", "[mcpwm]") @@ -761,3 +763,265 @@ TEST_CASE("mcpwm_duty_empty_full", "[mcpwm]") TEST_ESP_OK(mcpwm_del_operator(oper)); TEST_ESP_OK(mcpwm_del_timer(timer)); } + +TEST_CASE("mcpwm_generator_action_on_fault_trigger_event", "[mcpwm]") +{ + const int generator_gpio = 0; + printf("create timer and operator\r\n"); + + mcpwm_operator_config_t oper_config = { + .group_id = 0, + }; + mcpwm_oper_handle_t oper = NULL; + TEST_ESP_OK(mcpwm_new_operator(&oper_config, &oper)); + + printf("install gpio faults trigger\r\n"); + mcpwm_fault_handle_t gpio_faults[3]; + mcpwm_gpio_fault_config_t gpio_trigger_config[3]; + gpio_trigger_config[0].gpio_num = 2; + gpio_trigger_config[1].gpio_num = 4; + gpio_trigger_config[2].gpio_num = 5; + for (int i = 0 ; i < 3; i++) { + gpio_trigger_config[i].group_id = 0; + gpio_trigger_config[i].flags.active_level = 1; + gpio_trigger_config[i].flags.pull_down = 1; + gpio_trigger_config[i].flags.pull_up = 0; + gpio_trigger_config[i].flags.io_loop_back = 1; // so that we can write the GPIO value by GPIO driver + TEST_ESP_OK(mcpwm_new_gpio_fault(&gpio_trigger_config[i], &gpio_faults[i])); + } + + printf("create generator\r\n"); + mcpwm_generator_config_t gen_config = { + .gen_gpio_num = generator_gpio, + .flags.io_loop_back = 1, // so that we can read the GPIO value by GPIO driver + }; + mcpwm_gen_handle_t gen = NULL; + TEST_ESP_OK(mcpwm_new_generator(oper, &gen_config, &gen)); + + printf("set generator to output high on trigger0 and low on trigger1\r\n"); + TEST_ESP_OK(mcpwm_generator_set_action_on_fault_event(gen, + MCPWM_GEN_FAULT_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, gpio_faults[0], MCPWM_GEN_ACTION_HIGH))); + TEST_ESP_OK(mcpwm_generator_set_action_on_fault_event(gen, + MCPWM_GEN_FAULT_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, gpio_faults[1], MCPWM_GEN_ACTION_LOW))); + // no free trigger + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, mcpwm_generator_set_action_on_fault_event(gen, + MCPWM_GEN_FAULT_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, gpio_faults[2], MCPWM_GEN_ACTION_LOW))); + + TEST_ASSERT_EQUAL(0, gpio_get_level(generator_gpio)); + gpio_set_level(gpio_trigger_config[0].gpio_num, 1); + gpio_set_level(gpio_trigger_config[0].gpio_num, 0); + TEST_ASSERT_EQUAL(1, gpio_get_level(generator_gpio)); + vTaskDelay(pdMS_TO_TICKS(10)); + + TEST_ASSERT_EQUAL(1, gpio_get_level(generator_gpio)); + gpio_set_level(gpio_trigger_config[1].gpio_num, 1); + gpio_set_level(gpio_trigger_config[1].gpio_num, 0); + TEST_ASSERT_EQUAL(0, gpio_get_level(generator_gpio)); + vTaskDelay(pdMS_TO_TICKS(10)); + + printf("delete falut trigger, operator, generator\r\n"); + TEST_ESP_OK(mcpwm_del_fault(gpio_faults[0])); + TEST_ESP_OK(mcpwm_del_fault(gpio_faults[1])); + TEST_ESP_OK(mcpwm_del_fault(gpio_faults[2])); + TEST_ESP_OK(mcpwm_del_generator(gen)); + TEST_ESP_OK(mcpwm_del_operator(oper)); +} + +TEST_CASE("mcpwm_generator_action_on_soft_sync_trigger_event", "[mcpwm]") +{ + const int generator_gpio = 0; + printf("create timer and operator\r\n"); + mcpwm_timer_config_t timer_config = { + .group_id = 0, + .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT, + .resolution_hz = 1000000, + .count_mode = MCPWM_TIMER_COUNT_MODE_UP, + .period_ticks = 1000, + }; + mcpwm_timer_handle_t timer = NULL; + TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer)); + + mcpwm_operator_config_t oper_config = { + .group_id = 0, + }; + mcpwm_oper_handle_t oper = NULL; + TEST_ESP_OK(mcpwm_new_operator(&oper_config, &oper)); + + printf("connect timer and operator\r\n"); + TEST_ESP_OK(mcpwm_operator_connect_timer(oper, timer)); + + printf("install soft sync source trigger\r\n"); + mcpwm_sync_handle_t soft_sync = NULL; + mcpwm_soft_sync_config_t soft_sync_config = {}; + TEST_ESP_OK(mcpwm_new_soft_sync_src(&soft_sync_config, &soft_sync)); + + mcpwm_timer_sync_phase_config_t sync_phase_config = { + .count_value = 0, + .direction = MCPWM_TIMER_DIRECTION_UP, + .sync_src = soft_sync, + }; + TEST_ESP_OK(mcpwm_timer_set_phase_on_sync(timer, &sync_phase_config)); + + printf("create generator\r\n"); + mcpwm_generator_config_t gen_config = { + .gen_gpio_num = generator_gpio, + .flags.io_loop_back = 1, // so that we can read the GPIO value by GPIO driver + }; + mcpwm_gen_handle_t gen = NULL; + TEST_ESP_OK(mcpwm_new_generator(oper, &gen_config, &gen)); + + printf("set generator to output high on soft sync trigger\r\n"); + TEST_ESP_OK(mcpwm_generator_set_action_on_sync_event(gen, + MCPWM_GEN_SYNC_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, soft_sync, MCPWM_GEN_ACTION_HIGH))); + + //more than 1 sync is not supported + mcpwm_sync_handle_t invalid_soft_sync = NULL; + TEST_ESP_OK(mcpwm_new_soft_sync_src(&soft_sync_config, &invalid_soft_sync)); + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_generator_set_action_on_sync_event(gen, + MCPWM_GEN_SYNC_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, invalid_soft_sync, MCPWM_GEN_ACTION_LOW))); + + TEST_ASSERT_EQUAL(0, gpio_get_level(generator_gpio)); + mcpwm_soft_sync_activate(soft_sync); + TEST_ASSERT_EQUAL(1, gpio_get_level(generator_gpio)); + vTaskDelay(pdMS_TO_TICKS(10)); + + printf("delete soft sync trigger, timer, operator, generator\r\n"); + TEST_ESP_OK(mcpwm_del_sync_src(soft_sync)); + TEST_ESP_OK(mcpwm_del_sync_src(invalid_soft_sync)); + TEST_ESP_OK(mcpwm_del_generator(gen)); + TEST_ESP_OK(mcpwm_del_operator(oper)); + TEST_ESP_OK(mcpwm_del_timer(timer)); +} + +TEST_CASE("mcpwm_generator_action_on_timer_sync_trigger_event", "[mcpwm]") +{ + const int generator_gpio = 0; + printf("create timer and operator\r\n"); + mcpwm_timer_config_t timer_config = { + .group_id = 0, + .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT, + .resolution_hz = 1000000, + .count_mode = MCPWM_TIMER_COUNT_MODE_UP, + .period_ticks = 1000, + }; + mcpwm_timer_handle_t timer = NULL; + TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer)); + + mcpwm_operator_config_t oper_config = { + .group_id = 0, + }; + mcpwm_oper_handle_t oper = NULL; + TEST_ESP_OK(mcpwm_new_operator(&oper_config, &oper)); + + printf("connect timer and operator\r\n"); + TEST_ESP_OK(mcpwm_operator_connect_timer(oper, timer)); + + printf("install timer sync source trigger\r\n"); + mcpwm_sync_handle_t timer_sync = NULL; + mcpwm_timer_sync_src_config_t timer_sync_config = { + .timer_event = MCPWM_TIMER_EVENT_EMPTY, + }; + + TEST_ESP_OK(mcpwm_new_timer_sync_src(timer, &timer_sync_config, &timer_sync)); + + mcpwm_timer_sync_phase_config_t sync_phase_config = { + .count_value = 0, + .direction = MCPWM_TIMER_DIRECTION_UP, + .sync_src = timer_sync, + }; + TEST_ESP_OK(mcpwm_timer_set_phase_on_sync(timer, &sync_phase_config)); + + printf("create generator\r\n"); + mcpwm_generator_config_t gen_config = { + .gen_gpio_num = generator_gpio, + .flags.io_loop_back = 1, // so that we can read the GPIO value by GPIO driver + }; + mcpwm_gen_handle_t gen = NULL; + TEST_ESP_OK(mcpwm_new_generator(oper, &gen_config, &gen)); + + printf("set generator to output high on timer sync trigger\r\n"); + TEST_ESP_OK(mcpwm_generator_set_action_on_sync_event(gen, + MCPWM_GEN_SYNC_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, timer_sync, MCPWM_GEN_ACTION_HIGH))); + + TEST_ESP_OK(mcpwm_timer_enable(timer)); + + TEST_ASSERT_EQUAL(0, gpio_get_level(generator_gpio)); + TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_STOP_FULL)); + TEST_ASSERT_EQUAL(1, gpio_get_level(generator_gpio)); + vTaskDelay(pdMS_TO_TICKS(10)); + + printf("delete timer sync trigger, timer, operator, generator\r\n"); + TEST_ESP_OK(mcpwm_timer_disable(timer)); + TEST_ESP_OK(mcpwm_del_sync_src(timer_sync)); + TEST_ESP_OK(mcpwm_del_generator(gen)); + TEST_ESP_OK(mcpwm_del_operator(oper)); + TEST_ESP_OK(mcpwm_del_timer(timer)); +} + +TEST_CASE("mcpwm_generator_action_on_gpio_sync_trigger_event", "[mcpwm]") +{ + const int generator_gpio = 0; + printf("create timer and operator\r\n"); + mcpwm_timer_config_t timer_config = { + .group_id = 0, + .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT, + .resolution_hz = 1000000, + .count_mode = MCPWM_TIMER_COUNT_MODE_UP, + .period_ticks = 1000, + }; + mcpwm_timer_handle_t timer = NULL; + TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer)); + + mcpwm_operator_config_t oper_config = { + .group_id = 0, + }; + mcpwm_oper_handle_t oper = NULL; + TEST_ESP_OK(mcpwm_new_operator(&oper_config, &oper)); + + printf("connect timer and operator\r\n"); + TEST_ESP_OK(mcpwm_operator_connect_timer(oper, timer)); + + printf("install gpio sync source trigger\r\n"); + mcpwm_sync_handle_t gpio_sync = NULL; + mcpwm_gpio_sync_src_config_t gpio_sync_config = { + .group_id = 0, + .gpio_num = 2, + .flags.io_loop_back = true, // so that we can use gpio driver to simulate the sync signal + .flags.pull_down = true, // internally pull down + }; + TEST_ESP_OK(mcpwm_new_gpio_sync_src(&gpio_sync_config, &gpio_sync)); + + // put the GPIO into initial state + gpio_set_level(gpio_sync_config.gpio_num, 0); + + mcpwm_timer_sync_phase_config_t sync_phase_config = { + .count_value = 0, + .direction = MCPWM_TIMER_DIRECTION_UP, + .sync_src = gpio_sync, + }; + TEST_ESP_OK(mcpwm_timer_set_phase_on_sync(timer, &sync_phase_config)); + + printf("create generator\r\n"); + mcpwm_generator_config_t gen_config = { + .gen_gpio_num = generator_gpio, + .flags.io_loop_back = 1, // so that we can read the GPIO value by GPIO driver + }; + mcpwm_gen_handle_t gen = NULL; + TEST_ESP_OK(mcpwm_new_generator(oper, &gen_config, &gen)); + + printf("set generator to output high on gpio sync trigger\r\n"); + TEST_ESP_OK(mcpwm_generator_set_action_on_sync_event(gen, + MCPWM_GEN_SYNC_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, gpio_sync, MCPWM_GEN_ACTION_HIGH))); + + TEST_ASSERT_EQUAL(0, gpio_get_level(generator_gpio)); + gpio_set_level(gpio_sync_config.gpio_num, 1); + gpio_set_level(gpio_sync_config.gpio_num, 0); + TEST_ASSERT_EQUAL(1, gpio_get_level(generator_gpio)); + vTaskDelay(pdMS_TO_TICKS(10)); + + printf("delete gpio sync trigger, timer, operator, generator\r\n"); + TEST_ESP_OK(mcpwm_del_sync_src(gpio_sync)); + TEST_ESP_OK(mcpwm_del_generator(gen)); + TEST_ESP_OK(mcpwm_del_operator(oper)); + TEST_ESP_OK(mcpwm_del_timer(timer)); +} diff --git a/components/hal/esp32/include/hal/mcpwm_ll.h b/components/hal/esp32/include/hal/mcpwm_ll.h index 3d1fa42d7d19..cd3a7e86ee69 100644 --- a/components/hal/esp32/include/hal/mcpwm_ll.h +++ b/components/hal/esp32/include/hal/mcpwm_ll.h @@ -692,20 +692,20 @@ static inline void mcpwm_ll_operator_stop_update_action(mcpwm_dev_t *mcpwm, int * @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) +static inline void mcpwm_ll_operator_set_trigger_from_gpio_fault(mcpwm_dev_t *mcpwm, int operator_id, int trig_id, int fault_gpio_id) { mcpwm->operators[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id)); mcpwm->operators[operator_id].gen_cfg0.val |= (fault_gpio_id << (4 + 3 * trig_id)); } /** - * @brief Set trigger from timer sync event (when the timer taken the sync signal) + * @brief Set trigger from sync event (when the timer/gpio/soft taken the sync signal) * * @param mcpwm Peripheral instance address * @param operator_id Operator ID, index from 0 to 2 * @param trig_id Trigger ID, index from 0 to 1 */ -static inline void mcpwm_ll_operator_set_trigger_from_timer_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id) +static inline void mcpwm_ll_operator_set_trigger_from_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id) { // the timer here is not selectable, must be the one connected with the operator mcpwm->operators[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id)); diff --git a/components/hal/esp32c6/include/hal/mcpwm_ll.h b/components/hal/esp32c6/include/hal/mcpwm_ll.h index af9b4a455752..29381a8bfb5f 100644 --- a/components/hal/esp32c6/include/hal/mcpwm_ll.h +++ b/components/hal/esp32c6/include/hal/mcpwm_ll.h @@ -715,20 +715,20 @@ static inline void mcpwm_ll_operator_stop_update_action(mcpwm_dev_t *mcpwm, int * @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) +static inline void mcpwm_ll_operator_set_trigger_from_gpio_fault(mcpwm_dev_t *mcpwm, int operator_id, int trig_id, int fault_gpio_id) { mcpwm->operators[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id)); mcpwm->operators[operator_id].gen_cfg0.val |= (fault_gpio_id << (4 + 3 * trig_id)); } /** - * @brief Set trigger from timer sync event (when the timer taken the sync signal) + * @brief Set trigger from sync event (when the timer/gpio/soft taken the sync signal) * * @param mcpwm Peripheral instance address * @param operator_id Operator ID, index from 0 to 2 * @param trig_id Trigger ID, index from 0 to 1 */ -static inline void mcpwm_ll_operator_set_trigger_from_timer_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id) +static inline void mcpwm_ll_operator_set_trigger_from_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id) { // the timer here is not selectable, must be the one connected with the operator mcpwm->operators[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id)); diff --git a/components/hal/esp32h2/include/hal/mcpwm_ll.h b/components/hal/esp32h2/include/hal/mcpwm_ll.h index 3c5444d9f0eb..af042b08bf18 100644 --- a/components/hal/esp32h2/include/hal/mcpwm_ll.h +++ b/components/hal/esp32h2/include/hal/mcpwm_ll.h @@ -713,20 +713,20 @@ static inline void mcpwm_ll_operator_stop_update_action(mcpwm_dev_t *mcpwm, int * @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) +static inline void mcpwm_ll_operator_set_trigger_from_gpio_fault(mcpwm_dev_t *mcpwm, int operator_id, int trig_id, int fault_gpio_id) { mcpwm->operators[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id)); mcpwm->operators[operator_id].gen_cfg0.val |= (fault_gpio_id << (4 + 3 * trig_id)); } /** - * @brief Set trigger from timer sync event (when the timer taken the sync signal) + * @brief Set trigger from sync event (when the timer/gpio/soft taken the sync signal) * * @param mcpwm Peripheral instance address * @param operator_id Operator ID, index from 0 to 2 * @param trig_id Trigger ID, index from 0 to 1 */ -static inline void mcpwm_ll_operator_set_trigger_from_timer_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id) +static inline void mcpwm_ll_operator_set_trigger_from_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id) { // the timer here is not selectable, must be the one connected with the operator mcpwm->operators[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id)); diff --git a/components/hal/esp32s3/include/hal/mcpwm_ll.h b/components/hal/esp32s3/include/hal/mcpwm_ll.h index ba8e1d2535a2..ea73909c27ed 100644 --- a/components/hal/esp32s3/include/hal/mcpwm_ll.h +++ b/components/hal/esp32s3/include/hal/mcpwm_ll.h @@ -704,20 +704,20 @@ static inline void mcpwm_ll_operator_stop_update_action(mcpwm_dev_t *mcpwm, int * @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) +static inline void mcpwm_ll_operator_set_trigger_from_gpio_fault(mcpwm_dev_t *mcpwm, int operator_id, int trig_id, int fault_gpio_id) { mcpwm->operators[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id)); mcpwm->operators[operator_id].gen_cfg0.val |= (fault_gpio_id << (4 + 3 * trig_id)); } /** - * @brief Set trigger from timer sync event (when the timer taken the sync signal) + * @brief Set trigger from sync event (when the timer/gpio/soft taken the sync signal) * * @param mcpwm Peripheral instance address * @param operator_id Operator ID, index from 0 to 2 * @param trig_id Trigger ID, index from 0 to 1 */ -static inline void mcpwm_ll_operator_set_trigger_from_timer_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id) +static inline void mcpwm_ll_operator_set_trigger_from_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id) { // the timer here is not selectable, must be the one connected with the operator mcpwm->operators[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id)); diff --git a/components/hal/include/hal/mcpwm_types.h b/components/hal/include/hal/mcpwm_types.h index 7ee1beb495b2..973cbc5f92b1 100644 --- a/components/hal/include/hal/mcpwm_types.h +++ b/components/hal/include/hal/mcpwm_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -84,7 +84,7 @@ typedef enum { */ typedef enum { MCPWM_OPER_BRAKE_MODE_CBC, /*!< Brake mode: CBC (cycle by cycle)*/ - MCPWM_OPER_BRAKE_MODE_OST, /*!< Brake mode, OST (one shot) */ + MCPWM_OPER_BRAKE_MODE_OST, /*!< Brake mode: OST (one shot) */ MCPWM_OPER_BRAKE_MODE_INVALID, /*!< MCPWM operator invalid brake mode */ } mcpwm_operator_brake_mode_t; diff --git a/docs/en/api-reference/peripherals/mcpwm.rst b/docs/en/api-reference/peripherals/mcpwm.rst index ad7738051c8f..54eba78de7cd 100644 --- a/docs/en/api-reference/peripherals/mcpwm.rst +++ b/docs/en/api-reference/peripherals/mcpwm.rst @@ -301,6 +301,40 @@ Please note, the argument list of :cpp:func:`mcpwm_generator_set_actions_on_comp You can also set the compare action one by one by calling :cpp:func:`mcpwm_generator_set_action_on_compare_event` without varargs. +Set Generator Action on Fault Event +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One generator can set action on fault based trigger events, by calling :cpp:func:`mcpwm_generator_set_action_on_fault_event` with an action configurations. The action configuration is defined in :cpp:type:`mcpwm_gen_fault_event_action_t`: + +- :cpp:member:`mcpwm_gen_fault_event_action_t::direction` specifies the timer direction. The supported directions are listed in :cpp:type:`mcpwm_timer_direction_t`. +- :cpp:member:`mcpwm_gen_fault_event_action_t::fault` specifies the fault used for the trigger. See `MCPWM Faults <#mcpwm-faults>`__ for how to allocate a fault. +- :cpp:member:`mcpwm_gen_fault_event_action_t::action` specifies the generator action to be taken. The supported actions are listed in :cpp:type:`mcpwm_generator_action_t`. + +When no free trigger slot is left in the operator to which the generator belongs, this function will return the :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ + +The trigger only support GPOI fault. when the input is not a GPIO fault, this function will return the :c:macro:`ESP_ERR_NOT_SUPPORTED` error. + +There's a helper macro :c:macro:`MCPWM_GEN_FAULT_EVENT_ACTION` to simplify the construction of a trigger event action entry. + +Please note, fault event does not have variadic function like :cpp:func:`mcpwm_generator_set_actions_on_fault_event`. + +Set Generator Action on Sync Event +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One generator can set action on sync based trigger events, by calling :cpp:func:`mcpwm_generator_set_action_on_sync_event` with an action configurations. The action configuration is defined in :cpp:type:`mcpwm_gen_sync_event_action_t`: + +- :cpp:member:`mcpwm_gen_sync_event_action_t::direction` specifies the timer direction. The supported directions are listed in :cpp:type:`mcpwm_timer_direction_t`. +- :cpp:member:`mcpwm_gen_sync_event_action_t::sync` specifies the sync source used for the trigger. See `MCPWM Sync Sources <#mcpwm-sync-sources>`__ for how to allocate a sync source. +- :cpp:member:`mcpwm_gen_sync_event_action_t::action` specifies the generator action to be taken. The supported actions are listed in :cpp:type:`mcpwm_generator_action_t`. + +When no free trigger slot is left in the operator to which the generator belongs, this function will return the :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ + +The trigger only support one sync action, regardless of the kinds. When set sync actions more than once, this function will return the :c:macro:`ESP_ERR_INVALID_STATE` error. + +There's a helper macro :c:macro:`MCPWM_GEN_SYNC_EVENT_ACTION` to simplify the construction of a trigger event action entry. + +Please note, sync event does not have variadic function like :cpp:func:`mcpwm_generator_set_actions_on_sync_event`. + .. _mcpwm-classical-pwm-waveforms-and-generator-configurations: @@ -959,7 +993,7 @@ API Reference .. [1] - Different ESP chip series might have a different number of MCPWM resources (e.g. groups, timers, comparators, operators, generators and so on). Please refer to the [`TRM <{IDF_TARGET_TRM_EN_URL}#mcpwm>`__] for details. The driver won't forbid you from applying for more MCPWM resources, but it will return an error when there are no hardware resources available. Please always check the return value when doing :ref:`mcpwm-resource-allocation-and-initialization`. + Different ESP chip series might have a different number of MCPWM resources (e.g. groups, timers, comparators, operators, generators, triggers and so on). Please refer to the [`TRM <{IDF_TARGET_TRM_EN_URL}#mcpwm>`__] for details. The driver won't forbid you from applying for more MCPWM resources, but it will return an error when there are no hardware resources available. Please always check the return value when doing :ref:`mcpwm-resource-allocation-and-initialization`. .. [2] The callback function and the sub-functions invoked by itself should also be placed in IRAM. You need to take care of this by yourself. diff --git a/docs/zh_CN/api-reference/peripherals/mcpwm.rst b/docs/zh_CN/api-reference/peripherals/mcpwm.rst index 8bd775853b48..e098269be1a2 100644 --- a/docs/zh_CN/api-reference/peripherals/mcpwm.rst +++ b/docs/zh_CN/api-reference/peripherals/mcpwm.rst @@ -299,7 +299,41 @@ MCPWM 比较器可以在定时器计数器等于比较值时发送通知。若 需注意,:cpp:func:`mcpwm_generator_set_actions_on_compare_event` 的参数列表 **必须** 以 :c:macro:`MCPWM_GEN_COMPARE_EVENT_ACTION_END` 结束。 -也可以调用 :cpp:func:`mcpwm_generator_set_action_on_compare_event` 逐一设置定时器操作,无需涉及变量参数。 +也可以调用 :cpp:func:`mcpwm_generator_set_action_on_compare_event` 逐一设置比较器操作,无需涉及变量参数。 + +设置生成器对故障事件执行的操作 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +调用 :cpp:func:`mcpwm_generator_set_action_on_fault_event` 并辅以操作配置,可以针对故障事件,为生成器设置操作。操作配置定义在 :cpp:type:`mcpwm_gen_fault_event_action_t` 中: + +- :cpp:member:`mcpwm_gen_fault_event_action_t::direction` 指定定时器计数方向,可以调用 :cpp:type:`mcpwm_timer_direction_t` 查看支持的方向。 +- :cpp:member:`mcpwm_gen_fault_event_action_t::fault` 指定用于触发器的故障。有关分配故障的方法,请参见 `MCPWM 故障`_。 +- :cpp:member:`mcpwm_gen_fault_event_action_t::action` 指定随即进行的生成器操作,可以调用 :cpp:type:`mcpwm_generator_action_t` 查看支持的操作。 + +当生成器所属的操作器中没有空闲触发器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_ + +触发器支持的故障仅为 GPIO 故障,当传入故障不为 GPIO 故障时,将返回 :c:macro:`ESP_ERR_NOT_SUPPORTED` 错误。 + +可借助辅助宏 :c:macro:`MCPWM_GEN_FAULT_EVENT_ACTION` 构建触发事件操作条目。 + +需注意,故障事件没有类似 :cpp:func:`mcpwm_generator_set_actions_on_fault_event` 这样的可变参数函数。 + +设置生成器对同步事件执行的操作 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +调用 :cpp:func:`mcpwm_generator_set_action_on_sync_event` 并辅以操作配置,可以针对同步事件,为生成器设置操作。操作配置定义在 :cpp:type:`mcpwm_gen_sync_event_action_t` 中: + +- :cpp:member:`mcpwm_gen_sync_event_action_t::direction` 指定定时器计数方向,可以调用 :cpp:type:`mcpwm_timer_direction_t` 查看支持的方向。 +- :cpp:member:`mcpwm_gen_sync_event_action_t::sync` 指定用于触发器的同步源。有关分配同步源的方法,请参见 `MCPWM 同步源`_。 +- :cpp:member:`mcpwm_gen_sync_event_action_t::action` 指定随即进行的生成器操作,可以调用 :cpp:type:`mcpwm_generator_action_t` 查看支持的操作。 + +当生成器所属的操作器中没有空闲触发器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_ + +无论同步为何种类型,触发器仅支持一种同步操作,如果多次设置同步操作,将返回 :c:macro:`ESP_ERR_INVALID_STATE` 错误。 + +可借助辅助宏 :c:macro:`MCPWM_GEN_SYNC_EVENT_ACTION` 构建触发事件操作条目。 + +需注意,同步事件没有类似 :cpp:func:`mcpwm_generator_set_actions_on_sync_event` 这样的可变参数函数。 .. _mcpwm-classical-pwm-waveforms-and-generator-configurations: @@ -959,7 +993,7 @@ API Reference .. [1] - 不同的 ESP 芯片上的 MCPWM 资源数量可能存在差异(如组、定时器、比较器、操作器、生成器等)。详情请参见 [`TRM <{IDF_TARGET_TRM_EN_URL}#mcpwm>`__]。当分配了超出资源数量的 MCPWM 资源时,在检测到没有可用硬件资源后,驱动程序将返回错误。请在进行 :ref:`mcpwm-resource-allocation-and-initialization` 时务必检查返回值。 + 不同的 ESP 芯片上的 MCPWM 资源数量可能存在差异(如组、定时器、比较器、操作器、生成器、触发器等)。详情请参见 [`TRM <{IDF_TARGET_TRM_EN_URL}#mcpwm>`__]。当分配了超出资源数量的 MCPWM 资源时,在检测到没有可用硬件资源后,驱动程序将返回错误。请在进行 :ref:`mcpwm-resource-allocation-and-initialization` 时务必检查返回值。 .. [2] 回调函数及其调用的子函数需手动存放进 IRAM 中。