Wake ADC after interrupting sleep mode

The ADC will not read the analouge0 input after the interruption of the sleep mode. Everything else before and after the few lines concerning the analogRead and sensorValue work. I have amalgamated two sketches (sleep mode with interrupt) and the (analogue read) sketch but the result from the analogue read is the same whatever the voltage applied to A0. LED on pin 13 should increase or decrease its ON duration depending on the A0 condition but always remains the same, a very short flash. Do I need to use an ISR to read the value of A0? Is there a line of code to re-start the ADC before a read can be made? Have I got things in the wrong order? I have spent two days looking at interrupt, sleep and ISR tutorials but can’t seem to get the analogue read to work. My intention is to have the 328 running on batteries in a remote location (hence the power save mode) with the external interrupt provided by a RTC. I’m using Duemilanove and 0022. Any constructive comments would be appreciated.

#include <avr/sleep.h>

const byte LED = 13;
int sensorPin = A0;    // select the input pin for the potentiometer
int sensorValue = 0;  // variable to store the value coming from the sensor 
void wake ()
{
  // cancel sleep as a precaution
  sleep_disable();
  // must do this as the pin will probably stay low for a while
  detachInterrupt (0);
}  // end of wake

void setup () 
  {
  digitalWrite (2, HIGH);  // enable pull-up
  }  // end of setup

void loop () 
{
 
  pinMode (LED, OUTPUT);
  digitalWrite (LED, HIGH);
 delay (1000);
 digitalWrite (LED, LOW);
  delay (50);
                                           //At this point it will not read the analogue input.
  sensorValue = analogRead(sensorPin);     
  // turn the ledPin on
  digitalWrite(LED, HIGH);  
  // stop the program for <sensorValue> milliseconds:
  delay(sensorValue);          
  // turn the ledPin off:        
  digitalWrite(LED, LOW);   
  // stop the program for for <sensorValue> milliseconds:
  delay(sensorValue);  
  pinMode (LED, INPUT);
  
  // disable ADC
  ADCSRA = 0;  
  
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_enable();

  // Do not interrupt before we go to sleep, or the
  // ISR will detach interrupts and we won't wake.
  noInterrupts ();
  
  // will be called when pin D2 goes low  
  attachInterrupt (0, wake, LOW);
 
  // turn off brown-out enable in software
  // BODS must be set to one and BODSE must be set to zero within four clock cycles
  MCUCR = bit (BODS) | bit (BODSE);
  // The BODS bit is automatically cleared after three clock cycles
  MCUCR = bit (BODS); 
  
  // We are guaranteed that the sleep_cpu call will be done
  // as the processor executes the next instruction after
  // interrupts are turned on.
  interrupts ();  // one cycle
  sleep_cpu ();   // one cycle

  } // end of loop
  1. Switch to 1.0.5 to start.

  2. How about enabling the ADC after coming back from sleep?

You turn it off: // disable ADC ADCSRA = 0;

Turn it back on.

Hello CrossRoads. Thanks for the prompt reply. I have already tried including the following codes with no effect.
ADCSRA I= (1ADATE);
ADCSRA I= (1<<ADEN);
ADCSRA I= (1,ADSC);
ADCSRA = 1;
ADCSRA_1;
There are a couple more that I have tried but didn’t keep note of them.

Data sheet section 24: The Power Reduction ADC bit, PRADC, in ”Minimizing Power Consumption” on page 41 must be disabled by writing a logical zero to enable the ADC.

Pg 41: 10.9 Power Reduction Register The Power Reduction Register (PRR), see ”PRR – Power Reduction Register” on page 44, provides a method to stop the clock to individual peripherals to reduce power consumption. The current state of the peripheral is frozen and the I/O registers can not be read or written. Resources used by the peripheral when stopping the clock will remain occupied, hence the peripheral should in most cases be disabled before stopping the clock. Waking up a module, which is done by clearing the bit in PRR, puts the module in the same state as before shutdown. Module shutdown can be used in Idle mode and Active mode to significantly reduce the overall power consumption. In all other sleep modes, the clock is already stopped.

10.10 Minimizing Power Consumption There are several possibilities to consider when trying to minimize the power consumption in an AVR controlled system. In general, sleep modes should be used as much as possible, and the sleep mode should be selected so that as few as possible of the device’s functions are operating. All functions not needed should be disabled. In particular, the following modules may need special consideration when trying to achieve the lowest possible power consumption.

10.10.1 Analog to Digital Converter If enabled, the ADC will be enabled in all sleep modes. To save power, the ADC should be disabled before entering any sleep mode. When the ADC is turned off and on again, the next conversion will be an extended conversion. Refer to ”Analog-to-Digital Converter” on page 242 for details on ADC operation.

So it sounds like you have the right idea, just the wrong register; and perhaps it will take 2 reads after power up to get a valid reading. (to overcome the "extended conversion").

What I did:

Write the contents of ADCSRA to a variable. Then set ADCSRA = 0 and go to sleep. After wakeup recover ADCSRA from the variable.

You can look at this post in my blog (includes an example sketch):

http://heliosoph.mit-links.info/arduino-powered-by-capacitor-optimized-tests/

I am about writing a whole series of posts about low power operation on the ATmega328P:

http://heliosoph.mit-links.info/

Elektrix

Thanks to both of you for the input. Reading the data sheet for the various registers to be written to seemed to me (new to this subject) to be very complex so I chickened out and went for the easy option of doing what Elektrix suggested. The code below works perfectly (it goes in to sleep mode with what my multimeter says is 0.1 microamp and upon waking reads the voltage on the A0 pin) so it’s mission accomplished. Thanks again for the input.

#include <avr/sleep.h>
const byte LED = 13;
int sensorPin = A0;    // select the input pin for the potentiometer
int sensorValue = 0;  // variable to store the value coming from the sensor
// keep the state of register ADCSRA
byte keep_ADCSRA; 
void wake ()
{
  // cancel sleep as a precaution
  sleep_disable();
  // must do this as the pin will probably stay low for a while
  detachInterrupt (0);
  ADCSRA = keep_ADCSRA;
}  // end of wake

void setup () 
{
  digitalWrite (2, HIGH);  // enable pull-up
}  // end of setup

void loop () 
{

  pinMode (LED, OUTPUT);
  // three second LED to confirm start of process:
  digitalWrite (LED, HIGH);
  delay (3000);
  digitalWrite (LED, LOW);
  delay (50);
  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);    
  // turn the ledPin on
  digitalWrite(LED, HIGH);  
  // stop the program for <sensorValue> milliseconds:
  delay(sensorValue);          
  // turn the ledPin off:        
  digitalWrite(LED, LOW);   
  // stop the program for for <sensorValue> milliseconds:
  delay(sensorValue); 

  pinMode (LED, INPUT);
  keep_ADCSRA = ADCSRA;
  // disable ADC
  ADCSRA = 0;  

  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_enable();

  // Do not interrupt before we go to sleep, or the
  // ISR will detach interrupts and we won't wake.
  noInterrupts ();

  // will be called when pin D2 goes low  
  attachInterrupt (0, wake, LOW);

  // turn off brown-out enable in software
  // BODS must be set to one and BODSE must be set to zero within four clock cycles
  MCUCR = bit (BODS) | bit (BODSE);
  // The BODS bit is automatically cleared after three clock cycles
  MCUCR = bit (BODS); 

  // We are guaranteed that the sleep_cpu call will be done
  // as the processor executes the next instruction after
  // interrupts are turned on.
  interrupts ();  // one cycle
  sleep_cpu ();   // one cycle

} // end of loop

Thank you all, I just ran into this problem and couldn't seem to figure it out. I was enabling the ADCSRA, but it still wouldn't wake up. I'm not able to change the BOD in the program because I have to set those in fuse bits only. I'm currently working with the mega2560, but as soon as a few more parts come in, I'm switching the project over to the 1284p.

void wake(){

 ADCSRA |= (1 << 7);
 detachInterrupt(0);
 delay(100);
}

void sleep()
{
 attachInterrupt(0, wake, LOW);
 //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
}

Source: Low Power Arduino! Deep Sleep Tutorial - YouTube

This code is used by to wake up from RTC.
So before call the sleep, you have to setAlarm() on PIN 2