From 41e6e25e2d5e3715847adb50cf67e2690c45fabf 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 | 24 +++++++++++++++++-- components/esp_pm/pm_impl.c | 2 ++ components/esp_pm/test_apps/esp_pm/README.md | 4 ++-- 4 files changed, 36 insertions(+), 5 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 747d426cd9..bd4043ad24 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 */ @@ -124,6 +124,15 @@ void esp_sleep_mmu_retention(bool backup_or_restore); bool mmu_domain_pd_allowed(void); #endif +/** + * @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 4b321238ca..92522c8526 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -248,6 +248,7 @@ typedef struct { #if SOC_DCDC_SUPPORTED uint64_t rtc_ticks_at_ldo_prepare; #endif + bool overhead_out_need_remeasure; } sleep_config_t; @@ -276,7 +277,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 @@ -291,6 +293,12 @@ static const char *TAG = "sleep"; static RTC_FAST_ATTR int32_t s_sleep_sub_mode_ref_cnt[ESP_SLEEP_MODE_MAX] = { 0 }; //in this mode, 2uA is saved, but RTC memory can't use at high temperature, and RTCIO can't be used as INPUT. +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); static uint32_t get_sleep_flags(uint32_t pd_flags, bool deepsleep); @@ -1397,6 +1405,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 oscillate clock and XTAL; @@ -1561,6 +1579,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); @@ -1645,9 +1664,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 67ea84ae34..5848c27a61 100644 --- a/components/esp_pm/pm_impl.c +++ b/components/esp_pm/pm_impl.c @@ -19,6 +19,7 @@ #include "esp_clk_tree.h" #include "soc/soc_caps.h" +#include "esp_private/esp_sleep_internal.h" #include "esp_private/crosscore_int.h" #include "esp_private/periph_ctrl.h" @@ -478,6 +479,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. diff --git a/components/esp_pm/test_apps/esp_pm/README.md b/components/esp_pm/test_apps/esp_pm/README.md index 3a502b1f86..bf47d80ec6 100644 --- a/components/esp_pm/test_apps/esp_pm/README.md +++ b/components/esp_pm/test_apps/esp_pm/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |