Sleep() Caused Insomnia when assisted by interrupts



  • Hi there!

    I feel I need to share this and I invite You to reflect upon this and share your ideas here.

    I've been working on a battery powered node with 2 push buttons. Normally it sleeps but it will wake up using two interrupts when one of the push buttons gets pressed.
    interruptReturn = sleep(PRIMARY_BUTTON_PIN-2, CHANGE, SECONDARY_BUTTON_PIN-2, CHANGE, ONE_DAY_SLEEP_TIME);

    I've spent many hours trying to figure out how to make this script work. I had problem with that once a push button was pressed it was generating and endless loop of interrupts. It never slept.

    It sounds weird but using the following line

    sleep(50); // Short delay to allow switch to properly settle
    

    instead of

    delay(50); // Short delay to allow switch to properly settle
    

    caused the never ending interrupt loop.

    Below is my final script.

    #define MY_BAUD_RATE 9600
    #define MY_RADIO_NRF24
    
    #include <SPI.h>
    #include <MySensors.h>
    #include <Vcc.h>
    const float VccMin   = 1.8;           // Minimum expected Vcc level, in Volts.
    const float VccMax   = 3.2;           // Maximum expected Vcc level, in Volts.
    const float VccCorrection = 1.0/1.0;  // Measured Vcc by multimeter divided by reported Vcc
    Vcc vcc(VccCorrection);
    
    #define NODE_ID 17
    #define SKETCH_NAME "2x Binary Switch Sleep"
    #define SKETCH_VERSION "3.2"
    
    #define CHILD_ID_1 0
    #define CHILD_ID_2 1
    #define PRIMARY_BUTTON_PIN 2 // Arduino Digital I/O pin for button/reed switch
    #define SECONDARY_BUTTON_PIN 3 // Arduino Digital I/O pin for button/reed switch
    
    #define BATTERY_REPORT_DAY 2
    #define BATTERY_REPORT_BY_IRT_CYCLE 10 // Adjust this according to usage frequency.
    #define ONE_DAY_SLEEP_TIME 86400000 // No wakeup timer at all
    
    int oldValue1=-1;
    int oldValue2=-1;
    int dayCounter = BATTERY_REPORT_DAY;
    int irtCounter = 0;
    int interruptReturn = MY_WAKE_UP_BY_TIMER;
    
    MyMessage msg1(CHILD_ID_1,V_TRIPPED);
    MyMessage msg2(CHILD_ID_2,V_TRIPPED);
    
    void setup()	
    {	
    	pinMode(PRIMARY_BUTTON_PIN,INPUT);
    	pinMode(SECONDARY_BUTTON_PIN,INPUT);
    	// We use external and very weak pull ups to save power
    	//digitalWrite(PRIMARY_BUTTON_PIN, HIGH);    // Enable internal pull-up
    	//digitalWrite(SECONDARY_BUTTON_PIN, HIGH);    // Enable internal pull-up
    }
    
    void presentation() {
    	sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
    	present(CHILD_ID_1, S_DOOR);
    	present(CHILD_ID_2, S_DOOR);
    }
    
    void loop() 
    {
    	if (interruptReturn == MY_WAKE_UP_BY_TIMER) { // Woke up by timer (or first run)
    		dayCounter++;
    		#ifdef MY_DEBUG
    		Serial.println("Woke up by timer (or first run)");
    		#endif
    		if (dayCounter >= BATTERY_REPORT_DAY) {
    			dayCounter = 0;
    			sendBatteryReport();
    		}
    	} else {    // Woke up by pin change
    		irtCounter++;
    		#ifdef MY_DEBUG
    		Serial.print("Woke up by pin change on pin D");Serial.println(interruptReturn+2);
    		#endif
    		if (interruptReturn == 0) {
    			delay(50); // Short delay to allow switch to properly settle
    			int value1 = digitalRead(PRIMARY_BUTTON_PIN);
    			if (value1 != oldValue1) {
    				send(msg1.set(value1==HIGH ? 0 : 1));
    				oldValue1 = value1;
    				Serial.print("Sent value: '"); Serial.print(value1==HIGH ? 0 : 1); Serial.println("'.");
    			}
    		} else {
    			delay(50); // Short delay to allow switch to properly settle
    			int value2 = digitalRead(SECONDARY_BUTTON_PIN);
    			if (value2 != oldValue2) {
    				send(msg2.set(value2==HIGH ? 0 : 1));
    				oldValue2 = value2;
    				Serial.print("Sent value: '"); Serial.print(value2==HIGH ? 0 : 1); Serial.println("'.");
    			}
    		}
    	}
    	if (irtCounter>=BATTERY_REPORT_BY_IRT_CYCLE) {
    		irtCounter = 0;
    		sendBatteryReport();
    	}
    	#ifdef MY_DEBUG
    	Serial.println("Zzzzzz");
    	#endif
    	delay(500); //delay to allow serial to fully print before sleep
    	// Sleep until something happens with the sensor, or one sleep_time has passed since last awake.
    	interruptReturn = sleep(PRIMARY_BUTTON_PIN-2, CHANGE, SECONDARY_BUTTON_PIN-2, CHANGE, ONE_DAY_SLEEP_TIME);
    }
    
    void sendBatteryReport() {
    	float v = vcc.Read_Volts();
    	float p = vcc.Read_Perc(VccMin, VccMax);
    	#ifdef MY_DEBUG
    	Serial.print("VCC = "); Serial.print(v); Serial.println(" Volts");
    	Serial.print("VCC = "); Serial.print(p); Serial.println(" %");
    	#endif
    	int batteryPcnt = static_cast<int>(p);
    	sendBatteryLevel(batteryPcnt);
    }
    

    The script above works now. (Arduino 1.6.13 and MySensors 2.1.0). It would be nice though to know why I can't use sleep(50) instead of delay(50) in my code. Any ideas?

    Cheers!


  • Mod

    If I'm not mistaken, delay it's just a pause in execution, while sleep is an actual powersave mode. You would normally use sleep for longer times instead of 50 milliseconds


  • Mod

    @รอเรือ what Arduino are you using? Might is be an esp8266? If so, take a peek at the return value from sleep() 😞



  • I think I might be having a similar issue on the slim node. It seems to work fine when pulled down by the circuit but enters an endless loop between the time based interrupt and pin when the circuit is open and being pulled up.

    What value of resistor are using for you pull up and were you having the issue on both rising/falling edge?



  • Hi guys!

    In the example above, it would be more appropriate using millis() in a loop than using sleep(50). It's also kind of wrong to use delay(50) I believe since it's taking up 100% of the CPU.

    Never mind. I'm just interested to understand how the sleep(50) inside the main loop would cause the "endless loop of interrupts" in my example. Actually I suspect it's a bug so it might be worth digging into it a bit.

    I've been experimenting with both strong and weak external pull-ups and I've also tried internal pull ups but it made no difference actually. I'm currently using an external resistor of 4,7M Ohm and it's working great (unless using sleep(50) inside the main loop of course).

    Hardware used is a Slim Node I never tried using a "pull down" instead of a "pull up" resistor.


  • Hardware Contributor

    Probably a stupid question but ... can you confirm the interrupt pin of NRF24 is not connected to your board ?



  • @Nca78

    I checked the board. Pin 8 IRQ of the NRF24L01+ module is not connected.


Log in to reply
 

Suggested Topics

7
Online

11.4k
Users

11.1k
Topics

112.7k
Posts