mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 23:08:11 +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
|
#ifdef BUTTON_USE_INTERRUPTS
|
||||||
for (uint8_t i = 0; i < MAX_ISR_BUTTONS; i++) {
|
for (uint8_t i = 0; i < MAX_ISR_BUTTONS; i++) {
|
||||||
if (_isr_table[i] == nullptr) {
|
if (_isr_table[i] == nullptr) {
|
||||||
_isr_table[i] = this;
|
// The nRF52 has only 8 GPIOTE channels, shared across every pin using
|
||||||
_isr_slot = i;
|
// attachInterrupt() (the radio's DIO1 takes one too). It returns 0 when
|
||||||
attachInterrupt(digitalPinToInterrupt(_pin), ISR_TRAMPOLINES[i], CHANGE);
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user