Martin's corner on the web

Power saving techniques on the Atmega32u4

Now that I have a Funky 2 prototype, I can toy with what I am most interested in: reducing power usage so that the Funky can operate on battery as long as possible. I have achieved amazing results with an Attiny84, and was slightly concerned how this much more capable and feature rich processor can handle low power applications.  It turns out we can do pretty good.

The MCU has the standard ultra low sleep modes, nothing fancy there. I was more interested in the consumption while awake. I was surprised to find out that on top of the classical power reducing stuff, we can actually switch the clock source in the software from the external 8Mhz clock to the internal RC (again 8Mhz). The datasheet explains in detail the necessary steps to achieve this, so it was pretty straight-forward. Strange enough, i didn’t notice any improvement, even the contrary… The Funky was running from regulated 3.3V power source (not via the USB plug)

Here is my test sketch, I leave some time between the settings so I can take measurement with my multimer. I noted the reading I was getting during each delay in the sketch itself:

#include <avr/power.h>

void setup(){

delay(10000);   //IMPORTANT!!! Allow time for changing firmware, or otherwise if we disable the USB too soon we are stuck and only a re-flash of the bootloader may help
//12.3mA at this point

delay(8000); //12.00mA

delay(8000); //11.85mA

delay(8000); //11.79mA

delay(8000); //11.75mA

 //Leave timer 0 going for delay() function
delay(8000); // 11.7mA

delay(8000); //11.6mA

delay(8000); //11.55mA

delay(8000);  // 11.35mA

delay(8000);  //9.97mA

USBCON |= (1 << FRZCLK);             // Freeze the USB Clock              
PLLCSR &= ~(1 << PLLE);              // Disable the USB Clock (PPL) 
USBCON &=  ~(1 << USBE  );           // Disable the USB  
delay(8000);  // 5.3mA

// Switch to RC Clock 
UDINT  &= ~(1 << SUSPI); // UDINT.SUSPI = 0; Usb_ack_suspend
USBCON |= ( 1 <<FRZCLK); // USBCON.FRZCLK = 1; Usb_freeze_clock
PLLCSR &= ~(1 << PLLE); // PLLCSR.PLLE = 0; Disable_pll

CLKSEL0 |= (1 << RCE); // CLKSEL0.RCE = 1; Enable_RC_clock()
while ( (CLKSTA & (1 << RCON)) == 0){}	// while (CLKSTA.RCON != 1);  while (!RC_clock_ready())
CLKSEL0 &= ~(1 << CLKS);  // CLKSEL0.CLKS = 0; Select_RC_clock()
CLKSEL0 &= ~(1 << EXTE);  // CLKSEL0.EXTE = 0; Disable_external_clock
delay(8000);  // 5.48mA .. hmmm?!
/// Enable External Clock
CLKSEL0 |= (1 << EXTE);	// CKSEL0.EXTE = 1;	// Enable_external_clock(); 
while ( (CLKSTA & (1 << EXTON)) == 0 ){} // while (CLKSTA.EXTON != 1);	// while (!External_clock_ready()); 
CLKSEL0 |= (1 << CLKS);	// CLKSEL0.CLKS = 1;	//	Select_external_clock(); 
PLLCSR |= (1 << PLLE);	// PLLCSR.PLLE = 1;	// Enable_pll(); 
CLKSEL0 &= ~(1 << RCE);	// CLKSEL0.RCE = 0;	// Disable_RC_clock(); 
while ( (PLLCSR & (1 << PLOCK)) == 0){}	// while (PLLCSR.PLOCK != 1);	// while (!Pll_ready()); 
USBCON &= ~(1 << FRZCLK);	// USBCON.FRZCLK = 0;	// Usb_unfreeze_clock(); 

void loop(){
// 3.9mA

void blip(int times, int dur) { 
  for(int i=0;i<times;i++){

So, the results are pretty good, the Funky v2 can run actively at 3.9mA and 4Mhz. The necessary hardware components may be enabled when needed and disabled again later to save precious power.

I am puzzled why running on the internal RC clock actually gave me slightly higher reading, maybe someone has explanation?

4 thoughts on “Power saving techniques on the Atmega32u4

  1. Kurt

    Maybe because the RC Oscillator needs some juice to work his magic?
    (disabled on X-tal mode……..)

    1. Martin Post author

      I am not really sure, maybe this example was bad. I have another one, where I get additional 0.3mA down by using the internal RC, so this only deepens the plot.

  2. Kurt Van Kelst

    i’m using the v1 board …is that the one with swapped mosi-miso ?

    i cant avrdude the chip …..

    avrdude -c usbtiny -p atmega32u4 just dont work ID ing the chip

    i only installed the crystal, 2*22pF caps and the 10 k reset resistor

    1. Martin Post author

      v1 is correct version; I once tried what you just did and it didn’t work. I then populated the USB stuff and powered the board from USB, removed the power jumper on the usbtiny and only then it worked. I never further investigated why that would be.