Hi everyone,
Fairly new to Arduino (month or two), very new to the forum as an active user (first post). I have been using the code below (picked it up somewhere (unfortunately, cannot recall original source, have seen it come back in several places) along the many forum posts and/or YouTube tutorials, for reading analog sensors on Arduino UNO R3 (8-bit ATmega328P) and added my own comments to better understand what is going on. This code is a function, used to read the actual supply voltage Vcc of the Arduino (e.g. ~5 VDC) by setting the corresponding bits in the ADMUX register, to read the internal (bandgap) reference voltage of 1.1 V (perform a single ADC conversion with AVcc as the reference) and then reverse-calculating what the actual Vcc should be (provided an exact and reproducible 1.1 V int. ref., can be determined/verified with an external DMM). The actual Vcc is returned by this function and can then be used to obtain more accurate analog readings between 0 - 5 V (corresponding to 0 - 1023).
I am working on a program which will exceed the 32 kB / 2 kB limitations of the UNO R3 but hoorah, Arduino just released the R4, with a lot more storage and memory. Unfortunately, this means that the code below, which is written for different AVR boards, will not work on the new R4 boards, using the Renesas RA4M1 32-bit ARM Cortex-M4 instead of the 8-bit ATmega328 on the R3. The ADC also got an upgrade and can now be used with (default) 10-bit, 12-bit, or 14-bit accuracy.
My question is: does anyone have enough knowledge of the new RA4M1 chip (ADC, registers, etc.) or maybe has already done this exercise, to update or expand the code below so it will also work on the new UNO R4 boards? Because this is well beyond my capabilities at the moment. Thanks in advance!
< I have found an entire UNO R4 forum section under hardware, but thought it was best placed here. If not, please advise or move accordingly. >
Kind regards, fdw
float intVREF = 1.100; // for more accuracy: verify actual value with DMM
unsigned long intVREFbin = intVREF * 1000 * 1024.0; // Arduino internal 1.1V ref. (+/- 0.1V) * 1000 mV/V * 1024 values
long readVcc()
{ // function to read actual supply voltage Vcc (in mV) of Arduino
long result;
// if/else statements for setting correct bits in ADMUX (ADC multiplexer) register, based on which Arduino (which ATmega chip) is being used
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif // setting ADMUX bits to read internal 1.1 V ref against AVcc (REFS1 = 0, REFS0 = 1, MUX3:0 = 1110)
delay(2); // Wait 2 ms for Vref to settle after change
ADCSRA |= _BV(ADSC); // Write ADSC bit to 1 in "ADC Control and Status Register A" for starting single ADC conversion
while (bit_is_set(ADCSRA, ADSC)); // when ADC conversion is over, ADSC bit will go back to 0
// ADC generates 10-bit result (containing measurement of 1.1V int. ref.) in ADC data registers: ADCH (high) and ADCL (low)
result = ADCL; // if result is left adjusted & requires <=8-bit precision, ADCH is sufficient, otherwise: ADCL read first (important!), then ADCH
result |= ADCH << 8; // ADCL, then ADCH (to ensure registers hold data of same conversion), 8-place bit shift to left: obtain full-precision 10 bit result
result = intVREFbin / result; // Calculate Vcc (in mV); intVREFbin = ~1100 mV * 1024
return result; // long result (Vcc in mV) is returned as a result of readVcc function as soon as conversion is over (ADSC = 0 again)
}

