diff --git a/components/driver/esp32/touch_sensor.c b/components/driver/esp32/touch_sensor.c index 452eff7311..bf9a91b363 100644 --- a/components/driver/esp32/touch_sensor.c +++ b/components/driver/esp32/touch_sensor.c @@ -70,13 +70,13 @@ static esp_err_t _touch_pad_read(touch_pad_t touch_num, uint16_t *touch_value, t esp_err_t touch_pad_isr_handler_register(void (*fn)(void *), void *arg, int no_use, intr_handle_t *handle_no_use) { ESP_RETURN_ON_FALSE(fn, ESP_ERR_INVALID_ARG, TOUCH_TAG, "Touch_Pad ISR null"); - return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M); + return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M, 0); } esp_err_t touch_pad_isr_register(intr_handler_t fn, void *arg) { ESP_RETURN_ON_FALSE(fn, ESP_ERR_INVALID_ARG, TOUCH_TAG, "Touch_Pad ISR null"); - return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M); + return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M, 0); } static uint32_t _touch_filter_iir(uint32_t in_now, uint32_t out_last, uint32_t k) diff --git a/components/driver/esp32s2/touch_sensor.c b/components/driver/esp32s2/touch_sensor.c index cbf99e263c..13322f6f60 100644 --- a/components/driver/esp32s2/touch_sensor.c +++ b/components/driver/esp32s2/touch_sensor.c @@ -106,10 +106,10 @@ esp_err_t touch_pad_isr_register(intr_handler_t fn, void *arg, touch_pad_intr_ma en_msk |= RTC_CNTL_TOUCH_APPROACH_LOOP_DONE_INT_ST_M; } #endif - esp_err_t ret = rtc_isr_register(fn, arg, en_msk); + esp_err_t ret = rtc_isr_register(fn, arg, en_msk, 0); /* Must ensure: After being registered, it is executed first. */ if ( (ret == ESP_OK) && (reg_flag == false) && (intr_mask & (TOUCH_PAD_INTR_MASK_SCAN_DONE | TOUCH_PAD_INTR_MASK_TIMEOUT)) ) { - rtc_isr_register(touch_pad_workaround_isr_internal, NULL, RTC_CNTL_TOUCH_SCAN_DONE_INT_ST_M | RTC_CNTL_TOUCH_TIMEOUT_INT_ST_M); + rtc_isr_register(touch_pad_workaround_isr_internal, NULL, RTC_CNTL_TOUCH_SCAN_DONE_INT_ST_M | RTC_CNTL_TOUCH_TIMEOUT_INT_ST_M, 0); reg_flag = true; } diff --git a/components/driver/esp32s3/touch_sensor.c b/components/driver/esp32s3/touch_sensor.c index e3d485951e..f3d2dab42b 100644 --- a/components/driver/esp32s3/touch_sensor.c +++ b/components/driver/esp32s3/touch_sensor.c @@ -85,7 +85,7 @@ esp_err_t touch_pad_isr_register(intr_handler_t fn, void *arg, touch_pad_intr_ma en_msk |= RTC_CNTL_TOUCH_APPROACH_LOOP_DONE_INT_ST_M; } #endif - esp_err_t ret = rtc_isr_register(fn, arg, en_msk); + esp_err_t ret = rtc_isr_register(fn, arg, en_msk, 0); return ret; } diff --git a/components/esp_hw_support/include/esp_private/rtc_ctrl.h b/components/esp_hw_support/include/esp_private/rtc_ctrl.h index 2a0f5916c0..bea8bbdd2a 100644 --- a/components/esp_hw_support/include/esp_private/rtc_ctrl.h +++ b/components/esp_hw_support/include/esp_private/rtc_ctrl.h @@ -14,6 +14,8 @@ extern "C" { #endif +#define RTC_INTR_FLAG_IRAM (BIT(0)) /*< Some rtc interrupts can be called with cache disabled */ + /** * @brief Register a handler for specific RTC_CNTL interrupts * @@ -25,13 +27,17 @@ extern "C" { * @param handler_arg argument to be passed to the handler * @param rtc_intr_mask combination of RTC_CNTL_*_INT_ENA bits indicating the * sources to call the handler for + * @param flags An ORred mask of the RTC_INTR_FLAG_* defines. You can pass different + * flags to it to realize different purpose. If 0, the interrupt will + * not handle anything special. If you pass `RTC_INTR_FLAG_IRAM`, means + * the interrupt can be triggered with cache disabled. * @return * - ESP_OK on success * - ESP_ERR_NO_MEM not enough memory to allocate handler structure * - other errors returned by esp_intr_alloc */ esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, - uint32_t rtc_intr_mask); + uint32_t rtc_intr_mask, uint32_t flags); /** * @brief Deregister the handler previously registered using rtc_isr_register * @param handler handler function to call (as passed to rtc_isr_register) @@ -43,6 +49,24 @@ esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, */ esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg); +/** + * @brief Disable the RTC interrupt that is allowed to be executed when cache is disabled. + * cache disabled. Internal interrupt handle function will call this function in interrupt + * handler function. Disable bits when `esp_intr_noniram_disable` is called. + * + * @param cpu CPU number. + */ +void rtc_isr_noniram_disable(uint32_t cpu); + +/** + * @brief Enable the RTC interrupt that is allowed to be executed when cache is disabled. + * cache disabled. Internal interrupt handle function will call this function in interrupt + * handler function. Enable bits when `esp_intr_noniram_enable` is called. + * + * @param cpu CPU number. + */ +void rtc_isr_noniram_enable(uint32_t cpu); + #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/intr_alloc.c b/components/esp_hw_support/intr_alloc.c index 9c5d204e58..1801f483c9 100644 --- a/components/esp_hw_support/intr_alloc.c +++ b/components/esp_hw_support/intr_alloc.c @@ -20,6 +20,7 @@ #include "esp_intr_alloc.h" #include "esp_attr.h" #include "hal/cpu_hal.h" +#include "esp_private/rtc_ctrl.h" #include "hal/interrupt_controller_hal.h" #if !CONFIG_FREERTOS_UNICORE @@ -797,6 +798,8 @@ void IRAM_ATTR esp_intr_noniram_disable(void) non_iram_int_disabled_flag[cpu] = true; oldint = interrupt_controller_hal_read_interrupt_mask(); interrupt_controller_hal_disable_interrupts(non_iram_ints); + // Disable the RTC bit which don't want to be put in IRAM. + rtc_isr_noniram_disable(cpu); // Save disabled ints non_iram_int_disabled[cpu] = oldint & non_iram_ints; portEXIT_CRITICAL_SAFE(&spinlock); @@ -812,6 +815,7 @@ void IRAM_ATTR esp_intr_noniram_enable(void) } non_iram_int_disabled_flag[cpu] = false; interrupt_controller_hal_enable_interrupts(non_iram_ints); + rtc_isr_noniram_enable(cpu); portEXIT_CRITICAL_SAFE(&spinlock); } diff --git a/components/esp_hw_support/rtc_module.c b/components/esp_hw_support/rtc_module.c index 76bdd26e8c..640f4c1db6 100644 --- a/components/esp_hw_support/rtc_module.c +++ b/components/esp_hw_support/rtc_module.c @@ -19,6 +19,7 @@ #include "esp_intr_alloc.h" #include "sys/lock.h" #include "esp_private/rtc_ctrl.h" +#include "esp_attr.h" #ifndef NDEBUG // Enable built-in checks in queue.h in debug builds @@ -26,7 +27,15 @@ #endif #include "sys/queue.h" +#define NOT_REGISTERED (-1) + portMUX_TYPE rtc_spinlock = portMUX_INITIALIZER_UNLOCKED; +// Disable the interrupt which cannot work without cache. +static DRAM_ATTR uint32_t rtc_intr_cache; +static DRAM_ATTR uint32_t rtc_intr_enabled; +static DRAM_ATTR int rtc_isr_cpu = NOT_REGISTERED; // Unused number +static void s_rtc_isr_noniram_hook(uint32_t rtc_intr_mask); +static void s_rtc_isr_noniram_hook_relieve(uint32_t rtc_intr_mask); /*--------------------------------------------------------------- INTERRUPT HANDLER @@ -37,15 +46,16 @@ typedef struct rtc_isr_handler_ { uint32_t mask; intr_handler_t handler; void* handler_arg; + uint32_t flags; SLIST_ENTRY(rtc_isr_handler_) next; } rtc_isr_handler_t; -static SLIST_HEAD(rtc_isr_handler_list_, rtc_isr_handler_) s_rtc_isr_handler_list = +static DRAM_ATTR SLIST_HEAD(rtc_isr_handler_list_, rtc_isr_handler_) s_rtc_isr_handler_list = SLIST_HEAD_INITIALIZER(s_rtc_isr_handler_list); -portMUX_TYPE s_rtc_isr_handler_list_lock = portMUX_INITIALIZER_UNLOCKED; +static DRAM_ATTR portMUX_TYPE s_rtc_isr_handler_list_lock = portMUX_INITIALIZER_UNLOCKED; static intr_handle_t s_rtc_isr_handle; -static void rtc_isr(void* arg) +IRAM_ATTR static void rtc_isr(void* arg) { uint32_t status = REG_READ(RTC_CNTL_INT_ST_REG); rtc_isr_handler_t* it; @@ -71,32 +81,37 @@ static esp_err_t rtc_isr_ensure_installed(void) REG_WRITE(RTC_CNTL_INT_ENA_REG, 0); REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX); - err = esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, 0, &rtc_isr, NULL, &s_rtc_isr_handle); + err = esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, ESP_INTR_FLAG_IRAM, &rtc_isr, NULL, &s_rtc_isr_handle); if (err != ESP_OK) { goto out; } - + rtc_isr_cpu = esp_intr_get_cpu(s_rtc_isr_handle); out: portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock); return err; } - -esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, uint32_t rtc_intr_mask) +esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, uint32_t rtc_intr_mask, uint32_t flags) { esp_err_t err = rtc_isr_ensure_installed(); if (err != ESP_OK) { return err; } - rtc_isr_handler_t* item = malloc(sizeof(*item)); + rtc_isr_handler_t* item = heap_caps_malloc(sizeof(*item), MALLOC_CAP_INTERNAL); if (item == NULL) { return ESP_ERR_NO_MEM; } item->handler = handler; item->handler_arg = handler_arg; item->mask = rtc_intr_mask; + item->flags = flags; portENTER_CRITICAL(&s_rtc_isr_handler_list_lock); + if (flags & RTC_INTR_FLAG_IRAM) { + s_rtc_isr_noniram_hook(rtc_intr_mask); + } else { + s_rtc_isr_noniram_hook_relieve(rtc_intr_mask); + } SLIST_INSERT_HEAD(&s_rtc_isr_handler_list, item, next); portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock); return ESP_OK; @@ -116,6 +131,9 @@ esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg) SLIST_REMOVE_AFTER(prev, next); } found = true; + if (it->flags & RTC_INTR_FLAG_IRAM) { + s_rtc_isr_noniram_hook_relieve(it->mask); + } free(it); break; } @@ -124,3 +142,37 @@ esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg) portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock); return found ? ESP_OK : ESP_ERR_INVALID_STATE; } + +/** + * @brief This helper function can be used to avoid the interrupt to be triggered with cache disabled. + * There are lots of different signals on RTC module (i.e. sleep_wakeup, wdt, brownout_detect, etc.) + * We might want some of them can be triggered with cache disabled, some are not. Therefore, this function + * is created to avoid those which do not want to be triggered with cache disabled. + * + * @param rtc_intr_mask the mask of the rtc interrupt. + */ +static void s_rtc_isr_noniram_hook(uint32_t rtc_intr_mask) +{ + rtc_intr_cache |= rtc_intr_mask; +} + +static void s_rtc_isr_noniram_hook_relieve(uint32_t rtc_intr_mask) +{ + rtc_intr_cache &= ~rtc_intr_mask; +} + +IRAM_ATTR void rtc_isr_noniram_disable(uint32_t cpu) +{ + if (rtc_isr_cpu == cpu) { + rtc_intr_enabled |= RTCCNTL.int_ena.val; + RTCCNTL.int_ena.val &= rtc_intr_cache; + } +} + +IRAM_ATTR void rtc_isr_noniram_enable(uint32_t cpu) +{ + if (rtc_isr_cpu == cpu) { + RTCCNTL.int_ena.val = rtc_intr_enabled; + rtc_intr_enabled = 0; + } +} diff --git a/components/esp_system/xt_wdt.c b/components/esp_system/xt_wdt.c index 67d9977fb8..90bbb8e443 100644 --- a/components/esp_system/xt_wdt.c +++ b/components/esp_system/xt_wdt.c @@ -62,7 +62,7 @@ esp_err_t esp_xt_wdt_init(const esp_xt_wdt_config_t *cfg) xt_wdt_hal_enable_backup_clk(&s_hal_ctx, rtc_clk_frequency_khz); } - ESP_GOTO_ON_ERROR(rtc_isr_register(rtc_xt_wdt_default_isr_handler, NULL, XT_WDT_LL_XTAL32_DEAD_INTR_MASK), err, TAG, "Failed to register isr"); + ESP_GOTO_ON_ERROR(rtc_isr_register(rtc_xt_wdt_default_isr_handler, NULL, XT_WDT_LL_XTAL32_DEAD_INTR_MASK, 0), err, TAG, "Failed to register isr"); xt_wdt_hal_enable(&s_hal_ctx, 1);