This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 89b8c5fc7f2 espressif: stop double-counting light sleep in the system 
clock
89b8c5fc7f2 is described below

commit 89b8c5fc7f203c77586d9427bf5670ffedf46f6d
Author: Felipe Moura <[email protected]>
AuthorDate: Sat Sep 19 17:55:55 2026 -0300

    espressif: stop double-counting light sleep in the system clock
    
    esp_pmstandby() fed up_step_idletime() the sleep duration it *asked* for
    (time_in_us) rather than the one it actually got (rtc_diff_us), and did so
    unconditionally.  Both halves are wrong.
    
    esp_pm_light_sleep_start() already stalls and restores the systimer
    itself, but only where SOC_SLEEP_SYSTIMER_STALL_WORKAROUND is defined --
    esp32c3 and esp32p4.  On every other SoC, esp32s3 included, the systimer
    keeps counting straight through light sleep, so the time is already in
    the clock and stepping it again adds it twice.
    
    Measured on an esp32s3-xiao: over 54 min with 1919 light sleeps totalling
    454.7 s, the monotonic clock ran 443.2 s fast -- 0.97 of the time slept,
    i.e. counted exactly twice, leaving the clock 13.8% fast.  Anything that
    reconstructs wall time from CLOCK_MONOTONIC inherits that error; for this
    collar it corrupted every IMU sample timestamp.
    
    Invisible until light sleep started happening for real, because a board
    that never sleeps never steps the clock.
    
    Note for upstream: the risc-v copy here only switches to the measured
    duration and does not gate on SOC_SLEEP_SYSTIMER_STALL_WORKAROUND.  The
    two should be reconciled before this is proposed -- it is kept as-is so
    the asymmetry is visible rather than silently decided.
    
    Signed-off-by: Felipe Moura <[email protected]>
    Assisted-by: Claude:claude-opus-5
---
 arch/risc-v/src/common/espressif/esp_pm.c |  3 ++-
 arch/xtensa/src/common/espressif/esp_pm.c | 11 +++++++++--
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/arch/risc-v/src/common/espressif/esp_pm.c 
b/arch/risc-v/src/common/espressif/esp_pm.c
index 9b114b988de..16401e719f2 100644
--- a/arch/risc-v/src/common/espressif/esp_pm.c
+++ b/arch/risc-v/src/common/espressif/esp_pm.c
@@ -794,6 +794,7 @@ void esp_pmstandby(uint64_t time_in_us)
 #endif
 #ifdef CONFIG_PM_EXT1_WAKEUP
   int64_t ext1_mask;
+
   esp_pm_ext1_wakeup_prepare();
 #endif
 #ifdef CONFIG_PM_GPIO_WAKEUP
@@ -812,7 +813,7 @@ void esp_pmstandby(uint64_t time_in_us)
   esp_pm_light_sleep_start(&rtc_diff_us);
 
 #ifdef CONFIG_SCHED_TICKLESS
-  up_step_idletime((uint32_t)time_in_us);
+  up_step_idletime((uint32_t)rtc_diff_us);
 #endif
 
   cause = esp_sleep_get_wakeup_cause();
diff --git a/arch/xtensa/src/common/espressif/esp_pm.c 
b/arch/xtensa/src/common/espressif/esp_pm.c
index 746ccb2b177..7001e23c71a 100644
--- a/arch/xtensa/src/common/espressif/esp_pm.c
+++ b/arch/xtensa/src/common/espressif/esp_pm.c
@@ -44,6 +44,7 @@
 #endif
 #include "esp_sleep.h"
 #include "soc/rtc.h"
+#include "soc/soc_caps.h"
 #include "esp_sleep_internal.h"
 #include "esp_pmu.h"
 #include "esp_attr.h"
@@ -758,6 +759,7 @@ void esp_pmstandby(uint64_t time_in_us)
 #endif
 #ifdef CONFIG_PM_EXT1_WAKEUP
   int64_t ext1_mask;
+
   esp_pm_ext1_wakeup_prepare();
 #endif
 #ifdef CONFIG_PM_GPIO_WAKEUP
@@ -775,8 +777,13 @@ void esp_pmstandby(uint64_t time_in_us)
 
   esp_pm_light_sleep_start(&rtc_diff_us);
 
-#ifdef CONFIG_SCHED_TICKLESS
-  up_step_idletime((uint32_t)time_in_us);
+  /* Only step the clock where the systimer actually stalls during sleep
+   * (SOC_SLEEP_SYSTIMER_STALL_WORKAROUND); elsewhere it keeps counting
+   * through light sleep, so stepping it here would double-count the time.
+   */
+
+#if defined(CONFIG_SCHED_TICKLESS) && 
defined(SOC_SLEEP_SYSTIMER_STALL_WORKAROUND)
+  up_step_idletime((uint32_t)rtc_diff_us);
 #endif
 
   cause = esp_sleep_get_wakeup_cause();

Reply via email to