perf(power): Tier-2 automatic light sleep, -64% idle (AI FYI) - #119
Open
johnbuckman wants to merge 1 commit into
Open
perf(power): Tier-2 automatic light sleep, -64% idle (AI FYI)#119johnbuckman wants to merge 1 commit into
johnbuckman wants to merge 1 commit into
Conversation
Enable ESP-IDF automatic light sleep (CONFIG_PM_ENABLE + tickless idle + esp_pm_configure light_sleep=on), with the NimBLE controller's low-power clock on RTC_SLOW (internal RC) since this board has no external 32kHz crystal. New opt-in from-source env [env:esp32s3_pm] carries the sdkconfig. Config flags alone do nothing here: the main loop never blocks, so the FreeRTOS idle task never runs and tickless idle never enters. The fix is a blocking yield at the end of loop(); with it, idle drops 110.6 -> 39.7 mA (-64%) on a V8.1 unit. All runtime bits are guarded by CONFIG_PM_ENABLE, so the change is inert on the stock precompiled build. Serial is hardened for light sleep: UART0 wake-on-rx, plus a stay-awake grace window after serial activity (t_lastSerialActivity) so a command's bytes aren't lost to a mid-command sleep. Functional serial regression is consistently 8/8 with idle power unchanged. AI-written change, posted as an FYI for review; not necessarily to merge. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.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.
What this changes
Enables ESP-IDF automatic light sleep so the SoC powers down between events instead of running the core continuously. Idle-ON current drops from 110.6 mA to 39.7 mA (-64%).
Three parts:
[env:esp32s3_pm]):CONFIG_PM_ENABLE+FREERTOS_USE_TICKLESS_IDLE+esp_pm_configure(light_sleep=on), and the NimBLE controller's low-power clock onRTC_SLOW(internal RC) — this board has no external 32 kHz crystal (CONFIG_RTC_CLK_SRC_INT_RC), and the default main-crystal LP clock dies in light sleep.loop()— the actual unlock (see below).All runtime code is guarded by
#if CONFIG_PM_ENABLE, so the stock precompiled build (env:esp32s3) is completely unchanged.How it was found
A config-only attempt (PM flags +
esp_pm_configure) gave no benefit — 87.7 mA, worse than plain 80 MHz scaling, and never dipped toward a sleep floor. Root cause:loop()has no blocking call (pureScale()->scale.update()is non-blocking), so the loop task never yields, the FreeRTOS idle task never runs, and tickless idle can never enter. Adding onevTaskDelayat the end ofloop()was the whole fix:Min dips to ~30 mA (asleep), max ~50 mA (awake) = real light-sleep duty-cycling.
Serial hardening
Light sleep turns off the UART clock, so incoming bytes were dropped mid-command. Fixed with:
esp_sleep_enable_uart_wakeup(UART_NUM_0)(+ threshold) so an incoming byte wakes the SoC;t_lastSerialActivityis stamped when serial bytes arrive, and the loop only yields the sleep-enablingvTaskDelay(10ms)when serial has been quiet >250 ms; during a burst it usesvTaskDelay(1)(below the tickless-idle threshold) so it stays awake and responsive without busy-spinning.Result: serial functional regression 8/8 consistently (5/5 runs during development), idle power unchanged (the grace window costs nothing at idle — it only stays awake during actual serial traffic).
How it was tested
Committed-code verification: boot log shows
[pm] esp_pm_configure ls=on 240/80 -> ESP_OKand[pm] uart0 wake-on-rx -> ESP_OK; USB-serial functional regression 8/8 (boot, weight stream through light sleep,v, oledoff/oledon, tare, stability); idle 39.7 mA @ 5.2 V on the KM003C. Build/flash:pio run -e esp32s3_pm -t upload.Relationship to #118
This is an alternative to, not stacked on, #118 (manual CPU 80 MHz scaling). PM/DFS does frequency scaling automatically, so the manual
setCpuFrequencyMhzcalls from #118 would conflict; this branch is cut frommainwithout them. If Tier-2 is adopted, it supersedes #118.Known gaps / NOT verified
Update: #121 builds directly on this branch (it includes these two commits) and extends it into a full power profile — BLE-wakeable low-power sleep and a 240 MHz pin when connected + live (for the upcoming extension mechanism), all verified over real BLE. If you're evaluating the light-sleep approach, #121 is the fuller version.