Skip to content

feat: optional hooks around long e-ink BUSY waits#8

Merged
itsthisjustin merged 4 commits into
Free-Ink:mainfrom
BrianPugh:feat/busy-wait-hooks
Jul 6, 2026
Merged

feat: optional hooks around long e-ink BUSY waits#8
itsthisjustin merged 4 commits into
Free-Ink:mainfrom
BrianPugh:feat/busy-wait-hooks

Conversation

@BrianPugh

Copy link
Copy Markdown
Contributor

Equivalent of crosspoint-reader/community-sdk#21; copying/pasting body below:

An e-ink refresh takes ~0.3–2 s, during which pollBusy() spins on the BUSY pin at whatever clock the host is running. This PR adds setBusyWaitHooks(begin, end): plain function pointers fired when a wait exceeds 20 ms and again when it completes, letting host firmware apply its own power policy for the wait window (CrossPoint uses it to drop the ESP32-C3 to 10 MHz there).

  • Fully backwards compatible: both hooks default to nullptr; behavior is unchanged unless installed. The only added cost is a null-check inside the 1 ms poll loop.
  • The 20 ms threshold means short command waits never fire the hooks, so hosts don't pay two clock switches on trivial waits. The end hook fires only if the begin hook did.
  • Covers both the X4 (active-HIGH) and X3 (active-LOW, two-phase) wait paths, including the X3 early-return path.

Measured on an X3 with a Nordic PPK2 at the battery terminals at 3.8v: with CrossPoint installing a 10 MHz downclock hook, a fast page turn drops from ~38 mC to ~29 mC (−24%), with fast/full/grayscale refreshes visually unchanged on device.

Supports crosspoint-reader/crosspoint-reader#2525

🤖 Generated with Claude Code

BrianPugh and others added 3 commits July 2, 2026 20:50
A refresh takes ~0.3-2 s during which EpdBus::waitBusy() only polls the
BUSY pin at full CPU clock. Add a pair of optional plain-function-pointer
hooks (setBusyWaitHooks, forwarded through FreeInkDisplay) fired when a
wait exceeds 20 ms and when it completes, so host firmware can apply its
own power policy (e.g. reduce the CPU clock) for the wait window. Hooking
the bus covers every driver that polls through waitBusy (SSD1677/X4,
UC8253/X3, ED2208/M5). No behavior change unless hooks are installed;
short command waits never trigger them.

Co-Authored-By: Claude Fable 5 <[email protected]>
A state change only commits after two consecutive matching samples
(DEBOUNCE_DELAY stability window). A host that polls slowly — e.g. an
idle loop pacing 50 ms light-sleep slices — can therefore drop a tap
shorter than its poll period: the press lands in one sample and the
next sample already reads released, so it never commits.

Expose the pending-debounce state so such hosts can re-poll quickly
until the change commits. Also sync lastState in applyStateChange()
so the accessor stays false on the hold-style input paths, which
bypass the debounce sampling.

Co-Authored-By: Claude Fable 5 <[email protected]>
Once a BUSY wait has proven long (same 20 ms threshold as the
begin/end hooks), each poll-delay iteration is offered to a host-
installed slice hook, which can e.g. light-sleep until the BUSY pin
leaves its active level. The hook returns false (or is absent) to
fall back to the plain delay. Gated by a longWait flag independent
of the begin hook's presence, so installing only the slice hook works.

Co-Authored-By: Claude Fable 5 <[email protected]>
keyz added a commit to keyz/crosspoint-reader that referenced this pull request Jul 5, 2026
@itsthisjustin
itsthisjustin merged commit f363600 into Free-Ink:main Jul 6, 2026
@itsthisjustin

Copy link
Copy Markdown
Contributor

If you've still got an x3 open and a way to scope it...

Can you put a logic analyzer on the panel SPI while stock firmware renders a sleep wallpaper. I need to know the actual CDI value, the exact plane bytes for a known image, and the timing. I want to diff our command stream against stock's byte-for-byte.

@BrianPugh

BrianPugh commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

I have a cheap Salae-clone that I've never used but have been meaning to 😄 . In prep, from looking at the PCB/code, I think the following is the description of the testpads. I would still need to probe/find the following:

  • DISPLAY_CS - GPIO21, Physical Pin 28
  • D/C - GPIO4, Physical Pin 9
  • BUSY - GPIO6, Physical Pin 12
  • RST - GPIO5, Physical Pin 5

There's a few test points on the right-side of the PCB, but I bet they're unrelated. I also haven't yet lifted up the tape covering the display/pcb connector; there could be more test points over there.

20240604_004615 copy

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants