From 713324ff9d176eddb1423883a828a1553606a631 Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Wed, 16 Aug 2023 10:51:30 +0800 Subject: [PATCH] feat(MCPWM): Support set interrupt priority --- .../driver/mcpwm/include/driver/mcpwm_cap.h | 2 + .../driver/mcpwm/include/driver/mcpwm_cmpr.h | 2 + .../driver/mcpwm/include/driver/mcpwm_fault.h | 6 +- .../driver/mcpwm/include/driver/mcpwm_oper.h | 4 +- .../driver/mcpwm/include/driver/mcpwm_timer.h | 2 + components/driver/mcpwm/mcpwm_cap.c | 9 ++ components/driver/mcpwm/mcpwm_cmpr.c | 9 ++ components/driver/mcpwm/mcpwm_com.c | 27 ++++ components/driver/mcpwm/mcpwm_fault.c | 9 ++ components/driver/mcpwm/mcpwm_oper.c | 9 ++ components/driver/mcpwm/mcpwm_private.h | 9 +- components/driver/mcpwm/mcpwm_timer.c | 10 ++ components/driver/pcnt/pulse_cnt.c | 6 +- .../test_apps/mcpwm/main/CMakeLists.txt | 1 + .../test_apps/mcpwm/main/test_mcpwm_common.c | 125 ++++++++++++++++++ .../test_apps/mcpwm/main/test_mcpwm_gen.c | 28 ++-- .../test_apps/mcpwm/main/test_mcpwm_utils.c | 2 +- docs/en/api-reference/peripherals/mcpwm.rst | 14 ++ docs/en/api-reference/peripherals/pcnt.rst | 2 +- .../zh_CN/api-reference/peripherals/mcpwm.rst | 14 ++ 20 files changed, 266 insertions(+), 24 deletions(-) create mode 100644 components/driver/test_apps/mcpwm/main/test_mcpwm_common.c diff --git a/components/driver/mcpwm/include/driver/mcpwm_cap.h b/components/driver/mcpwm/include/driver/mcpwm_cap.h index 709d97c478d9..248384399839 100644 --- a/components/driver/mcpwm/include/driver/mcpwm_cap.h +++ b/components/driver/mcpwm/include/driver/mcpwm_cap.h @@ -132,6 +132,8 @@ esp_err_t mcpwm_capture_timer_set_phase_on_sync(mcpwm_cap_timer_handle_t cap_tim */ typedef struct { int gpio_num; /*!< GPIO used capturing input signal */ + int intr_priority; /*!< MCPWM capture interrupt priority, + if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */ uint32_t prescale; /*!< Prescale of input signal, effective frequency = cap_input_clk/prescale */ struct { uint32_t pos_edge: 1; /*!< Whether to capture on positive edge */ diff --git a/components/driver/mcpwm/include/driver/mcpwm_cmpr.h b/components/driver/mcpwm/include/driver/mcpwm_cmpr.h index dc68df6d1788..0e5a77d8ab29 100644 --- a/components/driver/mcpwm/include/driver/mcpwm_cmpr.h +++ b/components/driver/mcpwm/include/driver/mcpwm_cmpr.h @@ -19,6 +19,8 @@ extern "C" { * @brief MCPWM comparator configuration */ typedef struct { + int intr_priority; /*!< MCPWM comparator interrupt priority, + if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */ struct { uint32_t update_cmp_on_tez: 1; /*!< Whether to update compare value when timer count equals to zero (tez) */ uint32_t update_cmp_on_tep: 1; /*!< Whether to update compare value when timer count equals to peak (tep) */ diff --git a/components/driver/mcpwm/include/driver/mcpwm_fault.h b/components/driver/mcpwm/include/driver/mcpwm_fault.h index d97f40df337d..ae289b58cdfe 100644 --- a/components/driver/mcpwm/include/driver/mcpwm_fault.h +++ b/components/driver/mcpwm/include/driver/mcpwm_fault.h @@ -20,8 +20,10 @@ extern "C" { * @brief MCPWM GPIO fault configuration structure */ typedef struct { - int group_id; /*!< In which MCPWM group that the GPIO fault belongs to */ - int gpio_num; /*!< GPIO used by the fault signal */ + int group_id; /*!< In which MCPWM group that the GPIO fault belongs to */ + int intr_priority; /*!< MCPWM GPIO fault interrupt priority, + if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */ + int gpio_num; /*!< GPIO used by the fault signal */ struct { uint32_t active_level: 1; /*!< On which level the fault signal is treated as active */ uint32_t io_loop_back: 1; /*!< For debug/test, the signal output from the GPIO will be fed to the input path as well */ diff --git a/components/driver/mcpwm/include/driver/mcpwm_oper.h b/components/driver/mcpwm/include/driver/mcpwm_oper.h index 38ab7164a4a9..845d333b7b1f 100644 --- a/components/driver/mcpwm/include/driver/mcpwm_oper.h +++ b/components/driver/mcpwm/include/driver/mcpwm_oper.h @@ -19,7 +19,9 @@ extern "C" { * @brief MCPWM operator configuration */ typedef struct { - int group_id; /*!< Specify from which group to allocate the MCPWM operator */ + int group_id; /*!< Specify from which group to allocate the MCPWM operator */ + int intr_priority; /*!< MCPWM operator interrupt priority, + if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */ struct { uint32_t update_gen_action_on_tez: 1; /*!< Whether to update generator action when timer counts to zero */ uint32_t update_gen_action_on_tep: 1; /*!< Whether to update generator action when timer counts to peak */ diff --git a/components/driver/mcpwm/include/driver/mcpwm_timer.h b/components/driver/mcpwm/include/driver/mcpwm_timer.h index 33ec450d8e4d..df8bc3da2e97 100644 --- a/components/driver/mcpwm/include/driver/mcpwm_timer.h +++ b/components/driver/mcpwm/include/driver/mcpwm_timer.h @@ -35,6 +35,8 @@ typedef struct { The step size of each count tick equals to (1 / resolution_hz) seconds */ mcpwm_timer_count_mode_t count_mode; /*!< Count mode */ uint32_t period_ticks; /*!< Number of count ticks within a period */ + int intr_priority; /*!< MCPWM timer interrupt priority, + if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */ struct { uint32_t update_period_on_empty: 1; /*!< Whether to update period when timer counts to zero */ uint32_t update_period_on_sync: 1; /*!< Whether to update period on sync event */ diff --git a/components/driver/mcpwm/mcpwm_cap.c b/components/driver/mcpwm/mcpwm_cap.c index 8ff7910bd9b3..965311bdfede 100644 --- a/components/driver/mcpwm/mcpwm_cap.c +++ b/components/driver/mcpwm/mcpwm_cap.c @@ -246,6 +246,10 @@ esp_err_t mcpwm_new_capture_channel(mcpwm_cap_timer_handle_t cap_timer, const mc mcpwm_cap_channel_t *cap_chan = NULL; ESP_GOTO_ON_FALSE(cap_timer && config && ret_cap_channel, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); ESP_GOTO_ON_FALSE(config->prescale && config->prescale <= MCPWM_LL_MAX_CAPTURE_PRESCALE, ESP_ERR_INVALID_ARG, err, TAG, "invalid prescale"); + if (config->intr_priority) { + ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, + TAG, "invalid interrupt priority:%d", config->intr_priority); + } // create instance firstly, then install onto platform cap_chan = calloc(1, sizeof(mcpwm_cap_channel_t)); @@ -256,6 +260,10 @@ esp_err_t mcpwm_new_capture_channel(mcpwm_cap_timer_handle_t cap_timer, const mc mcpwm_hal_context_t *hal = &group->hal; int cap_chan_id = cap_chan->cap_chan_id; + // if interrupt priority specified before, it cannot be changed until the group is released + // check if the new priority specified consistents with the old one + ESP_GOTO_ON_ERROR(mcpwm_check_intr_priority(group, config->intr_priority), err, TAG, "set group intrrupt priority failed"); + mcpwm_ll_capture_enable_negedge(hal->dev, cap_chan_id, config->flags.neg_edge); mcpwm_ll_capture_enable_posedge(hal->dev, cap_chan_id, config->flags.pos_edge); mcpwm_ll_invert_input(hal->dev, cap_chan_id, config->flags.invert_cap_signal); @@ -367,6 +375,7 @@ esp_err_t mcpwm_capture_channel_register_event_callbacks(mcpwm_cap_channel_handl if (!cap_channel->intr) { ESP_RETURN_ON_FALSE(cap_channel->fsm == MCPWM_CAP_CHAN_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "channel not in init state"); int isr_flags = MCPWM_INTR_ALLOC_FLAG; + isr_flags |= mcpwm_get_intr_priority_flag(group); ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(mcpwm_periph_signals.groups[group_id].irq_id, isr_flags, (uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), MCPWM_LL_EVENT_CAPTURE(cap_chan_id), mcpwm_capture_default_isr, cap_channel, &cap_channel->intr), TAG, "install interrupt service for cap channel failed"); diff --git a/components/driver/mcpwm/mcpwm_cmpr.c b/components/driver/mcpwm/mcpwm_cmpr.c index fd0c1fd061c2..77aae8f9cc66 100644 --- a/components/driver/mcpwm/mcpwm_cmpr.c +++ b/components/driver/mcpwm/mcpwm_cmpr.c @@ -75,6 +75,10 @@ esp_err_t mcpwm_new_comparator(mcpwm_oper_handle_t oper, const mcpwm_comparator_ esp_err_t ret = ESP_OK; mcpwm_cmpr_t *cmpr = NULL; ESP_GOTO_ON_FALSE(oper && config && ret_cmpr, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + if (config->intr_priority) { + ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, + TAG, "invalid interrupt priority:%d", config->intr_priority); + } cmpr = heap_caps_calloc(1, sizeof(mcpwm_cmpr_t), MCPWM_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(cmpr, ESP_ERR_NO_MEM, err, TAG, "no mem for comparator"); @@ -85,6 +89,10 @@ esp_err_t mcpwm_new_comparator(mcpwm_oper_handle_t oper, const mcpwm_comparator_ int oper_id = oper->oper_id; int cmpr_id = cmpr->cmpr_id; + // if interrupt priority specified before, it cannot be changed until the group is released + // check if the new priority specified consistents with the old one + ESP_GOTO_ON_ERROR(mcpwm_check_intr_priority(group, config->intr_priority), err, TAG, "set group intrrupt priority failed"); + mcpwm_ll_operator_enable_update_compare_on_tez(hal->dev, oper_id, cmpr_id, config->flags.update_cmp_on_tez); mcpwm_ll_operator_enable_update_compare_on_tep(hal->dev, oper_id, cmpr_id, config->flags.update_cmp_on_tep); mcpwm_ll_operator_enable_update_compare_on_sync(hal->dev, oper_id, cmpr_id, config->flags.update_cmp_on_sync); @@ -162,6 +170,7 @@ esp_err_t mcpwm_comparator_register_event_callbacks(mcpwm_cmpr_handle_t cmpr, co if (!cmpr->intr) { // we want the interrupt service to be enabled after allocation successfully int isr_flags = MCPWM_INTR_ALLOC_FLAG & ~ ESP_INTR_FLAG_INTRDISABLED; + isr_flags |= mcpwm_get_intr_priority_flag(group); ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(mcpwm_periph_signals.groups[group_id].irq_id, isr_flags, (uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), MCPWM_LL_EVENT_CMP_EQUAL(oper_id, cmpr_id), mcpwm_comparator_default_isr, cmpr, &cmpr->intr), TAG, "install interrupt service for comparator failed"); diff --git a/components/driver/mcpwm/mcpwm_com.c b/components/driver/mcpwm/mcpwm_com.c index 0b9a3d86159f..ac022989b19a 100644 --- a/components/driver/mcpwm/mcpwm_com.c +++ b/components/driver/mcpwm/mcpwm_com.c @@ -43,6 +43,7 @@ mcpwm_group_t *mcpwm_acquire_group_handle(int group_id) new_group = true; s_platform.groups[group_id] = group; group->group_id = group_id; + group->intr_priority = -1; group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; // enable APB to access MCPWM registers periph_module_enable(mcpwm_periph_signals.groups[group_id].module); @@ -96,6 +97,32 @@ void mcpwm_release_group_handle(mcpwm_group_t *group) } } +esp_err_t mcpwm_check_intr_priority(mcpwm_group_t *group, int intr_priority) +{ + esp_err_t ret = ESP_OK; + bool intr_priority_conflict = false; + portENTER_CRITICAL(&group->spinlock); + if (group->intr_priority == -1) { + group->intr_priority = intr_priority; + } else if (intr_priority != 0) { + intr_priority_conflict = (group->intr_priority != intr_priority); + } + portEXIT_CRITICAL(&group->spinlock); + ESP_RETURN_ON_FALSE(!intr_priority_conflict, ESP_ERR_INVALID_STATE, TAG, "intr_priority conflict, already is %d but attempt to %d", group->intr_priority, intr_priority); + return ret; +} + +int mcpwm_get_intr_priority_flag(mcpwm_group_t *group) +{ + int isr_flags = 0; + if (group->intr_priority) { + isr_flags |= 1 << (group->intr_priority); + } else { + isr_flags |= MCPWM_ALLOW_INTR_PRIORITY_MASK; + } + return isr_flags; +} + esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, soc_module_clk_t clk_src) { esp_err_t ret = ESP_OK; diff --git a/components/driver/mcpwm/mcpwm_fault.c b/components/driver/mcpwm/mcpwm_fault.c index 4ec4b13ca31d..725e36dcb276 100644 --- a/components/driver/mcpwm/mcpwm_fault.c +++ b/components/driver/mcpwm/mcpwm_fault.c @@ -93,6 +93,10 @@ esp_err_t mcpwm_new_gpio_fault(const mcpwm_gpio_fault_config_t *config, mcpwm_fa ESP_GOTO_ON_FALSE(config && ret_fault, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); ESP_GOTO_ON_FALSE(config->group_id < SOC_MCPWM_GROUPS && config->group_id >= 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid group ID:%d", config->group_id); + if (config->intr_priority) { + ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, + TAG, "invalid interrupt priority:%d", config->intr_priority); + } fault = heap_caps_calloc(1, sizeof(mcpwm_gpio_fault_t), MCPWM_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(fault, ESP_ERR_NO_MEM, err, TAG, "no mem for gpio fault"); @@ -103,6 +107,10 @@ esp_err_t mcpwm_new_gpio_fault(const mcpwm_gpio_fault_config_t *config, mcpwm_fa mcpwm_hal_context_t *hal = &group->hal; int fault_id = fault->fault_id; + // if interrupt priority specified before, it cannot be changed until the group is released + // check if the new priority specified consistents with the old one + ESP_GOTO_ON_ERROR(mcpwm_check_intr_priority(group, config->intr_priority), err, TAG, "set group intrrupt priority failed"); + // GPIO configuration gpio_config_t gpio_conf = { .intr_type = GPIO_INTR_DISABLE, @@ -245,6 +253,7 @@ esp_err_t mcpwm_fault_register_event_callbacks(mcpwm_fault_handle_t fault, const if (!gpio_fault->intr) { // we want the interrupt service to be enabled after allocation successfully int isr_flags = MCPWM_INTR_ALLOC_FLAG & ~ESP_INTR_FLAG_INTRDISABLED; + isr_flags |= mcpwm_get_intr_priority_flag(group); ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(mcpwm_periph_signals.groups[group_id].irq_id, isr_flags, (uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), MCPWM_LL_EVENT_FAULT_MASK(fault_id), mcpwm_gpio_fault_default_isr, gpio_fault, &gpio_fault->intr), TAG, "install interrupt service for gpio fault failed"); diff --git a/components/driver/mcpwm/mcpwm_oper.c b/components/driver/mcpwm/mcpwm_oper.c index 61851d171e9f..8962b10dcd6e 100644 --- a/components/driver/mcpwm/mcpwm_oper.c +++ b/components/driver/mcpwm/mcpwm_oper.c @@ -90,6 +90,10 @@ esp_err_t mcpwm_new_operator(const mcpwm_operator_config_t *config, mcpwm_oper_h ESP_GOTO_ON_FALSE(config && ret_oper, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); ESP_GOTO_ON_FALSE(config->group_id < SOC_MCPWM_GROUPS && config->group_id >= 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid group ID:%d", config->group_id); + if (config->intr_priority) { + ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, + TAG, "invalid interrupt priority:%d", config->intr_priority); + } oper = heap_caps_calloc(1, sizeof(mcpwm_oper_t), MCPWM_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(oper, ESP_ERR_NO_MEM, err, TAG, "no mem for operator"); @@ -100,6 +104,10 @@ esp_err_t mcpwm_new_operator(const mcpwm_operator_config_t *config, mcpwm_oper_h mcpwm_hal_context_t *hal = &group->hal; int oper_id = oper->oper_id; + // if interrupt priority specified before, it cannot be changed until the group is released + // check if the new priority specified consistents with the old one + ESP_GOTO_ON_ERROR(mcpwm_check_intr_priority(group, config->intr_priority), err, TAG, "set group intrrupt priority failed"); + // reset MCPWM operator mcpwm_hal_operator_reset(hal, oper_id); @@ -240,6 +248,7 @@ esp_err_t mcpwm_operator_register_event_callbacks(mcpwm_oper_handle_t oper, cons if (!oper->intr) { // we want the interrupt service to be enabled after allocation successfully int isr_flags = MCPWM_INTR_ALLOC_FLAG & ~ ESP_INTR_FLAG_INTRDISABLED; + isr_flags |= mcpwm_get_intr_priority_flag(group); ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(mcpwm_periph_signals.groups[group_id].irq_id, isr_flags, (uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), MCPWM_LL_EVENT_OPER_MASK(oper_id), mcpwm_operator_default_isr, oper, &oper->intr), TAG, "install interrupt service for operator failed"); diff --git a/components/driver/mcpwm/mcpwm_private.h b/components/driver/mcpwm/mcpwm_private.h index c91666be6073..d8e5f967231b 100644 --- a/components/driver/mcpwm/mcpwm_private.h +++ b/components/driver/mcpwm/mcpwm_private.h @@ -29,11 +29,13 @@ extern "C" { #endif #if CONFIG_MCPWM_ISR_IRAM_SAFE -#define MCPWM_INTR_ALLOC_FLAG (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_IRAM) +#define MCPWM_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_IRAM) #else -#define MCPWM_INTR_ALLOC_FLAG (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED) +#define MCPWM_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED) #endif +#define MCPWM_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED + #define MCPWM_PERIPH_CLOCK_PRE_SCALE (2) #define MCPWM_PM_LOCK_NAME_LEN_MAX 16 @@ -54,6 +56,7 @@ typedef struct mcpwm_cap_channel_t mcpwm_cap_channel_t; struct mcpwm_group_t { int group_id; // group ID, index from 0 + int intr_priority; // MCPWM interrupt priority mcpwm_hal_context_t hal; // HAL instance is at group level portMUX_TYPE spinlock; // group level spinlock uint32_t resolution_hz; // MCPWM group clock resolution @@ -232,6 +235,8 @@ struct mcpwm_cap_channel_t { mcpwm_group_t *mcpwm_acquire_group_handle(int group_id); void mcpwm_release_group_handle(mcpwm_group_t *group); +esp_err_t mcpwm_check_intr_priority(mcpwm_group_t *group, int intr_priority); +int mcpwm_get_intr_priority_flag(mcpwm_group_t *group); esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, soc_module_clk_t clk_src); #ifdef __cplusplus diff --git a/components/driver/mcpwm/mcpwm_timer.c b/components/driver/mcpwm/mcpwm_timer.c index 34aa1bd3e664..6a3ea03a1b65 100644 --- a/components/driver/mcpwm/mcpwm_timer.c +++ b/components/driver/mcpwm/mcpwm_timer.c @@ -91,6 +91,10 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle ESP_GOTO_ON_FALSE(config && ret_timer, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); ESP_GOTO_ON_FALSE(config->group_id < SOC_MCPWM_GROUPS && config->group_id >= 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid group ID:%d", config->group_id); + if (config->intr_priority) { + ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, + TAG, "invalid interrupt priority:%d", config->intr_priority); + } timer = heap_caps_calloc(1, sizeof(mcpwm_timer_t), MCPWM_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(timer, ESP_ERR_NO_MEM, err, TAG, "no mem for timer"); @@ -100,6 +104,11 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle int group_id = group->group_id; mcpwm_hal_context_t *hal = &group->hal; int timer_id = timer->timer_id; + + // if interrupt priority specified before, it cannot be changed until the group is released + // check if the new priority specified consistents with the old one + ESP_GOTO_ON_ERROR(mcpwm_check_intr_priority(group, config->intr_priority), err, TAG, "set group intrrupt priority failed"); + // select the clock source ESP_GOTO_ON_ERROR(mcpwm_select_periph_clock(group, (soc_module_clk_t)config->clk_src), err, TAG, "set group clock failed"); // reset the timer to a determined state @@ -191,6 +200,7 @@ esp_err_t mcpwm_timer_register_event_callbacks(mcpwm_timer_handle_t timer, const if (!timer->intr) { ESP_RETURN_ON_FALSE(timer->fsm == MCPWM_TIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state"); int isr_flags = MCPWM_INTR_ALLOC_FLAG; + isr_flags |= mcpwm_get_intr_priority_flag(group); ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(mcpwm_periph_signals.groups[group_id].irq_id, isr_flags, (uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), MCPWM_LL_EVENT_TIMER_MASK(timer_id), mcpwm_timer_default_isr, timer, &timer->intr), TAG, "install interrupt service for timer failed"); diff --git a/components/driver/pcnt/pulse_cnt.c b/components/driver/pcnt/pulse_cnt.c index 7fd1ffa965f3..952daddb072d 100644 --- a/components/driver/pcnt/pulse_cnt.c +++ b/components/driver/pcnt/pulse_cnt.c @@ -197,13 +197,13 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re int group_id = group->group_id; int unit_id = unit->unit_id; - // if interrupt priority specified before, it cannot be changed until `pcnt_release_group_handle()` called - // so we have to check if the new priority specified consistents with the old one + // if interrupt priority specified before, it cannot be changed until the group is released + // check if the new priority specified consistents with the old one bool intr_priority_conflict = false; portENTER_CRITICAL(&group->spinlock); if (group->intr_priority == -1) { group->intr_priority = config->intr_priority; - } else { + } else if (config->intr_priority != 0) { intr_priority_conflict = (group->intr_priority != config->intr_priority); } portEXIT_CRITICAL(&group->spinlock); diff --git a/components/driver/test_apps/mcpwm/main/CMakeLists.txt b/components/driver/test_apps/mcpwm/main/CMakeLists.txt index 2ca12ca39e3a..6cf3fe2cf4c1 100644 --- a/components/driver/test_apps/mcpwm/main/CMakeLists.txt +++ b/components/driver/test_apps/mcpwm/main/CMakeLists.txt @@ -6,6 +6,7 @@ set(srcs "test_app_main.c" "test_mcpwm_oper.c" "test_mcpwm_sync.c" "test_mcpwm_timer.c" + "test_mcpwm_common.c" "test_mcpwm_utils.c") if(CONFIG_MCPWM_ISR_IRAM_SAFE) diff --git a/components/driver/test_apps/mcpwm/main/test_mcpwm_common.c b/components/driver/test_apps/mcpwm/main/test_mcpwm_common.c new file mode 100644 index 000000000000..bd08856dec71 --- /dev/null +++ b/components/driver/test_apps/mcpwm/main/test_mcpwm_common.c @@ -0,0 +1,125 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "unity.h" +#include "esp_private/mcpwm.h" +#include "test_mcpwm_utils.h" +#include "driver/mcpwm_prelude.h" + +TEST_CASE("mcpwm_set_interrupt_priority", "[mcpwm]") +{ + printf("install timer\r\n"); + mcpwm_timer_config_t timer_config = { + .group_id = 0, + .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT, + .resolution_hz = 1 * 1000 * 1000, + .period_ticks = 20 * 1000, + .count_mode = MCPWM_TIMER_COUNT_MODE_UP, + .intr_priority = 3, + }; + mcpwm_timer_handle_t timer = NULL; + TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer)); + printf("register event callbacks\r\n"); + mcpwm_timer_event_callbacks_t timer_cbs = { + .on_stop = NULL, + .on_full = NULL, + .on_empty = NULL, + }; + TEST_ESP_OK(mcpwm_timer_register_event_callbacks(timer, &timer_cbs, NULL)); + timer_config.intr_priority = 1; + mcpwm_timer_handle_t timer2 = NULL; + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_new_timer(&timer_config, &timer2)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, mcpwm_timer_register_event_callbacks(timer2, &timer_cbs, NULL)); + + printf("install operator\r\n"); + mcpwm_operator_config_t operator_config = { + .group_id = 0, + .intr_priority = 0, + }; + mcpwm_oper_handle_t oper = NULL; + TEST_ESP_OK(mcpwm_new_operator(&operator_config, &oper)); + printf("register event callbacks\r\n"); + mcpwm_operator_event_callbacks_t oper_cbs = { + .on_brake_cbc = NULL, + .on_brake_ost = NULL, + }; + TEST_ESP_OK(mcpwm_operator_register_event_callbacks(oper, &oper_cbs, NULL)); + operator_config.intr_priority = 1; + mcpwm_oper_handle_t oper2 = NULL; + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_new_operator(&operator_config, &oper2)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, mcpwm_operator_register_event_callbacks(oper2, &oper_cbs, NULL)); + + printf("install comparator\r\n"); + mcpwm_comparator_config_t comparator_config = { + .intr_priority = 0, + }; + mcpwm_cmpr_handle_t comparator = NULL; + TEST_ESP_OK(mcpwm_new_comparator(oper, &comparator_config, &comparator)); + TEST_ESP_OK(mcpwm_operator_connect_timer(oper, timer)); + printf("register event callback\r\n"); + mcpwm_comparator_event_callbacks_t comparator_cbs = { + .on_reach = NULL, + }; + TEST_ESP_OK(mcpwm_comparator_register_event_callbacks(comparator, &comparator_cbs, NULL)); + comparator_config.intr_priority = 1; + mcpwm_cmpr_handle_t comparator2 = NULL; + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_new_comparator(oper, &comparator_config, &comparator2)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, mcpwm_comparator_register_event_callbacks(comparator2, &comparator_cbs, NULL)); + + printf("install gpio fault\r\n"); + const int fault_gpio = 0; + mcpwm_fault_handle_t fault = NULL; + mcpwm_gpio_fault_config_t gpio_fault_config = { + .group_id = 0, + .gpio_num = fault_gpio, + .intr_priority = 0, + }; + TEST_ESP_OK(mcpwm_new_gpio_fault(&gpio_fault_config, &fault)); + + printf("register event callback\r\n"); + mcpwm_fault_event_callbacks_t fault_cbs = { + .on_fault_enter = NULL, + .on_fault_exit = NULL, + }; + TEST_ESP_OK(mcpwm_fault_register_event_callbacks(fault, &fault_cbs, NULL)); + gpio_fault_config.intr_priority = 1; + mcpwm_fault_handle_t fault2 = NULL; + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_new_gpio_fault(&gpio_fault_config, &fault2)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, mcpwm_fault_register_event_callbacks(fault2, &fault_cbs, NULL)); + + printf("install capture timer\r\n"); + mcpwm_cap_timer_handle_t cap_timer = NULL; + mcpwm_capture_timer_config_t cap_timer_config = { + .clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT, + .group_id = 0, + }; + TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timer)); + printf("install capture\r\n"); + mcpwm_cap_channel_handle_t cap_channel = NULL; + mcpwm_capture_channel_config_t cap_chan_config = { + .gpio_num = -1, + .prescale = 2, + .intr_priority = 3, + }; + TEST_ESP_OK(mcpwm_new_capture_channel(cap_timer, &cap_chan_config, &cap_channel)); + + printf("register event callback\r\n"); + mcpwm_capture_event_callbacks_t cap_cbs = { + .on_cap = NULL, + }; + TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(cap_channel, &cap_cbs, NULL)); + cap_chan_config.intr_priority = 1; + mcpwm_cap_channel_handle_t cap_channel2 = NULL; + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_new_capture_channel(cap_timer, &cap_chan_config, &cap_channel2)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, mcpwm_capture_channel_register_event_callbacks(cap_channel2, &cap_cbs, NULL)); + + printf("delete all mcpwm objects\r\n"); + TEST_ESP_OK(mcpwm_del_comparator(comparator)); + TEST_ESP_OK(mcpwm_del_operator(oper)); + TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel)); + TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer)); + TEST_ESP_OK(mcpwm_del_timer(timer)); + TEST_ESP_OK(mcpwm_del_fault(fault)); +} 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 9fefc911f311..f4a6fef3865c 100644 --- a/components/driver/test_apps/mcpwm/main/test_mcpwm_gen.c +++ b/components/driver/test_apps/mcpwm/main/test_mcpwm_gen.c @@ -767,6 +767,7 @@ TEST_CASE("mcpwm_duty_empty_full", "[mcpwm]") TEST_CASE("mcpwm_generator_action_on_fault_trigger_event", "[mcpwm]") { const int generator_gpio = 0; + const int fault_gpio_num[3] = {2, 4, 5}; printf("create timer and operator\r\n"); mcpwm_operator_config_t oper_config = { @@ -777,17 +778,16 @@ TEST_CASE("mcpwm_generator_action_on_fault_trigger_event", "[mcpwm]") 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; + mcpwm_gpio_fault_config_t gpio_trigger_config = { + .group_id = 0, + .flags.active_level = 1, + .flags.pull_down = 1, + .flags.pull_up = 0, + .flags.io_loop_back = 1, // so that we can write the GPIO value by GPIO driver + }; 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])); + gpio_trigger_config.gpio_num = fault_gpio_num[i]; + TEST_ESP_OK(mcpwm_new_gpio_fault(&gpio_trigger_config, &gpio_faults[i])); } printf("create generator\r\n"); @@ -808,14 +808,14 @@ TEST_CASE("mcpwm_generator_action_on_fault_trigger_event", "[mcpwm]") 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); + gpio_set_level(fault_gpio_num[0], 1); + gpio_set_level(fault_gpio_num[0], 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); + gpio_set_level(fault_gpio_num[1], 1); + gpio_set_level(fault_gpio_num[1], 0); TEST_ASSERT_EQUAL(0, gpio_get_level(generator_gpio)); vTaskDelay(pdMS_TO_TICKS(10)); diff --git a/components/driver/test_apps/mcpwm/main/test_mcpwm_utils.c b/components/driver/test_apps/mcpwm/main/test_mcpwm_utils.c index d1c933b62ab7..0a9a03f80f27 100644 --- a/components/driver/test_apps/mcpwm/main/test_mcpwm_utils.c +++ b/components/driver/test_apps/mcpwm/main/test_mcpwm_utils.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 */ diff --git a/docs/en/api-reference/peripherals/mcpwm.rst b/docs/en/api-reference/peripherals/mcpwm.rst index b8d4712022a6..2743a6c9baa8 100644 --- a/docs/en/api-reference/peripherals/mcpwm.rst +++ b/docs/en/api-reference/peripherals/mcpwm.rst @@ -65,6 +65,7 @@ MCPWM Timers You can allocate a MCPWM timer object by calling :cpp:func:`mcpwm_new_timer` function, with a configuration structure :cpp:type:`mcpwm_timer_config_t` as the parameter. The configuration structure is defined as: - :cpp:member:`mcpwm_timer_config_t::group_id` specifies the MCPWM group ID. The ID should belong to [0, :c:macro:`SOC_MCPWM_GROUPS` - 1] range. Please note, timers located in different groups are totally independent. +- :cpp:member:`mcpwm_timer_config_t::intr_priority` sets the priority of the interrupt. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority. - :cpp:member:`mcpwm_timer_config_t::clk_src` sets the clock source of the timer. - :cpp:member:`mcpwm_timer_config_t::resolution_hz` sets the expected resolution of the timer. The driver internally will set a proper divider based on the clock source and the resolution. - :cpp:member:`mcpwm_timer_config_t::count_mode` sets the count mode of the timer. @@ -82,6 +83,7 @@ MCPWM Operators You can allocate a MCPWM operator object by calling :cpp:func:`mcpwm_new_operator` function, with a configuration structure :cpp:type:`mcpwm_operator_config_t` as the parameter. The configuration structure is defined as: - :cpp:member:`mcpwm_operator_config_t::group_id` specifies the MCPWM group ID. The ID should belong to [0, :c:macro:`SOC_MCPWM_GROUPS` - 1] range. Please note, operators located in different groups are totally independent. +- :cpp:member:`mcpwm_operator_config_t::intr_priority` sets the priority of the interrupt. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority. - :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_tez` sets whether to update the generator action when the timer counts to zero. Here and below, the timer refers to the one that is connected to the operator by :cpp:func:`mcpwm_operator_connect_timer`. - :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_tep` sets whether to update the generator action when the timer counts to peak. - :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_sync` sets whether to update the generator action when the timer takes a sync signal. @@ -98,6 +100,7 @@ MCPWM Comparators You can allocate a MCPWM comparator object by calling the :cpp:func:`mcpwm_new_comparator` function, with a MCPWM operator handle and configuration structure :cpp:type:`mcpwm_comparator_config_t` as the parameter. The operator handle is created by :cpp:func:`mcpwm_new_operator`. The configuration structure is defined as: +- :cpp:member:`mcpwm_comparator_config_t::intr_priority` sets the priority of the interrupt. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority. - :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tez` sets whether to update the compare threshold when the timer counts to zero. - :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tep` sets whether to update the compare threshold when the timer counts to the peak. - :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_sync` sets whether to update the compare threshold when the timer takes a sync signal. @@ -129,6 +132,7 @@ There are two types of faults: A fault signal reflected from the GPIO and a faul To allocate a GPIO fault object, you can call the :cpp:func:`mcpwm_new_gpio_fault` function, with the configuration structure :cpp:type:`mcpwm_gpio_fault_config_t` as the parameter. The configuration structure is defined as: - :cpp:member:`mcpwm_gpio_fault_config_t::group_id` sets the MCPWM group ID. The ID should belong to [0, :c:macro:`SOC_MCPWM_GROUPS` - 1] range. Please note, GPIO faults located in different groups are totally independent, i.e., GPIO faults in group 0 can not be detected by the operator in group 1. +- :cpp:member:`mcpwm_gpio_fault_config_t::intr_priority` sets the priority of the interrupt. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority. - :cpp:member:`mcpwm_gpio_fault_config_t::gpio_num` sets the GPIO number used by the fault. - :cpp:member:`mcpwm_gpio_fault_config_t::active_level` sets the active level of the fault signal. - :cpp:member:`mcpwm_gpio_fault_config_t::pull_up` and :cpp:member:`mcpwm_gpio_fault_config_t::pull_down` set whether to pull up and/or pull down the GPIO internally. @@ -184,6 +188,7 @@ The :cpp:func:`mcpwm_new_capture_timer` will return a pointer to the allocated c Next, to allocate a capture channel, you can call the :cpp:func:`mcpwm_new_capture_channel` function, with a capture timer handle and configuration structure :cpp:type:`mcpwm_capture_channel_config_t` as the parameter. The configuration structure is defined as: +- :cpp:member:`mcpwm_capture_channel_config_t::intr_priority` sets the priority of the interrupt. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority. - :cpp:member:`mcpwm_capture_channel_config_t::gpio_num` sets the GPIO number used by the capture channel. - :cpp:member:`mcpwm_capture_channel_config_t::prescale` sets the prescaler of the input signal. - :cpp:member:`mcpwm_capture_channel_config_t::pos_edge` and :cpp:member:`mcpwm_capture_channel_config_t::neg_edge` set whether to capture on the positive and/or negative edge of the input signal. @@ -195,6 +200,15 @@ The :cpp:func:`mcpwm_new_capture_channel` will return a pointer to the allocated On the contrary, calling :cpp:func:`mcpwm_del_capture_channel` and :cpp:func:`mcpwm_del_capture_timer` will free the allocated capture channel and timer object accordingly. +MCPWM interrupt priority +~~~~~~~~~~~~~~~~~~~~~~~~ + +MCPWM allows configuring interrupts separately for timer, operator, comparator, fault, and capture events. The interrupt priority is determined by the respective ``config_t::intr_priority``. Additionally, events within the same MCPWM group share a common interrupt source. When registering multiple interrupt events, the interrupt priorities need to remain consistent. + +.. note:: + + When registering multiple interrupt events within an MCPWM group, the driver will use the interrupt priority of the first registered event as the MCPWM group's interrupt priority. + .. _mcpwm-timer-operations-and-events: diff --git a/docs/en/api-reference/peripherals/pcnt.rst b/docs/en/api-reference/peripherals/pcnt.rst index 28f63e302ea2..a91f000550d6 100644 --- a/docs/en/api-reference/peripherals/pcnt.rst +++ b/docs/en/api-reference/peripherals/pcnt.rst @@ -46,7 +46,7 @@ To install a PCNT unit, there's a configuration structure that needs to be given - :cpp:member:`pcnt_unit_config_t::low_limit` and :cpp:member:`pcnt_unit_config_t::high_limit` specify the range for the internal hardware counter. The counter will reset to zero automatically when it crosses either the high or low limit. - :cpp:member:`pcnt_unit_config_t::accum_count` sets whether to create an internal accumulator for the counter. This is helpful when you want to extend the counter's width, which by default is 16bit at most, defined in the hardware. See also :ref:`pcnt-compensate-overflow-loss` for how to use this feature to compensate the overflow loss. -- :cpp:member:`pcnt_unit_config_t::intr_priority` sets the priority of the timer interrupt. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority. +- :cpp:member:`pcnt_unit_config_t::intr_priority` sets the priority of the interrupt. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority. .. note:: diff --git a/docs/zh_CN/api-reference/peripherals/mcpwm.rst b/docs/zh_CN/api-reference/peripherals/mcpwm.rst index 374b591008a5..3a39fb920d9f 100644 --- a/docs/zh_CN/api-reference/peripherals/mcpwm.rst +++ b/docs/zh_CN/api-reference/peripherals/mcpwm.rst @@ -65,6 +65,7 @@ MCPWM 定时器 调用 :cpp:func:`mcpwm_new_timer` 函数,以配置结构体 :cpp:type:`mcpwm_timer_config_t` 为参数,分配一个 MCPWM 定时器为对象。结构体定义为: - :cpp:member:`mcpwm_timer_config_t::group_id` 指定 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。需注意,位于不同组的定时器彼此独立。 +- :cpp:member:`mcpwm_timer_config_t::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。 - :cpp:member:`mcpwm_timer_config_t::clk_src` 设置定时器的时钟源。 - :cpp:member:`mcpwm_timer_config_t::resolution_hz` 设置定时器的预期分辨率。内部驱动将根据时钟源和分辨率设置合适的分频器。 - :cpp:member:`mcpwm_timer_config_t::count_mode` 设置定时器的计数模式。 @@ -82,6 +83,7 @@ MCPWM 操作器 调用 :cpp:func:`mcpwm_new_operator` 函数,以配置结构体 :cpp:type:`mcpwm_operator_config_t` 为参数,分配一个 MCPWM 操作器为对象。结构体定义为: - :cpp:member:`mcpwm_operator_config_t::group_id` 指定 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。需注意,位于不同组的操作器彼此独立。 +- :cpp:member:`mcpwm_operator_config_t::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。 - :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_tez` 设置是否在定时器计数为零时更新生成器操作。此处及下文提到的定时器指通过 :cpp:func:`mcpwm_operator_connect_timer` 连接到操作器的定时器。 - :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_tep` 设置当定时器计数达到峰值时是否更新生成器操作。 - :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_sync` 设置当定时器接收同步信号时是否更新生成器操作。 @@ -98,6 +100,7 @@ MCPWM 比较器 调用 :cpp:func:`mcpwm_new_comparator` 函数,以一个 MCPWM 操作器句柄和配置结构体 :cpp:type:`mcpwm_comparator_config_t` 为参数,分配一个 MCPWM 比较器为对象。操作器句柄由 :cpp:func:`mcpwm_new_operator` 生成,结构体定义为: +- :cpp:member:`mcpwm_comparator_config_t::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。 - :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tez` 设置当定时器计数为零时是否更新比较阈值。 - :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tep` 设置当定时器计数达到峰值时是否更新比较阈值。 - :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_sync` 设置当定时器接收同步信号时是否更新比较阈值。 @@ -129,6 +132,7 @@ MCPWM 故障分为两种类型:来自 GPIO 的故障信号和软件故障。 调用 :cpp:func:`mcpwm_new_gpio_fault` 函数,以配置结构体 :cpp:type:`mcpwm_gpio_fault_config_t` 为参数,分配一个 GPIO 故障为对象。结构体定义为: - :cpp:member:`mcpwm_gpio_fault_config_t::group_id` 设置 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。需注意,位于不同组的 GPIO 故障彼此独立,也就是说,1 组的操作器无法检测到 0 组的 GPIO 故障。 +- :cpp:member:`mcpwm_gpio_fault_config_t::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。 - :cpp:member:`mcpwm_gpio_fault_config_t::gpio_num` 设置故障所使用的 GPIO 编号。 - :cpp:member:`mcpwm_gpio_fault_config_t::active_level` 设置故障信号的有效电平。 - :cpp:member:`mcpwm_gpio_fault_config_t::pull_up` 和 :cpp:member:`mcpwm_gpio_fault_config_t::pull_down` 设置是否在内部拉高和/或拉低 GPIO。 @@ -184,6 +188,7 @@ MCPWM 组有一个专用定时器,用于捕获特定事件发生时的时间 接下来,可以调用 :cpp:func:`mcpwm_new_capture_channel` 函数,以一个捕获定时器句柄和配置结构体 :cpp:type:`mcpwm_capture_channel_config_t` 为参数,分配一个捕获通道。结构体定义为: +- :cpp:member:`mcpwm_capture_channel_config_t::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。 - :cpp:member:`mcpwm_capture_channel_config_t::gpio_num` 设置捕获通道使用的 GPIO 编号。 - :cpp:member:`mcpwm_capture_channel_config_t::prescale` 设置输入信号的预分频器。 - :cpp:member:`mcpwm_capture_channel_config_t::pos_edge` 和 :cpp:member:`mcpwm_capture_channel_config_t::neg_edge` 设置是否在输入信号的上升沿和/或下降沿捕获时间戳。 @@ -195,6 +200,15 @@ MCPWM 组有一个专用定时器,用于捕获特定事件发生时的时间 反之,调用 :cpp:func:`mcpwm_del_capture_channel` 和 :cpp:func:`mcpwm_del_capture_timer` 将释放已分配的捕获通道和定时器。 +MCPWM 中断优先级 +~~~~~~~~~~~~~~~~~~~~~~~~ + +MCPWM 允许为 定时器、操作器、比较器、故障以及捕获事件分别配置中断,中断优先级由各自的 ``config_t::intr_priority`` 决定。且同一个 MCPWM 组中的事件共享同一个中断源。注册多个中断事件时,中断优先级需要保持一致。 + +.. note:: + + MCPWM 组注册多个中断事件时,驱动将以第一个事件的中断优先级作为 MCPWM 组的中断优先级。 + .. _mcpwm-timer-operations-and-events: