Having trouble using Sleep() with wakeUpPin

I am trying to use Sleep() using a wakeUpPin. I have tried USB flashing the “bootloader-patch-update” firmware, but when I flash it via USB and then flash my own code I am unable to successfully sleep using a wakeUpPin. I am specifying “Spark.sleep(D1,CHANGE,20);” at the end of my function which causes my Core to blink white, then green a few times, then go back to the regular connected slow pulse. How do I properly enable this newer functionality? If I use “Spark.sleep(SLEEP_MODE_DEEP, 20);” the Core properly goes into deep sleep for 20 seconds and then returns.

If you’re using a CHANGE interrupt to wake the Core it would be good to make sure that your pin is not floating.
When using RISING or FALLING this will be cared for internally, where I usually go for the first option, since it uses pull down resistors and I got the feeling that this uses less power :wink:

So how does your external circuitry for the wake up pin look?

1 Like

I the pin setup in the code as an input using an internal pull down. The input it wired to a push button switch and the other part of the switch goes to 3.3v. I don’t think this is a physical problem, but a coding/firmware issue. From what I can see it looks like the Core is executing this function in the pre-bootloader patch…

How is this patch supposed to work? I am basically uploading the Tinker app combined with this patched firmware, but wouldn’t any new firmware I flash from the IDE overwrite this?

EDIT: After looking at the source of the bootloader patch it seems that that updates actually has code that writes raw data to the bootlaoder. That explains how it would survive a reflash from the IDE. Either way I have flashed this update multiple times and am still having issues.

@mnetwork, can you please share your code? I’ll try and take a look tonight and see if I can duplicate the issue. :stuck_out_tongue:

If you are using a switch anyhow - and not a sensor with “unpredictable” state at sleeping time - you could use RISING or FALLING (just to test my theory ;-)).

As for your firmware question, although I’m no pro with these things, I try to explain how I understand things.

When flashing a new firmware you don’t actually directly flash the whole available flash but only some dedicated areas for different “modules” of firmware (bootloader, CC3000, user firmwate, …).
So if you flash a bootloader bin it goes into a different location than a user firmware would be flashed, and when flashing your use FW the bootloader area remains untouched.

As for the OTA flashing (and maybe dfu too) this works in two steps. First the binary gets loaded/flashed into some temporary storage - I think with some info of what kind of FW it is and where it needs to go - and after verifying that the FW was transfered/stored correctly, in a following step it gets transfered into its final location. After that you’re good to go.


Sorry, you found an answer already and with @peekay123 on board you’re in the best hands, now.

Below is the code I’m using. I originally had the wakeup pin and my interrupt pin as the same, but thought that might be causing an issue so I separated them for testing. D0 and D1 both go to push buttons. Both push buttons go to 3.3v.

const int buttonpin = D0;
const int servopin = A0;

const int closepos = 90;
const int openpos = 180;

int currentpos = 0;

Servo myservo;

void setup() {
    pinMode(buttonpin, INPUT_PULLDOWN);
    pinMode(D1, INPUT_PULLDOWN);

    currentpos = closepos;
    
    attachInterrupt(buttonpin, moveservo, FALLING);
}

void loop() {
    //Nothing
}

void moveservo() {
    myservo.attach(servopin);
    
    if (currentpos == closepos) {
        myservo.write(openpos);
        currentpos = openpos;
        currentpos = openpos;
    } else if (currentpos == openpos) {
        myservo.write(closepos);
        currentpos = closepos;
        currentpos = closepos;
    }
    
    delay(250);
    myservo.detach();
    
    Spark.sleep(D1,CHANGE,20);
}

EDIT: Tried reflashing the bootloader-patch-update again. When the Sleep line runs the core just resets. I don’t get it!

@mnetwork, off the bat I noticed you are calling a lot of servo code and delay(250) within your button ISR. This is not good practice. Instead, you should set a flag that you check in loop() to then do the servo work and call Spark.sleep(). I’ll do a rewrite and test the Spark.sleep() and get back to you. :smile:

1 Like

Forgive me. Spark Core my first attempt at Arduino/Wiring, just started a day ago. I converted the code and that fixed my crash issue when my delay was above 500ms, but this sleep issue still remains. If I use the older sleep method (with “SLEEP_MODE_DEEP”) it sleeps normally, but if I use the new sleep method it just resets. Here is my new code:

const int buttonpin = D0;
const int servopin = A0;

const int closepos = 1;
const int openpos = 180;

int servoflag = 0;
int currentpos = 0;

Servo myservo;

void setup() {
    pinMode(buttonpin, INPUT_PULLDOWN);
    pinMode(D1, INPUT_PULLDOWN);
    //myservo.attach(servopin);
    
    //myservo.write(closepos);
    currentpos = closepos;
    
    attachInterrupt(buttonpin, moveservo, FALLING);
    
    //delay(250);
    //myservo.detach();
}

void loop() {
    
    if (servoflag == 1) {
        myservo.attach(servopin);
        
        if (currentpos == closepos) {
            myservo.write(1);
            delay(250);
            myservo.write(openpos);
            delay(1000);
            currentpos = openpos;
        } else if (currentpos == openpos) {
            myservo.write(1);
            delay(250);
            myservo.write(closepos);
            delay(1000);
            currentpos = closepos;
        }
        
        myservo.detach();
        servoflag = 0;
        
        Spark.sleep(D1,CHANGE,20);
        //Spark.sleep(SLEEP_MODE_DEEP, 20);
    }
}

void moveservo() {
    servoflag = 1;
}

UPDATE: So, I played with it a little more and changed “CHANGE” to “FALLING”. This caused it not to reset, but I still couldn’t use the button to wake it up. I then changed it to “RISING” and this WORKS. Why does CHANGE cause it to wake up right away and why does FALLING not work at all?

@mnetwork, you don’t have any debounce in the button interrupt. Also, once the button is pushed, you need to wait till it is released or else it will trigger another interrupt (due to bounce again). Finally, the CHANGE mode on Spark.sleep() will not work. It has to be rising or falling. Here is my take on your code (I could not test the servo stuff however):

#include "application.h"

const int buttonpin = D0;
const int servopin = A0;

const int closepos = 90;
const int openpos = 180;

int currentpos = 0;

Servo myservo;

volatile boolean buttonPressed = false;

void setup() {
	pinMode(buttonpin, INPUT_PULLDOWN);
	pinMode(D1, INPUT_PULLDOWN);
	pinMode(D7, OUTPUT);
	digitalWrite(D7, LOW);

	currentpos = closepos;
	
	attachInterrupt(buttonpin, moveservo, RISING);
}

void loop() {
	
	if (buttonPressed) {
		while (digitalRead(buttonpin) == HIGH);
		digitalWrite(D7, HIGH);
		
		myservo.attach(servopin);
		
		if (currentpos == closepos) {
			myservo.write(openpos);
			currentpos = openpos;
			currentpos = openpos;
		} else if (currentpos == openpos) {
			myservo.write(closepos);
			currentpos = closepos;
			currentpos = closepos;
		}
		
		delay(250);
		myservo.detach();
		buttonPressed = false;
		
		Spark.sleep(D1,RISING,20);
	}
	// do something else
}

void moveservo() {
	static unsigned long last_interrupt_time = 0;
	unsigned long interrupt_time = millis();
	if (interrupt_time - last_interrupt_time > 50)  // debounce time = 50milliseconds
	{
		buttonPressed = true;
	}
	last_interrupt_time = interrupt_time;
}

I added a D7 output (blue LED on board) to show button had been released after being pressed. Give it a shot and let me know how it goes :smile:

Thank you for your code. I do have to start using debounce, but I didn’t bother because I didn’t think that was the cause in this instance. If CHANGE does not work, why is it listed as an option in the documentation? I also found that it did not work. I updated my response above to say that I was able to get it working, but now have a new problem… It seems that when the Core wakes up (no matter if it is by interrupt or by timer) it runs the interrupt function associated with that pin… Here is my current code:

const int buttonpin = D0;
const int sleepbuttonpin = D1;
const int servopin = A0;

const int closepos = 1;
const int openpos = 180;

int servoflag = 0;
int sleepflag = 0;
int currentpos = 0;

Servo myservo;

void setup() {
    pinMode(buttonpin, INPUT_PULLDOWN);
    pinMode(D1, INPUT_PULLDOWN);

    currentpos = closepos;
    
    attachInterrupt(buttonpin, moveservo, FALLING);
    attachInterrupt(sleepbuttonpin, sleepmode, FALLING);
}

void loop() {
    
    if (servoflag == 1) {
        myservo.attach(servopin);
        
        if (currentpos == closepos) {
            myservo.write(1);
            delay(250);
            myservo.write(openpos);
            delay(1000);
            currentpos = openpos;
        } else if (currentpos == openpos) {
            myservo.write(1);
            delay(250);
            myservo.write(closepos);
            delay(1000);
            currentpos = closepos;
        }
        
        myservo.detach();
        servoflag = 0;
    }
    
    if (sleepflag == 1) {
        Spark.sleep(buttonpin,RISING,20);
        //Spark.sleep(D2,RISING,20);
    }
}

void moveservo() {
    servoflag = 1;
}

void sleepmode() {
    sleepflag = 1;
}

So in the code above the D0 pin is being used for the moveservo() function AND the wake interrupt. If I use the other button to put the Core to sleep and wait 20 seconds (or press the D0 button), the Core wakes up and the servo runs once as if I pressed the D0 button. Why would a wakeup trigger that interrupt?

Sorry for dwelling on this, but I think I've suggested the use of RISING or FALLING - knowing the possible issues - before (even in my first reply), but it is a bit frustrating if suggestions are not even given a chance.
And it is not that CHANGE doesn't work, but you'd need to use it in the correct context - which an open switch isn't, but any circuitry that never floats the pin would be (as my post above gave an example for)

The reason why your INPUT_PULLDOWN didn't make a difference is, that designating one of the three trigger options does implicitly require a pin mode that fits that desigantion (which for CHANGE is more like INPUT without pull-up/-down) - you'd not even need to set the pin mode at all, since designating it as interrupt does implicitly do that anyhow, but it's still good practice to do it (but correctly).
Edit: It does go for Spark.sleep(pin, trigger [, timeout]), but NOT for attachInterrupt() - I was wrong :blush:
At least this is what happens when doing attachInterrupt() and I guess the same goes for a wake up interrupt, but here @peekay123 might have a better founded insight.

Especially since my own experience does not fit to this

Paul ( @peekay123 ) could you please set me right on this?

@ScruffR, @mnetwork, the STM32 does support falling, rising and falling&rising trigger configurations. Furthermore, it is correct to first set the pinMode() for the interrupt pin prior to calling attachInterrupt(). The latter does not change the pinMode() on the pin.

So, I agree with @ScruffR that even though the interrupt pin is set to INPUT_PULLDOWN, it may be too weak to ensure noiseless operation, ie. without false triggering, in CHANGE mode. Instead, the pin should be set to INPUT_FLOATING with a strong (10K ohms) external pull-up or pull-down resistor. I will be testing this tonight in both pull-up and pull-down configurations. :smile:

Thank you. That theory does make sense. Let me know what you find with that.

What do you think about the other issue? I am trying to use a pin for BOTH an interrupt and a wake interrupt. When the Core wakes (via timeout or interrupt) it triggers the function associated with the interrupt. Why would this be? I now I can get around this by checking mills() before processing the code in the function, but I’m curious as to why this is happening.

Sorry Paul, but I'm somehow inclined to contradict, not because I have written prove, but out of experience.
Edit: Paul was right for attachInterrupt() after all, but for sleep() it does happen as mentioned
Given this little test sketch does work although pinMode() was set to OUTPUT prior Spark.sleep(), this does strongly suggest to me that some mode switching must take place (similar behaviour I've seen with attachInterrupt()) and I think to recall one of our Spark hardware geeks having said something similar too, but I can't find the respective post anymore :weary:

const int MODEPIN = A0; 
const int WAKEPIN = D6;

void setup()
{
  pinMode(D7, OUTPUT);
  pinMode(WAKEPIN, OUTPUT);
  
  digitalWrite(D7, HIGH);
  delay(5000);
  digitalWrite(D7, LOW);
  delay(5000);
}

void loop()
{
  unsigned long ms = millis();
  int mode = analogRead(MODEPIN);
  int trig;
  
  if (mode < 10)
    trig = RISING;
  else if (mode > 4085)
    trig = FALLING;
  else 
    trig = CHANGE;

  while (millis() - ms < 2000)
    if (CHANGE == trig) digitalWrite(D7, !digitalRead(D7));

  Spark.sleep(WAKEPIN, trig, 10);
}

This test sketch also shows that the pull-downs/-ups do suffice for RISING and FALLING respectively.
If trying the sketch with D7 as WAKEPIN (while disabling the D7-code lines) you'll see how the pull-up gets attached automatically when sleep(WAKEPIN, FALLING, 10) gets called and when then pulling the pin LOW the Core wakes.
Assuming the invers behaviour for RISING and the pull-down (without visual prove on D7) would then lead to:
"If RISING causes a pull-down and FALLING a pull-up to be attached independent of the previously selected pinMode setting, the logical consequence would be that CHANGE would either attach both or none of the pull resistors, of which the latter would be the more logical way to go."

@ScruffR, no problem! The statement I made was in regards to attachInterrupt() not having implicit code that changes the pinMode(). This much is true. However, Spark.sleep() sets up the STM32 backup registers for a processor STOP mode just prior to calling NVIC_SystemReset(). On the reboot, the firmware resets the pinMode for the wakepin then goes into STOP mode waiting for the pin event. When the processor exits STOP mode, it continues and runs the user code from the start.

So in your code, no matter what pinMode you set for WAKEPIN, it will be overridden by Spark.sleep() and set to INPUT for CHANGE mode, INPUT_PULLUP for FALLING mode and INPUT_PULLDOWN for RISING mode. It is the CHANGE mode that is the issue because it is set to INPUT with neither pull-up or pull-down making it susceptible to noise. This is the issue we are seeing here. :smile:

1 Like

Again I haven't tested my theory and I have no prove, but just to rule some things out.
Would you try to set your interrupt flags to zero in setup, rather than at the declaration of the variables?
Another - but less likely - reason to consider might be the D-pin glitch on startup.

@ScruffR, good point on the startup glitching! It would be interesting to move the WAKEPIN to an analog pin which does not suffer from that glitch. Also, it would be worth testing with an external pull-up or pull-down resistor using the CHANGE mode in Spark.sleep(). This would put to rest the pinMode issue with Spark.sleep() being susceptible to noise. I’ll have to give that a shot tonight. :smile:

This was one of the first things I tested and it did not change the outcome. The function is still run.

1 Like

Which of the two suggestions I made?

One other thing came to mind. You are using the servo pin to wake the Core and also start the servo.
Maybe after waking you should keep looping till the button is released and only after that attach the servo interrupt.

Another thing is that you’re using INPUT_PULLDOWN first, but then attach an interrupt on the FALLING edge.

Edit: Since attachInterrupt() does no resistor switching this can go
Switching pull resistors might take a while and thus trigger the interrupt.

Again - theories that might be completely ridiculous, but unless falsified still thinkable :stuck_out_tongue_winking_eye:

1 Like

I tried setting the flag variable to 0 in setup().

If it was an issue with waking wouldn’t it happen when it is powered on too? I also tried using a different pin for the wake interrupt and that stopped it from happening, so the pin being used in sleep() is directly related. I will try putting that delay/check in between pinMode and attachInterrupt. Worse case I do a mills() check on the interrupt function to not let it set the flag during the first few seconds. It just seemed a little hacky to me to have to do so.