View Categories

Writing Arduino Code Overview

9 min read

The Sleepy Pi 2 contains an Arduino processor (ATMEGA328P) and its functionality is governed by the code that the Arduino contains. That means that to shutdown / start the Raspberry Pi you need to write / load / run some code on the Arduino. Fortunately there are some examples and a library that help you along the way.

Sleepy Pi 2 library #

Sleepy Pi 2 Class Diagram
Sleepy Pi 2 Class Diagram

The Sleepy Pi Arduino library contains routines that control the main functionality of the hardware. The latest version can be downloaded from GitHub.

Inheritance #

In code terms it takes the form of a Sleepy Pi class and in true C++ tradition makes use of inheritance. For those new to programming and C++, inheritance provides a convenient way to make use of other code and integrate it into main class as if it born with it in.

The Sleepy Pi currently makes use of three libraries:

  • PCF8523 to control the on-board Real-time Clock
  • LowPower to provide sleep and low power modes to minimize power whilst we are waiting for something to happen.
  • (Time Library) which is used by the PCF8523

These must be present in your Sketchbook/libraries folder so that the Arduino IDE knows where to find them.
To use an inherited routine as if it was our own we simply use the “.” notation:
For example, to use the LowPower libraries “powerDown” feature on SleepyPi we could write:

SleepyPi.powerDown(SLEEP_8S, ADC_CONTROL_OFF, BOD_OFF);

Concepts #

The Sleepy Pi is a very flexible user programmable board and it can turn it’s hand to many things. In broad concept though, the Sleepy Pi is designed to maximize battery life in Raspberry Pi applications that do not require the RaspPi to be on all the time. In order to do this best, when the Arduino has cut the power to the RaspPi, it should itself go into a low power mode and then “wakeup” either on some event or periodically to check something. The following sections will focus on the ways to integrate the Sleepy Pi ‘s power management features into an application.

Sleepy Pi 2 Arduino Block Diagram
Sleepy Pi 2 Arduino Block Diagram

Low Power Mode #

Getting your processor to sleep can be a bit of a Black Art at times and generally doesn’t involve rocking it or taking it for a drive, but instead wading through the intricacies of the processor datasheet. This is where the LowPower library comes in and takes the pain out of using low power sleep modes.

LowPower Library #

There are a number of different flavours of sleep and they each have a different levels of power consumption. In essence these are (in rough order from highest power to lowest):

  • Idle.
  • Adc reduction mode.
  • Power save.
  • Power down.
  • Standby.
  • Extended Standby.

For a complete overview of this visit the Rocketscream website and also our article on the power implications. When used with the Sleepy Pi, the code snippet becomes:

#include "LowPower.h"
#include "SleepyPi2.h"

void setup()
{
   // No setup is required for this library
}
void loop()
{
   // Sleep for 8 s with ADC module and BOD module off
   SleepyPi.powerDown(SLEEP_8S, ADC_CONTROL_OFF, BOD_OFF);

   // Do something here
   // Example: read sensor, log data, transmit data
}

Arduino Wakeup Options #

If you’ve got the Arduino in a low power mode and the Raspberry Pi turned off, at some point you are going to want to trigger a wakeup in response to some sort of stimulus. I’ve found that shouting at it, is not too effective, nor is throwing a cup of water over it. Instead, I’ve found that these sorts of methods work best:

  • Triggering an Interrupt / Digital GPIO
  • Periodically i.e Using the Alarm Clock / Watchdog
  • Programmatic i.e Analogue Input

When the Arduino is awake, you can then decide whether or not to actually wake the Beast aka the Raspberry Pi. You might decide that whatever it is that you are monitoring doesn’t warrant the full wakeup and so you can set the Arduino back to sleep again.

Interrupt / Digital GPIO #

This is using a GPIO pin to wakeup the Arduino, typically using an interrupt. In it’s simplest form this can be the on-board button which is fed to the INT1 interrupt. See the ButtonOnOff example for guidance of how to do this. Although INT1 is connected to the switch, it also has connections to put something in parallel such as a remote switch.

The other “Standard” Interrupt which is INT0 is fed to the on-board Alarm Clock and is discussed in the section on Periodically waking the Arduino.

Aside from INT0 and INT1 you can use the other GPIO pins and wake on “change” on the pin. These can be enabled on any pin from Arduino 2 – 13 and A0 – A5. However, practically speaking and bearing in mind the pins already being used, I’d probably start with these Arduino numbered pins:

  • 5, 6, 8,9,10,11 (14, 15)

14 and 15 are two analogue pins, so might want to use those for something else.

To see how to implement a wake on pin change, see the WakeOnPin example. It’s also worth checking out the new EnableInterrupts library as an alternative.

Periodically #

There are two options to wake the Arduino:

  • Watchdog (short times)
  • Alarm Clock (longer times)

Watchdog #

The Watchdog Timer is an internal timer that can still run when the main parts of the processor are asleep and can be used for short duration wakeups (up to 8s cycle time). The easiest way to implement it, is via the Low Power library described above where it is built into the low power call. You can set fixed times as follows:

  • 15ms
  • 30ms
  • 60ms
  • 120ms
  • 250ms
  • 500ms
  • 1s
  • 2s
  • 4s
  • 8s

The watchdog is a great way to wake-up the Sleepy Pi to perform some periodic task – like take a sensor reading, check whether some other event has happened.

Here is a simple example of using the watchdog timer:

#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 idle state for 8 s with the rest of peripherals turned off
    SleepyPi.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, 
    SPI_OFF, USART0_OFF, TWI_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

}

Alarm Clock #

The Sleepy Pi 2 has got a Real-Time Clock (RTC) on board which can function as an Alarm Clock and trigger periodic waking. This is great for scheduling wakeup and a particular time and for longer periods than the Watchdog can provide.

The RTC can operate in 2 modes:

  • Periodic
  • Alarm

The Periodic mode operates via Timer1 and allows you to set a periodic wakeup i.e. one that isn’t anchored to a particular time. Note: you can use periodic wakeups without actually setting the correct real-world time on the clock because they are relative times i.e. every 30 seconds. An example such as WakePeriodically shows how to use this functionality.

The Alarm mode functions very much like a traditional Alarm clock i.e. you can set it to wakeup 7:00 am on Monday 15th (or just every Monday).

Note that there is only 1 Alarm that can be active at any one time, so for example, if you need to wake in the morning and go to bed in the evening, you need to set the evening alarm after you awake. The WakeDuringDay example demonstrates this.

The datasheet for the PCF8523 RTC gives more insight as to what timings can be achieved.

Programmatically #

Programmatically waking the Arduino is really just a variation of the Periodic wakeup, but warrants it’s own section to highlight what can be done with it. Digital inputs can be connected to interrupts and these have a mechanism to trigger the Arduino to wake up, but not everything you might want to monitor comes in as a digital input. Here are some examples of what could be monitored instead:

  • Battery Voltage – via an Analogue input
  • Light Level – via an Analogue input
  • Sound Level – via an Analogue input
  • I2c Sensor – via the i2c bus
  • SPI Sensor – via SPI bus
  • and so on….

I hope that you can see that the list is pretty endless. The basic concept to grasp here, is that to optimise power and achieve the lowest power you can, you want the Arduino in a sleep mode as much as you can. Most sensors don’t need to be monitored continuously and when you are not reading the sensor, you want to be asleep. You then periodically wakeup at a frequency of your choice, read the sensor and make a decision: go back to sleep again or trigger some event such as waking the Raspberry Pi.

As an example, take the case of waking a remote camera system during the hours of daylight. You could either do this via the Alarm Clock or you could use light level to detect sunrise and sunset (or combination of both). If you are checking light level you could use something like a Light Dependent Resistor (LDR) connected in a resistor divider to an analogue pin. This will change voltage in response to light level. You need to then decide how often you need to check the light level and you can either do it very often via the Watchdog or longer i.e. every few minutes with the Alarm Clock in periodic mode.  The code would look very similar in broad concept to the code shown in the Watchdog example above. In this case we read the analogue light level voltage and check it against a threshold. If it’s above the threshold for sunrise, then wakeup the main camera system. Similarly when the light level falls at sunset we shut down the camera system.

It’s worth noting that the time taken for the Arduino to wakeup and read an analogue value or some other type of sensor, is very quick and doesn’t massively effect your power budget, so you can “afford” to check sensors quite regularly.

For a deeper dive into the code used see the article on Sleeping and Waking.

Leave a Reply

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

Shopping Cart
Scroll to Top