3
\$\begingroup\$

enter image description hereI'm experimenting with an ATmega328p on a breadboard using the standard Arduino bootloader. I'm looking at the power consumption as I want to power the device from a solar panel and a large cap. I've got a sketch that get's the device into the lowest power sleep mode. I'm measuring the power supply current and this drops to 23uA with the brownout detector enabled when the supply is above the brown out threshold of 2.7V. If the power supply is adjusted to below the brownout detector threshold then the power supply current jumps up to 881uA. I've tied all floating pins to ground but this doesn't seem to help. Is this expected behaviour or am I doing something wrong ?

/*
 * Sketch for testing sleep mode with wake up on WDT.
 * Donal Morrissey - 2011.
 *
 */
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

#define DIVIDER_PIN (13)
#define LOAD_PIN (12)

volatile int f_wdt=1;



/***************************************************
 *  Name:        ISR(WDT_vect)
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Watchdog Interrupt Service. This
 *               is executed when watchdog timed out.
 *
 ***************************************************/
 ISR(WDT_vect)
 {
   if(f_wdt == 0)
   {
      f_wdt=1;
   }
   else
   {
     // Serial.println("WDT Overrun!!!"); // this shouldn't happen
   }
}


/***************************************************
 *  Name:        enterSleep
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Enters the arduino into sleep mode.
 *
 ***************************************************/
 void enterSleep(void)
 {
   byte keep_ADCSRA;

   keep_ADCSRA=ADCSRA; // save adc register
   ADCSRA=0; // disable A/D converter

   set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // SLEEP_MODE_PWR_DOWN for lowest power consumption
   sleep_enable();

   /* Now enter sleep mode. */
   sleep_mode();

   /* The program will continue from here after the WDT timeout*/
   sleep_disable(); /* First thing to do is disable sleep. */

   /* Re-enable the peripherals. */
   power_all_enable();

   ADCSRA = keep_ADCSRA;                          //re-enable A/D converter

 }

void setup()
{

  // All pins as outputs set to 0 to save current
  //for (byte i = 1; i <= A5; i++)
  //  {
  //  pinMode (i, OUTPUT);  
  //  digitalWrite (i, LOW);  
  //  }

  pinMode(LOAD_PIN, OUTPUT);
  digitalWrite(LOAD_PIN, 0);
  pinMode(DIVIDER_PIN, OUTPUT);
  digitalWrite(DIVIDER_PIN, 0);

  pinMode(PD0,INPUT); // rxd input for serial comms
  pinMode(A0,INPUT); // a0 needed as input to read cap voltage

  Serial.begin(9600);

  /*** Setup the WDT ***/

  /* Clear the reset flag. */
  MCUSR &= ~(1<<WDRF);

  /* In order to change WDE or the prescaler, we need to
   * set WDCE (This will allow updates for 4 clock cycles).
   */
  WDTCSR |= (1<<WDCE) | (1<<WDE);

  /* set new watchdog timeout prescaler value */
  WDTCSR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */

  /* Enable the WD interrupt (note no reset). */
  WDTCSR |= _BV(WDIE);

 // Serial.println("Initialisation complete.");
 // delay(100); //Allow for serial print to complete.
}


unsigned int val=0;
double voltage; 
void loop()
{
  if(f_wdt == 1)
  {
    /* Don't forget to clear the flag. */
    f_wdt = 0;

    /* Re-enter sleep mode. */
    enterSleep();

    // power up the voltage divider and take a reading
    digitalWrite(DIVIDER_PIN, 1);
    delayMicroseconds(250); // settling time
    val = analogRead(A0);    
    digitalWrite(DIVIDER_PIN, 0);
    voltage=(val*18.0)/10.24;

    if (voltage>500.0) {
      digitalWrite(LOAD_PIN,1);
      delay(100);         // 0.1 second on
      digitalWrite(LOAD_PIN,0);
    }  
  }
}
\$\endgroup\$
3
  • \$\begingroup\$ Could you please add a circuit diagram of your setup? Or at least a photo of you breadboard. \$\endgroup\$
    – next-hack
    Commented Sep 10, 2017 at 15:38
  • 1
    \$\begingroup\$ Brownout holds the MCU in reset, which floats all pins (even those that are being used as outputs). Depending on what you have connected to the pins, they may not be held low during reset. I can't tell from your photo whether this is the case, need a schematic! \$\endgroup\$ Commented Sep 10, 2017 at 17:26
  • \$\begingroup\$ Sorry I haven't got a schematic a the moment. I connected all unused pins to ground directly and used 100k pulldown resistors on the pins I'm using as outputs. \$\endgroup\$ Commented Sep 10, 2017 at 19:07

1 Answer 1

1
\$\begingroup\$

Connecting all floating/unconnected pins to ground isn't recommended.

The ATmega328p data sheet states in Section 14.2.6 Unconnected Pins (page 88):

If some pins are unused, it is recommended to ensure that these pins have a defined level. Even though most of the digital inputs are disabled in the deep sleep modes as described above, floating inputs should be avoided to reduce current consumption in all other modes where the digital inputs are enabled (Reset, Active mode and Idle mode).

The simplest method to ensure a defined level of an unused pin, is to enable the internal pull-up. In this case, the pull-up will be disabled during reset. If low power consumption during reset is important, it is recommended to use an external pull-up or pull-down.

(emphasis mine)

So with a - say - 100 kOhm pull-down resistor you should see 1 µA or less per unused pin during reset. (cf. Input Leakage rows in Table 30-1, page 323 of the data-sheet).


Sidenotes:

  1. Reset mode may be active for an extended amount of time, e.g. when a brown-out condition is detected (cf. BOD).
  2. The 1 µA current figure is an upper bound/maximum rating. Under normal conditions, the typical current is likely lower (and increasingly difficult to measure exactly).
\$\endgroup\$
6
  • \$\begingroup\$ for more details on how to detail with unconnected pins: arduino.stackexchange.com/q/88319/13174 \$\endgroup\$ Commented Mar 6, 2022 at 19:16
  • \$\begingroup\$ If the pin is 'unused', the current drain should be negligible (nA) typically, regardless of whether internal or external pullup or pulldown is used. 30uA is valid if you have an external 100K pullup and either drive the pin low or ground it externally. \$\endgroup\$ Commented Mar 6, 2022 at 19:41
  • 1
    \$\begingroup\$ Because the internal pullups are disabled during reset. Therefore the inputs can float around and cause excessive current draw. When you add the external resistor (even a dead short) the draw become negligible (nA) not 30uA. It is not recommended to use a dead short, of course, for the reasons described in the datasheet. \$\endgroup\$ Commented Mar 6, 2022 at 20:57
  • 1
    \$\begingroup\$ @SpehroPefhany Ok, the current figure was bogus, I've updated my answer. (some more details about the leakage part: How much current is used with a μC GPIO input and pullup resistor?) Perhaps it's worth stressing that the internal pull-ups are disabled during reset. \$\endgroup\$ Commented Mar 6, 2022 at 21:32
  • 2
    \$\begingroup\$ Yes. Maybe worth pointing out that the 1uA limit (which even applies at 105°C) is grossly overstated, it's more a limitation of the chip testing. Typically, especially at room temperature, it will be nA. \$\endgroup\$ Commented Mar 6, 2022 at 21:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.