Power Saving in 8 bit AVR

With increasing popularity of battery powered portable devices microcontroller manufacturers started making the controllers more efficient for the specific purpose. For battery powered devices the most important and common parameter is the power consumption. There are some applications like remote weather loggers which run for years with a set of AA batteries, which needs average power consumption to be in nano amps.

To accomplish these power consumption levels the manufacturers introduced a new feature with different names, Microchips Nanowatt, Texas Instruments MSP430 series and from my favourite atmel its Picopower. All these techniques may work differently but the objective is same.

Atmels AVR 8bit has the following 6 Modes

  • Idle
  • ADC Noise Reduction
  • Power save
  • Power Down
  • StandBy
  • Extended Standby

 

avr-sleep-modes

sleep modes in 8 bit AVR

 

For the New controllers with PINChange interrupt the following table(Pinchange added as a wake up source)

for the controllers with pinchange interrupt

for the controllers with pinchange interrupt

Now what about the coding,

There are inbuilt functions for all the related job in WinAVR, so you can use the same in AVR Studio or Arduino. There are few arduino libraries e.g.  jeelib (github.com/jcw/jeelib)  for arduino based on the winavr functions, but i think the base winavr functions are best.

just include <avr/power.h> and <avr/sleep.h>

avr/sleep.h includes macros set_sleep_mode(MODE), sleep_enable(), sleep_disable(), sleep_cpu().

#define sleep_enable() \
do { \
_SLEEP_CONTROL_REG |= (uint8_t)_SLEEP_ENABLE_MASK; \
} while(0)
#define sleep_disable() \
do { \
_SLEEP_CONTROL_REG &= (uint8_t)(~_SLEEP_ENABLE_MASK); \
} while(0)
#define sleep_cpu() \
do { \
__asm__ __volatile__ ( sleep \n\t :: ); \
} while(0)

 

#define sleep_mode() \
do { \
sleep_enable(); \
sleep_cpu(); \
sleep_disable(); \
} while (0)

 

and avr/power.h includes functions for disabling peripherals. function to enable each peripheral,  function to disable each peripheral, function for disabling all, function to enable all.

in simple codes

——————————————————

#include <avr/sleep.h>

….code lines…

set_sleep_mode();

sleep_mode();

—————————————————–

these above two lines are enough to make a device sleep.

but before going to sleep you must enable interrupt and a method for wake-up from sleep mode, additionally you can disable the brownout detector (for least power consumption) in run time from the codes, but this functionality is available for some specific chips in pico series although you can disable it outside of the code by setting the fuse bits.

Example code

#include <avr/interrupt.h>
#include <avr/sleep.h>
set_sleep_mode(<mode>);
cli();
if (some_condition)
{
sleep_bod_disable();
sei();
}
sei();
However arduino people found a bug in the above code, if u r planning to wake up through a interrupt, and normal case we dettach the interrupt in the ISR, so if the interrupt is triggered before the system goes to sleep, the system will sleep without a wakeup hook. So modified the code as below. They modified the sequence and added disable_sleep in ISR which will inhibit the previous case.
sleep_enable();
attachInterrupt(0, pin2_isr, LOW);
/* 0, 1, or many lines of code here */
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
cli();
sleep_bod_disable();
sei();
sleep_cpu();
/* wake up here */
sleep_disable();
void pin2_isr()
{
sleep_disable();
detachInterrupt(0);
pin2_interrupt_flag = 1;
}