From a8c8b831b89cd2738b77aed858e921e398bc0e93 Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 26 Mar 2026 14:53:33 +0800 Subject: [PATCH 1/4] fix(esp_hw_support): fix private shared interrupt release path Treat ESP_INTR_FLAG_SHARED_PRIVATE as shared when selecting interrupt lines and avoid misclassifying private shared vectors as non-shared during free. Also fix two error-path leaks in esp_intr_alloc_info by freeing the temporary handle and rolling back group_name on allocation failure. refactor(esp_hw_support): add semantic vector descriptor helpers Introduce helper macros to classify vector descriptor state (shared, non-shared, private shared, and uninitialized) and apply them in allocator/free/dump paths. This makes private-shared semantics explicit and reduces repeated bitwise checks. Rename vector descriptor helpers to explicitly distinguish public shared, private shared, and shared-family states. This improves readability and avoids ambiguity when handling mixed shared/non-shared flag combinations. --- .../test_apps/uart/main/test_uart.c | 4 +-- components/esp_hw_support/intr_alloc.c | 36 ++++++++++++------- .../test_apps/rtc_clk/main/test_app_main.c | 2 +- 3 files changed, 27 insertions(+), 15 deletions(-) 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_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) From 8509ec1958272b8f5f11c8c06714e0e4f64f32b4 Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 26 Mar 2026 12:17:45 +0800 Subject: [PATCH 2/4] refactor(pcnt): use private shared interrupt groups Route PCNT unit interrupts through private shared groups bound by module name so units in the same PCNT instance share one CPU line without allowing other peripherals to join. Remove redundant PCNT-side priority conflict checks and rely on the interrupt allocator for conflict validation. Switch the PCNT test app to unity leak utilities and clean newlib reent state during teardown so leak checks are more stable with lazy allocations. --- components/esp_driver_pcnt/src/pulse_cnt.c | 67 +++++++++---------- .../test_apps/pulse_cnt/main/test_app_main.c | 26 ++----- .../test_apps/pulse_cnt/main/test_pulse_cnt.c | 3 +- 3 files changed, 41 insertions(+), 55 deletions(-) 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])); From 4084c88a2e83b86c2ba7f43c211c7fb443b027f5 Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 26 Mar 2026 16:09:15 +0800 Subject: [PATCH 3/4] refactor(rmt): switch group interrupts to private shared binding Bind RMT channel interrupts by module name and allocate them as private shared so channels in the same RMT instance reuse one CPU interrupt line without exposing it to other peripherals. Drop RMT-side interrupt priority conflict state and let the interrupt allocator enforce compatibility. Use soc_rmt_signals[group_id].module_name when creating RMT PM locks and drop the per-channel formatted lock name buffer. This keeps naming consistent with interrupt binding and removes unnecessary string formatting state. --- components/esp_driver_rmt/src/rmt_common.c | 51 +------------------ components/esp_driver_rmt/src/rmt_private.h | 29 ++--------- components/esp_driver_rmt/src/rmt_rx.c | 20 ++++---- components/esp_driver_rmt/src/rmt_tx.c | 22 ++++---- components/esp_hal_rmt/esp32/rmt_periph.c | 1 + components/esp_hal_rmt/esp32c3/rmt_periph.c | 1 + components/esp_hal_rmt/esp32c5/rmt_periph.c | 1 + components/esp_hal_rmt/esp32c6/rmt_periph.c | 1 + components/esp_hal_rmt/esp32h2/rmt_periph.c | 1 + components/esp_hal_rmt/esp32h21/rmt_periph.c | 1 + components/esp_hal_rmt/esp32h4/rmt_periph.c | 1 + components/esp_hal_rmt/esp32p4/rmt_periph.c | 1 + components/esp_hal_rmt/esp32s2/rmt_periph.c | 1 + components/esp_hal_rmt/esp32s3/rmt_periph.c | 1 + .../esp_hal_rmt/include/hal/rmt_periph.h | 1 + 15 files changed, 38 insertions(+), 95 deletions(-) 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_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; From d889e75ee644c99b862232b2b1b367502337a18b Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 27 Mar 2026 19:01:56 +0800 Subject: [PATCH 4/4] refactor(mcpwm): move interrupt conflict checks to allocator --- components/esp_driver_mcpwm/src/mcpwm_cap.c | 22 +++++--- components/esp_driver_mcpwm/src/mcpwm_cmpr.c | 22 +++++--- components/esp_driver_mcpwm/src/mcpwm_com.c | 27 --------- components/esp_driver_mcpwm/src/mcpwm_fault.c | 22 +++++--- components/esp_driver_mcpwm/src/mcpwm_oper.c | 22 +++++--- .../esp_driver_mcpwm/src/mcpwm_private.h | 12 ++-- components/esp_driver_mcpwm/src/mcpwm_timer.c | 22 +++++--- .../test_apps/mcpwm/main/test_mcpwm_common.c | 55 +++++++++++++++---- 8 files changed, 117 insertions(+), 87 deletions(-) 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]")