Pages: [1]   Go Down
Author Topic: Bandgap voltage problems (revisited)  (Read 823 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 35
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am trying to write a sketch that measures the bandgap voltage as precise as possible, and writes the value to the eeprom for future reference
I want to use a 2.5v reference ic on AREF

for those dropping in on this discussion - please read up on the matter - a good starting point is this thread:
http://arduino.cc/forum/index.php/topic,38119.0.html

My code is heavely based on the previous work of Coding Badly, and RetroLefty

My problem is - the code using the sleep mode to produce better results seems to reset the analogreference to internal - where I would like to use an external reference, using a LM336 2v5 (an affordable 2.5 volt reference ic)

my code:

Code:
// use reference 2,47v on AREF to measure the bandgap voltage

#include <avr/sleep.h>

ISR(ADC_vect)
{
}

// This performs an A/D conversion using the current ADMUX settings.  You must set ADMUX before calling this function.
int rawAnalogReadWithSleep( void )
{
  // Generate an interrupt when the conversion is finished
  ADCSRA |= _BV( ADIE );

  // Enable Noise Reduction Sleep Mode
  set_sleep_mode( SLEEP_MODE_ADC );
  sleep_enable();

  // Any interrupt will wake the processor including the millis interrupt so we have to...
  // Loop until the conversion is finished
  do
  {
    // The following line of code is only important on the second pass.  For the first pass it has no effect.
    // Ensure interrupts are enabled before sleeping
    sei();
    // Sleep (MUST be called immediately after sei)
    sleep_cpu();
    // Checking the conversion status has to be done with interrupts disabled to avoid a race condition
    // Disable interrupts so the while below is performed without interruption
    cli();
  }
  // Conversion finished?  If not, loop.
  while( ( (ADCSRA & (1<<ADSC)) != 0 ) );

  // No more sleeping
  sleep_disable();
  // Enable interrupts
  sei();

  // The Arduino core does not expect an interrupt when a conversion completes so turn interrupts off
  ADCSRA &= ~ _BV( ADIE );

  // Return the conversion result
  return( ADC );
}

int bandgapRead(byte us =250) // returns raw measurement of bandgap with aref = 2,47v
{
       
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)  // For mega boards
//  const long InternalReferenceVoltage = 1100L;  // Adjust this value to your boards specific internal BG voltage x1000
        // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc reference
        // MUX4 MUX3 MUX2 MUX1 MUX0  --> 11110 1.1V (VBG)         -Selects channel 30, bandgap voltage, to measure
  ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR)| (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
 
#elif defined(__AVR_ATmega8__)  // Atmega8 has a 1.3V bandgap. UNTESTED!!! // http://forums.adafruit.com/viewtopic.php?f=25&t=12547
//  const long InternalReferenceVoltage = 1300L;  // Adjust this value to your boards specific internal BG voltage x1000
        // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc external reference
        // MUX3 MUX2 MUX1 MUX0  --> 1110 1.1V (VBG)         -Selects channel 14, bandgap voltage, to measure
  ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#else  // For 168/328 boards
//  const long InternalReferenceVoltage = 1100L;  // Adjust this value to your boards specific internal BG voltage x1000
        // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc external reference
        // MUX3 MUX2 MUX1 MUX0  --> 1110 1.1V (VBG)         -Selects channel 14, bandgap voltage, to measure
  ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#endif

  delay(us);  // Let mux settle a little to get a more stable A/D conversion
        // Start a conversion 
//  ADCSRA |= _BV( ADSC );
        // Wait for it to complete
//  while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
        // Scale the value
//  return ((InternalReferenceVoltage * 1023L) / ADC); // calculates for straight line value
  return (rawAnalogReadWithSleep());
}

void setup() {
    // initialize the serial port
    Serial.begin(9600);

  pinMode(10, OUTPUT);    // set the digital pin as output:
  digitalWrite (10, HIGH);

  pinMode (9, OUTPUT);  // quick and dirty - make pin9 a gnd - for easy led connection when using pin10
  digitalWrite(9, LOW);

  analogReference (EXTERNAL);
  delay (200);
  pinMode (A5, INPUT);
  int dummy = analogRead (A5); // dummyread
  delay (10000);  // measuring the AREF pin produces a nice 2.47v during this delay
                  // but as soon as we try and measure the bandgap voltage
                  // analogreference seems to revert to internal

  digitalWrite (10, LOW);
}

void loop()
{

  Serial.println (bandgapRead());
  delay(200);
}


In case someone has a atmega8, please verify if the bandgap voltage is indeed 1.3v ?
Thank you all for your contributions
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 201
Posts: 8706
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In case someone has a atmega8, please verify if the bandgap voltage is indeed 1.3v ?

The ATmega8 datasheet says:
Min:      1.15V
Typical: 1.23V
Max:     1.40V

Your 1.3V would be in the normal range.

Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Pages: [1]   Go Up
Jump to: