1
\$\begingroup\$

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.

\$\endgroup\$
  • 2
    \$\begingroup\$ Have you set up every input pin to have an internal pullup or pulldown, and are those in harmony with any external pullup/pulldown? Have you verified that the current draw is your processor, and not something else on the board? \$\endgroup\$ – TimWescott Jul 18 '19 at 15:06
  • \$\begingroup\$ I have not set any pullup or pulldown pins. That is something I wanted to test tonight setting them up with a for loop pinMode(i, OUTPUT). Unfortunately I have about 5 pins I am using during the loop. I tested all 5 pins/components by removing them one at a time but the current draw still sat at 2mA. My power conversion for sure created an issue. The power regulator circuit power draw which was about 2mA as well. So I have to find a new power regulator. \$\endgroup\$ – realShadow Jul 18 '19 at 15:15
  • 1
  • 1
    \$\begingroup\$ Read this: gammon.com.au/power and this: donalmorrissey.blogspot.com/2010/04/… ….your solution is either not asleep, or you are drawing peripheral current. When the 328P IS asleep it draws less than 1uA, so something is wrong in your schema or software. A schematic may help get more advice. \$\endgroup\$ – Jack Creasey Jul 18 '19 at 17:20
  • \$\begingroup\$ Thanks so much guys. As soon as I am home tonight I will test a few things, starting with pulling the pins low. If that still does not bring the right results I will take the chip off the board and build up the circuit, piece by piece and try to achieve the results that way. I will for sure advise the results of my endeavor. \$\endgroup\$ – realShadow Jul 18 '19 at 19:42
1
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ thanks @TimWescott. I will try your suggestion and report back! \$\endgroup\$ – realShadow Jul 18 '19 at 19:43
  • \$\begingroup\$ I appreciate your answer but I needed to start from scratch. I updated my initial post. \$\endgroup\$ – realShadow Jul 19 '19 at 2:43
1
\$\begingroup\$

thanks for your help. I figured out what the issue was. The servo drew the 2mA while the chip was asleep. I was able to use a BJT and turned the power to the servo off. That still uses more current than I want it to but at 80μA I can have the project running for at least 1 year before I have to replace the battery.

Thanks for pushing me in the right direction.

\$\endgroup\$
  • \$\begingroup\$ Make sure you don't have a voltage on the servo's signal pin that is above its supply voltage when off, otherwise you may partially repower it in an out of spec and wasteful way. \$\endgroup\$ – Chris Stratton Jul 22 '19 at 23:42
  • \$\begingroup\$ Thanks Chris. I pull that pin low once I am done with the work it is supposed to do, I think. But I'll check it again just to be sure... \$\endgroup\$ – realShadow Jul 24 '19 at 0:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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