Electronic – 328p-pu drawing too much current in sleep mode

atmega328psleep

I have a ATmega328p-pu and run it at 8MHz with the internal oscillator. I am executing some code and then send the chip to sleep. I deactivate the brownout and ADC before activating the sleep. I have a button connected to interrupt 0 (digital pin 2) to wake the chip back up. All in all the setup works but the chip still draws about 2mA in its sleep mode. I watched some tutorials that showed the current draw should be the μA range. At the current draw that I am getting now I cannot use the project for its intended purposes.

how can I reduce the energy draw below 2mA into the μA range?

void setup() {
    ...
    attachInterrupt(digitalPinToInterrupt(button), digitalInterrupt, FALLING);
}

void loop() {
     //activate Analog to Digital Converter after wakeup
     ADCSRA |= (1 << 7);
     //execute my code and do stuff
     ...
     //Disable ADC - don't forget to flip back after waking up if using ADC in your application ADCSRA |= (1 << 7);
     ADCSRA &= ~(1 << 7);
     //ENABLE SLEEP - this enables the sleep mode
     SMCR |= (1 << 2); //power down mode
     SMCR |= 1;//enable sleep
     //BOD DISABLE - this must be called right before the __asm__ sleep instruction
     MCUCR |= (3 << 5); //set both BODS and BODSE at the same time
     MCUCR = (MCUCR & ~(1 << 5)) | (1 << 6); //then set the BODS bit and clear the BODSE bit at the same time
     __asm__  __volatile__("sleep"); //in line assembler to go to sleep  */

}

void digitalInterrupt() {
    //I do nothing here I have everything in the loop.
}

EDIT
I started from scratch as I could not isolate the part of the code that caused the chip to stay in a state of half awake. I used Nick Gammons instructions to build the code and make the chip go to sleep. I got the results expected with only 0.004μA of current draw! PERFECT. only one issue I can't solve. I have a servo I need to rotate. The pin I am using is the Digital Pin 3 because of the PWM signal. This part of the code is creating the issue and does not allow the chip to go back to sleep. If I may be so bold to ask you guys for help again why that would prevent the chip to go to sleep? How would I structure the code to turn the servo and once back in the original position to turn the chip off???

#include <avr/sleep.h>
#include <Servo.h>
//number of samples to take per reading
#define NUM_SAMPLES 10
int sum = 0;                    // sum of samples taken
unsigned char sample_count = 0; // current sample number
float voltage = 0.0;            // calculated voltage
int redLED = 5;
int yellowLED = 6;
int greenLED = 7;
int servoPin = 3;
int button = 2;

Servo Servo1;


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(button), digitalInterrupt, FALLING);
  for (byte i = 0; i <= A5; i++) {
    if (i != button){
      pinMode(i, OUTPUT);    
      digitalWrite(i, LOW); 
    }  
  }
  pinMode(A2, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("Sending chip to sleep");
  delay(100);

  /*Servo1.attach(servoPin);
  Servo1.write(90);
  delay(5000);
  Servo1.write(0);
  delay(2000);
  Servo1.detach();

  //----------------------READ VOLTAGE--------------------------
  while (sample_count < NUM_SAMPLES) {
    sum += analogRead(A2);
    sample_count++;
    delay(10);
  }
  voltage = ((float)sum / (float)NUM_SAMPLES * 4.923) / 1024.0;
  voltage = voltage * 11.39;

  sample_count = 0;
  sum = 0;
  delay(100);
  //----------------------READ VOLTAGE--------------------------

  //Deactivate ADC (Analog to Digital Converter)
  ADCSRA = 0;
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  noInterrupts ();
  attachInterrupt (digitalPinToInterrupt(button), digitalInterrupt, FALLING);

  sleep_enable ();
  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS); 
  interrupts ();
  sleep_cpu ();
}


void digitalInterrupt() {
  Serial.println("interrupt");
  sleep_disable ();
  detachInterrupt (digitalPinToInterrupt(button));
  ADCSRA = 1;
}

EDIT 2

After experimenting a little more I figured it was not the Servo that prevented the chip from sleeping. It was actually my multimeter that did not allow enough current to get to the circuit so the chip reset and started over. Once I figured that out also found out that the servo constantly draws 2mA. I think I found my issue. So I have to figure out how to turn off the power to the servo and then the only thing left HOPEFULLY should be to find a voltage regulator that does not draw 2mA.

Best Answer

If I am reading the datasheet correctly, the pins are set up with no pull up out of reset.

A CMOS input will draw supply current if its input is between the upper and lower thresholds -- basically, there's a NMOS and a PMOS transistor, and if the input voltage is half way in between then both transistors are partially on.

You need to program all unused input pins to be pullups. This should have an immediate impact on your current consumption.

Note that this is a partial answer -- there's undoubtedly more going on.