feat(pm): add light sleep tick overflow protection configuration

This commit is contained in:
wuzhenghui
2026-01-26 16:01:49 +08:00
parent c46c14683f
commit 5a5ef9fb08
2 changed files with 53 additions and 3 deletions

View File

@@ -241,6 +241,44 @@ menu "Power Management"
NOTE: Enabling these callbacks may change sleep duration calculations based on time spent in callback and
hence it is highly recommended to keep them as short as possible
config PM_LIGHTSLEEP_TICK_OVERFLOW_PROTECTION
bool "Enable light sleep tick overflow protection"
depends on FREERTOS_USE_TICKLESS_IDLE
default n
help
Limits tick compensation after light sleep wakeup to prevent vTaskStepTick() assertion
failure when actual wakeup overhead exceeds estimation (due to cache misses, CPU
frequency changes, or flash latency variations).
When enabled:
- Silently limits slept_ticks to xExpectedIdleTime when oversleep is within tolerance
(configured by PM_LIGHTSLEEP_TICK_OVERFLOW_TOLERANCE), preventing assertion failure
- Does not limit when oversleep exceeds tolerance (may indicate a bug), assertion failure may occur
- May lose ticks in rare cases, causing xTickCount to lag behind esp_timer
When disabled (default):
- Accurate tick compensation, better precision
- May trigger assertion failure and system crash if overslept
Keep disabled by default to maintain RTOS tick accuracy. Enable only when you experience
assertion failures related to vTaskStepTick() and can accept slight inaccuracy of RTOS
tick time compared to real time.
config PM_LIGHTSLEEP_TICK_OVERFLOW_TOLERANCE
int "Light sleep tick overflow tolerance"
depends on PM_LIGHTSLEEP_TICK_OVERFLOW_PROTECTION
default 2
range 1 10
help
Maximum number of ticks that can be overslept before triggering.
When oversleep is within this tolerance, the system silently limits slept_ticks to
prevent assertion failure. When oversleep exceeds this tolerance, assertion failure
may occur and system may crash.
Higher values provide more tolerance for estimation variance but may hide real issues
and cause more tick loss, leading to greater RTOS tick time inaccuracy compared to real time.
Lower values provide better RTOS tick accuracy but may cause false positives.
config PM_WORKAROUND_FREQ_LIMIT_ENABLED
bool
default y if SPI_FLASH_FREQ_LIMIT_C5_240MHZ

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2016-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,6 +8,7 @@
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/lock.h>
#include <sys/param.h>
#include <assert.h>
@@ -834,10 +835,21 @@ static inline void IRAM_ATTR other_core_should_skip_light_sleep(int core_id)
}
// Adjust RTOS tick count based on the amount of time spent in sleep.
FORCE_INLINE_ATTR void pm_step_tick(int64_t slept_us)
FORCE_INLINE_ATTR void pm_step_tick(int64_t slept_us, TickType_t xExpectedIdleTime)
{
uint32_t slept_ticks = slept_us / (portTICK_PERIOD_MS * 1000LL);
if (slept_ticks) {
#if CONFIG_PM_LIGHTSLEEP_TICK_OVERFLOW_PROTECTION
/* Limit slept_ticks when oversleep is within tolerance to prevent assertion failure */
if ((slept_ticks > xExpectedIdleTime) &&
(slept_ticks <= (xExpectedIdleTime + CONFIG_PM_LIGHTSLEEP_TICK_OVERFLOW_TOLERANCE))) {
slept_ticks = xExpectedIdleTime;
}
#endif // CONFIG_PM_LIGHTSLEEP_TICK_OVERFLOW_PROTECTION
if (slept_ticks > xExpectedIdleTime) {
ESP_EARLY_LOGE(TAG, "Light sleep overslept: expect %"PRIu32" idle ticks but slept %"PRIu32" ticks.",
(uint32_t)xExpectedIdleTime, slept_ticks);
}
/* Adjust RTOS tick count based on the amount of time spent in sleep */
vTaskStepTick(slept_ticks);
@@ -886,7 +898,7 @@ void vApplicationSleep( TickType_t xExpectedIdleTime )
// In this case, there is no need to call vTaskStepTick, because the OS tick count will
// automatically catch up in the next systick interrupt handler.
if (err == ESP_OK) {
pm_step_tick(slept_us);
pm_step_tick(slept_us, xExpectedIdleTime);
}
other_core_should_skip_light_sleep(core_id);
#ifdef WITH_PROFILING