From 1f55983287a3a0ee1eb55310b47d4c51b5ef27d6 Mon Sep 17 00:00:00 2001 From: xhlsa <126936838+xhlsa@users.noreply.github.com> Date: Sun, 13 Sep 2026 19:36:24 -0700 Subject: [PATCH] EXTI: clear pending bits before dispatching handlers EXTI_IRQHandler() cleared each line's pending bit after its handler returned. An edge arriving on that line while the handler ran set the bit again and was then wiped, so the interrupt was silently lost. Any EXTI user whose handler takes a while, or that triggers a follow-up edge (e.g. a radio BUSY/DIO line), can stall waiting for an interrupt that already came. Clear the snapshot of active lines first, as Betaflight does. Edges arriving during dispatch stay pending and re-enter the handler. Found porting Betaflight's SPI ExpressLRS receiver, where it stalled the SX1280 interrupt chain; reproduced in a host simulation of the EXTI pending/enable model. Co-Authored-By: Claude Opus 5 --- src/main/drivers/exti.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/drivers/exti.c b/src/main/drivers/exti.c index 3ef0ef32417..6292bf04af9 100644 --- a/src/main/drivers/exti.c +++ b/src/main/drivers/exti.c @@ -216,11 +216,15 @@ void EXTI_IRQHandler(void) { uint32_t exti_active = EXTI_REG_IMR & EXTI_REG_PR; + // Clear before dispatching (as Betaflight does): an edge on the same line + // while its handler runs must stay pending rather than be wiped when the + // handler returns. + EXTI_REG_PR = exti_active; + while (exti_active) { unsigned idx = 31 - __builtin_clz(exti_active); uint32_t mask = 1 << idx; extiChannelRecs[idx].handler->fn(extiChannelRecs[idx].handler); - EXTI_REG_PR = mask; // clear pending mask (by writing 1) exti_active &= ~mask; } }