Lowpower et ADC

Salut a tous,

Je suis bloqué sur un problème que je ne comprends pas.

En fait je veux avoir la tension interne de l'Atmega en utilisant ce code:

const long InternalReferenceVoltage = 1124;  // Adjust this value to your board's specific internal BG voltage
// Code courtesy of "Coding Badly" and "Retrolefty" from the Arduino forum
// results are Vcc * 100
// So for example, 5V would be 500.
int getBandgap () 
  {
  // REFS0 : Selects AVcc external reference
  // MUX3 MUX2 MUX1 : Selects 1.1V (VBG)  
   //ADCSRA |= (1<<ADEN); //Enable ADC
   ADMUX = bit (REFS0) | bit (MUX3) | bit (MUX2) | bit (MUX1);
   ADCSRA |= bit( ADSC );  // start conversion
   while (ADCSRA & bit (ADSC))
     { }  // wait for conversion to complete
   int result = (((InternalReferenceVoltage * 1024) / ADC) + 5) / 10; 
   return result;
  } // end of getBandgap

Le souci que j'ai c'est que cumulé avec une mise en veille et un réveil par watchdog le convertisseur ADC me revoie n'importe quoi comme valeurs.

Le code complet est le suivant:

#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/power.h>

const int LED = 13;                         //LED on pin 13
const unsigned long KEEP_RUNNING = 2000;    //milliseconds

byte previousADCSRA;
byte previousADCSRA1;

//***********************************************************************************************************************//
// LOWPOWER FUNCTIONS
//***********************************************************************************************************************//
// watchdog intervals
// sleep bit patterns for WDTCSR
enum 
{
  WDT_16_MS  =  0b000000,
  WDT_32_MS  =  0b000001,
  WDT_64_MS  =  0b000010,
  WDT_128_MS =  0b000011,
  WDT_256_MS =  0b000100,
  WDT_512_MS =  0b000101,
  WDT_1_SEC  =  0b000110,
  WDT_2_SEC  =  0b000111,
  WDT_4_SEC  =  0b100000,
  WDT_8_SEC  =  0b100001,
 };  // end of WDT intervals enum

// watchdog interrupt
ISR (WDT_vect) 
{
  wdt_disable();  // disable watchdog
}
void go_to_sleep_for (const byte sleep_time)
{
  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval 
  WDTCSR = bit (WDIE) | sleep_time;    // set WDIE, and delay
  wdt_reset();  // pat the dog

  set_sleep_mode (SLEEP_MODE_PWR_DOWN); // prepare for powerdown  
  sleep_enable(); 

  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS);
  Serial.println("BEFORE:");
  Serial.print("ADCSRA=");
  Serial.println(ADCSRA);
  delay(20);
  previousADCSRA = ADCSRA;
  Serial.print("previousADCSRA=");
  Serial.println(previousADCSRA);
  delay(20);
  ADCSRA &= ~(1<<ADEN); //Disable ADC
  ACSR = (1<<ACD); //Disable the analog comparator
  DIDR0 = 0x3F; //Disable digital input buffers on all ADC0-ADC5 pins
  DIDR1 = (1<<AIN1D)|(1<<AIN0D); //Disable digital input buffer on AIN1/0

  power_twi_disable();
  power_spi_disable();
  power_usart0_disable(); //Needed for serial.print
  power_timer0_disable(); //Needed for delay and millis()
  power_timer1_disable();
  power_timer2_disable(); //Needed for asynchronous 32kHz operation

  sleep_cpu ();   // power down !
  
}

void wakeup() {
    power_twi_enable();
    power_spi_enable();
    power_usart0_enable();
    power_timer0_enable();
    power_timer1_enable();
    power_timer2_enable();
    power_adc_enable();
    ADCSRA = previousADCSRA;
    
    Serial.println("AFTER:");
    Serial.print("ADCSRA=");
    Serial.println(ADCSRA);
    Serial.print("previousADCSRA=");
    Serial.println(previousADCSRA);
    Serial.println(" ");
    delay(20);
    // BOD is automatically restarted at wakeup
}

void setup(void)
  {
  Serial.begin(115200);

  for (byte i=0; i<20; i++) {    //make all pins inputs with pullups enabled
        pinMode(i, INPUT_PULLUP);
    }
    for (byte i=0; i<20; i++) {
        digitalWrite(i, LOW);
    }

  pinMode(LED, OUTPUT);          //make the led pin an output
    digitalWrite(LED, LOW);        //drive it low so it doesn't source current

 // set analog reference voltage
  analogReference(INTERNAL);
  
  }
    
void loop(void)
  {
  Serial.println (getBandgap ());
  delay(20);
  delay(KEEP_RUNNING);           //opportunity to measure active supply current 
  digitalWrite(LED, HIGH);       //one blink before sleeping
  delay(10);
  digitalWrite(LED, LOW);
  
  go_to_sleep_for (WDT_8_SEC);
  sleep_disable();
  wakeup();
  }

const long InternalReferenceVoltage = 1124;  // Adjust this value to your board's specific internal BG voltage
// Code courtesy of "Coding Badly" and "Retrolefty" from the Arduino forum
// results are Vcc * 100
// So for example, 5V would be 500.
int getBandgap () 
  {
  // REFS0 : Selects AVcc external reference
  // MUX3 MUX2 MUX1 : Selects 1.1V (VBG)  
   //ADCSRA |= (1<<ADEN); //Enable ADC
   ADMUX = bit (REFS0) | bit (MUX3) | bit (MUX2) | bit (MUX1);
   ADCSRA |= bit( ADSC );  // start conversion
   while (ADCSRA & bit (ADSC))
     { }  // wait for conversion to complete
   int result = (((InternalReferenceVoltage * 1024) / ADC) + 5) / 10; 
   return result;
  } // end of getBandgap

L'ADCSRA renvoie des valeurs bidon et est perturbé par l'interogation "ADCSRA |= bit( ADSC ); // start conversion" ce qui fait que je n'ai pas les bonnes valeurs en sortie.

La mesure devrait renvoyer une valeur aux alentours des 500 (5v) alors que ça renvoi tantot des 200 ou des 330 etc...

Quelqu'un aurait une idée de ce qui se passe?

Bon apparemment je crois avoir trouvé la réponse ici:
http://jeelabs.org/2012/05/04/measuring-vcc-via-the-bandgap/

Il faudrait laisser un temps d'au moins 70µs entre la sortie de veille et la prise de la mesure pour que cela fonctionne.

Avec 200µs ça a l'air de fonctionner

:wink:

hello
ok
par contre: tu n'endors jamais le comparateur, mais tu le réveilles