@@ -165,14 +165,28 @@ void detachInterrupt(uint32_t pin)
165
165
166
166
for (int ch = 0 ; ch < NUMBER_OF_GPIO_TE ; ch ++ ) {
167
167
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
168
181
channelMap [ch ] = -1 ;
169
182
callbacksInt [ch ] = NULL ;
170
183
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 ;
176
190
break ;
177
191
}
178
192
}
0 commit comments