@@ -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