[EXPERIMENTAL — do not merge] Deep sleep: drop debug-UART RX block#54
Draft
Coral-coder wants to merge 5 commits into
Draft
[EXPERIMENTAL — do not merge] Deep sleep: drop debug-UART RX block#54Coral-coder wants to merge 5 commits into
Coral-coder wants to merge 5 commits into
Conversation
Add monotonic (never-reset) counters for time spent in WFI, deep WFI and deep sleep, alongside the existing analytics counters (which reset each collection). A per-minute sampler, piggybacked on the existing minute regular-timer so it adds no wake-ups, records deep-sleep and wall-clock deltas into a 60-entry ring covering the last hour. Expose soc_sf32lb_deep_sleep_residency_permille(minutes) for the last 1/10/60 minutes and soc_sf32lb_cpu_time_get() for the since-boot totals, to back an on-watch Deep Sleep Stats screen. Started from services_normal once the regular-timer service is up. Signed-off-by: Coral Coder <dsthunder@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Coral Coder <dsthunder@gmail.com>
Add a "Deep Sleep Stats" row (sf32lb52 only) under Settings -> Debugging that opens a live screen showing the fraction of time the chip spent in deep sleep over the last 1 minute, 10 minutes and 1 hour, plus the current battery drain rate and estimated time to empty. The values refresh once a second while the screen is open. Signed-off-by: Coral Coder <dsthunder@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Coral Coder <dsthunder@gmail.com>
Swap the static Deep Sleep Stats sub-screen for a toggleable overlay that floats over the watchface and reports how many milliseconds per second the chip spent in, and out of, deep sleep, averaged over the trailing minute. Replace the per-minute residency ring with a lazily-sampled rolling window that yields deep-sleep ms per wall-clock second. It samples only when read, so it adds no wake-ups and costs nothing while the overlay is off. The HUD is a discreet, transparent, unfocused modal, so it redraws with the watchface on each wake (via the AppAndModal compositor path) rather than running a timer that would keep the watch awake. The toggle lives under Settings -> Debugging (sf32lb52 only) and persists across reboots via a new shell pref. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Coral Coder <dsthunder@gmail.com>
True deep sleep is unreachable in normal always-on use: it needs a >=50 ms uninterrupted idle window the workload rarely leaves, so the chip's real resting floor is deep WFI. The old HUD read the deep-sleep counter, which sits at ~0, and lumped deep WFI into "awake" -- misleading. Point the metric at the states the chip actually reaches: report a per-minute idle breakdown -- deep (deep WFI or deeper), light WFI, and running -- each in average ms per wall-clock second, summing to ~1000. Rename the debug row to "Idle States HUD". Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Coral Coder <dsthunder@gmail.com>
The debug console arms the UART RX receiver for the whole uptime, which holds a permanent DEEPSLEEP sleep-block and caps the chip at deep WFI -- so true deep sleep never happens on debug builds, regardless of whether anything is connected to the port. Add CONFIG_EXPERIMENTAL_DEEP_SLEEP (enabled for obelix here) that drops that block so the SoC can reach deep sleep when idle, to prove on hardware that the console block is the ceiling. Also split the Idle States HUD into a 4-way breakdown -- dsleep / dwfi / wfi / run -- so true deep sleep shows separately from deep WFI when it engages. For power investigation only; not for merge. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Coral Coder <dsthunder@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hypothesis being tested
On debug builds the watch never reaches true DEEPSLEEP — it's capped at DEEP-WFI. Root cause found in the trace: the debug console arms the UART RX receiver at boot (
main.c:189→dbgserial_input.c:30), and enabling RX takes a permanent DEEPSLEEP sleep-block (uart/sf32lb.c:137). It's a pure software refcount held the whole uptime — independent of whether anything is connected to the port. Because the block is at the DEEPSLEEP level, deep-WFI stays allowed, which is exactly the observed0 deepsleep, deep-wfi is the floor.What this build does
Adds
CONFIG_EXPERIMENTAL_DEEP_SLEEP(enabled for obelix here) that drops the UART RX deep-sleep block (symmetrically — no refcount imbalance). Log output over TX is unaffected; console input is lost only while the chip is actually asleep. This lets the SoC reach true deep sleep when idle, to prove on-device that the console block is the ceiling.Also splits the Idle States HUD into a 4-way breakdown so deep sleep is visible separately:
How to run the experiment
dsleepjumps from 0 to a high number → hypothesis confirmed: the console UART block was the ceiling. Next step is a proper gate (only block while a byte is mid-reception).dsleepstays 0 → the UART block was not the cause; look elsewhere (I was wrong).Build note: compiles + links for
obelix@pvt. (A clean local rebuild trips an unrelated pre-existing-Werror=maybe-uninitializedin the SiFli SDKbt_rf_fulcal.c; CI builds that same tree green, so it's a local-toolchain artifact, not from this change.)Close without merging once the result is captured.
Generated by Claude Code