Repository navigation
X4 Pro power saving: state of upstream, light-sleep attempt, findings #3
Copy link
Copy link
Open
Description
Where upstream stands (develop 038d615, 2026-09-22)
The X4 Pro ([env:x4pro], ESP32-S3 + 8 MB PSRAM) ships with exactly one power mechanism: HalPowerManager::setPowerSaving drops the CPU 240 → 80 MHz after 3 s of no input and restores it on any activity or render lock. The idle loop still wakes every 10 ms, polling the GT911 over I2C and the ADC. There is no CONFIG_PM_ENABLE, no tickless idle, no DFS, no light sleep. The x4pro profile extends base only and deliberately skips custom_sdkconfig (the USB-OTG/MSC path needs pioarduino's prebuilt TinyUSB graph), so the Arduino sdkconfig cannot be changed without solving that first. That is the structural blocker for real esp_pm.
What was tried upstream
- perf: light-sleep idle + refresh downclock — ~3.2x active reading time (X3-measured) crosspoint-reader/crosspoint-reader#2525 (BrianPugh): manual
esp_light_sleep_start()in 50 ms slices when idle, plus sleep slices during the e-ink BUSY wait. PPK2 on an X3: idle 9.68 → 2.78 mA, ~3.2× reading time. Merged 2026-08-13. - chore: revert light sleep code but keep battery drain fix crosspoint-reader/crosspoint-reader#3077: reverted perf: light-sleep idle + refresh downclock — ~3.2x active reading time (X3-measured) crosspoint-reader/crosspoint-reader#2525 four days later. Plugging USB into an X4 froze the device. Root cause per fix: x4 usb attach freeze crosspoint-reader/crosspoint-reader#3082 (open, untested — author has no X4): the GPIO13 battery-MOSFET
gpio_hold_enwas left latched across the whole idle period, so the pad could not follow the VBUS power-path transition. - feat: GT911 INT and button GPIO wake for longer light-sleep slices crosspoint-reader/crosspoint-reader#3055: GT911 INT + button GPIO wake for longer slices, closed after the revert.
- An
esp_pm+ tickless + DFS 80–240 prototype was measured on X4 Pro hardware (feat: light-sleep-surviving frontlight (FREEINK_FRONTLIGHT_LS) Free-Ink/freeink-sdk#39 body: 92 % light-sleep residency over 31 min) but never submitted to CrossPoint. - Saving power approach question - Manual Light sleep or auto light sleep crosspoint-reader/crosspoint-reader#2639 (manual light sleep vs
CONFIG_PM_ENABLE+ PM locks) and Add display PM locks for auto light sleep Free-Ink/freeink-sdk#12 (display PM locks) open since July, no maintainer decision. - Big Battery Drain on X4 Pro whilst device is asleep crosspoint-reader/crosspoint-reader#2857 (X4 Pro ~1.5 %/h drain while asleep, re-confirmed on 1.6.0) has no maintainer response. X4 Pro optimize power consumption crosspoint-reader/crosspoint-reader#3514 was closed as "the light is power hungry".
What we did (branch agent/lightsleep-5d3e on this fork)
- Reverted the revert (81e1927) on develop 038d615, resolving conflicts toward perf: light-sleep idle + refresh downclock — ~3.2x active reading time (X3-measured) crosspoint-reader/crosspoint-reader#2525's idle tail while keeping develop's
rawInputActive(). - Cherry-picked both fix: x4 usb attach freeze crosspoint-reader/crosspoint-reader#3082 commits.
- X4 Pro has no VBUS-detect GPIO (
usbDetect = PIN_UNASSIGNED), so the fix: x4 usb attach freeze crosspoint-reader/crosspoint-reader#3082 USB-attach wake never armed there. AddedusbWakePin()that falls back to the charger STAT line (GPIO21, HIGH while charging) as the light-sleep wake source. - Compiled the BUSY-wait sleep slices out for the X4 Pro and added a
display.isRefreshPending()guard so an idle slice is never entered while an async refresh is in flight (light sleep gates the GPIO edge detector, which would lose the BUSY-done ISR the async finish waits on).
What we learned on the real X4 Pro
- The X4 freeze class does not apply. GPIO13 is the display chip-select on the Pro and the hold code is gated by
isXteinkDevice(), which excludesBoard::XteinkX4Pro. - USB gate works. With a host attached the SOF frame counter on USB-Serial-JTAG holds sleep off; CDC stayed alive over a 40 s idle window with logs every 10 s. Charger STAT covers the plug-in transient; at charge termination STAT drops but SOF already has the link.
- Ghosting is not sleep. Rapid page turns showed heavy trails on every build, including with the refresh-time sleep compiled out. This is the panel's normal partial-refresh behaviour, controlled by the refresh-frequency setting. A no-sleep control build was about to be flashed when this was clarified; the A/B toggle was removed again.
- Two S3 details worth keeping:
LOW_POWER_FREQis 80 MHz on PSRAM boards (PSRAM clocks off the CPU), andFREEINK_FRONTLIGHT_LSis already on for x4pro, so a lit frontlight does not block sleep. - Recovery is always available: the S3 ROM loader answers on USB-JTAG regardless of firmware state; nothing here touches bootloader, partitions or NVS.
Not done
- No current measurement yet on the X4 Pro (no PPK2 in the loop). The X3 numbers from perf: light-sleep idle + refresh downclock — ~3.2x active reading time (X3-measured) crosspoint-reader/crosspoint-reader#2525 are the only data.
- Responsiveness after idle not yet characterised beyond "up to one 50 ms slice by design".
- The refresh-time sleep half is compiled out for the Pro; it may be safe to re-enable now that ghosting is understood to be unrelated.
- Tickless idle /
CONFIG_PM_ENABLE: blocked on the x4pro profile's inability to rebuild the Arduino core. Options are acustom_sdkconfigexperiment on the x4pro env to see whether TinyUSB actually breaks, or an ESP-IDF-native build of CrossPoint. - Upstream: fix: x4 usb attach freeze crosspoint-reader/crosspoint-reader#3082 needs an X4 tester; a one-line report that the fix plus this STAT fallback works on the Pro would unblock re-landing perf: light-sleep idle + refresh downclock — ~3.2x active reading time (X3-measured) crosspoint-reader/crosspoint-reader#2525.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity