new function: analogReadInternal()

66 views
Skip to first unread message

Cano

unread,
Jan 20, 2014, 2:55:28 PM1/20/14
to devel...@arduino.cc
I would like to propose a new function

analogReadInternal() or analogReadInternal1V1() or analogRead1V1() or extension of existing analogRead(REFERENCE_1V1) where REFERENCE_1V1 is some constant (254 perhaps?)

//reads internal 1V1 reference against VCC
int analogReadInternal() {
  #if defined(__AVR_ATtiny84__)
    ADMUX = _BV(MUX5) | _BV(MUX0); // For ATtiny84
  #else
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);  // For ATmega328
  #endif
  delay(1); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  uint8_t low = ADCL;
  return (ADCH << 8) | low;
}

function reads internal reference 1V1 against VCC, normally it would always return the same number. However while 1V1 is always the same, VCC is not. If you are running Arduino from a battery and running low on battery or have some large load connected your VCC rail will be lower than 5V

one could test if they are enough power like this

int readVCC() {
 return ((uint32_t)1024 * (uint32_t)1100) / analogReadInternal();
}


Cano

unread,
Jan 20, 2014, 2:59:17 PM1/20/14
to devel...@arduino.cc
ATMega328 has also some other internal devices connected to the analog channel, like (very inaccurate) thermometer, we should have a function to read that too.
maybe extending analogRead(REFERENCE_1V1) and analogRead(INTERNAL_THERMOMETER) will be a good idea

Brian Cook

unread,
Jan 20, 2014, 3:24:59 PM1/20/14
to Cano, devel...@arduino.cc

> uint8_t low = ADCL;
> return (ADCH << 8) | low;

...is a bad idea. Use the ADC register instead...

> return ADC;

- Brian

Cano

unread,
Jan 21, 2014, 10:04:32 AM1/21/14
to devel...@arduino.cc, Cano, bc...@rowdydogsoftware.com
What's bad about it? This is how atmel recommends to read the results in their data sheet and also this is how it is currently implemented in analogRead() function. I believe (haven't tested) that assembly would look the same for both cases.

Brian Cook

unread,
Jan 21, 2014, 4:13:21 PM1/21/14
to Cano, devel...@arduino.cc

What's bad about it?

The optimizer is free to reorder the instructions.  The compiler you are currently using may do the right thing some of the time or even all of the time but a future version may not.  ADC is guaranteed by the compiler developers to always work correctly.


This is how atmel recommends to read the results in their data sheet...

The ATmega328 datasheet does not have a C code snippet for reading the ADC result.


...and also this is how it is currently implemented in analogRead() function.

"Current" being very relative.  The code in question was very likely first written when "ADC" was not provided or at a time when the compiler performed the read incorrectly.  Undoubtedly no one has reviewed that snippet of code since it was first written.


- Brian


On Monday, January 20, 2014 3:24:59 PM UTC-5, Brian Cook wrote:

>   uint8_t low = ADCL;
>   return (ADCH << 8) | low;

...is a bad idea.  Use the ADC register instead...

> return ADC;

- Brian

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

Reply all
Reply to author
Forward
0 new messages