Skip to content

X4 Pro power saving: state of upstream, light-sleep attempt, findings #3

Description

@ShahriarAhnaf

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

What we did (branch agent/lightsleep-5d3e on this fork)

  1. 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().
  2. Cherry-picked both fix: x4 usb attach freeze crosspoint-reader/crosspoint-reader#3082 commits.
  3. 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. Added usbWakePin() that falls back to the charger STAT line (GPIO21, HIGH while charging) as the light-sleep wake source.
  4. 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 excludes Board::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_FREQ is 80 MHz on PSRAM boards (PSRAM clocks off the CPU), and FREEINK_FRONTLIGHT_LS is 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions