Wednesday 28 April 2010

Sleeping Arduino - Part 3 Wake Up Via the UART

Overview
In the third part of this "Sleeping Arduino" series, we will be covering how to wake the Arduino via the USB UART (serial interface over USB). When the Arduino's ATMEGA microcontroller is not receiving any communications from the PC via the serial link, it will enter a sleep mode (the very efficient 
SLEEP_MODE_PWR_DOWN, see here for more info on the power modes). Once serial data is sent from the PC to the Arduino board, it will wake for a period and re-enter sleep mode when no data is being received from the PC.

To wake the ATMEGA, we will be using the external interrupt INT0 on digital Pin 2 of the ATMEGA (as covered in Part 2 of this series), connected to the digital Pin 0 (which is the ATMEGA's UART receive line).

To do this we will use the following hardware:
  • Arduino Diecimila with usb cable (or a Freeduino, which is 100% Arduino Diecimila compatible)
  • One 220 Ohm Resistor

If you don't want to use a resistor, you can use a less efficient power mode mode and wake the Arduino using the UART interrupt as specified in Ruben's blog entry here.

USB UART
The following schematics show two of the devices on the Arduino Board. The first is the ATMEGA8 (could also be ATMEGA168) microcontroller, the other is the FT232RL, which is the USB UART interface device.
Note the TXD and RXD pins of the FT232RL are connected to the RXD and TXD of the ATMEGA respectively. These pins are exposed on J1 as digital pins 0 and 1.




When there is no data being transmitted on the serial TX and RX lines, they are pulled high at 5volts. Once data is transmitted the lines will change state with the data. We will use the initial state change to low to fire our external interrupt and wake the ATMEGA.

Circuit
The circuit for this entry is very basic. On your Arduino board just connect one leg of the 220 Ohm resistor into digital pin 0 (RX) and the second leg into digital pin 2 (INT0) on connector J1.

Source Code
The source code for this is exactly the same as the source code for Part 2 of this series.


#include <avr/sleep.h>
#include <avr/power.h>


int pin2 = 2;


/***************************************************
 *  Name:        pin2Interrupt
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Service routine for pin2 interrupt  
 *
 ***************************************************/
void pin2Interrupt(void)
{
  /* This will bring us back from sleep. */
  
  /* We detach the interrupt to stop it from 
   * continuously firing while the interrupt pin
   * is low.
   */
  detachInterrupt(0);
}


/***************************************************
 *  Name:        enterSleep
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Enters the arduino into sleep mode.
 *
 ***************************************************/
void enterSleep(void)
{
  
  /* Setup pin2 as an interrupt and attach handler. */
  attachInterrupt(0, pin2Interrupt, LOW);
  delay(100);
  
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  
  sleep_enable();
  
  sleep_mode();
  
  /* The program will continue from here. */
  
  /* First thing to do is disable sleep. */
  sleep_disable(); 
}


/***************************************************
 *  Name:        setup
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Setup for the Arduino.           
 *
 ***************************************************/
void setup()
{
  Serial.begin(9600);
  
  /* Setup the pin direction. */
  pinMode(pin2, INPUT);
  
  Serial.println("Initialisation complete.");
}



/***************************************************
 *  Name:        loop
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Main application loop.
 *
 ***************************************************/
int seconds=0;
void loop()
{
  delay(1000);
  seconds++;
  
  Serial.print("Awake for ");
  Serial.print(seconds, DEC);
  Serial.println(" second");
  
  if(seconds == 3)
  {
    Serial.println("Entering sleep");
    delay(200);
    seconds = 0;
    enterSleep();
  }
}


This source code can be downloaded here.


All parts of this series:

Sunday 25 April 2010

Sleeping Arduino - Part 2 Wake Up Via An External Interrupt

Overview
In the second entry of this "Sleeping Arduino" series, we will be covering how to wake the Arduino via an external interrupt. We will be using the external interrupt circuit that has been covered in a previous blog Arduino External Interrupts. Please be sure to get the basic external interrupt example working before attempting to follow this entry, this will prove that your hardware setup is correct.


Operation
Our code will operate as follows:
  1. Set up the serial port and set pin 2 (INT0) as an input;
  2. Run the loop function which will:
    1. Stay awake for 3 seconds;
    2. Once the 3 seconds have elapsed, SLEEP_MODE_PWR_DOWN will be entered;
    3. All code execution stops;
  3. The user then pushes the switch and pin 2 (INT0) will become low;
  4. The INT0 interrupt will fire and bring the Arduino out of sleep mode;
  5. Code execution continues where it had previously stopped.

Circuit
The circuit is set up as specified in the Arduino External Interrupts blog.


Source Code

#include <avr/sleep.h>
#include <avr/power.h>


int pin2 = 2;


/***************************************************
 *  Name:        pin2Interrupt
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Service routine for pin2 interrupt  
 *
 ***************************************************/
void pin2Interrupt(void)
{
  /* This will bring us back from sleep. */
  
  /* We detach the interrupt to stop it from 
   * continuously firing while the interrupt pin
   * is low.
   */
  detachInterrupt(0);
}


/***************************************************
 *  Name:        enterSleep
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Enters the arduino into sleep mode.
 *
 ***************************************************/
void enterSleep(void)
{
  
  /* Setup pin2 as an interrupt and attach handler. */
  attachInterrupt(0, pin2Interrupt, LOW);
  delay(100);
  
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  
  sleep_enable();
  
  sleep_mode();
  
  /* The program will continue from here. */
  
  /* First thing to do is disable sleep. */
  sleep_disable(); 
}


/***************************************************
 *  Name:        setup
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Setup for the Arduino.           
 *
 ***************************************************/
void setup()
{
  Serial.begin(9600);
  
  /* Setup the pin direction. */
  pinMode(pin2, INPUT);
  
  Serial.println("Initialisation complete.");
}



/***************************************************
 *  Name:        loop
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Main application loop.
 *
 ***************************************************/
int seconds=0;
void loop()
{
  delay(1000);
  seconds++;
  
  Serial.print("Awake for ");
  Serial.print(seconds, DEC);
  Serial.println(" second");
  
  if(seconds == 3)
  {
    Serial.println("Entering sleep");
    delay(200);
    seconds = 0;
    enterSleep();
  }
  
}

The sketch for this program can be downloaded here.





All parts of this series:


Sleeping Arduino - Part 1

Overview
In this series of blogs I will be describing how to put an Arduino Diecimila into sleep mode, thus reducing the power consumption of the device, and detail several mechanisms for waking the Arduino. This can be quite useful (even necessary) when you are powering your Arduino via a battery and/or solar panel.


Four mechanisms for waking the Arduino from sleep will be covered:
  • via an external interrupt. The Diecimila will wake up only when an external interrupt occurs.
  • via the UART (USB serial interface). The Diecimila will remain asleep until data is received over the serial interface.
  • via an internal timer. The Diecimila will periodically be woken up from sleep via Timer1, carry out an action and go back to sleep.
  • via the watchdog timer. The Diecimila will periodically wake up from sleep via the Watchdog timer, carry out an action and go back to sleep. Note using the Watchdog for this provides the longest sleep time and lowest power consumption (see here).
Note: There are various versions of Arduino available (see the I/O Board section of here), we will be using the Arduino Diecimila with an ATmega168 micro-controller. The source code provided below may run on other versions of Arduino, but the power consumption values will most likely be different.


This tutorial assumes the user is able to run the Arduino environment, create sketches and run them on the USB based Arduino Diecimila. For further information please see the official Getting Started with Arduino web page.


Arduino Power Consumption
There are several devices on the Arduino Diecimila that consume battery power, including:
  • ATmega168 micro-controller
  • FT232RL USB UART
  • The power regulator
The Arduino Diecimila I have uses about 35mAmps during normal operation and in power-down sleep mode about 15mAmps. There isn't a huge difference here, the main problem is that the power regulator draws 10mAmps, irrespective of the sleep state the Arduino is in. The ATmega168 micro-controller draws about 0.05 mAmps when in power-down sleep mode and 20mAmps during normal operation.


A cheap 9 Volt alkaline battery will have a typical capacity of 565 mAh. If used to power our Arduino Diecimila, it will last for about
  • 16 hours (565mAh/35mA) under normal operation
  • up to almost 38 hours (565mAh/15mA) in power-down sleep mode, depending on how often and for how long the Arduino is woken from sleep mode.
If you require your battery to last longer, you would have to consider the following options:
  • Use a battery with a bigger capacity, e.g. 9 Volt Lithium batteries have a typical capacity of 1200mAh, or you could use a battery pack, made up of several batteries.
  • Use a solar panel with/without a battery pack. If a battery pack is used, it can be charged by the solar panel during daylight hours.
  • Use the ATmega168 micro-controller stand-alone outside of the Arduino, see here.


Also note that the power consumption will be influenced by any external circuit that is connected to the Arduino, e.g. if you are interfacing with a bread board or using an Arduino shield.


Arduino Sleep Modes
The ATmega168 micro-controller in our Arduino Diecimila supports several modes of sleep:
  • SLEEP_MODE_IDLE - the least power savings
  • SLEEP_MODE_ADC
  • SLEEP_MODE_PWR_SAVE
  • SLEEP_MODE_STANDBY
  • SLEEP_MODE_PWR_DOWN - the most power savings


The more power saving the sleep mode provides, the less functionality is active.
E.g. in Power-Down sleep mode, only the external interrupt and watch dog timer (WDT) are active, in Idle sleep mode the UART, timers, ADC, etc are all active, just the CPU and Flash clocks are disabled. See Section 9 of the ATmega168 datasheet for more information.






When the micro-controller is entered into sleep mode by your code, the execution of code will pause at that point. In order to resume execution of your code, the micro-controller must then be woken from sleep mode by one of it's internal hardware modules, e.g. timer expiring, external interrupt, WDT, etc.


There are several Arduino library functions used to control sleep mode. They are:

  • set_sleep_mode(mode) - Configures the Atmega168 for the specified sleep mode (see above for supported sleep modes);
  • sleep_enable() - Enables the sleep mode to be entered;
  • sleep_mode() - Enters the sleep mode. Before this is called, the appropriate mechanism for waking the microcontroller must have been set up;
  • sleep_disable() - Disables the sleep mode;

The following is the basic code needed to put the Arduino into a sleep mode:

 void enterSleep(void)  
 {  
  set_sleep_mode(A_SLEEP_MODE);  
  sleep_enable();  
  sleep_mode();  
  /** The program will continue from here. **/  
  /* First thing to do is disable sleep. */  
  sleep_disable();   
 }  

Note that once the mechanism to wake the device from sleep mode has occurred, execution of code will continue, starting at the next code statement after the sleep_mode() function call.


Waking the Arduino
The following entries cover the various approaches available to bringing the Arduino out of a sleep mode:


If you would like to use an internal timer to wake the Arduino, and don't know which one to use, have a look at the table I've put together here.




Resources
http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
http://rubenlaguna.com/wp/2008/10/15/arduino-sleep-mode-waking-up-when-receiving-data-on-the-usart/
 

Arduino External Interrupts

Overview 
In this tutorial I will be showing you how to get your 
Arduino Diecimila to respond an external interrupt. When the interrupt occurs, the Arduino will toggle the state of an LED. The external interrupt we will be using will be INT0, which is Digital Pin 2 on the Arduino.

Here is what we'll use:

  • Arduino Diecimila with usb cable (or a Freeduino, which is 100% Arduino Diecimila compatible)
  • Solderless breadboard
  • Several jump wires
  • 220 Ohm resistor
  • Push switch (optional)
All components other than the Arduino should be easily purchased at your local hobby electronics store (such as Maplin in the UK).
This tutorial assumes the user is able to run the Arduino environment and run a program on the arduino board. For further information please see 
Getting Started with Arduino.

Arduino External Interrupts
Atmega168 micro-controller on the Arduino Diecimila boards have two external interrupts available: INT0 and INT1, located on digital pins 2 and 3 respectively.
The Atmega168 supports four trigger modes for external interrupts:
  • LOW -  a low level trigger
  • CHANGE - a change in level trigger
  • RISING - a rising edge of a level trigger
  • FALLING - a falling edge of a level trigger



For this tutorial we will be using a FALLING trigger mode. So, digital pin 2 will be connected to 5v via a pull-up resistor. When we want to generate the interrupt we will connect the pin to ground.

When configuring our external interrupt we will use the Arduino library function attachInterrupt(interrupt, function, mode). This function takes three parameters:
  • interrupt - This is the interrupt source, either 0 for INT0 or 1 for INT1;
  • function - The function to call when the interrupt occurs;
  • mode - The trigger mode as specified above;

External Interrupt Circuit
The following is the schematic of the circuit we will be using:

The following is a picture of the circuit as I have set it up on the bread board:

Notes On This Circuit
  • You don't need a push switch, you could replace the switch with a wire that you connected to ground in order to fire the interrupt.
  • We will have to implement software debouncing in order to prevent the interrupt from firing multiple times as the switch contacts settle.


Source Code
int interrupt_pin = 2;
int led_pin = 2;

volatile int toggle = 0;

/***************************************************
 *  Name:        pin2Interrupt
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Service routine for pin2 interrupt  
 *
 ***************************************************/
void pin2Interrupt(void)
{
  /* This will bring us back from sleep. */
  toggle = 1;
  
  /* Delay in here as a very crude debouncing mechanism. */ 
  delay(100);
}



/***************************************************
 *  Name:        setup
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Setup for the Arduino.           
 *
 ***************************************************/
void setup()
{
  Serial.begin(9600);
  
  /* Setup the interrupt pin */
  pinMode(interrupt_pin, INPUT);
  attachInterrupt(0, pin2Interrupt, FALLING);
  
  Serial.println("Initialisation complete.");
}



/***************************************************
 *  Name:        loop
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Main application loop.
 *
 ***************************************************/
int seconds=0;
void loop()
{
  if (toggle == 1)
  {
    Serial.println("Toggle");
    digitalWrite(led_pin, !digitalRead(led_pin));
    toggle = 0;
  }
}

The source file can be downloaded from here.