I am writing a library to interface with a GPS receiver and am implementing a function to calculate the offset between the Arduino's internal clock (using the millis() counter) and the GPS clock. To do this, I have a function that configures the receiver then looks for a "timepulse" event from the receiver that indicates that it is now a particular time of day. The timepulse is a 10% duty cycle square wave but the actual sync event is the rising edge of each pulse, which is being detected by an interrupt. I have run into a problem where the interrupt fires as soon as its attached, rather than upon the next rising edge.
I've found several other references saying that the attachInterrupt() function is supposed to(?) clear interrupt flags before enabling but this seems like its not working. Also others that say the interrupts can sometimes have a sort of "memory" from events that occurred before attaching.
Can anyone tell me either what I'm doing wrong here or how I should be manually clearing the interrupt? I also get the impression that the method to do this varies board to board, is there a board-agnostic solution to this problem?
Additional Details
- Arduino MKR1010
- Using board pin 0 for the interrupt
- Interrupt is called from a class object. Yes the class is needed, but only ever one instance.
- Interrupt input is a clean square wave from another device, not a bouncy button.
-
@Coding_Badly I saw several of your posts saying that
EIFR = bit(INTF0);achieves this but I think that was for AVR?
Similar issues
- attachInterrupt() seems to fire initially and incorrectly. - #8 by J-M-L
- Need Interrupt to Only Fire Once - #11 by mckennalee24
- CTC interrupt occurring too soon - #12 by jremington
- How to clear interrupt flag for PINCHANGE interrupts.
- External interrupts flags are not cleared before enabling the interrupt
My Code (Simplified)
#include <Wire.h>
class UBLOX_INTERFACE
{
private:
const uint8_t i2cAddress;
const uint8_t timePulsePin; //The digital input pin on the Arduino used to measure the receiver's timepulse signal
static volatile bool timepulseDetected; //Declaration. Used in the time sync interrupt
public:
UBLOX_INTERFACE(const uint8_t addressParam, const uint8_t timePulsePinParam) : i2cAddress(addressParam), timePulsePin(timePulsePinParam) {};
void setup();
static void timepulseInterrupt();
void gnssTimepulse();
};
volatile bool UBLOX_INTERFACE::timepulseDetected = false; //Definition
UBLOX_INTERFACE ublox(0x42, 0);
void setup()
{
pinMode(1, OUTPUT); //Used so I can see when the interrupt is fired on the logic analyzer
Serial.begin(19200);
while(!Serial){}
Wire.begin();
ublox.setup();
}
void loop()
{
ublox.gnssTimepulse();
delay(1000);
Serial.println();
}
void UBLOX_INTERFACE::setup() { pinMode(timePulsePin, INPUT_PULLDOWN); }
void UBLOX_INTERFACE::gnssTimepulse()
{
Serial.println("Enter TP function");
timepulseDetected = false;
Serial.print("tpDetected before attach: ");
Serial.println(timepulseDetected);
attachInterrupt(digitalPinToInterrupt(timePulsePin), timepulseInterrupt, RISING);
Serial.print("tpDetected after attach: ");
Serial.println(timepulseDetected);
while(true) //Normally there is a timeout to escape this loop, removed for brevity
{
Serial.print("tpDetected during loop: ");
Serial.println(timepulseDetected);
if(timepulseDetected == true) //Defaults to false, only true when interrupt fires
{
Serial.println("TP detected");
break;
}
delay(10); //Added so I don't spam the serial output as much
}
detachInterrupt(digitalPinToInterrupt(timePulsePin)); //Don't want this firing at any other time
timepulseDetected = false; //Once you get to this point in the code this variable is no longer needed
delay(10);
digitalWrite(1, LOW); //TODO remove this test stuff
Serial.println("Leave TP Function");
}
void UBLOX_INTERFACE::timepulseInterrupt()
{
timepulseDetected = true;
digitalWrite(1, HIGH); //Used so I can see when the interrupt is fired on the logic analyzer
}
Serial Monitor Output
The output from this code shows that immediately after attaching the interrupt, it fires. The same can be seen in the output from a logic analyzer where the interrupt firing is nowhere near the event that supposedly triggered that interrupt.


Working Simple Code
#define OUTPUT_PIN 1
#define INTERRUPT_PIN 0
volatile byte state = LOW;
void setup() {
pinMode(OUTPUT_PIN, OUTPUT);
pinMode(INTERRUPT_PIN, INPUT_PULLDOWN);
delay(2000);
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), interrupt, RISING);
}
void loop() {
// nothing here!
}
void interrupt() {
state = !state;
digitalWrite(OUTPUT_PIN, state);
}
Output
In this case the interrupt fires as expected, on the rising edge of the timepulse signal. I don't understand why this code works and mine does not. Though functionally simpler, they seem to be doing fundamentally the same thing.

How to reset clear interrupt flag MKR MKR1010 SAMD SAMD21