Skip to content

feat(expander): snapshot INTF / INTCAP at begin() for deep-sleep wake source detection#304

Merged
JosipKuci merged 1 commit into
SolderedElectronics:masterfrom
lanrat:fix/capture-int-flags-at-begin
May 19, 2026
Merged

feat(expander): snapshot INTF / INTCAP at begin() for deep-sleep wake source detection#304
JosipKuci merged 1 commit into
SolderedElectronics:masterfrom
lanrat:fix/capture-int-flags-at-begin

Conversation

@lanrat
Copy link
Copy Markdown
Contributor

@lanrat lanrat commented May 19, 2026

IOExpander::begin() does a 22-byte sequential bulk read of MCP23017
registers 0x00..0x15. That sequence passes through INTFA/B (0x0E,
0x0F) before INTCAPA/B (0x10, 0x11) — and on the MCP23017, reading
INTCAP clears the INTF latch as a side effect.

So after begin() returns, the live INTF register reads as 0, even
when a wake-triggering interrupt was actually pending. Applications
using the MCP's INT line to wake the host from deep sleep can't
determine which pin caused the wake. v11.0.1's getIntState() reads
INTCAP fresh, but INTCAP can be overwritten by any new interrupt event
between begin() and the call (e.g. capacitive noise during boot).
The only reliable moment to capture the wake source is during begin()
itself.

Fix

Snapshot the cached pre-clear INTF/INTCAP values into dedicated members
in begin(), expose via two new public methods:

uint16_t getInterruptFlagsAtBegin();    // INTFA in low, INTFB in high
uint16_t getInterruptCaptureAtBegin();  // INTCAPA in low, INTCAPB in high

Callers pair them to distinguish rising vs falling edges:

uint16_t intf    = display.expander1.getInterruptFlagsAtBegin();
uint16_t intcap  = display.expander1.getInterruptCaptureAtBegin();
uint16_t rising  = intf &  intcap;   // press
uint16_t falling = intf & ~intcap;   // release

Verification

Inkplate 10 V1 with setIntPin(_, RISING) on the three touchpads.
Pressing each pad produces the expected INTFB/INTCAPB bit set;
release-edge wakes show INTFB != 0 but INTCAPB == 0 and are
correctly filtered out by the application.

Compat / scope

Strictly additive — no existing API or behavior is modified. Two new
public methods, 4 bytes of state per instance. Same file gating as the
existing MCP code (ARDUINO_INKPLATE6 || ARDUINO_INKPLATE10 || ARDUINO_INKPLATE6PLUS).

… source detection

IOExpander::begin() does a 22-byte sequential bulk read of the MCP23017's
registers starting at 0x00. That sequence passes through INTFA (0x0E) and
INTFB (0x0F) BEFORE INTCAPA (0x10) and INTCAPB (0x11) — and on the MCP,
reading INTCAP is what clears the INTF latch as a side effect. So by the
time begin() returns, the latch is cleared at the chip; subsequent calls
to getInt() return 0 even when a wake-triggering interrupt was actually
pending before begin() ran.

v11.0.1 added getIntState() which reads INTCAP fresh — but INTCAP can be
overwritten by any new interrupt event (capacitive noise, application
activity arming new interrupts, etc.) between begin() and the call. For
applications that need to reliably determine a deep-sleep wake source,
the only correct moment to capture INTF/INTCAP is during begin() itself,
before any subsequent transactions can disturb either register.

Snapshot the captured INTF and INTCAP into dedicated member variables
inside begin(), and expose them via:

    uint16_t getInterruptFlagsAtBegin();    // INTFA in low byte, INTFB in high byte
    uint16_t getInterruptCaptureAtBegin();  // INTCAPA in low, INTCAPB in high

Callers pair the two to reconstruct rising vs falling edges on each
interrupt-enabled pin even after begin() has cleared the live latch:

    rising  = INTF & INTCAP    // pins HIGH at trigger = press
    falling = INTF & ~INTCAP   // pins LOW at trigger  = release

Backward-compatible: no existing API or behavior changes; new public
methods and two new private members only.
@JosipKuci JosipKuci merged commit 0e4ada7 into SolderedElectronics:master May 19, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants