Skip to content

Commit 5668d81

Browse files
stevew817adbridge
authored andcommitted
EFM32 IRQ handling fix
* IRQ handling got updated previously to a non-functional state when both callbacks were registered (it'd fire a fall callback for both rise and fall events). With this update, that faulty behaviour is corrected. Due to delays between the detection of the edge and the handling of the interrupt (and the fact that information about which edge you received on the pin is not stored anywhere), there is no way to be absolutely sure which edge got triggered on the pin. Therefore, we make a best-guess effort by looking at the pin state at the time of IRQ handling, and fire a callback as if that was the end state of the event. This will usually work out fine, except in cases were the signal is toggling faster than the IRQ handler's response time. In that case, a user won't get both callbacks (as expected for a pulse), but only the last event. * Stripped some dead code.
1 parent 4b76891 commit 5668d81

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

targets/TARGET_Silicon_Labs/TARGET_EFM32/gpio_irq_api.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,26 @@ static void handle_interrupt_in(uint8_t pin)
6161
return;
6262
}
6363

64-
// Get trigger event
64+
// trying to discern which GPIO IRQ we got
6565
gpio_irq_event event = IRQ_NONE;
66-
if (GPIO->EXTIFALL & (1 << pin)) {
66+
if (((GPIO->EXTIFALL & (1 << pin)) != 0) && ((GPIO->EXTIRISE & (1 << pin)) == 0)) {
67+
// Only the fall handler is active, so this must be a falling edge
6768
event = IRQ_FALL;
68-
} else if (GPIO->EXTIRISE & (1 << pin)) {
69+
} else if (((GPIO->EXTIFALL & (1 << pin)) == 0) && ((GPIO->EXTIRISE & (1 << pin)) != 0)) {
70+
// Only the rise handler is active, so this must be a rising edge
6971
event = IRQ_RISE;
72+
} else {
73+
// Ambiguous as to which IRQ we've received. Poll the pin to check which one to fire.
74+
// NOTE: If trying to detect a pulse where the width is shorter than this handler's
75+
// reaction time, there will only be one callback (for the trailing edge) called.
76+
77+
// we are storing two ports in each uint8, so we must acquire the one we want.
78+
// If pin is odd, the port is encoded in the 4 most significant bits.
79+
// If pin is even, the port is encoded in the 4 least significant bits
80+
uint8_t isRise = GPIO_PinInGet((pin & 0x1) ?
81+
channel_ports[(pin>>1) & 0x7] >> 4 & 0xF :
82+
channel_ports[(pin>>1) & 0x7] >> 0 & 0xF, pin);
83+
event = (isRise == 1 ? IRQ_RISE : IRQ_FALL);
7084
}
7185
GPIO_IntClear(pin);
7286
irq_handler(channel_ids[pin], event);
@@ -132,9 +146,6 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable)
132146
/* Disable, set config and enable */
133147
gpio_irq_disable(obj);
134148

135-
bool was_disabled = false;
136-
if(GPIO->IEN == 0) was_disabled = true;
137-
138149
GPIO_IntConfig((GPIO_Port_TypeDef)((obj->pin >> 4) & 0xF), obj->pin &0xF, obj->risingEdge, obj->fallingEdge, obj->risingEdge || obj->fallingEdge);
139150
}
140151

0 commit comments

Comments
 (0)