diff --git a/components/esp_driver_mcpwm/src/mcpwm_cap.c b/components/esp_driver_mcpwm/src/mcpwm_cap.c index fd0365ee279..e85ec9b4119 100644 --- a/components/esp_driver_mcpwm/src/mcpwm_cap.c +++ b/components/esp_driver_mcpwm/src/mcpwm_cap.c @@ -275,10 +275,6 @@ 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 interrupt 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); @@ -293,6 +289,7 @@ esp_err_t mcpwm_new_capture_channel(mcpwm_cap_timer_handle_t cap_timer, const mc cap_chan->gpio_num = config->gpio_num; cap_chan->fsm = MCPWM_CAP_CHAN_FSM_INIT; + cap_chan->intr_priority = config->intr_priority; *ret_cap_channel = cap_chan; ESP_LOGD(TAG, "new capture channel (%d,%d) at %p", group->group_id, cap_chan_id, cap_chan); @@ -384,11 +381,18 @@ esp_err_t mcpwm_capture_channel_register_event_callbacks(mcpwm_cap_channel_handl // lazy install interrupt service 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(soc_mcpwm_signals[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"); + int isr_flags = MCPWM_INTR_ALLOC_FLAG | + (cap_channel->intr_priority ? (1 << cap_channel->intr_priority) : MCPWM_ALLOW_INTR_PRIORITY_MASK); + esp_intr_alloc_info_t intr_info = { + .source = soc_mcpwm_signals[group_id].irq_id, + .flags = isr_flags, + .intrstatusreg = (uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), + .intrstatusmask = MCPWM_LL_EVENT_CAPTURE(cap_chan_id), + .handler = mcpwm_capture_default_isr, + .arg = cap_channel, + .bind_by.name = soc_mcpwm_signals[group_id].module_name, + }; + ESP_RETURN_ON_ERROR(esp_intr_alloc_info(&intr_info, &cap_channel->intr), TAG, "install interrupt service for cap channel failed"); } portENTER_CRITICAL(&group->spinlock); diff --git a/components/esp_driver_mcpwm/src/mcpwm_cmpr.c b/components/esp_driver_mcpwm/src/mcpwm_cmpr.c index 56c4fee11bd..f7140c53680 100644 --- a/components/esp_driver_mcpwm/src/mcpwm_cmpr.c +++ b/components/esp_driver_mcpwm/src/mcpwm_cmpr.c @@ -112,16 +112,13 @@ esp_err_t mcpwm_new_comparator(mcpwm_oper_handle_t oper, const mcpwm_comparator_ int oper_id = oper->oper_id; int cmpr_id = cmpr->base.cmpr_id; - // if interrupt priority specified before, it cannot be changed until the group is released - // check if the new priority specified consistent with the old one - ESP_GOTO_ON_ERROR(mcpwm_check_intr_priority(group, config->intr_priority), err, TAG, "set group interrupt 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); // fill in other comparator members cmpr->base.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + cmpr->intr_priority = config->intr_priority; *ret_cmpr = &cmpr->base; ESP_LOGD(TAG, "new operator comparator (%d,%d,%d) at %p", group->group_id, oper_id, cmpr_id, cmpr); return ESP_OK; @@ -233,11 +230,18 @@ esp_err_t mcpwm_comparator_register_event_callbacks(mcpwm_cmpr_handle_t cmpr, co // lazy install interrupt service if (!oper_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(soc_mcpwm_signals[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, oper_cmpr, &oper_cmpr->intr), TAG, "install interrupt service for comparator failed"); + int isr_flags = (MCPWM_INTR_ALLOC_FLAG & ~ESP_INTR_FLAG_INTRDISABLED) | + (oper_cmpr->intr_priority ? (1 << oper_cmpr->intr_priority) : MCPWM_ALLOW_INTR_PRIORITY_MASK); + esp_intr_alloc_info_t intr_info = { + .source = soc_mcpwm_signals[group_id].irq_id, + .flags = isr_flags, + .intrstatusreg = (uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), + .intrstatusmask = MCPWM_LL_EVENT_CMP_EQUAL(oper_id, cmpr_id), + .handler = mcpwm_comparator_default_isr, + .arg = oper_cmpr, + .bind_by.name = soc_mcpwm_signals[group_id].module_name, + }; + ESP_RETURN_ON_ERROR(esp_intr_alloc_info(&intr_info, &oper_cmpr->intr), TAG, "install interrupt service for comparator failed"); } portENTER_CRITICAL(&group->spinlock); diff --git a/components/esp_driver_mcpwm/src/mcpwm_com.c b/components/esp_driver_mcpwm/src/mcpwm_com.c index bd3de91f0a6..2c186c726b6 100644 --- a/components/esp_driver_mcpwm/src/mcpwm_com.c +++ b/components/esp_driver_mcpwm/src/mcpwm_com.c @@ -35,7 +35,6 @@ 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; #if MCPWM_USE_RETENTION_LINK sleep_retention_module_t module = mcpwm_reg_retention_info[group_id].retention_module; @@ -131,32 +130,6 @@ 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/esp_driver_mcpwm/src/mcpwm_fault.c b/components/esp_driver_mcpwm/src/mcpwm_fault.c index 543d9a555e0..b8ae3514486 100644 --- a/components/esp_driver_mcpwm/src/mcpwm_fault.c +++ b/components/esp_driver_mcpwm/src/mcpwm_fault.c @@ -86,10 +86,6 @@ 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 interrupt priority failed"); - // GPIO configuration gpio_func_sel(config->gpio_num, PIN_FUNC_GPIO); gpio_input_enable(config->gpio_num); @@ -107,6 +103,7 @@ esp_err_t mcpwm_new_gpio_fault(const mcpwm_gpio_fault_config_t *config, mcpwm_fa // fill in other operator members fault->base.type = MCPWM_FAULT_TYPE_GPIO; fault->gpio_num = config->gpio_num; + fault->intr_priority = config->intr_priority; fault->base.del = mcpwm_del_gpio_fault; *ret_fault = &fault->base; ESP_LOGD(TAG, "new gpio fault (%d,%d) at %p, GPIO: %d", group_id, fault_id, fault, config->gpio_num); @@ -229,11 +226,18 @@ esp_err_t mcpwm_fault_register_event_callbacks(mcpwm_fault_handle_t fault, const // lazy install interrupt service 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(soc_mcpwm_signals[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"); + int isr_flags = (MCPWM_INTR_ALLOC_FLAG & ~ESP_INTR_FLAG_INTRDISABLED) | + (gpio_fault->intr_priority ? (1 << gpio_fault->intr_priority) : MCPWM_ALLOW_INTR_PRIORITY_MASK); + esp_intr_alloc_info_t intr_info = { + .source = soc_mcpwm_signals[group_id].irq_id, + .flags = isr_flags, + .intrstatusreg = (uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), + .intrstatusmask = MCPWM_LL_EVENT_FAULT_MASK(fault_id), + .handler = mcpwm_gpio_fault_default_isr, + .arg = gpio_fault, + .bind_by.name = soc_mcpwm_signals[group_id].module_name, + }; + ESP_RETURN_ON_ERROR(esp_intr_alloc_info(&intr_info, &gpio_fault->intr), TAG, "install interrupt service for gpio fault failed"); } // different mcpwm events share the same interrupt control register diff --git a/components/esp_driver_mcpwm/src/mcpwm_oper.c b/components/esp_driver_mcpwm/src/mcpwm_oper.c index 9160a91e333..f1c4c0325c7 100644 --- a/components/esp_driver_mcpwm/src/mcpwm_oper.c +++ b/components/esp_driver_mcpwm/src/mcpwm_oper.c @@ -82,10 +82,6 @@ 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 interrupt priority failed"); - // reset MCPWM operator mcpwm_hal_operator_reset(hal, oper_id); @@ -103,6 +99,7 @@ esp_err_t mcpwm_new_operator(const mcpwm_operator_config_t *config, mcpwm_oper_h // fill in other operator members oper->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + oper->intr_priority = config->intr_priority; *ret_oper = oper; ESP_LOGD(TAG, "new operator (%d,%d) at %p", group_id, oper_id, oper); return ESP_OK; @@ -233,11 +230,18 @@ esp_err_t mcpwm_operator_register_event_callbacks(mcpwm_oper_handle_t oper, cons // lazy install interrupt service 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(soc_mcpwm_signals[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"); + int isr_flags = (MCPWM_INTR_ALLOC_FLAG & ~ESP_INTR_FLAG_INTRDISABLED) | + (oper->intr_priority ? (1 << oper->intr_priority) : MCPWM_ALLOW_INTR_PRIORITY_MASK); + esp_intr_alloc_info_t intr_info = { + .source = soc_mcpwm_signals[group_id].irq_id, + .flags = isr_flags, + .intrstatusreg = (uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), + .intrstatusmask = MCPWM_LL_EVENT_OPER_MASK(oper_id), + .handler = mcpwm_operator_default_isr, + .arg = oper, + .bind_by.name = soc_mcpwm_signals[group_id].module_name, + }; + ESP_RETURN_ON_ERROR(esp_intr_alloc_info(&intr_info, &oper->intr), TAG, "install interrupt service for operator failed"); } // enable/disable interrupt events diff --git a/components/esp_driver_mcpwm/src/mcpwm_private.h b/components/esp_driver_mcpwm/src/mcpwm_private.h index d918b0f4a1f..20b82a59110 100644 --- a/components/esp_driver_mcpwm/src/mcpwm_private.h +++ b/components/esp_driver_mcpwm/src/mcpwm_private.h @@ -42,9 +42,9 @@ extern "C" { #endif #if CONFIG_MCPWM_ISR_CACHE_SAFE -#define MCPWM_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_IRAM) +#define MCPWM_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED_PRIVATE | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_IRAM) #else -#define MCPWM_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED) +#define MCPWM_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED_PRIVATE | ESP_INTR_FLAG_INTRDISABLED) #endif // Use retention link only when the target supports sleep retention is enabled @@ -76,7 +76,6 @@ 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 prescale; // group prescale @@ -103,6 +102,7 @@ struct mcpwm_timer_t { mcpwm_timer_fsm_t fsm; // driver FSM portMUX_TYPE spinlock; // spin lock intr_handle_t intr; // interrupt handle + int intr_priority; // interrupt priority used by this timer uint32_t resolution_hz; // resolution of the timer uint32_t peak_ticks; // peak ticks that the timer could reach to mcpwm_timer_sync_src_t *sync_src; // timer sync_src @@ -125,6 +125,7 @@ struct mcpwm_oper_t { mcpwm_timer_t *timer; // which timer is connected to this operator portMUX_TYPE spinlock; // spin lock intr_handle_t intr; // interrupt handle + int intr_priority; // interrupt priority used by this operator mcpwm_gen_t *generators[MCPWM_LL_GET(GENERATORS_PER_OPERATOR)]; // mcpwm generator array mcpwm_oper_cmpr_t *comparators[MCPWM_LL_GET(COMPARATORS_PER_OPERATOR)]; // mcpwm operator comparator array #if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR @@ -160,6 +161,7 @@ struct mcpwm_cmpr_t { struct mcpwm_oper_cmpr_t { mcpwm_cmpr_t base; // base class intr_handle_t intr; // interrupt handle + int intr_priority; // interrupt priority used by this comparator mcpwm_compare_event_cb_t on_reach; // ISR callback function which would be invoked on timer counter reaches compare value void *user_data; // user data which would be passed to the comparator callbacks }; @@ -191,6 +193,7 @@ struct mcpwm_gpio_fault_t { int fault_id; // fault detector ID, index from 0 int gpio_num; // GPIO number of fault detector intr_handle_t intr; // interrupt handle + int intr_priority; // interrupt priority used by this fault detector mcpwm_fault_event_cb_t on_fault_enter; // ISR callback function that would be invoked when fault signal got triggered mcpwm_fault_event_cb_t on_fault_exit; // ISR callback function that would be invoked when fault signal got clear void *user_data; // user data which would be passed to the isr_cb @@ -267,14 +270,13 @@ struct mcpwm_cap_channel_t { int gpio_num; // GPIO number used by the channel mcpwm_cap_channel_fsm_t fsm; // driver FSM intr_handle_t intr; // Interrupt handle + int intr_priority; // interrupt priority used by this capture channel mcpwm_capture_event_cb_t on_cap; // Callback function which would be invoked in capture interrupt routine void *user_data; // user data which would be passed to the capture callback }; 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); esp_err_t mcpwm_set_prescale(mcpwm_group_t *group, uint32_t expect_module_resolution_hz, uint32_t module_prescale_max, uint32_t *ret_module_prescale); diff --git a/components/esp_driver_mcpwm/src/mcpwm_timer.c b/components/esp_driver_mcpwm/src/mcpwm_timer.c index fb58e76d8fb..4ca9c68ebd6 100644 --- a/components/esp_driver_mcpwm/src/mcpwm_timer.c +++ b/components/esp_driver_mcpwm/src/mcpwm_timer.c @@ -94,10 +94,6 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle mcpwm_hal_context_t *hal = &group->hal; int timer_id = timer->timer_id; - // 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 interrupt priority failed"); - // select the clock source mcpwm_timer_clock_source_t clk_src = config->clk_src ? config->clk_src : MCPWM_TIMER_CLK_SRC_DEFAULT; ESP_GOTO_ON_ERROR(mcpwm_select_periph_clock(group, (soc_module_clk_t)clk_src), err, TAG, "set group clock failed"); @@ -125,6 +121,7 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle // fill in other timer specific members timer->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; timer->fsm = MCPWM_TIMER_FSM_INIT; + timer->intr_priority = config->intr_priority; *ret_timer = timer; #if MCPWM_USE_RETENTION_LINK @@ -208,11 +205,18 @@ esp_err_t mcpwm_timer_register_event_callbacks(mcpwm_timer_handle_t timer, const // lazy install interrupt service 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(soc_mcpwm_signals[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"); + int isr_flags = MCPWM_INTR_ALLOC_FLAG | + (timer->intr_priority ? (1 << timer->intr_priority) : MCPWM_ALLOW_INTR_PRIORITY_MASK); + esp_intr_alloc_info_t intr_info = { + .source = soc_mcpwm_signals[group_id].irq_id, + .flags = isr_flags, + .intrstatusreg = (uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), + .intrstatusmask = MCPWM_LL_EVENT_TIMER_MASK(timer_id), + .handler = mcpwm_timer_default_isr, + .arg = timer, + .bind_by.name = soc_mcpwm_signals[group_id].module_name, + }; + ESP_RETURN_ON_ERROR(esp_intr_alloc_info(&intr_info, &timer->intr), TAG, "install interrupt service for timer failed"); } // enable/disable interrupt events diff --git a/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_common.c b/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_common.c index 141b518948a..18dbb21dafe 100644 --- a/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_common.c +++ b/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_common.c @@ -9,6 +9,36 @@ #include "driver/mcpwm_prelude.h" #include "test_mcpwm_utils.h" +TEST_MCPWM_CALLBACK_ATTR +static bool test_mcpwm_timer_on_full_cb(mcpwm_timer_handle_t timer, const mcpwm_timer_event_data_t *edata, void *user_data) +{ + return false; +} + +TEST_MCPWM_CALLBACK_ATTR +static bool test_mcpwm_oper_on_brake_cbc_cb(mcpwm_oper_handle_t oper, const mcpwm_brake_event_data_t *edata, void *user_data) +{ + return false; +} + +TEST_MCPWM_CALLBACK_ATTR +static bool test_mcpwm_cmpr_on_reach_cb(mcpwm_cmpr_handle_t comparator, const mcpwm_compare_event_data_t *edata, void *user_data) +{ + return false; +} + +TEST_MCPWM_CALLBACK_ATTR +static bool test_mcpwm_fault_on_enter_cb(mcpwm_fault_handle_t fault, const mcpwm_fault_event_data_t *edata, void *user_data) +{ + return false; +} + +TEST_MCPWM_CALLBACK_ATTR +static bool test_mcpwm_cap_on_cap_cb(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_data_t *edata, void *user_data) +{ + return false; +} + TEST_CASE("mcpwm_set_interrupt_priority", "[mcpwm]") { printf("install timer\r\n"); @@ -25,13 +55,13 @@ TEST_CASE("mcpwm_set_interrupt_priority", "[mcpwm]") printf("register event callbacks\r\n"); mcpwm_timer_event_callbacks_t timer_cbs = { .on_stop = NULL, - .on_full = NULL, + .on_full = test_mcpwm_timer_on_full_cb, .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_OK(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"); @@ -43,13 +73,13 @@ TEST_CASE("mcpwm_set_interrupt_priority", "[mcpwm]") 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_cbc = test_mcpwm_oper_on_brake_cbc_cb, .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_OK(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"); @@ -61,12 +91,12 @@ TEST_CASE("mcpwm_set_interrupt_priority", "[mcpwm]") 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, + .on_reach = test_mcpwm_cmpr_on_reach_cb, }; 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_OK(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"); @@ -81,13 +111,13 @@ TEST_CASE("mcpwm_set_interrupt_priority", "[mcpwm]") printf("register event callback\r\n"); mcpwm_fault_event_callbacks_t fault_cbs = { - .on_fault_enter = NULL, + .on_fault_enter = test_mcpwm_fault_on_enter_cb, .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_OK(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"); @@ -108,21 +138,26 @@ TEST_CASE("mcpwm_set_interrupt_priority", "[mcpwm]") printf("register event callback\r\n"); mcpwm_capture_event_callbacks_t cap_cbs = { - .on_cap = NULL, + .on_cap = test_mcpwm_cap_on_cap_cb, }; 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_OK(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_comparator(comparator2)); TEST_ESP_OK(mcpwm_del_operator(oper)); + TEST_ESP_OK(mcpwm_del_operator(oper2)); TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel)); + TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel2)); TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer)); TEST_ESP_OK(mcpwm_del_timer(timer)); + TEST_ESP_OK(mcpwm_del_timer(timer2)); TEST_ESP_OK(mcpwm_del_fault(fault)); + TEST_ESP_OK(mcpwm_del_fault(fault2)); } TEST_CASE("mcpwm_group_set_prescale_dynamically", "[mcpwm]") diff --git a/components/esp_driver_pcnt/src/pulse_cnt.c b/components/esp_driver_pcnt/src/pulse_cnt.c index 7d7a3269f78..d78ea94430a 100644 --- a/components/esp_driver_pcnt/src/pulse_cnt.c +++ b/components/esp_driver_pcnt/src/pulse_cnt.c @@ -43,9 +43,9 @@ #endif #if CONFIG_PCNT_ISR_IRAM_SAFE -#define PCNT_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED) +#define PCNT_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED_PRIVATE) #else -#define PCNT_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED) +#define PCNT_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED_PRIVATE) #endif #define PCNT_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED @@ -69,7 +69,6 @@ struct pcnt_platform_t { struct pcnt_group_t { int group_id; // Group ID, index from 0 - int intr_priority; // PCNT interrupt priority pcnt_clock_source_t clk_src; // PCNT clock source portMUX_TYPE spinlock; // to protect per-group register level concurrent access pcnt_hal_context_t hal; @@ -106,6 +105,7 @@ struct pcnt_unit_t { int low_limit; // low limit value int high_limit; // high limit value int clear_signal_gpio_num; // which gpio clear signal input + int intr_priority; // PCNT interrupt priority int accum_value; // accumulated count value pcnt_step_interval_t step_info; // step interval info pcnt_chan_t *channels[PCNT_LL_GET(CHANS_PER_UNIT)]; // array of PCNT channels @@ -138,6 +138,32 @@ static void pcnt_release_group_handle(pcnt_group_t *group); static void pcnt_default_isr(void *args); static esp_err_t pcnt_select_periph_clock(pcnt_unit_t *unit, pcnt_clock_source_t clk_src); +static esp_err_t pcnt_unit_install_interrupt(pcnt_unit_t *unit) +{ + pcnt_group_t *group = unit->group; + int group_id = group->group_id; + int unit_id = unit->unit_id; + int isr_flags = PCNT_INTR_ALLOC_FLAGS; + + if (unit->intr_priority) { + isr_flags |= 1 << (unit->intr_priority); + } else { + isr_flags |= PCNT_ALLOW_INTR_PRIORITY_MASK; + } + + esp_intr_alloc_info_t intr_info = { + .source = soc_pcnt_signals[group_id].irq_id, + .flags = isr_flags, + .intrstatusreg = (uint32_t)pcnt_ll_get_intr_status_reg(group->hal.dev), + .intrstatusmask = PCNT_LL_UNIT_WATCH_EVENT(unit_id), + .handler = pcnt_default_isr, + .arg = unit, + .bind_by.name = soc_pcnt_signals[group_id].module_name, + }; + + return esp_intr_alloc_info(&intr_info, &unit->intr); +} + static esp_err_t pcnt_register_to_group(pcnt_unit_t *unit) { pcnt_group_t *group = NULL; @@ -223,30 +249,11 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re ESP_GOTO_ON_ERROR(pcnt_select_periph_clock(unit, pcnt_clk_src), err, TAG, "select periph clock failed"); ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)group->clk_src, true), err, TAG, "clock source enable failed"); - // 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 if (config->intr_priority != 0) { - intr_priority_conflict = (group->intr_priority != config->intr_priority); - } - portEXIT_CRITICAL(&group->spinlock); - ESP_GOTO_ON_FALSE(!intr_priority_conflict, ESP_ERR_INVALID_STATE, err, TAG, "intr_priority conflict, already is %d but attempt to %d", group->intr_priority, config->intr_priority); - // to accumulate count value, we should install the interrupt handler first, and in the ISR we do the accumulation bool to_install_isr = (config->flags.accum_count == 1); + unit->intr_priority = config->intr_priority; if (to_install_isr) { - int isr_flags = PCNT_INTR_ALLOC_FLAGS; - if (group->intr_priority) { - isr_flags |= 1 << (group->intr_priority); - } else { - isr_flags |= PCNT_ALLOW_INTR_PRIORITY_MASK; - } - ESP_GOTO_ON_ERROR(esp_intr_alloc_intrstatus(soc_pcnt_signals[group_id].irq_id, isr_flags, - (uint32_t)pcnt_ll_get_intr_status_reg(group->hal.dev), PCNT_LL_UNIT_WATCH_EVENT(unit_id), - pcnt_default_isr, unit, &unit->intr), err, + ESP_GOTO_ON_ERROR(pcnt_unit_install_interrupt(unit), err, TAG, "install interrupt service failed"); } @@ -516,7 +523,6 @@ esp_err_t pcnt_unit_register_event_callbacks(pcnt_unit_handle_t unit, const pcnt ESP_RETURN_ON_FALSE(unit && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); // unit event callbacks should be registered in init state pcnt_group_t *group = unit->group; - int group_id = group->group_id; int unit_id = unit->unit_id; #if CONFIG_PCNT_ISR_IRAM_SAFE @@ -531,15 +537,7 @@ esp_err_t pcnt_unit_register_event_callbacks(pcnt_unit_handle_t unit, const pcnt // lazy install interrupt service if (!unit->intr) { ESP_RETURN_ON_FALSE(unit->fsm == PCNT_UNIT_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "unit not in init state"); - int isr_flags = PCNT_INTR_ALLOC_FLAGS; - if (group->intr_priority) { - isr_flags |= 1 << (group->intr_priority); - } else { - isr_flags |= PCNT_ALLOW_INTR_PRIORITY_MASK; - } - ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(soc_pcnt_signals[group_id].irq_id, isr_flags, - (uint32_t)pcnt_ll_get_intr_status_reg(group->hal.dev), PCNT_LL_UNIT_WATCH_EVENT(unit_id), - pcnt_default_isr, unit, &unit->intr), + ESP_RETURN_ON_ERROR(pcnt_unit_install_interrupt(unit), TAG, "install interrupt service failed"); } // enable/disable PCNT interrupt events @@ -907,7 +905,6 @@ static pcnt_group_t *pcnt_acquire_group_handle(int group_id) s_platform.groups[group_id] = group; // register to platform // initialize pcnt group members group->group_id = group_id; - group->intr_priority = -1; group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; // enable APB access pcnt registers PERIPH_RCC_ATOMIC() { diff --git a/components/esp_driver_pcnt/test_apps/pulse_cnt/main/test_app_main.c b/components/esp_driver_pcnt/test_apps/pulse_cnt/main/test_app_main.c index 71e240d551f..4316eea96df 100644 --- a/components/esp_driver_pcnt/test_apps/pulse_cnt/main/test_app_main.c +++ b/components/esp_driver_pcnt/test_apps/pulse_cnt/main/test_app_main.c @@ -1,38 +1,26 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "unity.h" -#include "unity_test_runner.h" +#include "unity_test_utils.h" #include "esp_heap_caps.h" +#include "esp_newlib.h" // Some resources are lazy allocated in pulse_cnt driver, the threshold is left for that case -#define TEST_MEMORY_LEAK_THRESHOLD (-300) - -static size_t before_free_8bit; -static size_t before_free_32bit; - -static void check_leak(size_t before_free, size_t after_free, const char *type) -{ - ssize_t delta = after_free - before_free; - printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); - TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); -} +#define TEST_MEMORY_LEAK_THRESHOLD (300) void setUp(void) { - before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + unity_utils_record_free_mem(); } void tearDown(void) { - size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); - check_leak(before_free_8bit, after_free_8bit, "8BIT"); - check_leak(before_free_32bit, after_free_32bit, "32BIT"); + esp_reent_cleanup(); //clean up some of the newlib's lazy allocations + unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD); } void app_main(void) diff --git a/components/esp_driver_pcnt/test_apps/pulse_cnt/main/test_pulse_cnt.c b/components/esp_driver_pcnt/test_apps/pulse_cnt/main/test_pulse_cnt.c index 543b1d3a925..f48c2f65732 100644 --- a/components/esp_driver_pcnt/test_apps/pulse_cnt/main/test_pulse_cnt.c +++ b/components/esp_driver_pcnt/test_apps/pulse_cnt/main/test_pulse_cnt.c @@ -23,6 +23,7 @@ TEST_CASE("pcnt_unit_install_uninstall", "[pcnt]") .low_limit = -100, .high_limit = 100, .intr_priority = 0, + .flags.accum_count = true, }; pcnt_unit_handle_t units[PCNT_LL_GET(UNITS_PER_INST)]; int count_value = 0; @@ -36,7 +37,7 @@ TEST_CASE("pcnt_unit_install_uninstall", "[pcnt]") // unit with a different interrupt priority unit_config.intr_priority = 3; - TEST_ESP_ERR(ESP_ERR_INVALID_STATE, pcnt_new_unit(&unit_config, &units[PCNT_LL_GET(UNITS_PER_INST) - 1])); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, pcnt_new_unit(&unit_config, &units[PCNT_LL_GET(UNITS_PER_INST) - 1])); unit_config.intr_priority = 0; TEST_ESP_OK(pcnt_new_unit(&unit_config, &units[PCNT_LL_GET(UNITS_PER_INST) - 1])); diff --git a/components/esp_driver_rmt/src/rmt_common.c b/components/esp_driver_rmt/src/rmt_common.c index 05670cbc505..9a913910641 100644 --- a/components/esp_driver_rmt/src/rmt_common.c +++ b/components/esp_driver_rmt/src/rmt_common.c @@ -39,8 +39,6 @@ rmt_group_t *rmt_acquire_group_handle(int group_id) group->occupy_mask = UINT32_MAX & ~((1 << RMT_LL_GET(CHANS_PER_INST)) - 1); // group clock won't be configured at this stage, it will be set when allocate the first channel group->clk_src = 0; - // group interrupt priority is shared between all channels, it will be set when allocate the first channel - group->intr_priority = RMT_GROUP_INTR_PRIORITY_UNINITIALIZED; // enable the bus clock for the RMT peripheral PERIPH_RCC_ATOMIC() { rmt_ll_enable_bus_clock(group_id, true); @@ -217,8 +215,7 @@ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t // note, even if the clock source is APB, we still use CPU_FREQ_MAX lock to ensure the stability of the RMT operation. esp_pm_lock_type_t pm_lock_type = chan->dma_chan ? ESP_PM_NO_LIGHT_SLEEP : ESP_PM_CPU_FREQ_MAX; - sprintf(chan->pm_lock_name, "rmt_%d_%d", group->group_id, chan->channel_id); // e.g. rmt_0_0 - ret = esp_pm_lock_create(pm_lock_type, 0, chan->pm_lock_name, &chan->pm_lock); + ret = esp_pm_lock_create(pm_lock_type, 0, soc_rmt_signals[group->group_id].module_name, &chan->pm_lock); ESP_RETURN_ON_ERROR(ret, TAG, "create pm lock failed"); #endif // CONFIG_PM_ENABLE @@ -293,52 +290,6 @@ esp_err_t rmt_disable(rmt_channel_handle_t channel) return channel->disable(channel); } -bool rmt_set_intr_priority_to_group(rmt_group_t *group, int intr_priority) -{ - bool priority_conflict = false; - portENTER_CRITICAL(&group->spinlock); - if (group->intr_priority == RMT_GROUP_INTR_PRIORITY_UNINITIALIZED) { - // intr_priority never allocated, accept user's value unconditionally - // intr_priority could only be set once here - group->intr_priority = intr_priority; - } else { - // group intr_priority already specified - // If interrupt priority specified before, it CANNOT BE CHANGED until `rmt_release_group_handle()` called - // So we have to check if the new priority specified conflicts with the old one - if (intr_priority) { - // User specified intr_priority, check if conflict or not - // Even though the `group->intr_priority` is 0, an intr_priority must have been specified automatically too, - // although we do not know it exactly now, so specifying the intr_priority again might also cause conflict. - // So no matter if `group->intr_priority` is 0 or not, we have to check. - // Value `0` of `group->intr_priority` means "unknown", NOT "unspecified"! - if (intr_priority != (group->intr_priority)) { - // intr_priority conflicts! - priority_conflict = true; - } - } - // else do nothing - // user did not specify intr_priority, then keep the old priority - // We'll use the `RMT_INTR_ALLOC_FLAG | RMT_ALLOW_INTR_PRIORITY_MASK`, which should always success - } - // The `group->intr_priority` will not change any longer, even though another task tries to modify it. - // So we could exit critical here safely. - portEXIT_CRITICAL(&group->spinlock); - return priority_conflict; -} - -int rmt_isr_priority_to_flags(rmt_group_t *group) -{ - int isr_flags = 0; - if (group->intr_priority) { - // Use user-specified priority bit - isr_flags |= (1 << (group->intr_priority)); - } else { - // Allow all LOWMED priority bits - isr_flags |= RMT_ALLOW_INTR_PRIORITY_MASK; - } - return isr_flags; -} - #if RMT_USE_RETENTION_LINK static esp_err_t rmt_create_sleep_retention_link_cb(void *arg) { diff --git a/components/esp_driver_rmt/src/rmt_private.h b/components/esp_driver_rmt/src/rmt_private.h index 13434a0016c..ffd6a6865c5 100644 --- a/components/esp_driver_rmt/src/rmt_private.h +++ b/components/esp_driver_rmt/src/rmt_private.h @@ -61,15 +61,15 @@ extern "C" { // RMT driver object is per-channel, the interrupt source is shared between channels #if CONFIG_RMT_TX_ISR_CACHE_SAFE -#define RMT_TX_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_IRAM) +#define RMT_TX_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED_PRIVATE | ESP_INTR_FLAG_IRAM) #else -#define RMT_TX_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED) +#define RMT_TX_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED_PRIVATE) #endif #if CONFIG_RMT_RX_ISR_CACHE_SAFE -#define RMT_RX_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_IRAM) +#define RMT_RX_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED_PRIVATE | ESP_INTR_FLAG_IRAM) #else -#define RMT_RX_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED) +#define RMT_RX_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED_PRIVATE) #endif // Hopefully the channel offset won't change in other targets @@ -79,8 +79,6 @@ extern "C" { #define RMT_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED #define RMT_DMA_NODES_PING_PONG 2 // two nodes ping-pong -#define RMT_PM_LOCK_NAME_LEN_MAX 16 -#define RMT_GROUP_INTR_PRIORITY_UNINITIALIZED (-1) // RMT is a slow peripheral, it only supports AHB-GDMA #define RMT_DMA_DESC_ALIGN 4 @@ -143,7 +141,6 @@ struct rmt_group_t { rmt_tx_channel_t *tx_channels[RMT_LL_GET(TX_CANDIDATES_PER_INST)]; // array of RMT TX channels rmt_rx_channel_t *rx_channels[RMT_LL_GET(RX_CANDIDATES_PER_INST)]; // array of RMT RX channels rmt_sync_manager_t *sync_manager; // sync manager, this can be extended into an array if there're more sync controllers in one RMT group - int intr_priority; // RMT interrupt priority }; struct rmt_channel_t { @@ -161,7 +158,6 @@ struct rmt_channel_t { gdma_channel_handle_t dma_chan; // DMA channel #if CONFIG_PM_ENABLE esp_pm_lock_handle_t pm_lock; // power management lock - char pm_lock_name[RMT_PM_LOCK_NAME_LEN_MAX]; // pm lock name #endif // RMT channel common interface // The following IO functions will have per-implementation for TX and RX channel @@ -257,23 +253,6 @@ void rmt_release_group_handle(rmt_group_t *group); */ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t clk_src, uint32_t expect_channel_resolution); -/** - * @brief Set interrupt priority to RMT group - * @param group RMT group to set interrupt priority to - * @param intr_priority User-specified interrupt priority (in num, not bitmask) - * @return If the priority conflicts - * - true: Interrupt priority conflict with previous specified - * - false: Interrupt priority set successfully - */ -bool rmt_set_intr_priority_to_group(rmt_group_t *group, int intr_priority); - -/** - * @brief Convert the interrupt priority to flags - * @param group RMT group - * @return isr_flags which is compatible to `ESP_INTR_FLAG_*` - */ -int rmt_isr_priority_to_flags(rmt_group_t *group); - /** * @brief Create sleep retention link * diff --git a/components/esp_driver_rmt/src/rmt_rx.c b/components/esp_driver_rmt/src/rmt_rx.c index 8bc8142f89d..dbf250b4f27 100644 --- a/components/esp_driver_rmt/src/rmt_rx.c +++ b/components/esp_driver_rmt/src/rmt_rx.c @@ -242,15 +242,17 @@ esp_err_t rmt_new_rx_channel(const rmt_rx_channel_config_t *config, rmt_channel_ // RMT interrupt is mandatory if the channel doesn't use DMA // --- install interrupt service // interrupt is mandatory to run basic RMT transactions, so it's not lazy installed in `rmt_tx_register_event_callbacks()` - // 1-- Set user specified priority to `group->intr_priority` - bool priority_conflict = rmt_set_intr_priority_to_group(group, config->intr_priority); - ESP_GOTO_ON_FALSE(!priority_conflict, ESP_ERR_INVALID_ARG, err, TAG, "intr_priority conflict"); - // 2-- Get interrupt allocation flag - int isr_flags = rmt_isr_priority_to_flags(group) | RMT_RX_INTR_ALLOC_FLAG; - // 3-- Allocate interrupt using isr_flag - ret = esp_intr_alloc_intrstatus(soc_rmt_signals[group_id].irq, isr_flags, - (uint32_t)rmt_ll_get_interrupt_status_reg(hal->regs), - RMT_LL_EVENT_RX_MASK(channel_id), rmt_rx_default_isr, rx_channel, &rx_channel->base.intr); + int isr_flags = (config->intr_priority ? (1 << config->intr_priority) : RMT_ALLOW_INTR_PRIORITY_MASK) | RMT_RX_INTR_ALLOC_FLAG; + esp_intr_alloc_info_t intr_info = { + .source = soc_rmt_signals[group_id].irq, + .flags = isr_flags, + .intrstatusreg = (uint32_t)rmt_ll_get_interrupt_status_reg(hal->regs), + .intrstatusmask = RMT_LL_EVENT_RX_MASK(channel_id), + .handler = rmt_rx_default_isr, + .arg = rx_channel, + .bind_by.name = soc_rmt_signals[group_id].module_name, + }; + ret = esp_intr_alloc_info(&intr_info, &rx_channel->base.intr); ESP_GOTO_ON_ERROR(ret, err, TAG, "install rx interrupt failed"); } diff --git a/components/esp_driver_rmt/src/rmt_tx.c b/components/esp_driver_rmt/src/rmt_tx.c index 660bb126552..fbe3b48037a 100644 --- a/components/esp_driver_rmt/src/rmt_tx.c +++ b/components/esp_driver_rmt/src/rmt_tx.c @@ -300,18 +300,18 @@ esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_ rmt_hal_tx_channel_reset(&group->hal, channel_id); portEXIT_CRITICAL(&group->spinlock); // install tx interrupt - // --- install interrupt service // interrupt is mandatory to run basic RMT transactions, so it's not lazy installed in `rmt_tx_register_event_callbacks()` - // 1-- Set user specified priority to `group->intr_priority` - bool priority_conflict = rmt_set_intr_priority_to_group(group, config->intr_priority); - ESP_GOTO_ON_FALSE(!priority_conflict, ESP_ERR_INVALID_ARG, err, TAG, "intr_priority conflict"); - // 2-- Get interrupt allocation flag - int isr_flags = rmt_isr_priority_to_flags(group) | RMT_TX_INTR_ALLOC_FLAG; - // 3-- Allocate interrupt using isr_flag - ret = esp_intr_alloc_intrstatus(soc_rmt_signals[group_id].irq, isr_flags, - (uint32_t) rmt_ll_get_interrupt_status_reg(hal->regs), - RMT_LL_EVENT_TX_MASK(channel_id), rmt_tx_default_isr, tx_channel, - &tx_channel->base.intr); + int isr_flags = (config->intr_priority ? (1 << config->intr_priority) : RMT_ALLOW_INTR_PRIORITY_MASK) | RMT_TX_INTR_ALLOC_FLAG; + esp_intr_alloc_info_t intr_info = { + .source = soc_rmt_signals[group_id].irq, + .flags = isr_flags, + .intrstatusreg = (uint32_t)rmt_ll_get_interrupt_status_reg(hal->regs), + .intrstatusmask = RMT_LL_EVENT_TX_MASK(channel_id), + .handler = rmt_tx_default_isr, + .arg = tx_channel, + .bind_by.name = soc_rmt_signals[group_id].module_name, + }; + ret = esp_intr_alloc_info(&intr_info, &tx_channel->base.intr); ESP_GOTO_ON_ERROR(ret, err, TAG, "install tx interrupt failed"); // install DMA service #if SOC_RMT_SUPPORT_DMA diff --git a/components/esp_driver_uart/test_apps/uart/main/test_uart.c b/components/esp_driver_uart/test_apps/uart/main/test_uart.c index c52c233ffe0..be04b9ebfb7 100644 --- a/components/esp_driver_uart/test_apps/uart/main/test_uart.c +++ b/components/esp_driver_uart/test_apps/uart/main/test_uart.c @@ -794,7 +794,7 @@ TEST_CASE("uart rx glitch filter (read write test + auto baud rate detection tes .test_times = 10, }; TaskHandle_t inject_glitch_task_handle; - xTaskCreate(uart_signal_inject_glitch_task, "uart_signal_inject_glitch_task", 1024, (void *)&port_param, 6, &inject_glitch_task_handle); + xTaskCreate(uart_signal_inject_glitch_task, "uart_signal_inject_glitch_task", 2048, (void *)&port_param, 6, &inject_glitch_task_handle); // 1. read write test #if !UART_LL_GLITCH_FILT_ONLY_ON_AUTOBAUD @@ -825,7 +825,7 @@ TEST_CASE("uart rx glitch filter (read write test + auto baud rate detection tes uint32_t detected_baudrate = res.clk_freq_hz * 2 / res.pos_period; // assume the wave has a slow falling slew rate uint32_t actual_baudrate = 0; uart_get_baudrate(uart_num, &actual_baudrate); - TEST_ASSERT_INT32_WITHIN(actual_baudrate * 0.03, actual_baudrate, detected_baudrate); + TEST_ASSERT_INT32_WITHIN(actual_baudrate * 0.05, actual_baudrate, detected_baudrate); // wait for write task to finish and self deleted while (eTaskGetState(write_task_handle) != eDeleted) { vTaskDelay(1); diff --git a/components/esp_hal_rmt/esp32/rmt_periph.c b/components/esp_hal_rmt/esp32/rmt_periph.c index 84669b64e52..f27af906959 100644 --- a/components/esp_hal_rmt/esp32/rmt_periph.c +++ b/components/esp_hal_rmt/esp32/rmt_periph.c @@ -11,6 +11,7 @@ const soc_rmt_signal_desc_t soc_rmt_signals[1] = { [0] = { .irq = ETS_RMT_INTR_SOURCE, + .module_name = "rmt0", .channels = { [0] = { .tx_sig = RMT_SIG_OUT0_IDX, diff --git a/components/esp_hal_rmt/esp32c3/rmt_periph.c b/components/esp_hal_rmt/esp32c3/rmt_periph.c index 1f11259e394..e938ee07b10 100644 --- a/components/esp_hal_rmt/esp32c3/rmt_periph.c +++ b/components/esp_hal_rmt/esp32c3/rmt_periph.c @@ -10,6 +10,7 @@ const soc_rmt_signal_desc_t soc_rmt_signals[1] = { [0] = { .irq = ETS_RMT_INTR_SOURCE, + .module_name = "rmt0", .channels = { [0] = { .tx_sig = RMT_SIG_OUT0_IDX, diff --git a/components/esp_hal_rmt/esp32c5/rmt_periph.c b/components/esp_hal_rmt/esp32c5/rmt_periph.c index 4bc8ffb5b0d..69458a85948 100644 --- a/components/esp_hal_rmt/esp32c5/rmt_periph.c +++ b/components/esp_hal_rmt/esp32c5/rmt_periph.c @@ -11,6 +11,7 @@ const soc_rmt_signal_desc_t soc_rmt_signals[1] = { [0] = { .irq = ETS_RMT_INTR_SOURCE, + .module_name = "rmt0", .channels = { [0] = { .tx_sig = RMT_SIG_OUT0_IDX, diff --git a/components/esp_hal_rmt/esp32c6/rmt_periph.c b/components/esp_hal_rmt/esp32c6/rmt_periph.c index e09b7171c38..51ee06886fc 100644 --- a/components/esp_hal_rmt/esp32c6/rmt_periph.c +++ b/components/esp_hal_rmt/esp32c6/rmt_periph.c @@ -11,6 +11,7 @@ const soc_rmt_signal_desc_t soc_rmt_signals[1] = { [0] = { .irq = ETS_RMT_INTR_SOURCE, + .module_name = "rmt0", .channels = { [0] = { .tx_sig = RMT_SIG_OUT0_IDX, diff --git a/components/esp_hal_rmt/esp32h2/rmt_periph.c b/components/esp_hal_rmt/esp32h2/rmt_periph.c index e09b7171c38..51ee06886fc 100644 --- a/components/esp_hal_rmt/esp32h2/rmt_periph.c +++ b/components/esp_hal_rmt/esp32h2/rmt_periph.c @@ -11,6 +11,7 @@ const soc_rmt_signal_desc_t soc_rmt_signals[1] = { [0] = { .irq = ETS_RMT_INTR_SOURCE, + .module_name = "rmt0", .channels = { [0] = { .tx_sig = RMT_SIG_OUT0_IDX, diff --git a/components/esp_hal_rmt/esp32h21/rmt_periph.c b/components/esp_hal_rmt/esp32h21/rmt_periph.c index 9935ab948d7..8aa6b814472 100644 --- a/components/esp_hal_rmt/esp32h21/rmt_periph.c +++ b/components/esp_hal_rmt/esp32h21/rmt_periph.c @@ -11,6 +11,7 @@ const soc_rmt_signal_desc_t soc_rmt_signals[1] = { [0] = { .irq = ETS_RMT_INTR_SOURCE, + .module_name = "rmt0", .channels = { [0] = { .tx_sig = RMT_SIG_OUT0_IDX, diff --git a/components/esp_hal_rmt/esp32h4/rmt_periph.c b/components/esp_hal_rmt/esp32h4/rmt_periph.c index 9935ab948d7..8aa6b814472 100644 --- a/components/esp_hal_rmt/esp32h4/rmt_periph.c +++ b/components/esp_hal_rmt/esp32h4/rmt_periph.c @@ -11,6 +11,7 @@ const soc_rmt_signal_desc_t soc_rmt_signals[1] = { [0] = { .irq = ETS_RMT_INTR_SOURCE, + .module_name = "rmt0", .channels = { [0] = { .tx_sig = RMT_SIG_OUT0_IDX, diff --git a/components/esp_hal_rmt/esp32p4/rmt_periph.c b/components/esp_hal_rmt/esp32p4/rmt_periph.c index 13d1181b3f9..a30d52d0ca7 100644 --- a/components/esp_hal_rmt/esp32p4/rmt_periph.c +++ b/components/esp_hal_rmt/esp32p4/rmt_periph.c @@ -11,6 +11,7 @@ const soc_rmt_signal_desc_t soc_rmt_signals[1] = { [0] = { .irq = ETS_RMT_INTR_SOURCE, + .module_name = "rmt0", .channels = { [0] = { .tx_sig = RMT_SIG_PAD_OUT0_IDX, diff --git a/components/esp_hal_rmt/esp32s2/rmt_periph.c b/components/esp_hal_rmt/esp32s2/rmt_periph.c index a0f0b17ebac..7f346f58440 100644 --- a/components/esp_hal_rmt/esp32s2/rmt_periph.c +++ b/components/esp_hal_rmt/esp32s2/rmt_periph.c @@ -10,6 +10,7 @@ const soc_rmt_signal_desc_t soc_rmt_signals[1] = { [0] = { .irq = ETS_RMT_INTR_SOURCE, + .module_name = "rmt0", .channels = { [0] = { .tx_sig = RMT_SIG_OUT0_IDX, diff --git a/components/esp_hal_rmt/esp32s3/rmt_periph.c b/components/esp_hal_rmt/esp32s3/rmt_periph.c index 117b933af49..309a4482591 100644 --- a/components/esp_hal_rmt/esp32s3/rmt_periph.c +++ b/components/esp_hal_rmt/esp32s3/rmt_periph.c @@ -10,6 +10,7 @@ const soc_rmt_signal_desc_t soc_rmt_signals[1] = { [0] = { .irq = ETS_RMT_INTR_SOURCE, + .module_name = "rmt0", .channels = { [0] = { .tx_sig = RMT_SIG_OUT0_IDX, diff --git a/components/esp_hal_rmt/include/hal/rmt_periph.h b/components/esp_hal_rmt/include/hal/rmt_periph.h index b51e9c187e2..4effffa3f8a 100644 --- a/components/esp_hal_rmt/include/hal/rmt_periph.h +++ b/components/esp_hal_rmt/include/hal/rmt_periph.h @@ -25,6 +25,7 @@ extern "C" { typedef struct { const int irq; + const char *module_name; struct { struct { const int tx_sig; diff --git a/components/esp_hw_support/intr_alloc.c b/components/esp_hw_support/intr_alloc.c index 1ab1835c4aa..daa73d7bd1d 100644 --- a/components/esp_hw_support/intr_alloc.c +++ b/components/esp_hw_support/intr_alloc.c @@ -101,6 +101,12 @@ struct shared_vector_desc_t { /* Define an alias for visibility flags */ #define VECDESC_FL_PRIVATE (VECDESC_FL_NONSHARED) +#define VECDESC_IS_PUBLIC_SHARED(vd) ((((vd)->flags & (VECDESC_FL_SHARED | VECDESC_FL_PRIVATE)) == VECDESC_FL_SHARED)) +#define VECDESC_IS_NONSHARED(vd) ((((vd)->flags & VECDESC_FL_NONSHARED) != 0) && (((vd)->flags & VECDESC_FL_SHARED) == 0)) +#define VECDESC_IS_PRIVATE_SHARED(vd) ((((vd)->flags & (VECDESC_FL_SHARED | VECDESC_FL_PRIVATE)) == (VECDESC_FL_SHARED | VECDESC_FL_PRIVATE))) +#define VECDESC_IS_SHARED_FAMILY(vd) (VECDESC_IS_PUBLIC_SHARED(vd) || VECDESC_IS_PRIVATE_SHARED(vd)) +#define VECDESC_IS_UNINITIALIZED(vd) (((vd)->flags & (VECDESC_FL_SHARED | VECDESC_FL_NONSHARED)) == 0) + #if SOC_CPU_HAS_FLEXIBLE_INTC /* On targets that have configurable interrupts levels, store the assigned level in the flags */ @@ -211,7 +217,7 @@ static vector_desc_t * find_desc_for_source(int source, int cpu) { vector_desc_t *vd = vector_desc_head; while(vd != NULL) { - if (!(vd->flags & VECDESC_FL_SHARED)) { + if (!VECDESC_IS_SHARED_FAMILY(vd)) { if (vd->source == source && cpu == vd->cpu) { break; } @@ -352,13 +358,13 @@ static bool is_vect_desc_usable(vector_desc_t *vd, int flags, int cpu, int force } //check if interrupt is already in use by a non-shared interrupt - if ((vd->flags & VECDESC_FL_NONSHARED) != 0 && (vd->flags & VECDESC_FL_SHARED) == 0) { + if (VECDESC_IS_NONSHARED(vd)) { ALCHLOG("....Unusable: already in (non-shared) use."); return false; } //Check shared interrupt flags - if ((vd->flags & VECDESC_FL_SHARED) != 0) { - const bool vect_private = (vd->flags & VECDESC_FL_PRIVATE) != 0; + if (VECDESC_IS_SHARED_FAMILY(vd)) { + const bool vect_private = VECDESC_IS_PRIVATE_SHARED(vd); const bool flag_shared = (flags & ESP_INTR_FLAG_SHARED) != 0; const bool flag_shared_private = (flags & ESP_INTR_FLAG_SHARED_PRIVATE) != 0; @@ -473,11 +479,11 @@ static int get_available_int(int flags, int cpu, int force, int source, bool new continue; } - if (flags & ESP_INTR_FLAG_SHARED) { + if (flags & (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_SHARED_PRIVATE)) { //We're allocating a shared int. //See if int is already used as a shared interrupt. - if (vd->flags & VECDESC_FL_SHARED) { + if (VECDESC_IS_SHARED_FAMILY(vd)) { //We can use this already-marked-as-shared interrupt. Count the already attached isrs in order to see //how useful it is. int no = 0; @@ -672,6 +678,7 @@ bool esp_intr_ptr_in_isr_region(void* ptr) /* Sanity check, should not occur */ if (shared_handle->vector_desc == NULL) { esp_os_exit_critical(&spinlock); + free(ret); return ESP_ERR_INVALID_STATE; } /* If a shared vector was given, force the current interrupt source to same CPU interrupt line */ @@ -731,6 +738,11 @@ bool esp_intr_ptr_in_isr_region(void* ptr) //Populate vector entry and add to linked list. shared_vector_desc_t *sh_vec = heap_caps_malloc(sizeof(shared_vector_desc_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); if (sh_vec == NULL) { + if (create_new_group) { + assert(vd->group_name != NULL); + free(vd->group_name); + vd->group_name = NULL; + } esp_os_exit_critical(&spinlock); free(ret); return ESP_ERR_NO_MEM; @@ -881,7 +893,7 @@ esp_err_t ESP_INTR_IRAM_ATTR esp_intr_set_in_iram(intr_handle_t handle, bool is_ return ESP_ERR_INVALID_ARG; } vector_desc_t *vd = handle->vector_desc; - if (vd->flags & VECDESC_FL_SHARED) { + if (VECDESC_IS_SHARED_FAMILY(vd)) { return ESP_ERR_INVALID_ARG; } esp_os_enter_critical(&spinlock); @@ -939,7 +951,7 @@ static esp_err_t intr_free_for_current_cpu(intr_handle_t handle) esp_os_enter_critical(&spinlock); esp_intr_disable(handle); - if (handle->vector_desc->flags & VECDESC_FL_SHARED) { + if (VECDESC_IS_SHARED_FAMILY(handle->vector_desc)) { //Find and kill the shared int shared_vector_desc_t *svd = handle->vector_desc->shared_vec_info; shared_vector_desc_t *prevsvd = NULL; @@ -973,7 +985,7 @@ static esp_err_t intr_free_for_current_cpu(intr_handle_t handle) free_shared_vector ? "empty now." : "still in use"); } - if ((handle->vector_desc->flags & VECDESC_FL_NONSHARED) || free_shared_vector) { + if (VECDESC_IS_NONSHARED(handle->vector_desc) || free_shared_vector) { ESP_EARLY_LOGV(TAG, "esp_intr_free: Disabling int, killing handler"); #if CONFIG_ESP_TRACE_ENABLE if (!free_shared_vector) { @@ -1209,7 +1221,7 @@ esp_err_t esp_intr_dump(FILE *stream) } else if (intr_desc.flags & ESP_CPU_INTR_DESC_FLAG_SPECIAL) { fprintf(stream, "CPU-internal"); } else { - if (vd == NULL || (vd->flags & (VECDESC_FL_RESERVED | VECDESC_FL_NONSHARED | VECDESC_FL_SHARED)) == 0) { + if (vd == NULL || VECDESC_IS_UNINITIALIZED(vd)) { fprintf(stream, "Free"); if (is_general_use) { ++general_use_ints_free; @@ -1218,9 +1230,9 @@ esp_err_t esp_intr_dump(FILE *stream) } } else if (vd->flags & VECDESC_FL_RESERVED) { fprintf(stream, "Reserved (run-time)"); - } else if (vd->flags & VECDESC_FL_NONSHARED) { + } else if (VECDESC_IS_NONSHARED(vd)) { fprintf(stream, "Used: %s", esp_isr_names[vd->source]); - } else if (vd->flags & VECDESC_FL_SHARED) { + } else if (VECDESC_IS_SHARED_FAMILY(vd)) { fprintf(stream, "Shared: "); for (shared_vector_desc_t *svd = vd->shared_vec_info; svd != NULL; svd = svd->next) { fprintf(stream, "%s ", esp_isr_names[svd->source]); diff --git a/components/esp_hw_support/test_apps/rtc_clk/main/test_app_main.c b/components/esp_hw_support/test_apps/rtc_clk/main/test_app_main.c index 4dbd00f512f..fc4ed7d7278 100644 --- a/components/esp_hw_support/test_apps/rtc_clk/main/test_app_main.c +++ b/components/esp_hw_support/test_apps/rtc_clk/main/test_app_main.c @@ -13,7 +13,7 @@ #include "esp_heap_trace.h" #endif -#define TEST_MEMORY_LEAK_THRESHOLD_DEFAULT -300 +#define TEST_MEMORY_LEAK_THRESHOLD_DEFAULT -350 static int leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; void set_leak_threshold(int threshold)