Enabling ADC in the main loop in power saving mode

I am trying to put together a small project based on this example by Nick Gammon (here). However I need to do analogRead in the main loop. I see, that ADC is disabled in goToSleep procedure. Can I just simply enable it in the main loop with ADCSRA = 1 before my analogRead instruction? Or do I have to finetune some other bits? Sorry for this question - I am not very comfortable manipulating bits on Arduino/Attiny. :frowning:

Wrong bit. I think it’s the high bit, and you should use bitwise or to sethe it so you don’t trash whatever else is that register. Use the ADEN define so you don’t have to remember the bit

That is

ADCSRA |= (1<<ADEN)

edit - I’m an idiot, I shouldn’t post so soon after waking up.

  ADCSRA |= (1 << ADEN);

Well, it doesn’t seem to work. I have amended goToSleep this way. In the main loop I just do analogRead. If I remove both ADCSRA assignment instructions, everything works fine. I believe I can get extra power saving when disabling ADC during sleep.

void goToSleep ()
  {
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  ADCSRA = 0;            // turn off ADC
  power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
  noInterrupts ();       // timed sequence coming up
  resetWatchdog ();      // get watchdog ready
  sleep_enable ();       // ready to sleep
  interrupts ();         // interrupts are required now
  sleep_cpu ();          // sleep                
  sleep_disable ();      // precaution
  ADCSRA |= (1 << ADEN);
  power_all_enable ();   // power everything back on
  }  // end of goToSleep

gvgv:
Well, it doesn't seem to work.

What makes you say that?

Where is the rest of your code?

9 times out of 10, when someone says something like that and posts a snippet, the problem is in the code they didn't post. Post the whole sketch

I tried it.
Here is the code. Maybe I am missing something.The program is supposed to run briefly a motor if the light in the room is switched off. The motor can also be triggered by a push button. This program runs fine. But if I uncomment both ADCSRA instructions, it doesn’t seem to do analogRead.

//  https://www.gammon.com.au/forum/?id=11497&reply=6#reply6 

#include <avr/sleep.h>    // Sleep Modes
#include <avr/power.h>    // Power management
#include <avr/wdt.h>      // Watchdog timer

const byte SWITCH = 0;               // pin 5 / PCINT0
const byte motor = 1;                // pin 6     
int lightSensor = A1;                // fotoresistor, pin 7

int lightThreshold = 400;            // dark >600, light ~220)
int lightOldStatus = 0;              // light was on = 1. off =0
int lightNewStatus = 0;              // light is on = 1. off =0
int intEnabled = 0;
int sek = 1000;

ISR (PCINT0_vect) 
 {
     intEnabled = 1;                                
 }  // end of PCINT0_vect
 
// watchdog interrupt
ISR (WDT_vect) 
{
   wdt_disable();  // disable watchdog
}  // end of WDT_vect

void resetWatchdog ()
  {
  MCUSR = 0;     // clear various "reset" flags
  WDTCR = bit (WDCE) | bit (WDE) | bit (WDIF);  // allow changes, disable reset, clear existing interrupt
  // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
  WDTCR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
  // pat the dog
  wdt_reset();  
  }  // end of resetWatchdog
  
void setup ()
  {
  resetWatchdog ();  // do this first in case WDT fires
  
  pinMode (lightSensor,INPUT);
  pinMode (SWITCH, INPUT);
  digitalWrite (SWITCH, HIGH);  // internal pull-up
  
  // pin change interrupt (example for D0)
  PCMSK  = bit (PCINT0);  // want pin D0 / pin 5
  GIFR  |= bit (PCIF);    // clear any outstanding interrupts
  GIMSK |= bit (PCIE);    // enable pin change interrupts 
  }  // end of setup

void loop ()
  {
  // If the light was switched off, run motor 1 time
 
  if (analogRead(lightSensor) > lightThreshold)   { lightNewStatus = 1; }    
  else   { lightNewStatus = 0;  }
   
  if (lightOldStatus == 1 && lightNewStatus == 0  || intEnabled == 1)      
     { 
       motorOn();              
       intEnabled = 0;
     }  

  lightOldStatus = lightNewStatus;
  goToSleep ();

  }  // end of loop
  
void goToSleep ()
  {
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
 // ADCSRA = 0;            // turn off ADC
  power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
  noInterrupts ();       // timed sequence coming up
  resetWatchdog ();      // get watchdog ready
  sleep_enable ();       // ready to sleep
  interrupts ();         // interrupts are required now
  sleep_cpu ();          // sleep                
  sleep_disable ();      // precaution
//  ADCSRA |= (1 << ADEN);
  power_all_enable ();   // power everything back on
  }  // end of goToSleep 

void motorOn(void)
{
  
  digitalWrite(motor, HIGH);
  delay(10*sek);    
   digitalWrite(motor, LOW);             
   delay(2*sek);    // 2 sek
}   // end of motorOn
 // ADCSRA = 0;            // turn off ADC

...does more than turn off the ADC. It also stops its clock.

OK, thanks. How do I enable the ADC clock to be able to do analogRead?

A much better choice would be to leave the clock alone…

  ADCSRA &= ~ (1 << ADEN);

Nope, still doesn’t want to work. Here’s my new goToSleep:

void goToSleep ()
  {
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  ADCSRA &= ~ (1 << ADEN);            // turn off ADC
  power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
  noInterrupts ();       // timed sequence coming up
  resetWatchdog ();      // get watchdog ready
  sleep_enable ();       // ready to sleep
  interrupts ();         // interrupts are required now
  sleep_cpu ();          // sleep                
  sleep_disable ();      // precaution
  ADCSRA |= (1 << ADEN);
  power_all_enable ();   // power everything back on
  }  // end of goToSleep

Try powering before enabling…

  power_all_enable ();   // power everything back on
  ADCSRA |= (1 << ADEN);

Yep, that worked. Thanks Coding Badly! :slight_smile:

You are welcome. I am glad to know it is working. (I do wonder why. Maybe ADEN is cleared while ADC power is off?)

Well, I am not experienced enough to answer that. Maybe we have to ask Nick Gammon. I pasted entire his sketch, just added a few instructions to read photoresistor in the main loop.

I guess the power_all_diasable function sets PRR (power reduction register). It disables the peripherals completly for even more power savings (look to the Datasheet). However I have read ADC disabled by PRR and enabled by ADEN consumes more power than enabled ADC (and does not work). So you need disable ADC and then set PRR to properly save power.