From 18506d945ff58b00d73ab761572c453b1c1315dc Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Fri, 21 Mar 2025 20:49:24 +0800 Subject: [PATCH] feat(esp_hw_support): remeasure sleep_time_overhead_out if min_freq_mhz changed --- .../include/esp_private/esp_sleep_internal.h | 11 +++++++- components/esp_hw_support/sleep_modes.c | 25 +++++++++++++++++-- components/esp_pm/pm_impl.c | 2 ++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/components/esp_hw_support/include/esp_private/esp_sleep_internal.h b/components/esp_hw_support/include/esp_private/esp_sleep_internal.h index e46c936be9..33fe3d8856 100644 --- a/components/esp_hw_support/include/esp_private/esp_sleep_internal.h +++ b/components/esp_hw_support/include/esp_private/esp_sleep_internal.h @@ -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 */ @@ -71,6 +71,15 @@ esp_err_t esp_deep_sleep_register_phy_hook(esp_deep_sleep_cb_t new_dslp_cb); */ void esp_deep_sleep_deregister_phy_hook(esp_deep_sleep_cb_t old_dslp_cb); +/** + * @brief Notify the sleep process that `sleep_time_overhead_out` needs to be remeasured, which must be called + * in the following scenarios: + * 1. When the CPU frequency changes to below the crystal oscillator frequency. + * 2. When a new callback function is registered in the sleep process. + * 3. Other events occur that affect the execution time of the CPU sleep process. + */ +void esp_sleep_overhead_out_time_refresh(void); + #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 9992677e44..6c09b6cbe8 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -213,6 +213,7 @@ typedef struct { uint32_t rtc_clk_cal_period; uint32_t fast_clk_cal_period; uint64_t rtc_ticks_at_sleep_start; + bool overhead_out_need_remeasure; } sleep_config_t; @@ -239,7 +240,8 @@ static sleep_config_t s_config = { .lock = portMUX_INITIALIZER_UNLOCKED, .ccount_ticks_record = 0, .sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US, - .wakeup_triggers = 0 + .wakeup_triggers = 0, + .overhead_out_need_remeasure = true }; /* Internal variable used to track if light sleep wakeup sources are to be @@ -262,6 +264,13 @@ void esp_sleep_periph_use_8m(bool use_or_not) s_periph_use_8m_flag = use_or_not; } +void esp_sleep_overhead_out_time_refresh(void) +{ + portENTER_CRITICAL(&s_config.lock); + s_config.overhead_out_need_remeasure = true; + portEXIT_CRITICAL(&s_config.lock); +} + static uint32_t get_power_down_flags(void); #if SOC_PM_SUPPORT_EXT0_WAKEUP static void ext0_wakeup_prepare(void); @@ -1259,6 +1268,16 @@ esp_err_t esp_light_sleep_start(void) // Re-calibrate the RTC clock sleep_low_power_clock_calibration(false); + if (s_config.overhead_out_need_remeasure) { + uint32_t cur_cpu_freq = esp_clk_cpu_freq() / MHZ; + uint32_t xtal_freq = rtc_clk_xtal_freq_get(); + if (cur_cpu_freq < xtal_freq) { + s_config.sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US * xtal_freq / cur_cpu_freq; + } else { + s_config.sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US; + } + } + /* * Adjustment time consists of parts below: * 1. Hardware time waiting for internal 8M oscilate clock and XTAL; @@ -1407,6 +1426,7 @@ esp_err_t esp_light_sleep_start(void) if (s_light_sleep_wakeup) { s_config.sleep_time_overhead_out = (esp_cpu_get_cycle_count() - s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL); + s_config.overhead_out_need_remeasure = false; } portEXIT_CRITICAL(&s_config.lock); @@ -1491,9 +1511,10 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us) if (time_in_us > ((BIT64(SOC_LP_TIMER_BIT_WIDTH_LO + SOC_LP_TIMER_BIT_WIDTH_HI) - 1) / esp_clk_tree_lp_slow_get_freq_hz(ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX)) * MHZ ) { return ESP_ERR_INVALID_ARG; } - + portENTER_CRITICAL(&s_config.lock); s_config.wakeup_triggers |= RTC_TIMER_TRIG_EN; s_config.sleep_duration = time_in_us; + portEXIT_CRITICAL(&s_config.lock); return ESP_OK; } diff --git a/components/esp_pm/pm_impl.c b/components/esp_pm/pm_impl.c index e157d4f742..a352d176c8 100644 --- a/components/esp_pm/pm_impl.c +++ b/components/esp_pm/pm_impl.c @@ -16,6 +16,7 @@ #include "esp_log.h" #include "esp_cpu.h" +#include "esp_private/esp_sleep_internal.h" #include "esp_private/crosscore_int.h" #include "esp_private/uart_private.h" @@ -463,6 +464,7 @@ esp_err_t esp_pm_configure(const void* vconfig) // Enable the wakeup source here because the `esp_sleep_disable_wakeup_source` in the `else` // branch must be called if corresponding wakeup source is already enabled. esp_sleep_enable_timer_wakeup(0); + esp_sleep_overhead_out_time_refresh(); } else if (s_light_sleep_en) { // Since auto light-sleep will enable the timer wakeup source, to avoid affecting subsequent possible // deepsleep requests, disable the timer wakeup source here.