From 55be8bdc0d2b16e31c77e3de8bf8a256175c9b6d Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Mon, 3 Mar 2025 14:16:44 +0800 Subject: [PATCH] feat(esp_timer): added kconfig option for placing IRAM code into flash --- components/esp_pm/Kconfig | 2 +- components/esp_timer/Kconfig | 8 ++- .../private_include/esp_timer_impl.h | 9 +++- components/esp_timer/src/esp_timer.c | 42 ++++++++-------- .../esp_timer/src/esp_timer_impl_common.c | 8 +-- components/esp_timer/src/esp_timer_impl_lac.c | 17 ++++--- .../esp_timer/src/esp_timer_impl_systimer.c | 17 ++++--- components/esp_timer/src/ets_timer_legacy.c | 11 +++-- components/esp_timer/src/system_time.c | 4 +- .../esp_timer/test_apps/main/test_ets_timer.c | 49 ++++++++++++------- .../test_apps/pytest_esp_timer_ut.py | 26 +++++----- .../test_apps/sdkconfig.ci.flash_auto_suspend | 3 ++ components/unity/unity_utils_cache.c | 7 ++- ...dkconfig.flash_auto_suspend_iram_reduction | 2 + 14 files changed, 123 insertions(+), 82 deletions(-) create mode 100644 components/esp_timer/test_apps/sdkconfig.ci.flash_auto_suspend diff --git a/components/esp_pm/Kconfig b/components/esp_pm/Kconfig index b4fbae2b2c..63340d08db 100644 --- a/components/esp_pm/Kconfig +++ b/components/esp_pm/Kconfig @@ -49,7 +49,7 @@ menu "Power Management" config PM_SLP_IRAM_OPT bool "Put lightsleep related codes in internal RAM" - depends on SOC_LIGHT_SLEEP_SUPPORTED + depends on SOC_LIGHT_SLEEP_SUPPORTED && ESP_TIMER_IN_IRAM help If enabled, about 2.1KB of lightsleep related source code would be in IRAM and chip would sleep longer for 310us at 160MHz CPU frequency most each time. diff --git a/components/esp_timer/Kconfig b/components/esp_timer/Kconfig index 5560dc6936..9ffe0f5d1e 100644 --- a/components/esp_timer/Kconfig +++ b/components/esp_timer/Kconfig @@ -1,5 +1,9 @@ menu "ESP Timer (High Resolution Timer)" + config ESP_TIMER_IN_IRAM + bool "Place esp_timer functions in IRAM" if SPI_FLASH_AUTO_SUSPEND + default y + config ESP_TIMER_PROFILING bool "Enable esp_timer profiling features" default n @@ -25,7 +29,7 @@ menu "ESP Timer (High Resolution Timer)" help Configure the stack size of "timer_task" task. This task is used to dispatch callbacks of timers created using ets_timer and esp_timer - APIs. If you are seing stack overflow errors in timer task, increase + APIs. If you are seeing stack overflow errors in timer task, increase this value. Note that this is not the same as FreeRTOS timer task. To configure @@ -102,7 +106,7 @@ menu "ESP Timer (High Resolution Timer)" bool "Support ISR dispatch method" default n help - Allows using ESP_TIMER_ISR dispatch method (ESP_TIMER_TASK dispatch method is also avalible). + Allows using ESP_TIMER_ISR dispatch method (ESP_TIMER_TASK dispatch method is also available). - ESP_TIMER_TASK - Timer callbacks are dispatched from a high-priority esp_timer task. - ESP_TIMER_ISR - Timer callbacks are dispatched directly from the timer interrupt handler. The ISR dispatch can be used, in some cases, when a callback is very simple diff --git a/components/esp_timer/private_include/esp_timer_impl.h b/components/esp_timer/private_include/esp_timer_impl.h index d6484cbb95..50bdd06d75 100644 --- a/components/esp_timer/private_include/esp_timer_impl.h +++ b/components/esp_timer/private_include/esp_timer_impl.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,6 +19,13 @@ #include #include "esp_err.h" #include "esp_intr_alloc.h" +#include "sdkconfig.h" + +#if CONFIG_ESP_TIMER_IN_IRAM +#define ESP_TIMER_IRAM_ATTR IRAM_ATTR +#else +#define ESP_TIMER_IRAM_ATTR +#endif // CONFIG_ESP_TIMER_IN_IRAM /** * @brief Minimal initialization of platform specific layer of esp_timer diff --git a/components/esp_timer/src/esp_timer.c b/components/esp_timer/src/esp_timer.c index 9e841ef808..f3eb60bdfe 100644 --- a/components/esp_timer/src/esp_timer.c +++ b/components/esp_timer/src/esp_timer.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -132,7 +132,7 @@ esp_err_t esp_timer_create(const esp_timer_create_args_t* args, * But actually in IDF esp_timer_restart is used only in one place, which requires keeping * in IRAM when PM_SLP_IRAM_OPT = y and ESP_TASK_WDT USE ESP_TIMER = y. */ -esp_err_t IRAM_ATTR esp_timer_restart(esp_timer_handle_t timer, uint64_t timeout_us) +esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_restart(esp_timer_handle_t timer, uint64_t timeout_us) { esp_err_t ret = ESP_OK; @@ -177,7 +177,7 @@ esp_err_t IRAM_ATTR esp_timer_restart(esp_timer_handle_t timer, uint64_t timeout return ret; } -esp_err_t IRAM_ATTR esp_timer_start_once(esp_timer_handle_t timer, uint64_t timeout_us) +esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_once(esp_timer_handle_t timer, uint64_t timeout_us) { if (timer == NULL) { return ESP_ERR_INVALID_ARG; @@ -210,7 +210,7 @@ esp_err_t IRAM_ATTR esp_timer_start_once(esp_timer_handle_t timer, uint64_t time return err; } -esp_err_t IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period_us) +esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period_us) { if (timer == NULL) { return ESP_ERR_INVALID_ARG; @@ -240,7 +240,7 @@ esp_err_t IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t return err; } -esp_err_t IRAM_ATTR esp_timer_stop(esp_timer_handle_t timer) +esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_stop(esp_timer_handle_t timer) { if (timer == NULL) { return ESP_ERR_INVALID_ARG; @@ -291,7 +291,7 @@ esp_err_t esp_timer_delete(esp_timer_handle_t timer) return err; } -static IRAM_ATTR esp_err_t timer_insert(esp_timer_handle_t timer, bool without_update_alarm) +static ESP_TIMER_IRAM_ATTR esp_err_t timer_insert(esp_timer_handle_t timer, bool without_update_alarm) { #if WITH_PROFILING timer_remove_inactive(timer); @@ -319,7 +319,7 @@ static IRAM_ATTR esp_err_t timer_insert(esp_timer_handle_t timer, bool without_u return ESP_OK; } -static IRAM_ATTR esp_err_t timer_remove(esp_timer_handle_t timer) +static ESP_TIMER_IRAM_ATTR esp_err_t timer_remove(esp_timer_handle_t timer) { esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD; timer_list_lock(dispatch_method); @@ -344,7 +344,7 @@ static IRAM_ATTR esp_err_t timer_remove(esp_timer_handle_t timer) #if WITH_PROFILING -static IRAM_ATTR void timer_insert_inactive(esp_timer_handle_t timer) +static ESP_TIMER_IRAM_ATTR void timer_insert_inactive(esp_timer_handle_t timer) { /* May be locked or not, depending on where this is called from. * Lock recursively. @@ -361,30 +361,30 @@ static IRAM_ATTR void timer_insert_inactive(esp_timer_handle_t timer) } } -static IRAM_ATTR void timer_remove_inactive(esp_timer_handle_t timer) +static ESP_TIMER_IRAM_ATTR void timer_remove_inactive(esp_timer_handle_t timer) { LIST_REMOVE(timer, list_entry); } #endif // WITH_PROFILING -static IRAM_ATTR bool timer_armed(esp_timer_handle_t timer) +static ESP_TIMER_IRAM_ATTR bool timer_armed(esp_timer_handle_t timer) { return timer->alarm > 0; } -static IRAM_ATTR void timer_list_lock(esp_timer_dispatch_t timer_type) +static ESP_TIMER_IRAM_ATTR void timer_list_lock(esp_timer_dispatch_t timer_type) { portENTER_CRITICAL_SAFE(&s_timer_lock[timer_type]); } -static IRAM_ATTR void timer_list_unlock(esp_timer_dispatch_t timer_type) +static ESP_TIMER_IRAM_ATTR void timer_list_unlock(esp_timer_dispatch_t timer_type) { portEXIT_CRITICAL_SAFE(&s_timer_lock[timer_type]); } #ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD -static IRAM_ATTR bool timer_process_alarm(esp_timer_dispatch_t dispatch_method) +static ESP_TIMER_IRAM_ATTR bool timer_process_alarm(esp_timer_dispatch_t dispatch_method) #else static bool timer_process_alarm(esp_timer_dispatch_t dispatch_method) #endif @@ -463,14 +463,14 @@ static void timer_task(void* arg) } #ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD -IRAM_ATTR void esp_timer_isr_dispatch_need_yield(void) +ESP_TIMER_IRAM_ATTR void esp_timer_isr_dispatch_need_yield(void) { assert(xPortInIsrContext()); s_isr_dispatch_need_yield = pdTRUE; } #endif -static void IRAM_ATTR timer_alarm_handler(void* arg) +static void ESP_TIMER_IRAM_ATTR timer_alarm_handler(void* arg) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; bool isr_timers_processed = false; @@ -491,7 +491,7 @@ static void IRAM_ATTR timer_alarm_handler(void* arg) } } -static IRAM_ATTR inline bool is_initialized(void) +static ESP_TIMER_IRAM_ATTR inline bool is_initialized(void) { return s_timer_task != NULL; } @@ -687,7 +687,7 @@ esp_err_t esp_timer_dump(FILE* stream) return ESP_OK; } -int64_t IRAM_ATTR esp_timer_get_next_alarm(void) +int64_t ESP_TIMER_IRAM_ATTR esp_timer_get_next_alarm(void) { int64_t next_alarm = INT64_MAX; for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) { @@ -703,7 +703,7 @@ int64_t IRAM_ATTR esp_timer_get_next_alarm(void) return next_alarm; } -int64_t IRAM_ATTR esp_timer_get_next_alarm_for_wake_up(void) +int64_t ESP_TIMER_IRAM_ATTR esp_timer_get_next_alarm_for_wake_up(void) { int64_t next_alarm = INT64_MAX; for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) { @@ -723,7 +723,7 @@ int64_t IRAM_ATTR esp_timer_get_next_alarm_for_wake_up(void) return next_alarm; } -esp_err_t IRAM_ATTR esp_timer_get_period(esp_timer_handle_t timer, uint64_t *period) +esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_get_period(esp_timer_handle_t timer, uint64_t *period) { if (timer == NULL || period == NULL) { return ESP_ERR_INVALID_ARG; @@ -738,7 +738,7 @@ esp_err_t IRAM_ATTR esp_timer_get_period(esp_timer_handle_t timer, uint64_t *per return ESP_OK; } -esp_err_t IRAM_ATTR esp_timer_get_expiry_time(esp_timer_handle_t timer, uint64_t *expiry) +esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_get_expiry_time(esp_timer_handle_t timer, uint64_t *expiry) { if (timer == NULL || expiry == NULL) { return ESP_ERR_INVALID_ARG; @@ -758,7 +758,7 @@ esp_err_t IRAM_ATTR esp_timer_get_expiry_time(esp_timer_handle_t timer, uint64_t return ESP_OK; } -bool IRAM_ATTR esp_timer_is_active(esp_timer_handle_t timer) +bool ESP_TIMER_IRAM_ATTR esp_timer_is_active(esp_timer_handle_t timer) { if (timer == NULL) { return false; diff --git a/components/esp_timer/src/esp_timer_impl_common.c b/components/esp_timer/src/esp_timer_impl_common.c index eb31d75d01..94eef0bfc9 100644 --- a/components/esp_timer/src/esp_timer_impl_common.c +++ b/components/esp_timer/src/esp_timer_impl_common.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -32,13 +32,13 @@ void esp_timer_impl_unlock(void) void esp_timer_private_lock(void) __attribute__((alias("esp_timer_impl_lock"))); void esp_timer_private_unlock(void) __attribute__((alias("esp_timer_impl_unlock"))); -void IRAM_ATTR esp_timer_impl_set_alarm(uint64_t timestamp) +void ESP_TIMER_IRAM_ATTR esp_timer_impl_set_alarm(uint64_t timestamp) { esp_timer_impl_set_alarm_id(timestamp, 0); } #ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD -void IRAM_ATTR esp_timer_impl_try_to_set_next_alarm(void) +void ESP_TIMER_IRAM_ATTR esp_timer_impl_try_to_set_next_alarm(void) { portENTER_CRITICAL_ISR(&s_time_update_lock); unsigned now_alarm_idx; // ISR is called due to this current alarm @@ -65,7 +65,7 @@ void IRAM_ATTR esp_timer_impl_try_to_set_next_alarm(void) #endif /* FIXME: This value is safe for 80MHz APB frequency, should be modified to depend on clock frequency. */ -uint64_t IRAM_ATTR esp_timer_impl_get_min_period_us(void) +uint64_t ESP_TIMER_IRAM_ATTR esp_timer_impl_get_min_period_us(void) { return 50; } diff --git a/components/esp_timer/src/esp_timer_impl_lac.c b/components/esp_timer/src/esp_timer_impl_lac.c index 79503303af..f3978d22d8 100644 --- a/components/esp_timer/src/esp_timer_impl_lac.c +++ b/components/esp_timer/src/esp_timer_impl_lac.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -106,7 +106,7 @@ extern portMUX_TYPE s_time_update_lock; /* Alarm values to generate interrupt on match */ extern uint64_t timestamp_id[2]; -uint64_t IRAM_ATTR esp_timer_impl_get_counter_reg(void) +uint64_t ESP_TIMER_IRAM_ATTR esp_timer_impl_get_counter_reg(void) { uint32_t lo, hi; uint32_t lo_start = REG_READ(COUNT_LO_REG); @@ -137,14 +137,14 @@ uint64_t IRAM_ATTR esp_timer_impl_get_counter_reg(void) return result.val; } -int64_t IRAM_ATTR esp_timer_impl_get_time(void) +int64_t ESP_TIMER_IRAM_ATTR esp_timer_impl_get_time(void) { return esp_timer_impl_get_counter_reg() / TICKS_PER_US; } int64_t esp_timer_get_time(void) __attribute__((alias("esp_timer_impl_get_time"))); -void IRAM_ATTR esp_timer_impl_set_alarm_id(uint64_t timestamp, unsigned alarm_id) +void ESP_TIMER_IRAM_ATTR esp_timer_impl_set_alarm_id(uint64_t timestamp, unsigned alarm_id) { assert(alarm_id < sizeof(timestamp_id) / sizeof(timestamp_id[0])); portENTER_CRITICAL_SAFE(&s_time_update_lock); @@ -174,7 +174,7 @@ void IRAM_ATTR esp_timer_impl_set_alarm_id(uint64_t timestamp, unsigned alarm_id portEXIT_CRITICAL_SAFE(&s_time_update_lock); } -static void IRAM_ATTR timer_alarm_isr(void *arg) +static void ESP_TIMER_IRAM_ATTR timer_alarm_isr(void *arg) { #if ISR_HANDLERS == 1 /* Clear interrupt status */ @@ -220,7 +220,7 @@ static void IRAM_ATTR timer_alarm_isr(void *arg) #endif // ISR_HANDLERS != 1 } -void IRAM_ATTR esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us) +void ESP_TIMER_IRAM_ATTR esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us) { portENTER_CRITICAL_SAFE(&s_time_update_lock); assert(apb_ticks_per_us >= 3 && "divider value too low"); @@ -278,7 +278,10 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) int isr_flags = ESP_INTR_FLAG_INTRDISABLED | ((1 << CONFIG_ESP_TIMER_INTERRUPT_LEVEL) & ESP_INTR_FLAG_LEVELMASK) - | ESP_INTR_FLAG_IRAM; +#if CONFIG_ESP_TIMER_IN_IRAM + | ESP_INTR_FLAG_IRAM +#endif + ; esp_err_t err = esp_intr_alloc(INTR_SOURCE_LACT, isr_flags, &timer_alarm_isr, NULL, diff --git a/components/esp_timer/src/esp_timer_impl_systimer.c b/components/esp_timer/src/esp_timer_impl_systimer.c index 97d3c56ab4..2b6c9050bc 100644 --- a/components/esp_timer/src/esp_timer_impl_systimer.c +++ b/components/esp_timer/src/esp_timer_impl_systimer.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -60,12 +60,12 @@ extern portMUX_TYPE s_time_update_lock; /* Alarm values to generate interrupt on match */ extern uint64_t timestamp_id[2]; -uint64_t IRAM_ATTR esp_timer_impl_get_counter_reg(void) +uint64_t ESP_TIMER_IRAM_ATTR esp_timer_impl_get_counter_reg(void) { return systimer_hal_get_counter_value(&systimer_hal, SYSTIMER_COUNTER_ESPTIMER); } -int64_t IRAM_ATTR esp_timer_impl_get_time(void) +int64_t ESP_TIMER_IRAM_ATTR esp_timer_impl_get_time(void) { // we hope the execution time of this function won't > 1us // thus, to save one function call, we didn't use the existing `systimer_hal_get_time` @@ -74,7 +74,7 @@ int64_t IRAM_ATTR esp_timer_impl_get_time(void) int64_t esp_timer_get_time(void) __attribute__((alias("esp_timer_impl_get_time"))); -void IRAM_ATTR esp_timer_impl_set_alarm_id(uint64_t timestamp, unsigned alarm_id) +void ESP_TIMER_IRAM_ATTR esp_timer_impl_set_alarm_id(uint64_t timestamp, unsigned alarm_id) { assert(alarm_id < sizeof(timestamp_id) / sizeof(timestamp_id[0])); portENTER_CRITICAL_SAFE(&s_time_update_lock); @@ -84,7 +84,7 @@ void IRAM_ATTR esp_timer_impl_set_alarm_id(uint64_t timestamp, unsigned alarm_id portEXIT_CRITICAL_SAFE(&s_time_update_lock); } -static void IRAM_ATTR timer_alarm_isr(void *arg) +static void ESP_TIMER_IRAM_ATTR timer_alarm_isr(void *arg) { #if ISR_HANDLERS == 1 // clear the interrupt @@ -129,7 +129,7 @@ static void IRAM_ATTR timer_alarm_isr(void *arg) #endif // ISR_HANDLERS != 1 } -void IRAM_ATTR esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us) +void ESP_TIMER_IRAM_ATTR esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us) { #if !SOC_SYSTIMER_FIXED_DIVIDER systimer_hal_on_apb_freq_update(&systimer_hal, apb_ticks_per_us); @@ -200,7 +200,10 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) #if !SOC_SYSTIMER_INT_LEVEL | ESP_INTR_FLAG_EDGE #endif - | ESP_INTR_FLAG_IRAM; +#if CONFIG_ESP_TIMER_IN_IRAM + | ESP_INTR_FLAG_IRAM +#endif + ; esp_err_t err = esp_intr_alloc(ETS_SYSTIMER_TARGET2_INTR_SOURCE, isr_flags, &timer_alarm_isr, NULL, diff --git a/components/esp_timer/src/ets_timer_legacy.c b/components/esp_timer/src/ets_timer_legacy.c index 2e8a024473..1bf801e530 100644 --- a/components/esp_timer/src/ets_timer_legacy.c +++ b/components/esp_timer/src/ets_timer_legacy.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2010-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -21,6 +21,7 @@ #include "freertos/semphr.h" #include "sdkconfig.h" #include "esp_timer.h" +#include "esp_timer_impl.h" // for ETSTimer type #include "rom/ets_sys.h" @@ -34,7 +35,7 @@ #define TIMER_INITIALIZED_FIELD(p_ets_timer) ((p_ets_timer)->timer_expire) #define TIMER_INITIALIZED_VAL 0x12121212 -static IRAM_ATTR bool timer_initialized(ETSTimer *ptimer) +static ESP_TIMER_IRAM_ATTR bool timer_initialized(ETSTimer *ptimer) { return TIMER_INITIALIZED_FIELD(ptimer) == TIMER_INITIALIZED_VAL; } @@ -58,7 +59,7 @@ void ets_timer_setfn(ETSTimer *ptimer, ETSTimerFunc *pfunction, void *parg) } } -void IRAM_ATTR ets_timer_arm_us(ETSTimer *ptimer, uint32_t time_us, bool repeat_flag) +void ESP_TIMER_IRAM_ATTR ets_timer_arm_us(ETSTimer *ptimer, uint32_t time_us, bool repeat_flag) { assert(timer_initialized(ptimer)); esp_timer_stop(ESP_TIMER(ptimer)); // no error check @@ -69,7 +70,7 @@ void IRAM_ATTR ets_timer_arm_us(ETSTimer *ptimer, uint32_t time_us, bool repeat_ } } -void IRAM_ATTR ets_timer_arm(ETSTimer *ptimer, uint32_t time_ms, bool repeat_flag) +void ESP_TIMER_IRAM_ATTR ets_timer_arm(ETSTimer *ptimer, uint32_t time_ms, bool repeat_flag) { uint64_t time_us = 1000LL * (uint64_t) time_ms; assert(timer_initialized(ptimer)); @@ -90,7 +91,7 @@ void ets_timer_done(ETSTimer *ptimer) } } -void IRAM_ATTR ets_timer_disarm(ETSTimer *ptimer) +void ESP_TIMER_IRAM_ATTR ets_timer_disarm(ETSTimer *ptimer) { if (timer_initialized(ptimer)) { esp_timer_stop(ESP_TIMER(ptimer)); diff --git a/components/esp_timer/src/system_time.c b/components/esp_timer/src/system_time.c index e9f4c52dc0..9b7ed25568 100644 --- a/components/esp_timer/src/system_time.c +++ b/components/esp_timer/src/system_time.c @@ -35,12 +35,12 @@ void esp_timer_impl_init_system_time(void) #endif } -int64_t IRAM_ATTR esp_system_get_time(void) +int64_t ESP_TIMER_IRAM_ATTR esp_system_get_time(void) { return esp_timer_get_time() + s_correction_us; } -uint32_t IRAM_ATTR esp_system_get_time_resolution(void) +uint32_t ESP_TIMER_IRAM_ATTR esp_system_get_time_resolution(void) { return 1000; } diff --git a/components/esp_timer/test_apps/main/test_ets_timer.c b/components/esp_timer/test_apps/main/test_ets_timer.c index 22ab9ef56e..a9045562e8 100644 --- a/components/esp_timer/test_apps/main/test_ets_timer.c +++ b/components/esp_timer/test_apps/main/test_ets_timer.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,7 @@ #include "esp_rom_sys.h" #include "esp_private/spi_flash_os.h" #include "rom/ets_sys.h" +#include "unity_test_utils_cache.h" static void test_correct_delay_timer_func(void* arg) { @@ -210,40 +211,52 @@ static void IRAM_ATTR test_iram_timer_func(void* arg) *b = true; } +#define INTERVAL 5 + +void IRAM_ATTR test_iram_arm_disarm(void *ctx) +{ + ETSTimer *timer1 = (ETSTimer*)ctx; + + ets_timer_arm(timer1, INTERVAL, false); + // redundant call is deliberate (test code path if already armed) + ets_timer_arm(timer1, INTERVAL, false); + ets_timer_disarm(timer1); +} + +void IRAM_ATTR test_iram_arm(void *ctx) +{ + ETSTimer *timer1 = (ETSTimer*)ctx; + + ets_timer_arm(timer1, INTERVAL, false); +} + +void IRAM_ATTR test_iram_disarm(void *ctx) +{ + ETSTimer *timer1 = (ETSTimer*)ctx; + + ets_timer_disarm(timer1); +} + /* WiFi/BT coexistence will sometimes arm/disarm timers from an ISR where flash may be disabled. */ IRAM_ATTR TEST_CASE("ETSTimers arm & disarm run from IRAM", "[ets_timer]") { volatile bool flag = false; ETSTimer timer1; - const int INTERVAL = 5; ets_timer_setfn(&timer1, &test_iram_timer_func, (void *)&flag); /* arm a disabled timer, then disarm a live timer */ - - spi_flash_guard_get()->start(); // Disables flash cache - - ets_timer_arm(&timer1, INTERVAL, false); - // redundant call is deliberate (test code path if already armed) - ets_timer_arm(&timer1, INTERVAL, false); - ets_timer_disarm(&timer1); - - spi_flash_guard_get()->end(); // Re-enables flash cache + unity_utils_run_cache_disable_stub(test_iram_arm_disarm, &timer1); TEST_ASSERT_FALSE(flag); // didn't expire yet /* do the same thing but wait for the timer to expire */ - - spi_flash_guard_get()->start(); - ets_timer_arm(&timer1, INTERVAL, false); - spi_flash_guard_get()->end(); + unity_utils_run_cache_disable_stub(test_iram_arm, &timer1); vTaskDelay(2 * INTERVAL / portTICK_PERIOD_MS); TEST_ASSERT_TRUE(flag); - spi_flash_guard_get()->start(); - ets_timer_disarm(&timer1); - spi_flash_guard_get()->end(); + unity_utils_run_cache_disable_stub(test_iram_disarm, &timer1); ets_timer_done(&timer1); } diff --git a/components/esp_timer/test_apps/pytest_esp_timer_ut.py b/components/esp_timer/test_apps/pytest_esp_timer_ut.py index 26e520e27b..1c3c991fbe 100644 --- a/components/esp_timer/test_apps/pytest_esp_timer_ut.py +++ b/components/esp_timer/test_apps/pytest_esp_timer_ut.py @@ -4,19 +4,6 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize -CONFIGS = [ - pytest.param('general', marks=[pytest.mark.supported_targets]), - pytest.param('release', marks=[pytest.mark.supported_targets]), - pytest.param('single_core', marks=[pytest.mark.esp32]), - pytest.param('freertos_compliance', marks=[pytest.mark.esp32]), - pytest.param('isr_dispatch_esp32', marks=[pytest.mark.esp32]), - pytest.param('isr_dispatch_esp32c3', marks=[pytest.mark.esp32c3]), - pytest.param('cpu1_esp32', marks=[pytest.mark.esp32]), - pytest.param('any_cpu_esp32', marks=[pytest.mark.esp32]), - pytest.param('cpu1_esp32s3', marks=[pytest.mark.esp32s3]), - pytest.param('any_cpu_esp32s3', marks=[pytest.mark.esp32s3]), -] - @pytest.mark.generic @idf_parametrize( @@ -65,3 +52,16 @@ def test_esp_timer_psram(dut: Dut) -> None: @idf_parametrize('target', ['esp32c2'], indirect=['target']) def test_esp_timer_esp32c2_xtal_26mhz(dut: Dut) -> None: dut.run_all_single_board_cases(timeout=120) + + +@pytest.mark.flash_suspend +@pytest.mark.parametrize( + 'config', + [ + 'flash_auto_suspend', + ], + indirect=True, +) +@idf_parametrize('target', ['esp32c3'], indirect=['target']) +def test_esp_timer_flash_auto_suspend(dut: Dut) -> None: + dut.run_all_single_board_cases(timeout=120) diff --git a/components/esp_timer/test_apps/sdkconfig.ci.flash_auto_suspend b/components/esp_timer/test_apps/sdkconfig.ci.flash_auto_suspend new file mode 100644 index 0000000000..7d27ffd82f --- /dev/null +++ b/components/esp_timer/test_apps/sdkconfig.ci.flash_auto_suspend @@ -0,0 +1,3 @@ +CONFIG_SPI_FLASH_AUTO_SUSPEND=y +CONFIG_ESP_TIMER_IN_IRAM=n +CONFIG_SPI_FLASH_FORCE_ENABLE_XMC_C_SUSPEND=y diff --git a/components/unity/unity_utils_cache.c b/components/unity/unity_utils_cache.c index 5d44ec0a0e..8c13bc529d 100644 --- a/components/unity/unity_utils_cache.c +++ b/components/unity/unity_utils_cache.c @@ -1,9 +1,10 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ +#include "sdkconfig.h" #include "unity.h" #include "unity_test_utils_cache.h" #include "esp_attr.h" @@ -12,11 +13,15 @@ IRAM_ATTR void unity_utils_run_cache_disable_stub(void (*post_cache_disable)(void *), void *user_ctx) { +#if !CONFIG_SPI_FLASH_AUTO_SUSPEND // callback function must reside in IRAM TEST_ASSERT_TRUE(esp_ptr_in_iram(post_cache_disable)); // disable flash cache spi_flash_guard_get()->start(); +#endif post_cache_disable(user_ctx); // enable flash cache +#if !CONFIG_SPI_FLASH_AUTO_SUSPEND spi_flash_guard_get()->end(); +#endif } diff --git a/tools/test_apps/configs/sdkconfig.flash_auto_suspend_iram_reduction b/tools/test_apps/configs/sdkconfig.flash_auto_suspend_iram_reduction index 756b665313..8a5619bd19 100644 --- a/tools/test_apps/configs/sdkconfig.flash_auto_suspend_iram_reduction +++ b/tools/test_apps/configs/sdkconfig.flash_auto_suspend_iram_reduction @@ -13,3 +13,5 @@ CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH=y # Options that will enable IRAM reduction option that are only usable together with flash auto-suspend CONFIG_SPI_FLASH_AUTO_SUSPEND=y CONFIG_LIBC_MISC_IN_IRAM=n +CONFIG_ESP_TIMER_IN_IRAM=n +CONFIG_SPI_FLASH_PLACE_FUNCTIONS_IN_IRAM=n