Skip to content

Commit cbbc57b

Browse files
committed
Ensure CONFIG is fully cleared
1 parent 280ecaf commit cbbc57b

File tree

1 file changed

+19
-5
lines changed

1 file changed

+19
-5
lines changed

cores/nRF5/WInterrupts.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,28 @@ void detachInterrupt(uint32_t pin)
165165

166166
for (int ch = 0; ch < NUMBER_OF_GPIO_TE; ch++) {
167167
if ((uint32_t)channelMap[ch] == pin) {
168+
// Unfortunately, simply marking a variable as volatile is not enough to
169+
// prevent GCC from reordering or combining memory accesses, without also
170+
// having an explicit sequence point.
171+
// See https://gcc.gnu.org/onlinedocs/gcc/Volatiles.html
172+
//
173+
// Here, ensure a sequence point by adding a memory barrier
174+
// followed with four nops after having disabled the interrupt,
175+
// to ensure the peripheral registers have been updated.
176+
NRF_GPIOTE->INTENCLR = (1 << ch);
177+
asm volatile ("" : : : "memory");
178+
__asm__ __volatile__ ("nop\n\tnop\n\tnop\n\tnop\n");
179+
180+
// now cleanup the rest of the use of the channel
168181
channelMap[ch] = -1;
169182
callbacksInt[ch] = NULL;
170183
callbackDeferred[ch] = false;
171-
172-
NRF_GPIOTE->CONFIG[ch] &= ~GPIOTE_CONFIG_MODE_Event;
173-
174-
NRF_GPIOTE->INTENCLR = (1 << ch);
175-
184+
NRF_GPIOTE->EVENTS_IN[ch] = 0; // clear the event
185+
// Finally, clear the CONFIG register only after ensure
186+
// all the other state has been written to the peripheral registers
187+
asm volatile ("" : : : "memory");
188+
__asm__ __volatile__ ("nop\n\tnop\n\tnop\n\tnop\n");
189+
NRF_GPIOTE->CONFIG[ch] = 0;
176190
break;
177191
}
178192
}

0 commit comments

Comments
 (0)