XMEGA power down mode for battery powered devices

This post describes how to implement firmware-controlled device power switching on an XMEGA. I am working on a portable device that is powered from a Li-Ion cell, has an USB socket for charging, MCU, couple of LEDs and a button. I wanted to keep the design as simple as possible, so there is just one button connected to the MCU and no separate power switch. Most of the information applies equally to all AVR MCUs.

XMEGA has the following sleep modes:

The deeper the sleep mode – the lower power consumption and less clocks (and peripherals) running. In this case a button wake up happens via the asynchronous port interrupt, so no clocks are necessary and “power down” mode can be used.

Schematic is not necessary to understand everything – just imagine an XMEGA32A4U, 3,3V LDO from battery to the MCU and a single button from any XMEGA IO pin to GND.

The single button has the following functions:

  • Power on – short press
  • Power off – long hold (until all LEDs light up) and release (all LEDs go off)
  • Software function – short press (while the device is running, not relevant for the power control driver)

This single-button approach has the benefit that the device is very simple to operate, no extra switches, nor PCB tracks are necessary.

Pin definitions

Button is wired to PA4, LEDs are wired to PD0, PD1 and PA1. Button init macro configures the pin as an input with a pullup. LED init macro configures the pins as outputs.

Power control driver

Main loop (or wherever the button driver is placed) has to count how long a button is held down and call power_down() at the appropriate moment. Then the following sequence takes place:

  1. All extra hardware is disabled (in my case the enable line of GPS LDO is pulled low to turn it off)
  2. Watchdog is disabled (I am not sure if it is necessary, as all clocks in power down mode are disabled, so there should be no way for the watchdog to run – to be verified…)
  3. XMEGA detaches itself from USB (it is always good to make a clean detach, than rely on the PC to time out – at least PC software can be aware of the disconnection)
  4. All LEDs are lit
  5. Because the button is being pressed, now the function has to wait until it is released. Without waiting for button release the code would enter sleep mode, detect that the button is down (normal press for power on) and immediately wake up
  6. After the button is released there is a delay to allow it to bounce (again to avoid an unwanted wakeup)
  7. All LEDs are turned off
  8. Pin interrupt is enabled (active level low)
  9. XMEGA enters power down mode

Now with the MCU in power down mode when a button is pressed the pin interrupt is executed. The press can be brief as the interrupt is sensitive to the edge. Interrupt enables the watchdog and then busy waits for it to reset the MCU. It is a very safe way to assure that the device will always start in a clean state. If it was not reset for a long time then some software problems could appear (example: timer overflow counting how long the device was running) and a not easily removable battery would certainly not help.

There is a 1,5 second delay, because the device has a bootloader. The bootloader is executed at every reset and checks if the button is pressed. If there was no delay, then the button press would always lead to bootloader activation (as the whole reset operation takes just ~64ms).