mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 14:58:12 +00:00
fix(eink): fall back to polling when no GPIOTE channel is free
begin() claimed the trampoline slot and set _isr_slot before calling attachInterrupt(), so a button that lost the GPIOTE race (only 8 channels, shared with the radio's DIO1) would take the ISR branch forever while its interrupt never fired. attachInterrupt() returns 0 when channels are exhausted — only commit the slot on success, else leave _isr_slot = -1 so check() uses the polling path. Combined with the live-pin reconcile, an exhausted button degrades cleanly to plain polling instead of misbehaving. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -89,9 +89,17 @@ void MomentaryButton::begin() {
|
||||
#ifdef BUTTON_USE_INTERRUPTS
|
||||
for (uint8_t i = 0; i < MAX_ISR_BUTTONS; i++) {
|
||||
if (_isr_table[i] == nullptr) {
|
||||
_isr_table[i] = this;
|
||||
_isr_slot = i;
|
||||
attachInterrupt(digitalPinToInterrupt(_pin), ISR_TRAMPOLINES[i], CHANGE);
|
||||
// The nRF52 has only 8 GPIOTE channels, shared across every pin using
|
||||
// attachInterrupt() (the radio's DIO1 takes one too). It returns 0 when
|
||||
// they're exhausted — only claim the trampoline slot if a channel was
|
||||
// actually allocated. Otherwise leave _isr_slot = -1 so check() uses the
|
||||
// polling path: that button still works, it just won't capture edges
|
||||
// that land during a blocking display refresh. Retrying another index is
|
||||
// pointless — the channel pool, not the trampoline slot, is what ran out.
|
||||
if (attachInterrupt(digitalPinToInterrupt(_pin), ISR_TRAMPOLINES[i], CHANGE) != 0) {
|
||||
_isr_table[i] = this;
|
||||
_isr_slot = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user