Trouble with interrupts waking from sleep

Hi there. I’m having trouble attaching interrupts to the pins on my Electron and waking me up from sleep, I need someone to tell me what I’m doing wrong. I have the following code:

time_t sleepTime = 0;
volatile bool interruptFired = false;

// Handle the wake-up interrupt going off
static void intWakeUp() {
    interruptFired = true;
    digitalWrite(D7, HIGH);
    delay (50);
    digitalWrite(D7, LOW);
}

void setup() {
    // Opens up a Serial port so you can listen over USB
    Serial.begin(9600);

    // Wait for USB to sort itself out
    delay (5000);
    
    // Attach an interrupt to the wake-up pin.
    pinMode(WKP, INPUT_PULLDOWN);
    if (attachInterrupt(WKP, intWakeUp, RISING)) {
        Serial.println ("Interrupt attached to WKP pin.");
    } else {
        Serial.println ("WARNING: couldn't attach interrupt to WKP pin.");
    }

    // Enable interrupts
    interrupts();
}

void loop() {
    time_t sleepForSeconds = 10;

    // Wait for USB to sort itself out.
    delay (5000);
    
    if (interruptFired) {
        interruptFired = false;
        Serial.printf("Interrupt fired at %s.\n", Time.timeStr().c_str());
    }
    
    Serial.printf("Sleeping for %d seconds at %s.\n", sleepForSeconds, Time.timeStr().c_str());
    if (sleepTime != 0) {
        Serial.printf("...%d seconds after waking.\n", Time.now() - sleepTime);
    }

    // Leave a little time for serial prints to leave the building before sleepy-byes
    delay (500);

    // Sleep unless sleepy-time has ended or the wake-up interrupt pin has gone off
    sleepTime = Time.now();
    System.sleep(WKP, RISING, sleepForSeconds, SLEEP_NETWORK_STANDBY);
}

If I run this and then, after the first run around the loop(), I attack the WKP pin with 3V3, I see the following:

Interrupt attached to WKP pin.
Sleeping for 10 seconds at Sun Jun 12 16:28:07 2016.
Sleeping for 10 seconds at Sun Jun 12 16:28:23 2016.
...15 seconds after waking.
Sleeping for 10 seconds at Sun Jun 12 16:28:37 2016.
...14 seconds after waking.
Sleeping for 10 seconds at Sun Jun 12 16:28:45 2016.
...8 seconds after waking.

So WKP is definitely waking the system up, you can see from the shorter sleep durations, and I can see the LED come on cyan. But my flag is never set and D7 never flashes. I’ve tried switching from WKP to D4 for a bit of variety but the effect is the same. This is with core firmware 0.5.1.

What am I doing wrong?

Fist thing: Don’t use delay() inside an ISR!

No need to call interrupts() unless you previously called noInterrupts()

Just a side-note, since no relevance in your case:
System.sleep(WKP, RISING, sleepForSeconds, SLEEP_NETWORK_STANDBY); does alter the pinMode() as required for the selected trigger edge (RISING -> INPUT_PULLDOWN, FALLING -> INPUT_PULLUP, CHANGE -> INPUT).
So if you had (which you haven’t) two contradicting edges for your interrupt and the wake call, then you’d need to re-set the pinMode() after wake to fit for your interrupt (might be changing in future).

Yeah, I know, but this is a debug program and I wanted a visible indication in case the serial out wasn’t considered trustworthy. Removing it doesn’t help.

I’m acutally surprised that you didn’t get an SOS Hard Fault with that in there :confused:

And I think you’ve forgotten pinMode(D7, OUTPUT) in order to have your D7 LED light up.

Sorry, yes, the original code had the D7 output thingy, just forgot to transfer it to the debug program. Any other clues?

I’ve tested your code, and it actually has to do with both my points.

The delay() in there did manage to stall the processor (breathing cyan gets stuck) when you trigger the interrupt on first setup.
And using sleep() waking on the same pin as your attachInterrupt() causes the attachInterrupt() to be overruled by sleep, so you’d need to reattach after wake.

Try this instead

const int intPin = WKP;

time_t sleepTime = 0;
volatile bool interruptFired = false;

// Handle the wake-up interrupt going off
static void intWakeUp() {
    interruptFired = true;
    digitalWrite(D7, !digitalRead(D7));
}

void setup() {
    Serial.begin(9600);

    pinMode(D7, OUTPUT);
    
    pinMode(intPin, INPUT_PULLDOWN);
    if (attachInterrupt(intPin, intWakeUp, RISING)) {
        Serial.println ("Interrupt attached to WKP pin.");
    } else {
        Serial.println ("WARNING: couldn't attach interrupt to WKP pin.");
    }
}

void loop() {
    time_t sleepForSeconds = 10;

    delay(10000);

    if (interruptFired) {
        interruptFired = false;
        Serial.printf("Interrupt fired at %s.\n", Time.timeStr().c_str());
    }
    
    Serial.printf("Sleeping for %d seconds at %s.\n", sleepForSeconds, Time.timeStr().c_str());
    if (sleepTime != 0) {
        Serial.printf("...%d seconds after waking.\n", Time.now() - sleepTime);
    }
    
    // Leave a little time for serial prints to leave the building before sleepy-byes
    delay (500);

    // Sleep unless sleepy-time has ended or the wake-up interrupt pin has gone off
    sleepTime = Time.now();
    System.sleep(intPin, RISING, sleepForSeconds, SLEEP_NETWORK_STANDBY);

    if (attachInterrupt(intPin, intWakeUp, RISING)) {
        Serial.println ("Interrupt attached to WKP pin.");
    } else {
        Serial.println ("WARNING: couldn't attach interrupt to WKP pin.");
    }
}

Aaah! I’d assumed they’d be chained. Thanks very much for the help.

The problem is that I need to read an external device when the interrupt goes off in order to clear the interrupt. How would I do that with the sleep function if the interrupt functions aren’t chained? S’pose I have to check if the time has expired and imply it from that?

That's the common suggestion.
The other one is a sample'n'hold circuit which you read after wake.

OK, I’ll do that. Thanks again.

Actually, this should be raised as a documentation update, since the System.sleep() description makes no mention of overriding anyone’s attached interrupt. How would I go about doing that?

You could open a GitHub issue in the docs repo
https://github.com/spark/docs/issues/

And maybe also one in the firmware repo to address this, since this in fact seems to be counter-intuitive for Stop Mode sleep.
https://github.com/spark/firmware/issues/

For deep sleep this would not be an issue, since your code would again run through setup() and re-set everything as needed, anyway.

Done:


1 Like