Power Down consumption on custom board

Hi,

On a custom board, consisting in an Atmega328P and some few passives, I want to check the current consumption of the board in Power Down mode. The only pull-up resistor is the 10k one for the reset circuit. Then there are a number of de-coupling capacitors, that’s all. No external crystal used. The atmega is running at 8 MHz internal RC clock, 3.3VDC, BOD disabled.

I’ve picked some ideas from this post:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1285656727/5

So I’ve created a very simple sketch that puts the atmega in Power Down State:

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

void setup()
{                
  byte i;
  
  // Ensure no floating pins
  for(i=0; i<32 ; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }

  // Power-down state
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  // Disable functions
  power_all_disable();
  // Enter sleep mode
  sleep_mode();
}

void loop()
{
}

The issue is that I was hopping to see some few microamps entering the board but I’m finally monitoring 105 uA after entering the Power Down state. Being the circuit so simple I wonder whether I’m entering the low-power state and disabling the functions correctly… On the other hand, I’m now checking the possible leakage through the de-coupling capacitors.

Thanks in advance for your help.

Daniel.

Hi,

Is there any 3.3 V regulator?

48X24X48X:
Hi,

Is there any 3.3 V regulator?

No, I'm directly powering the board from an external power supply.

Thanks.

BOD disabled

Disabled by fuse settings?

// Ensure no floating pins
for(i=0; i<32 ; i++)
{
pinMode(i, OUTPUT);
digitalWrite(i, LOW);
}

There are no definitions for pins 20 through 31 and neither pinMode nor digitalWrite check for an out-of-bounds pin number. Change the for condition to “< 20”.

// Disable functions
power_all_disable();

I vaguely recall that this function does not catch everything. I can’t remember the details so you’ll have to search the forum.

Thank you very much for your response.

Yes

OK thanks. I copied that piece of code from an sketch written for the Atmega644…

[quote author=Coding Badly link=topic=53821.msg385112#msg385112 date=1298920637]

// Disable functions
power_all_disable();

I vaguely recall that this function does not catch everything. I can’t remember the details so you’ll have to search the forum.

[/quote][/quote]

Indeed, removing “power_all_disable()” from the code does not add a single uA to the consumption so I’ve decided to directly work with the PRR register instead:

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

void setup()
{                
  byte i;
  
  // Ensure no floating pins
  for(i=0; i<20 ; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }
  
  // Power-down board
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  
  sleep_enable();
  // Disable functions
  PRR = 0xFF;
  
  // Enter sleep mode
  sleep_mode();
}

void loop()
{
}

Unfortunately, the above changes still achieve 105 uA in the global consumption. I’m beginning to think that I have a damaged capacitor or a micro-shortcut somewhere on my board…

Thanks again.

From the datasheet…

9.11.3 PRR – Power Reduction Register

Bit 0 – PRADC: Power Reduction ADC
Writing a logic one to this bit shuts down the ADC. The ADC must be disabled before shut down.
The analog comparator cannot use the ADC input MUX when the ADC is shut down.

From the datasheet...

9.11.3 PRR – Power Reduction Register

Bit 0 – PRADC: Power Reduction ADC
Writing a logic one to this bit shuts down the ADC. The ADC must be disabled before shut down.
The analog comparator cannot use the ADC input MUX when the ADC is shut down.

But, if we don't enable the ADC at the 1st place, we don't have to do the above setting right?
Look at 9.10.1 of the datasheet.

The ADC is enabled by the core. I believe init in wiring.c does the deed.

Found it, it is in the wiring file in the core folder. The ADC is enabled by default.
For timers, I think for power down mode, the clock source is not available for it to work.

OK, trying to disable individual functions before stopping each function clock:

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

void setup()
{                
  byte i;
  
  // Ensure no floating pins
  for(i=0; i<20 ; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }
  
  // Power-down board
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  
  sleep_enable();
  // Disable functions 
  power_adc_disable();
  power_spi_disable();
  power_twi_disable();
  power_usart0_disable();
  power_timer0_disable();
  power_timer1_disable();
  power_timer2_disable();
  
  PRR = 0xFF;
  
  // Enter sleep mode
  sleep_mode();
}

void loop()
{
}

Consumption is still around 105 uA =(

Thanks guys!

I've investigated the possibility of "loosing" current through the decoupling capacitors but, even in the worst cases, they might be wasting a total of a few uAmps maximum. I think I'm going to order a couple of DIP-form atmegas in order to do the tests on a breadboard. Then I'll be able to mount only the essential components and measure the current consumption. That will let me discard any programming-related problem.

These...

// Disable functions
power_adc_disable();
power_spi_disable();
power_twi_disable();
power_usart0_disable();
power_timer0_disable();
power_timer1_disable();
power_timer2_disable();

...and this...

PRR = 0xFF;

...are equivalent. You still have not disabled the ADC.

You’re right!

Let’s do then:

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

void setup()
{                
  byte i;
  
  // Ensure no floating pins
  for(i=0; i<20 ; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }
  
  // Power-down board
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  
  sleep_enable();
  
  // Disable ADC
  ADCSRA &= ~(1 << ADEN);

  // Power down functions
  PRR = 0xFF;
  
  // Enter sleep mode
  sleep_mode();
}

void loop()
{
}

And the result is… less than 0.2 uAmps !!!

Thanks a lot guys for your great help!!

Can you wake up on external interrupt with these power down settings??

I think Atmel calls them “asynchronous interrupts”. Off the top of my head (read that as probably with mistakes): pin-change interrupts, USART activity, TWI address match, watchdog interrupt, INTx level. For the 328, the table in “9.1 Sleep Modes” provides a good overview.

I'm gonna add the other power down stuff then and see if the current draw goes down some then.

Yes, I'm able to periodically wake up the atmega from sleep using the watchdog. No problem except for the few uAmps that the watchdog sinks in power-down mode.

Baseline test with current sleep mode on my RF transmitter is 1.09mA, with highest current seen on my multimeter of 14.25mA during virtualwire transmission of 1 commanded byte (and however many bytes virtualwire adds to it for).
Now to add the other power down methods & see what happens:

// Disable ADC
ADCSRA &= ~(1 << ADEN);

// Power down functions
PRR = 0xFF;

A word of caution: some units may need to be reinitialized after power-off. I vaguely recall the USART being mentioned.

In other words, if something flaky happens after the processor awakens, check the datasheet first then start debugging!

Well, that sorta worked.
At initial power on, & first time entering sleep mode, current dropped to 0.99mA.
However, after the first key press/transmission, it jumped to 10.49mA after the send and stayed there.
Don’t have the receiver with me so I can’t tell if its still transmitting - the LED on D13 just stays on vs turning off after the transmission.

Did I get the code in the right place? And do I need to re-enable some part of it when I want to wake up for the next transmission?

// transmitter_Weapon_Feb2.pde
// Feb 2 - changed Lights Intensity to be used for Weapon select instead.
// Doesn't actually change any code, just a label change on the Remote keypad.

// -->> gave up on PCInts
// have to double Serial.Begin value with 8MHz ProMini
// have to double VirtualWire Bits/sec in Setup with 8MHz ProMini

// ALL SERIAL PRINTS COMMENTED OUT

// started with the code from this example
// http://www.arduino.cc/playground/Learning/arduinoSleepCode

// with sleep function called -> 1.09mA! should be >900 days (??) on 1000mAH batteries
// down from 8.95 mA in normal idle mode  -> just 7 days
// with bursts of ~14-15mA when a keypress is transmitted

// Processor: Arduino Mini-Pro running on PC USB power
// (ran on 3 AA batteries fed into VCC line prior to this Interrut attempt)
// Keypad: Velleman 4x4 Matrix
// RF Link Transmitter - Sparkfun MO-SAWR-A, 434MHz, WRL-08946

// Simple example of how to use VirtualWire to transmit messages
// Implements a simplex (one-way) transmitter with RF module. 

// See VirtualWire.h for detailed API docs
// Author: Mike McCauley (mikem@open.com.au)
// Copyright (C) 2008 Mike McCauley
// $Id: transmitter.pde,v 1.3 2009/03/30 00:07:24 mikem Exp $

// uses default pin 12 for transmit data
// uses default pin 11 for receive data

// added Keypad example from playground
// modified to send character in a buffer to the receiver from 4x4 matrix

// Velleman 4 x 4 matrix keypad 
// keypad 1 (Col1) to D10
// keypad 2 (Col2) to D9
// keypad 3 (Col3) to D8
// keypad 4 (Col4) to D7
// keypad 5 (Row1) to D6
// keypad 6 (Row2) to D5
// keypad 7 (Row3) to D4
// keypad 8 (Row4) to D3

// Rows have Internal Pullups

// Row 1, 2, 3, 4 Diode AND'D to D2 (INT0) to pull it low on a keypress
// Interrupt on D2 "wakePin" LOW - Input with Internal pullup

// D0, D1, D14, D15, D16, D17, D18, D19 set as inputs with internal pullups enabled

// 12/23/10 - started code to send out address read from switches to GND on D14, 15, 16, 17
// D14 - SW0
// D15 - SW1
// D16 - SW2
// D17 - SW3

// end of notes
// ***********************************************************************

                            // bring in the library(s)
#include <VirtualWire.h>    // Wireless transmitter/receiver library
#include <Keypad.h>         // Matrix Keypad library
#include <avr/sleep.h>      // powerdown library
#include <avr/interrupt.h>  // interrupts library

// ***********************************************************************
int SW0 = 14;               // bits to read in unique address - LSB
int SW1 = 15;               // bits to read in unique address
int SW2 = 16;               // bits to read in unique address
int SW3 = 17;               // bits to read in unique address - MSB
int address = 0;            // bits put together afteer reading switches
int add0;
int add1;
int add2;
int add3;

// define unused pins
int dpin0 = 0;              // apparently redefined by Serial as Serial Monitor works
int dpin1 = 1;              // apparently redefined by Serial as Serial Monitor works
int pin2 = 2;               // Int0 interrupt pin

int dpin18 = 18;
int dpin19 = 19;

// ***********************************************************************
// define the used pins

#define ledPin 13          // activity indicator, use for brief flash when transmit

// don't need to define pin12, handled by VirtualWire as default data_out pin to the transmitter

int sleep_count = 0;      // flag/counter to tell us to go sleep

// ***********************************************************************
// create an array to store data to be sent out
char msg[2]; // extra char added for address

// set up the Keypad
const byte ROWS = 4; // Four rows
const byte COLS = 4; // Four columns

// Define the Keymap
char keys[ROWS][COLS] = 
{
  {    '1','2','3','A'      }  ,  // row 1
  {    '4','5','6','B'      }  ,  // row 2
  {    '7','8','9','C'      }  ,  // row 3
  {    '*','0','#','D'      }  ,  // row 4
};

// Connect keypad ROW1, ROW2, ROW3 and ROW4 to these Arduino pins.
byte rowPins[ROWS] = { 6, 5, 4, 3  };  // Keypad uses internal pullups? No externals supplied
// these pins have separate external Diodes, anodes connected to Pin2 (Int0)
// Column pins are set low just before shut down,
// and Pin2 is pulled high internally.
// Pressing a Row button connects to a Low Columna and pulls the appropriate Row Diode Low for a Pin2 Low interrupt.
// Column pins are then set back high for the keypad library button determination.

// Connect keypad COL1, COL2, COL3, COL4 to these Arduino pins.
byte colPins[COLS] = { 10, 9, 8, 7 }; 

// Create the Keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

//***************************************************
// *  Name:        pin2Interrupt, "ISR" to run when interrupted in Sleep Mode
void pin2Interrupt()
{
  /* This brings us back from sleep. */
}

//***************************************************
// *  Name:        enterSleep
void enterSleep()
{
  /* Setup pin2 as an interrupt and attach handler. */
  attachInterrupt(0, pin2Interrupt, LOW);
  delay(50); // need this?
  /* the sleep modes
   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
   */
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // setting up for sleep ...
  sleep_enable();                       // setting up for sleep ...
  
// <<<<<<<<<<<<<<<<  March 2, 2011 - added some more power down stuff  >>>>>>>>>>>>>>>>

    // Disable ADC
  ADCSRA &= ~(1 << ADEN);

  // Power down functions
  PRR = 0xFF;
// <<<<<<<<<<<<<<<<<  end of new March 2 stuff  >>>>>>>>>>>>>>>>>>>>>>>

  sleep_mode();                         // now goes to Sleep and waits for the interrupt

  /* The program will continue from here after the interrupt. */
  detachInterrupt(0);                 //disable interrupts while we get ready to read the keypad 

  /* First thing to do is disable sleep. */
  sleep_disable(); 

  // set all the keypad columns back high so can read keypad presses again
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH); 
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH); 
  // then go to the void Loop()
}