View Categories

Sleeping And Waking

9 min read

This article goes into greater depth for the Arduino Code needed to  sleep and wake the System.

The key to writing Sleepy Pi 2 Arduino code is to understand that the Sleepy Pi 2 is essentially intelligently controlled Raspberry Pi power switch. Our goal is to control the power to the Raspberry Pi and around this we have several decisions to make:

  • What do we want to trigger a Rpi wakeup?
  • How long do we want to be “awake” for?

In addition to controlling the power to the Raspberry Pi, we also want to minimise the power used by the Arduino when the Raspberry Pi is off. The Arduino at the heart of the Sleepy Pi does have sleep modes so we can decide what level of sleep we need. 

Before sleeping or waking we need to address powering the Raspberry Pi. These aspects are covered in a separate article here.

Putting the System to Sleep #

n order to wake must first be put to sleep. In order to do this, we call one of the Low Power Sleep routines. The lowest power routine is SleepyPi.powerDown and will be used throughout this post, but there are others you can use. Which one we call, will depend to a certain extent on how we intend to wake and they will be described below.

It’s also worth noting that when we call the Sleep routine, for example:

SleepyPi.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); 

The code stops at that point. If you could step through the code line by line, we’d see it literally go into that routine and not come out. It stops dead in its track right there. On wakeup it then comes out of that routine and executes the next line of code and so on. 

It’s also a good idea to switch the Rpi off before you go to sleep….

Triggering a Wakeup #

The Sleepy Pi once asleep can be woken in many ways. These can be termed Asynchronous or Synchronous / Timed. 

Sleepy PI Wakeup Sources

Asynchronous triggers are not on a schedule and as their name implies can occur at any time. These include the INT1 interrupt and also a transition on another GPIO pin. 

Synchronous / Timed can be further divided in “scheduled” or “periodic”.  Scheduled are at a particular time whereas periodic are set repeating intervals.

Once we have woken up the Arduino we have to decide whether to wake up the Raspberry Pi. We can wake up the RPi by default when we wakeup, but we do also have the option to consider other factors in code before deciding whether to power the Rpi. For example we might check an analogue input, for example a light sensor. If if was light enough, wake up the Rpi and do something, like take a picture. 

Asynchronous Wakeup #

INT1 pin #

This is the simplest mode – we put the system to sleep forever. We power down the Raspberry Pi and put the Arduino into a deep sleep by this routine:

SleepyPi.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); 

To wake up the system we need a random or asynchronous event on the external interrupt INT1 pin of the Arduino. This is connected to the onboard white switch and is also brought out to a pin header. This can be used for a remote switch or an-other input. This input is pulled high, so a high to low transition is required to wake up the Arduino.

Sleepy Pi 2 INT1 External Interrupt

To show how this is set this up in code refer to the examples:

Examples include: WakeOnPin, ButtonOnOff, ButtonOnOff3

Other GPIO #

The Arduino can be woken on a GPIO pin change. This can be rising, falling or just a change. The setup for this is a little more involved and a third party library: PinChangeInt is used to make things easer. To use the library, first choose a pin to use as the wakeup source, configure it, create an interrupt routine, attach it. For example something like this:

//  Select a  pin to use
const int WAKEUP_PIN = 8; // Pin B0 - Arduino 8

// Define an interrupt routine 
void wakeup_isr()
{
    // Just a handler for the wakeup interrupt.
    // You could do something here
}
// …Configure "Wakeup" pin 
pinMode(WAKEUP_PIN, INPUT); // Set as input

digitalWrite(WAKEUP_PIN, HIGH);  // Enable internal pull-up

// …Attach WAKEUP_PIN to wakeup pi 
PCintPort::attachInterrupt(WAKEUP_PIN, &wakeup_isr, FALLING);  

// Wake up when wake up pin is falling
SleepyPi.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); 

You can use virtually any pin for this purpose  and on Sleepy Pi 2, just select a spare one.

Sleepy Pi 2 Expansion Connections
Sleepy Pi 2 Expansion Connections

Example: WakeOnPin.

With these modes we will be maintaining the lower possible mode until some arbitrary event happens. This could be weeks or many months between triggers for example might be a motion controlled camera.

Synchronous or Timed Wakeup #

This mode is superficially similar to the Asynchronous mode (and they are not mutually exclusive) but the key in thinking here is that we are going to use some sort of timed interrupt. This can take the form of using the on board Real Time Clock (RTC) to trigger an interrupt on the external INT0 pin or to use the Arduino Watchdog to trigger an internal interrupt.   

When we use the internal Arduino Watchdog, we can wake the Arduino up at regular intervals or periodically.

When we use the Real Time Clock we can wake the Arduino either periodically using a timer or on a schedule using the clock and calendar, very much like we would with an alarm clock. This can be a one-off or a repeating alarm for example everyday at 9-00am. You could also set the alarm to go off every hour, so there is overlap to the timer functionality. Basically there are many ways of doing the same thing.

Note: If we want to wake the Arduino periodically we use either the Watchdog or the RTC functions, they pretty much do the same thing. However the RTC allows you to set arbitrary intervals, whereas with the watchdog you have to adhere to its set intervals. 

Periodic with Watchdog #

The Watchdog is an internal timer that can be used for a variety of uses, chiefly for keeping a watch on the processor and to reset it if there is a problem. There is another use for it as a periodic timer and that is how we use it here. With the processor asleep, we can ask the Watchdog to wake us up periodically as an alternative to “Periodic with RTC Timer”. The main difference between these two approaches is that the Watchdog has a fixed set of intervals. These are:

  • 16ms – Constant: SLEEP_15MS
  • 32ms – Constant: SLEEP_30MS
  • 64ms – Constant: SLEEP_60MS
  • 0.125s – Constant: SLEEP_120MS
  • 0.25s – Constant: SLEEP_250MS
  • 0.5s – Constant: SLEEP_500MS
  • 1.0s – Constant: SLEEP_1S
  • 2.0s – Constant: SLEEP_2S
  • 4.0s – Constant: SLEEP_4S
  • 8.0s – Constant: SLEEP_8S

To use the Watchdog we select the mode of sleep that we want (as usual) and then select the interval from a predefined set of constants found in LowPower.h and shown above. For some reason the constants and the actual time don’t exactly line up, for example 16ms and SLEEP_15MS – don’t ask me why?

#include "SleepyPi2.h"
#include <TimeLib.h>
#include <LowPower.h>
#include <Wire.h>

const int LED_PIN = 13;

void setup() {

   // Configure "Standard" LED pin
   pinMode(LED_PIN, OUTPUT); 
   digitalWrite(LED_PIN,LOW); // Switch off LED

   // initialize serial communication: In Arduino IDE use "Serial Monitor"
   Serial.begin(9600);
}

void loop() {

    // Enter power down state for 8 s with the rest of peripherals turned off
    SleepyPi.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);

   // Do something here
   // Example: Read sensor, data logging, data transmission.
   Serial.println("I've Just woken up");
   digitalWrite(LED_PIN,HIGH); // Switch on LED
   delay(250); 
   digitalWrite(LED_PIN,LOW); // Switch off LED

}

Periodic with RTC Timer #

These modes all use the RTC’s onboard timer rather than it’s full clock / calendar. The code follows this form:

// Set the Periodic Timer SleepyPi.setTimer1(PeriodicTimer_Timebase, PeriodicTimer_Value); 
...
SleepyPi.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); 

You set the timebase for the timer and then the timer value. It’s a countdown timer, so when it gets to zero it fires.  The timebase you can use is either:

  • Seconds (eTB_SECOND)
  • Minutes (eTB_MINUTE)
  • Hours (eTB_HOUR) 

And the timer value is an 8-bit number so can be a maximum of 255. 

As you can see the Arduino wakes on a set periodic interval and sleeps in between. You can use this to check on something like an analogue input of just use it to wake the Rpi at set intervals, like every hour. You can use these modes in conjunction with qualification code, for example, take a picture every hour, but only during the daylight hours. 

Examples include: WakePeriodically, WakePiPeriodically, WakePiPeriodicallyDuringDay.

Scheduled with RTC Alarm #

This mode uses the RTC Alarm function. This acts like a typical alarm clock in that you set a time for the alarm to go off which then fires off the Alarm INT0 pin. It doesn’t have to be a set date, you can set it to go off every day at a set time. 

The code takes the normal form of first setting the alarm and then putting the Arduino to sleep. For example: 

// Setup the Alarm Time - wake every day at this time
SleepyPi.setAlarm(WakeUp_StartHour,WakeUp_StartMinute);   // Hours & Minutes i.e. 22:07 on the 24 hour clock    
...
SleepyPi.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); 

In this case the SleepyPi.setAlarm function is overloaded and can take a varying number of parameters. Use one of these to setup the alarm:

SleepyPi.setAlarm (minute_alarm ); 
SleepyPi.setAlarm (hour_alarm, minute_alarm );
SleepyPi.setAlarm( day_alarm, hour_alarm, minute_alarm );
SleepyPi.setWeekDayAlarm (weekday_alarm, hour_alarm, minute_alarm);

You can see from these options that you can set to wake every set number of minutes – very similar to what we could do using the timer or watchdog.

You could set an hour and minute, so for example, it would wake every day at 9:07 am for example.If you add day into this, then it would be that day per month, for example 17th of each month at 9:07. Alternately, you can set a day of the week so for example, this could be every Monday at 9:07am do something.

Leave a Reply

Your email address will not be published. Required fields are marked *

Shopping Cart
Scroll to Top