LowPowerLab Forum

Hardware support => Moteino => Topic started by: WhiteHare on September 21, 2015, 01:56:43 PM

Title: accurate Moteino battery voltage monitoring
Post by: WhiteHare on September 21, 2015, 01:56:43 PM
The Mega Moteino is nice, because it would offer access to the 2.56V internal voltage reference for calibrating the ADC.  But for regular 328p Moteino's, what's the best way to ensure accurate readings of battery voltage?

I've read that the gap reference 1.1v is only accurate to 10%.  I'd prefer something more accurate, like 1% or 0.1%.

Are folks using an external voltage reference, such as a zener diode or maybe a temperature compensated precision voltage reference?  Or are you using a dedicated battery monitoring chip?

I'm looking for an ultra low current way of monitoring my battery voltage.  Most likely my power source will be 3 alkaline AA's, so I want them to last as long as possible, but I will also need to check their voltage level from time to time and plot the measured voltages so that I can verify my power budget and Moteino setup are working as planned.  So, I'd prefer to have more than just a low battery indicator (if that's all I needed, it looks as though the HDC1008 actually includes one, which triggers at 2.8v).  This is such a universal problem for battery operated devices that I've got to believe there must be a really good solution.
Title: Re: accurate Moteino battery voltage monitoring
Post by: Felix on September 21, 2015, 01:59:19 PM
You can do it many ways, including what you mentioned.
I've found that just using a high impedance set of resistors to divide the voltage in a range readable by the ADC works great, is highly accurate and super cheap. It's used on my products like: WeatherShield, PowerShield, MotionMote, SonarMote.
Title: Re: accurate Moteino battery voltage monitoring
Post by: TomWS on September 21, 2015, 03:13:23 PM
I've read that the gap reference 1.1v is only accurate to 10%.  I'd prefer something more accurate, like 1% or 0.1%.
I suggest reading the WHOLE 328P spec.  If you do, you will find the table attached below which shows over full usable voltage and temperature range, the Bandgap voltage varies by 0.88%.  It is an unfortunate truth that the datasheet, appearing earlier in the spec DOES, in fact, say that the range is 1.0 to 1.2Volts.   I have to believe there is an errata sheet somewhere that corrects this.

The first clue that the 10% didn't make sense was that it is a 'bandgap' reference, ie, a voltage that is established by the physics of the junction - this is pretty solid...  The second clue is that it is very unlikely that the designers of the ATMega1284P were more 'with it' than the 328P in terms of producing a substantially more accurate reference.  What they had were more transistors to add more ADCMUX selections.

Tom


Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on September 21, 2015, 03:40:26 PM
Interesting!  It's the first time I've heard of that.  I wouldn't have even known to scour the datasheet regarding this, because the unanimous opinion seemed to be the 10% number.  Koudos for catching that one.

I do get the impression you've read the WHOLE 328p spec sheet, so riddle me this.  The title on that chart refers to a "calibrated" bandgap voltage.  Does that mean factory calibrated, or is there a calibration procedure, or does it somehow self-calibrate transparently?  Or do you basically just measure it once across AREF and ground and then use that number (perhaps adjusting for temperature, if so inclined)?  Obviously, I'm hoping it means factory calibrated.  I've also read there's a temperature sensor within the 328p, so maybe it would be good for calculating a temperature correction factor as I would think that it must be in extremely close proximity to the bandgap (as they're both on the same chip).
Title: Re: accurate Moteino battery voltage monitoring
Post by: joelucid on September 21, 2015, 04:40:58 PM
Quote
I'm looking for an ultra low current way of monitoring my battery voltage

In my recent battery based motes I've always used 2 battery cells without the voltage regulator. This gives you more energy per cell, a nicer form factor and you can use the calibrated internal band gap reference which I've found to be fairly accurate to measure Vcc.

Works well if you don't need 3.3v for your sensors.
Title: Re: accurate Moteino battery voltage monitoring
Post by: TomWS on September 21, 2015, 04:49:13 PM
I've also read there's a temperature sensor within the 328p, so maybe it would be good for calculating a correction factor as I would think that it must be in very close proximity to the bandgap.
Just one of the many pieces of useful information waiting for you as you pour through this wealth of information...

Tom
Title: Re: accurate Moteino battery voltage monitoring
Post by: kobuki on September 22, 2015, 06:22:05 AM
I'd just quickly like to drop these links here. All you need to know is the voltage reference is a bandgap one, so it stays sufficiently precise with varying temperatures. Not a precision reference, though, but I guess for measuring battery voltage, it's more than adequate. In retrospective, I have no idea why they state that 1.0-1.2V range.

https://en.wikipedia.org/wiki/Bandgap_voltage_reference
https://en.wikipedia.org/wiki/Band_gap
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on September 22, 2015, 10:09:44 AM
Just now had a look at voltage references on digikey.  It seems 0.88% isn't bad, especially considering it's free and I don't have to order extra parts.   :)

This youtube video sums up how to read bandgap voltage and use it to derive your battery voltage. 

His bottom line is this:
 
battery voltage = (1.1/analogRead(14))*1023. 

Done!  With 3x AA I won't even need a voltage divider.  :) :) :)
Title: Re: accurate Moteino battery voltage monitoring
Post by: TomWS on September 22, 2015, 11:35:57 AM
This youtube video sums up how to read bandgap voltage and use it to derive your battery voltage. 
Or you could just use the code that's been posted a million places around the web:
Code: [Select]
/******************************************************************************
*
*   readVcc()
*
******************************************************************************/
unsigned int readVcc(bool restoreMux) {
  unsigned long result;
  byte saveADMUX;
 
  saveADMUX = ADMUX;
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284P__)
    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

  #if defined(__AVR_ATmega2560__)
    /****
    it took me a while to figure-out the problem, but on MEGA 2560, immediately after analogRead(A8), ADCL started returning zero.
    So every attempt to read from A8-A16 on Arduino MEGA will damage the functionality of readVcc().
    I've resolved the problem by adding:
    ADCSRB = 0;
    just before
    delay(2);
    **********************************/
    //ADCSRB &= ~_BV(MUX5); // Without this the function always returns -1 on the ATmega2560

    ADCSRB = 0;
  #endif

  delay(20); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
  uint8_t high = ADCH; // unlocks both

  result = (high<<8) | low;
//  Serial.print("BatteryResult="); Serial.print(result);
  result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 (because...= 3300*1023/3 since 1.1 is exactly 1/3 of 3.3V)
// Serial.print(", after calculation:"); Serial.println(result);

  if (restoreMux) ADMUX = saveADMUX;

  return result; // Vcc in millivolts
}
Tom

UPDATED: removed PRINT macros and added restoreMux.
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on September 22, 2015, 01:09:18 PM
Looks to me as though both ways of doing it are assuming the bandgap voltage is 1.1v.  From looking at your chart, though, a better pick would be 1.13v, which is more  in the middle of the range between super hot and super cold.  Or, if it's for indoor use only, then the 25C curve would be a good pick.

Or, maybe just report the raw value of analogRead(14).  Then the gateway, if it happens to know the ambient temperature, could pick an appropriate constant based on your graph above (a pity it's not more complete).  If done in the dead of night, when ambient temperatues are more settled, that might yield another slight improvement for outdoor sensors.  It would be better than the onchip temp sensor, which the datasheet says is only accurate to +/- 10C.

The ultimate might be measuring the bandgap voltage on the chip under test.  Running a chip the full temperature range and recording the bandgap voltages at each point, over a range of Vcc's, should yield a pretty accurate lookup table for that chip, and maybe all chips depending on whether there's meaningful variation or not.  That lookup table could sit on flash memory in the gateway.  If anyone ever does those measurements, please post them!  It would fill in the gaps missing from the chart.
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on September 22, 2015, 02:58:32 PM
BTW, after just now comparing the self discharge rates (see attachment), I think I'll go with lithium rather than Alkaline batteries.

What might change my mind is if the Duracell Quantum version of the Alkaline battery has a much lower self discharge rate than typical alkaline batteries, because I've read that Costco sells the Quantums under their Kirkland brand name and so the price wouldn't be too bad.  However, so far I haven't found any data regarding Quantum self discharge rate.  Anyone happen to know?

Otherwise, what's the best brand (least self discharge rate) for Lithium AA's?  The Energizer Ultimate Lithium's claim they "hold power" for 20 years:

UPDATE TomWS: Unnecessary photo removed.

Even assuming marketing spin, that sounds tough to beat.  On Amazon they'd be about $1.50 each, if purchased in quantity of 20 or more.
Title: Re: accurate Moteino battery voltage monitoring
Post by: kobuki on September 22, 2015, 03:30:40 PM
You're spouting a lot of information commonly available on the net after like 5 minutes of googling. I'm not saying it's not useful at all, but I think your time is better spent looking at readily available information. It's vast, really. As I've said, the bandgap reference is not a precision one in the 328. If you want precision, you pay the price. Calibrating it at the full temperature range is good, but calibration values tend to skew over time, so it's best repeating them every half a year (IIRC it's the norm for most calibrated instruments). You will find that many folks advice a measurement of the bandgap itself chip by chip to achieve more accurate results for AD sampling. You can go that route if you want.

OTOH, choosing a suitable battery is not all about the least self-discharge rate. For small, several mA and sub-mA loads, Alkalines are better suited. They're the fraction of the price of a Lithium one and for that kind of usage they probably last the same. Lithium however is better suited for applications when a higher discarge rate is expected, like in digital cameras, high-performance flashlights, etc. Of course, if your aim is achieving a consumption rate similar to the battery packs' self-discharge rate, Lithium might be a better fit, and the 20 years shelf life might play a role.
Title: Re: accurate Moteino battery voltage monitoring
Post by: joelucid on September 22, 2015, 03:40:34 PM
Problem with the alkalines is the discharge curve is not flat at all - which is why 9V batteries work so great with Moteinos. Lithium is much better in that regard. Also speaking from experience: if you want to power your outdoor Mote during winter do yourself a favor: Lithium, not Alkaline.

Title: Re: accurate Moteino battery voltage monitoring
Post by: kobuki on September 22, 2015, 03:49:58 PM
Yeah, of course. On a case-by-case basis, usage differences help deciding for a given project or even placement. The curve not being flat is not necessarily a problem, though. In case of the (unmodified) Moteino, all needed is they provide at least 3.3V till they run out. According to my calculations, even 3xAA Alkalines can provide 1.5-2 years of operaion for a properly programmed mote. And - for me - it's good enough :)
Title: Re: accurate Moteino battery voltage monitoring
Post by: TomWS on September 22, 2015, 05:37:19 PM
Also speaking from experience: if you want to power your outdoor Mote during winter do yourself a favor: Lithium, not Alkaline.
I totally agree with Joe here and add, if you want to keep the voltage above 1.5V/battery for the longest amount of time, use Lithium Li-FeS2 primary cells.  Alkaline lose too much of their voltage earlier in their lifecycle.

Tom
Title: Re: accurate Moteino battery voltage monitoring
Post by: kobuki on September 22, 2015, 06:09:45 PM
Yes, for 5x the price they're bound to be better in at least one or 2 aspects. I have nothing against them (on the contrary, they're one of the best of their kind, apparently) and on the long term those extra few bucks are nothing even for hobbyists like many of us, I just don't feel their use justified for every case. With simple optimisations on the Moteino HW you admittedly used (8 MHz, regulator removed, etc) they last even longer, and in that case a cell can be used down to about 0.8V, which is pretty much their EOL. In that aspect, I can't see why I would want to keep their voltage above 1.5V, when what I need is > 3.3V (default case) for a 3-pack (temperature effects aside).
Title: Re: accurate Moteino battery voltage monitoring
Post by: TomWS on September 22, 2015, 06:24:41 PM
To add to my last post, here is the difference between an Alkaline and a Lithium discharge curve (both Eveready brand).  Unfortunately they don't really spec at low drain levels, but the key takeaway should be, Lithium have a much sharper knee than Alkaline and Alkalines are practically useless below freezing temperatures.

Tom
Title: Re: accurate Moteino battery voltage monitoring
Post by: kobuki on September 22, 2015, 06:57:10 PM
Yeah, I'm aware of these figures. data.energizer.com has the DS for many of their battery products, too. But again: why do I care about the curve, when all I need is > 3.3V (or less, about 2.4V, speaking specifically of mentioned Moteino mods), using 3 batteries in series? Naturally, I'd only bring the Lithium batteries out in the cold winter. But indoors, and in my case, I don't see obvious benefits.

I've just browsed this yesterday, very useful (there are lots of these on that forum), albeit they're at higher loads, compared to our needs (but not so unusual in practice, in small consumer devices): http://www.candlepowerforums.com/vb/showthread.php?64660-Alkaline-Battery-Shoot-Out
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on September 22, 2015, 06:58:37 PM
If it helps frame the objective at all, my most challenging use case is buried soil moisture sensors.  I'll probably have a lot of them, as my preliminary data indicates they will pay for themselves in water savings and a healthier landscape.  I really don't want to be digging these things up every 1.5-2 years to change the batteries.  If they could go 10 years or even longer, then that would be great.  The limiting factor for long timeframes seems to be the self discharge rate.

I asked about the quantum's because they are a lot cheaper and, according to Duracell (http://www.duracell.com/en-us/products/all-purpose-batteries/duracell-quantum), they have a "10 year guarantee in storage,"  which suggests a low self discharge rate.  I haven't yet found the hard data on that....

Also, thanks for the heads-up about freezing temperatures, as I'm planning other things (such as perimeter motion sensors) that would be above ground, and so I guess those should be lithium for at least that reason alone.
Title: Re: accurate Moteino battery voltage monitoring
Post by: kobuki on September 22, 2015, 07:14:43 PM
As I've noted, it's different for everyone, and for each case. Your sensors are going to be underground, very inconvenient to maintain - naturally you'll try to have them running without maintenance as long as possible. Battery however is only one of the components. You probably have a lot of work ahead of you, writing the firmware, the low power parts and design, etc. Our current design goals are very different, that's all.
Title: Re: accurate Moteino battery voltage monitoring
Post by: damonb on September 28, 2015, 11:24:59 PM
If you want to bury your entire sensing nodes you will severely compromise the range of your radio signal.
I have a network of Vegetronix sensors with Jeenodes, but I keep the controller and battery above ground. With a 10 minute sampling interval, i get about 2 years from 3x AA alkaline cells.
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on April 11, 2016, 05:57:11 PM
Epilog:  I found an interesting thread which outlines how to measure the bandgap voltage on a particular atmega328p rather than use an averaged figure:  http://forum.arduino.cc/index.php?topic=38119.0

Also, I'm thinking that since the best time to measure voltage is when it's under load, maybe measuring it sometime during an RFM69HW transmit would be a "free" way to generate a high load.  Not sure if that would introduce extra noise though that would undermine the result.  Many have posted that running the ADC while sleeping the rest of the atmega328p does help somewhat.
Title: Re: accurate Moteino battery voltage monitoring
Post by: emjay on April 12, 2016, 03:35:46 AM
The same technique is documented here http://jeelabs.org/2012/05/12/improved-vcc-measurement/ (http://jeelabs.org/2012/05/12/improved-vcc-measurement/) with useful graphics and less cruft.
Title: Re: accurate Moteino battery voltage monitoring
Post by: TomWS on April 12, 2016, 08:48:14 AM
The same technique is documented here http://jeelabs.org/2012/05/12/improved-vcc-measurement/ (http://jeelabs.org/2012/05/12/improved-vcc-measurement/) with useful graphics and less cruft.
Thanks for the link, emjay.  It's curious that he takes 4 measurements but only uses the last one.  Are the first three to stabilize the charge on the input?

Tom
Title: Re: accurate Moteino battery voltage monitoring
Post by: emjay on April 12, 2016, 08:54:46 AM
@Tom,

Exactly - when feeding the ADC input from a higher impedance than the usual recommended, it takes a while to get the (tiny) sampling cap charged up.  Even from a lower impedance, you can see a noticeable difference between the "first" sample (say after just switching to that channel) and the "second".
Title: Re: accurate Moteino battery voltage monitoring
Post by: TomWS on April 12, 2016, 09:56:03 AM
@Tom,

Exactly - when feeding the ADC input from a higher impedance than the usual recommended, it takes a while to get the (tiny) sampling cap charged up.  Even from a lower impedance, you can see a noticeable difference between the "first" sample (say after just switching to that channel) and the "second".
But in this case the sources (Vref==Vdd & Mux source==bandgap) are internal and presumably not high impedance.  ISTM that this algorithm might be faster if he changed the loop test slightly to stop on max of 4 times OR current reading == last reading (should be safe since presumably any change is monotonic).
Title: Re: accurate Moteino battery voltage monitoring
Post by: emjay on April 12, 2016, 10:59:24 AM
@Tom,

Sure, I hope Vdd is low impedance  ;)  But just set up for Vref to appear on that pin and try drawing a sip of current....
Certainly the successive readings could be logged and perhaps trimmed back to optimize, some scope for improvement if chasing microcoulombs is the target.
Title: Re: accurate Moteino battery voltage monitoring
Post by: TomWS on April 12, 2016, 01:15:52 PM
... some scope for improvement if chasing microcoulombs is the target.
Good point, but I was chasing microseconds  ;)

Good discussion, thanks!
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on April 14, 2016, 03:14:28 PM
In addition to being sometimes erroneous, I notice the first reading of the ADC also seems to take quite a bit longer than subsequent readings.  On an atmega328p running at 8Mhz, what I get is:

Code: [Select]
0. raw relative bandgap voltage=486  Elapsed time=0uS
1. raw relative bandgap voltage=397  Elapsed time=216uS  deltaT=216uS
2. raw relative bandgap voltage=360  Elapsed time=336uS  deltaT=120uS
3. raw relative bandgap voltage=348  Elapsed time=456uS  deltaT=120uS
4. raw relative bandgap voltage=344  Elapsed time=576uS  deltaT=120uS
5. raw relative bandgap voltage=343  Elapsed time=696uS  deltaT=120uS
6. raw relative bandgap voltage=343  Elapsed time=816uS  deltaT=120uS
7. raw relative bandgap voltage=343  Elapsed time=936uS  deltaT=120uS
8. raw relative bandgap voltage=343  Elapsed time=1056uS  deltaT=120uS
9. raw relative bandgap voltage=343  Elapsed time=1176uS  deltaT=120uS

from this sketch:
Code: [Select]
// number of microseconds for ADC to setttle before taking a measurement
#define ADC_SETTLE_MICROSECONDS 1000
#define NUM_ADC_SAMPLES 10

uint16_t getRelativeBandgapVoltage() {
  uint16_t rawBandgapMeasurement;
 
  // Read bandgap voltage reference (~1.1V) against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);    //need to do this for every sample or just the first?
  //delayMicroseconds(ADC_SETTLE_MICROSECONDS); // Settle before taking ADC measurement
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  rawBandgapMeasurement = ADCL;  //get the low order bits of ADC
  rawBandgapMeasurement |= ADCH<<8;  //combine with high order bits of ADC
  return rawBandgapMeasurement;
}

void setup() {
  long timeInMicroseconds[NUM_ADC_SAMPLES];
  uint16_t rbgv[NUM_ADC_SAMPLES];  // relative bandgap voltage
 
  Serial.begin(115200);
 
  for (int i=0;i<NUM_ADC_SAMPLES;i++) {
    timeInMicroseconds[i] = micros();
    rbgv[i] = getRelativeBandgapVoltage();
  }
  for (int i=0;i<NUM_ADC_SAMPLES;i++) {
    Serial.print(i);
    Serial.print(F(". raw relative bandgap voltage="));
    Serial.print( rbgv[i]);
    Serial.print(F("  Elapsed time="));
    Serial.print(timeInMicroseconds[i] - timeInMicroseconds[0]);
    Serial.print(F("uS"));
    if (i>0) {
      Serial.print(F("  deltaT="));
      Serial.print(timeInMicroseconds[i]-timeInMicroseconds[i-1]);
      Serial.print(F("uS"));
    }
    Serial.println();
    Serial.flush();
  }
}

void loop() {
}

With just minimal testing so far, I've already noticed a variation of anywhere from one to seven samples needed before arriving at the final number, so Tom's idea of only waiting for the same number to repeat two times in a row sounds nicely frugal while remaining easy to implement.  Not sure if there are conditions under which more than two in a row would be preferable.

The number of cycles can also be reduced just by adding some delay (ADC_SETTLE_MICROSECONDS, which is presently commented out in the above sketch).  So, maybe adding some sleep time (or simply attending to other matters) in place of a pure delay would be even more energy efficient.  Some of the common sketches for readVcc do sleep during the samples (to minimize noise and/or save energy), but I don't know of any that purposely sleep extra long so as to reduce the number of samples needed.

As illustrated by the above example in this post, the amount of elapsed time before converging on a particular number can definitely add-up to become non-trivial.  With that in mind, I'm curious to know whether freezing temperatures and/or high ambient heat and/or low VCC and/or a weak battery might affect the convergence time, and so I'll eventually run some tests to try to characterize that.  For instance, a weak battery might easily affect the settle time and/or samples required because AVcc might be falling from one sample to the next due to load.  For that reason, perhaps the number of samples and/or settle time should be reported and monitored as yet another possible indicator that a battery may need to be changed.  In the worse case, a weak battery might become even weaker just from chasing after an accurate measure of how weak it is!  With BOD turned off, it might even run itself into the ground.  So, for really weak batteries that are just barely holding on, maybe it might even make sense to halt reading the Vcc until it can be replaced...

Can anyone think of any other concerns that might play a role?  If so, I can maybe run some tests for those as well and post the results afterward.
Title: Re: accurate Moteino battery voltage monitoring
Post by: TomWS on April 14, 2016, 06:43:08 PM
@Whitehare, if you're running this test as soon as your system turns on, the culprit might be the cap on ARef settling into its final charge.  What happens if you don't run the test (leaving the ADC ref at its power on default) for a few milliseconds?

Measuring voltages at first application of power are likely to be wrong and in most cases unnecessary.  Measuring voltage after reset is valid if the proc is in a stopped state and reset via RTC, for example, should be ok.

Tom
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on April 14, 2016, 08:46:52 PM
@Whitehare, if you're running this test as soon as your system turns on, the culprit might be the cap on ARef settling into its final charge.  What happens if you don't run the test (leaving the ADC ref at its power on default) for a few milliseconds?

I had a similar thought, so to test that I inserted a "delay(1000)" (surely plenty of overkill, right?) at the very start of the setup() procedure on a stock Moteino R4 RFM69HW board (the earlier results I posted were from just an 8Mhz Pro Mini running at 3.3v).  On the Moteino, it turns out that with or without the added setup() delay, the first ADC sample takes the same 212uS either way:
Code: [Select]
0. raw relative bandgap voltage=386  Elapsed time=0uS
1. raw relative bandgap voltage=363  Elapsed time=212uS  deltaT=212uS
2. raw relative bandgap voltage=353  Elapsed time=324uS  deltaT=112uS
3. raw relative bandgap voltage=349  Elapsed time=436uS  deltaT=112uS
4. raw relative bandgap voltage=348  Elapsed time=548uS  deltaT=112uS
5. raw relative bandgap voltage=347  Elapsed time=660uS  deltaT=112uS
6. raw relative bandgap voltage=347  Elapsed time=772uS  deltaT=112uS
7. raw relative bandgap voltage=347  Elapsed time=884uS  deltaT=112uS
8. raw relative bandgap voltage=347  Elapsed time=996uS  deltaT=112uS
9. raw relative bandgap voltage=347  Elapsed time=1108uS  deltaT=112uS

So, the first surprise was that it made no difference.  The second surprise was that running the same code on a 16Mhz Moteino was barely any faster than on  an 8Mhz Pro Mini.  I haven't yet checked the datasheet to confirm, but it would seem the ADC moves at its own pace (?).

[Edit1:  That said, it is just a one time thing after power-up or reboot, at least while awake.  I confirmed that by putting the whole thing in a loop with a 30 second delay separating each batch of ADC reads.  However, I expect there will nonetheless be a similar price to pay each time the atmega328p wakes up from a full powerdown sleep.]

[Edit2: Anyhow, the main upshot from doing these time measurements was to motivate me to do an ADC noise reduction sleep whlie taking the ADC readings.  Noise doesn't presently seem to be an issue, but if doing that, then I'm hopeful (though haven't confirmed) that the somewhat lengthy ADC sampling will not tally up over time into a significant drain on battery life.]

[Edit3: By the way, the approach I'm taking to measuring bandgap voltage for calibration purposes is simply to power VCC during calibration with a known voltage source (whose value I input just once during the calibration using the serial console) and then automatically impute the true bandgap voltage by measuring the bandgap against it.  The above is part of the code which is leading to that.  Like others have done, I'm planning to store this validated bandgap voltage constant somewhere TBD in the eeprom memory and use that instead of just a "typical" value for bandgap voltage.  I expect that doing this will probably improve the accuracy of reported voltage measurements.]
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on April 15, 2016, 09:27:54 AM
I think I found a workable solution.   :)  According to the datasheet, "When the ADC is turned off and on again, the next conversion will be an extended conversion."  So, I simply start a conversion as the very first step in the setup() function by adding two lines of code at its very beginning:

Code: [Select]
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  ADCSRA |= _BV(ADSC); // Convert

I don't have the atmega328p waste time waiting for the conversion to complete, but rather just have it move on from there as per usual.  At least on the 8Mhz Pro Mini, doing that gets the first "extended conversion" speed bump entirely out of the way before the regular sampling starts:

Code: [Select]
0. raw relative bandgap voltage=312  Elapsed time=0uS
1. raw relative bandgap voltage=325  Elapsed time=120uS  deltaT=120uS
2. raw relative bandgap voltage=328  Elapsed time=240uS  deltaT=120uS
3. raw relative bandgap voltage=329  Elapsed time=360uS  deltaT=120uS
4. raw relative bandgap voltage=330  Elapsed time=480uS  deltaT=120uS
5. raw relative bandgap voltage=330  Elapsed time=600uS  deltaT=120uS
6. raw relative bandgap voltage=330  Elapsed time=720uS  deltaT=120uS
7. raw relative bandgap voltage=330  Elapsed time=840uS  deltaT=120uS
8. raw relative bandgap voltage=330  Elapsed time=960uS  deltaT=120uS
9. raw relative bandgap voltage=330  Elapsed time=1080uS  deltaT=120uS

On the 16Mhz Moteino, the results at first don't appear to be as good:
Code: [Select]
0. raw relative bandgap voltage=388  Elapsed time=0uS
1. raw relative bandgap voltage=363  Elapsed time=156uS  deltaT=156uS
2. raw relative bandgap voltage=352  Elapsed time=268uS  deltaT=112uS
3. raw relative bandgap voltage=348  Elapsed time=380uS  deltaT=112uS
4. raw relative bandgap voltage=347  Elapsed time=492uS  deltaT=112uS
5. raw relative bandgap voltage=346  Elapsed time=604uS  deltaT=112uS
6. raw relative bandgap voltage=346  Elapsed time=716uS  deltaT=112uS
7. raw relative bandgap voltage=346  Elapsed time=828uS  deltaT=112uS
8. raw relative bandgap voltage=346  Elapsed time=940uS  deltaT=112uS
9. raw relative bandgap voltage=346  Elapsed time=1052uS  deltaT=112uS
but I think that's probably because at 16Mhz it finishes with the rest of setup() before the conversion initiated at the start of setup completes.  So, rather than resetting the "extended conversion" that's already in progress, I'm hypothesizing that the ADC makes the mcu wait (156-112=44uS) until the "extended conversion" completes before initiating a new sample.  In real life, using the method of running on its 8Mhz internal resonator to gain the benefits of a 3.8uS wake-up, I expect the Moteino results will be the same as the 8Mhz Pro Mini above.
Title: Re: accurate Moteino battery voltage monitoring
Post by: TomWS on April 15, 2016, 12:43:22 PM
It's interesting that in the 8MHz case the bandgap reading is now increasing for the first few, rather than dropping as I would have expected with the charging cap scenario.  This still appears to be the case in the 16MHz case so seems consistent with my expectations.

Tom
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on April 15, 2016, 04:30:34 PM
Good catch.  It does seem strange, especially when you consider that the same pro mini in the earlier sketch (reply #28)  had a falling voltage.

As a cross-check, I plugged a different pro mini into the same usb-to-ttl adapter as used by the Moteino, and it also demonstrates a rising voltage when running the most recent sketch.  So, I don't know why these Pro Mini's are behaving differently in that respect, when running the latest version of the sketch.

Changing the subject, here's some food for thought: if on the Moteino I add a 330uSec delay before starting the regular sampling loop (but still having launched the extended conversion as before at the start of the setup() function), then over several trial runs the ADC appears to nail the final bandgap voltage on its first try every time:

Code: [Select]
0. raw relative bandgap voltage=346  Elapsed time=0uS
1. raw relative bandgap voltage=346  Elapsed time=116uS  deltaT=116uS
2. raw relative bandgap voltage=346  Elapsed time=228uS  deltaT=112uS
3. raw relative bandgap voltage=346  Elapsed time=340uS  deltaT=112uS
4. raw relative bandgap voltage=346  Elapsed time=452uS  deltaT=112uS
5. raw relative bandgap voltage=346  Elapsed time=564uS  deltaT=112uS
6. raw relative bandgap voltage=346  Elapsed time=676uS  deltaT=112uS
7. raw relative bandgap voltage=346  Elapsed time=788uS  deltaT=112uS
8. raw relative bandgap voltage=346  Elapsed time=900uS  deltaT=112uS
9. raw relative bandgap voltage=346  Elapsed time=1012uS  deltaT=112uS
That leads me to wonder whether running the multiple samples without any pause at the beginning, as before, is of any benefit, or worse yet, may actually slow down the sampling capacitor from reaching its final settled voltage level.

[Edit: I don't know that 330uSec is the magic number that would work on all Moteino's in all conditions, but perhaps it is, or perhaps there is a more conservative number like, say, 400uSec, that is such a magic number, and where you come out ahead (at least on average) by using it.  I really don't know, as I just now stumbled across this.]
Title: Re: accurate Moteino battery voltage monitoring
Post by: TomWS on April 15, 2016, 04:44:02 PM
It does seem strange, especially when you consider that the same pro mini in the earlier sketch (reply #28)  had a falling voltage.
It's not a falling 'voltage', it's a falling reading on the bandgap due to a rising voltage on the ARef pin.  That the reading is now rising on the first few at 8MHz is odd.
Quote
Changing the subject, here's some food for thought: if on the Moteino I add a 330uSec delay before starting the regular sampling loop (but still having launched the extended conversion as before at the start of the setup() function), then over several trial runs the ADC appears to nail the final bandgap voltage on its first try every time:
I don't understand where this 330uS delay is.  It's between what and what?
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on April 15, 2016, 04:52:22 PM
Here's the sketch:

Code: [Select]
// number of microseconds for ADC to setttle before taking a measurement
#define ADC_SETTLE_MICROSECONDS 330
#define NUM_ADC_SAMPLES 10

uint16_t getRelativeBandgapVoltage() {
  uint16_t rawBandgapMeasurement;
 
  // Read bandgap voltage reference (~1.1V) against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);    //need to do this for every sample or just the first?
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  rawBandgapMeasurement = ADCL;  //get the low order bits of ADC
  rawBandgapMeasurement |= ADCH<<8;  //combine with high order bits of ADC
  return rawBandgapMeasurement;
}

void setup() {
  long timeInMicroseconds[NUM_ADC_SAMPLES];
  uint16_t rbgv[NUM_ADC_SAMPLES];  // relative bandgap voltage
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);   
  ADCSRA |= _BV(ADSC); // Convert

  Serial.begin(115200);
 
  delayMicroseconds(ADC_SETTLE_MICROSECONDS);
  for (int i=0;i<NUM_ADC_SAMPLES;i++) {
    timeInMicroseconds[i] = micros();
    rbgv[i] = getRelativeBandgapVoltage();
  }
  for (int i=0;i<NUM_ADC_SAMPLES;i++) {
    Serial.print(i);
    Serial.print(F(". raw relative bandgap voltage="));
    Serial.print( rbgv[i]);
    Serial.print(F("  Elapsed time="));
    Serial.print(timeInMicroseconds[i] - timeInMicroseconds[0]);
    Serial.print(F("uS"));
    if (i>0) {
      Serial.print(F("  deltaT="));
      Serial.print(timeInMicroseconds[i]-timeInMicroseconds[i-1]);
      Serial.print(F("uS"));
    }
    Serial.println();
    Serial.flush();
  }
}

void loop() {
}

Title: Re: accurate Moteino battery voltage monitoring
Post by: ChemE on January 12, 2017, 05:13:41 PM
Forgive me for necro'ing this thread but picking up on WhiteHare's work, I've been able to get pretty good readings much faster by cranking up the ADC from 125kHz to 1Mhz.  The datasheet says not to run it faster than 200kHz for 10-bit precision and then basically says if you run it at 1Mhz you don't lose much precision.  Much more information here: http://www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/

Actually, on my TH Nodes, I've been able to take battery voltage readings in 0 extra time!  I wake up and start a conversion and rather than twiddling my thumbs waiting for the ADC to finish, I start issuing commands to my HTU21D.  Right before going to sleep to wait for my first no hold temperature measurement I grab the results from the ADC.  Issuing a command on the fastest possible I2C bus takes around 92us which is longer than the ADC needs for an extended measurement when the prescaler is cranked up to 32 instead of the default 128.  Net result, I get my battery voltage for free except the extra current to keep the ADC on for 100us.

Code: [Select]
startT = micros();           // ==================== START THE CLOCK ====================
    sbi(ADCSRA, ADSC);  // start a conversion
    issueCommand(WRITE_USER_REGISTER, ELEVEN_BIT_TEMP);    // this conversation takes 88uS - plenty long enough for the ADC
    issueCommand(TRIGGER_TEMP_MEASURE_NOHOLD,0);
    Vcc = ADCL;
    Vcc |= ADCH<<8;
    //Vcc = 112296/Vcc;  // 16-bit math takes way too long adding around 40us to this timed loop
    LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_OFF);
    readRaw(&data[0]);
    issueCommand(WRITE_USER_REGISTER, EIGHT_BIT_RH);
    issueCommand(TRIGGER_HUMD_MEASURE_NOHOLD,0);
    LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_OFF); 
    readRaw(&data[2]);
    stopTWI();
    elapsed = micros()-startT;  // ==================== STOP THE CLOCK ====================
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on January 12, 2017, 06:59:31 PM
Nice!  Thank you for your follow-up post.
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on February 07, 2017, 02:15:34 PM
Maybe it's thanks to the atmega328p's now very fast 4usec wake-up from sleep, but I was finding the ADC a bit slow at getting up to speed.

Prior to sleeping the atmega, I am turning off the ADC with this:
Code: [Select]
ADCSRA = 0; // disable ADC
which is also how Nick Gammon does it. (https://www.gammon.com.au/forum/?id=11497)

Presently I'm using TomWS's method of reading the ADC until I get two of the same values in a row.  It seems like a good approach.  However, I'm finding that if the atmega328p doesn't do one or the other of the the below code snippets to reanimate the ADC immediately after the 4usec wake-up, then TomWS's method often seems to yield erroneous values.

I noticed that ADCSRA has the value 144 just prior to turning it off, so now I wake the ADC up with:
Code: [Select]
  
ADCSRA=144;  //restore ADC settings from just prior to sleeping
as soon as the atmega328p awakens.  That does seem to help.

Instead of that, I've seen code where some people do:
Code: [Select]
  ADCSRA |= (1<<ADEN);  //Power up the ADC
  ADCSRA |= (1<<ADSC);  //Start converting

At the moment, I'm not sure which is better. 

What are you all doing in this respect?
Title: Re: accurate Moteino battery voltage monitoring
Post by: ChemE on February 07, 2017, 03:50:44 PM
144 is setting bits 7 (ADEN) and 4 (ADIF) which according to the datasheet is cleared by writing a logical 1 to this bit:

•   Bit 4 – ADIF: ADC Interrupt Flag
This bit is set when an ADC conversion completes and the Data Registers are updated. The ADC Conversion
Complete Interrupt is executed if the ADIE bit and the I-bit in SREG are set. ADIF is cleared by hardware when
executing the corresponding interrupt handling vector. Alternatively, ADIF is cleared by writing a logical one to
the flag. Beware that if doing a Read-Modify-Write on ADCSRA, a pending interrupt can be disabled. This also
applies if the SBI and CBI instructions are used.

You are also setting the ADC clock div to 2 by zeroing out bits 2:0 so you are running your ADC at 8MHz assuming you are running the 328p at 16MHz anyway.

To make your code more readable I'd change your wakeup to:

Code: [Select]
ADCSRA |= (1<<ADEN) | (1<<ADIF);  // Power up the ADC and reset the interrupt flag

EDIT: Thinking about it a little further, you are reading 144 just prior to sleeping because a conversion was finished.  Setting the ADIF bit doesn't actually set it so just setting the ADEN bit should be completely equivalent to setting ADCSRA = 144.
Title: Re: accurate Moteino battery voltage monitoring
Post by: ChemE on February 07, 2017, 04:01:55 PM
Sorry, I failed to answer how I do it.

Code: [Select]
#define       sbi(sfr, bit)           (_SFR_BYTE(sfr) |= _BV(bit))
#define       cbi(sfr, bit)           (_SFR_BYTE(sfr) &= ~_BV(bit))
#define       ENABLE_ADC              cbi(PRR, PRADC); sbi(ADCSRA, ADEN);  // Enable the ADC
#define       DISABLE_ADC             cbi(ADCSRA, ADEN); sbi(PRR, PRADC); // Disable the ADC to save power
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on February 07, 2017, 04:34:34 PM
You are also setting the ADC clock div to 2 by zeroing out bits 2:0 so you are running your ADC at 8MHz assuming you are running the 328p at 16MHz anyway.

I'm running the atmega328p at 8mhz on its internal resonator, because that's the only way I know of to wake it up from a deep sleep in less than 4usec.  So, from your comment, I guess that means I'm running the ADC at 4Mhz then.  However, that's still 4x faster than the 1Mhz maximum you seem to be recommending in your earlier post.  Should I increase the prescaler and reduce it down to 1Mhz?
Title: Re: accurate Moteino battery voltage monitoring
Post by: ChemE on February 07, 2017, 06:10:40 PM
If you are getting accurate or at least repeatable results at 4MHz then I wouldn't bother slowing down.  I ran at that speed because it was still fast enough to get a conversion started and completed in the time it takes to issue a command on the I2C bus.  In my application I didn't have a need to clock the ADC faster since it was no longer rate limiting for me.
Title: Re: accurate Moteino battery voltage monitoring
Post by: Felix on February 09, 2017, 03:10:01 PM
Just gave this a try and my readings all seem to take double the amount I see from WhiteHare,
Any ideas why this could be?
(I'm using WhiteHare's code on a Moteino modded to 8mhz, mixed with some other radio code that doesn't touch the ADC or anything)

Code: [Select]
0. raw relative bandgap voltage=333  Elapsed time=0uS
1. raw relative bandgap voltage=333  Elapsed time=416uS  deltaT=416uS
2. raw relative bandgap voltage=333  Elapsed time=640uS  deltaT=224uS
3. raw relative bandgap voltage=333  Elapsed time=864uS  deltaT=224uS
4. raw relative bandgap voltage=333  Elapsed time=1088uS  deltaT=224uS
5. raw relative bandgap voltage=333  Elapsed time=1312uS  deltaT=224uS
6. raw relative bandgap voltage=332  Elapsed time=1536uS  deltaT=224uS
7. raw relative bandgap voltage=333  Elapsed time=1760uS  deltaT=224uS
8. raw relative bandgap voltage=333  Elapsed time=1984uS  deltaT=224uS
9. raw relative bandgap voltage=333  Elapsed time=2208uS  deltaT=224uS
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on February 09, 2017, 03:26:01 PM
When I made that post I was running the code on a 16Mhz Moteino.   ;)
Title: Re: accurate Moteino battery voltage monitoring
Post by: Felix on February 09, 2017, 07:15:51 PM
When I made that post I was running the code on a 16Mhz Moteino.   ;)
Makes sense, I was under the impression you were running 8mhz as well.
I just included calibration math for the reading and readings now take 384us (after settling; first reading takes 500us). I could do the math afterwards but I think the overall time is the same, turning off the ADC sooner would save a little juice.
Title: Re: accurate Moteino battery voltage monitoring
Post by: ChemE on February 09, 2017, 09:00:47 PM
Makes sense, I was under the impression you were running 8mhz as well.
I just included calibration math for the reading and readings now take 384us (after settling; first reading takes 500us). I could do the math afterwards but I think the overall time is the same, turning off the ADC sooner would save a little juice.

Have you tried cranking up your ADC bus speed yet?  I settled at 1MHz and WhiteHare is at 4MHz and we both appear to be getting super-consistent results.
Title: Re: accurate Moteino battery voltage monitoring
Post by: Felix on February 13, 2017, 03:26:31 PM
No, just with defaults, which I'm not sure what those are.
If you have handy code that would be great, otherwise I will dig the DS or web when I get some time...
Thanks
Title: Re: accurate Moteino battery voltage monitoring
Post by: ChemE on February 13, 2017, 05:29:01 PM
No, just with defaults, which I'm not sure what those are.
If you have handy code that would be great, otherwise I will dig the DS or web when I get some time...
Thanks

The default ADC speed set by init() which is called in Setup() is 125kHz.  Ask and ye shall receive...

Code: [Select]
#include "Arduino.h"

// Define various ADC prescaler
#define       ADC_PS_16               (1 << ADPS2)
#define       ADC_PS_32               (1 << ADPS2) |                (1 << ADPS0)
#define       ADC_PS_64               (1 << ADPS2) | (1 << ADPS1)
#define       ADC_PS_128              (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0)
#define       sbi(sfr, bit)           (_SFR_BYTE(sfr) |= _BV(bit))
#define       cbi(sfr, bit)           (_SFR_BYTE(sfr) &= ~_BV(bit))
#define       START_ADC_CONVERSION    sbi(ADCSRA, ADSC);  // start a conversion
#define       ENABLE_ADC              cbi(PRR, PRADC); sbi(ADCSRA, ADEN);  //ADCSRA |= bit(ADEN); // Enable the ADC
#define       DISABLE_ADC             cbi(ADCSRA, ADEN); sbi(PRR, PRADC); // Disable the ADC to save power

static inline void Fast_ADC_Init(void) {
  sei();
  // Timer 0 initialization from wiring.c for a ATmega 328P (Arduino Uno rev 3) + 12 bytes to sketch size
  TCCR0A = _BV(WGM01) | _BV(WGM00);      // set timer 0 prescale factor to 64
  TCCR0B = _BV(CS01) | _BV(CS00);        // set timer 0 prescale factor to 64
  TIMSK0 = _BV(TOIE0);                 // enable timer 0 overflow interrupt
 
  // Timer 2 initialization from wiring.c for an ATmega 328P (Arduino Uno rev 3) + 20 bytes to sketch size
  TCCR2A |= _BV(COM2A1) | _BV(WGM20);    // Enable timer 2 to _delay_ms() works properly
  TCCR2B |= CS22;                        // set clkT2S/64 (From prescaler)
 
  // ADC Housekeeping
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);    // Set the multiplexer to read the internal bandgap voltage
  //ADCSRA &= ~ADC_PS_128;    // Unset the bits set by init()
  ADCSRA |= ADC_PS_32;    // set our own prescaler to 32
}

Just call Fast_Init_ADC() in your setup code and you'll be running at 1MHz and comparing to the internal 1.1V bandgap.  I never invoke init() in my release code so I have to do those things in my Fast_Init_ADC.  If you are calling init() either directly or by using Arduino's Setup() routine, then you can change Fast_Init_ADC() to just:

Code: [Select]
static inline void Fast_ADC_Init(void) {
  // ADC Housekeeping
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);    // Set the multiplexer to read the internal bandgap voltage
  ADCSRA &= ~ADC_PS_128;    // Unset the bits set by init()
  ADCSRA |= ADC_PS_32;    // set our own prescaler to 32
}
Title: Re: accurate Moteino battery voltage monitoring
Post by: Felix on February 14, 2017, 10:49:58 AM
Thanks ChemE,
I'm running 8mhz so to get 1mhz I think the setting has to be:

Code: [Select]
ADCSRA |= ADC_PS_16

The power-on ADC prescaler is 128 (62.5khz at FCPU=8mhz).

I seem to get flat readings at 500khz though so I think i'll stick with that. I have to first clear the prescaler bits before setting a new value.
Results:

Code: [Select]
ADCSRA = 10000100
0. raw relative bandgap voltage=296  Elapsed time=0uS
1. raw relative bandgap voltage=297  Elapsed time=200uS  deltaT=200uS
2. raw relative bandgap voltage=296  Elapsed time=392uS  deltaT=192uS
3. raw relative bandgap voltage=296  Elapsed time=592uS  deltaT=200uS
4. raw relative bandgap voltage=296  Elapsed time=784uS  deltaT=192uS
Title: Re: accurate Moteino battery voltage monitoring
Post by: perky on February 14, 2017, 11:42:58 AM
According to the datasheet max sample rate for full resolution is 15kS/s, which is 150kHz for 10 bit successive approximation. For 8 bit that increases to 76.9kS/s, or around 615kHz. So it seems 8 bit would be OK, but 10 bit might not be as far as I can tell.
Mark.
Title: Re: accurate Moteino battery voltage monitoring
Post by: WhiteHare on February 14, 2017, 02:50:37 PM
Does running the ADC at a faster rate lead to a much faster convergence (i.e. TomWS's method of waiting for two successive voltage readings in a row that match), or does it take about the same amount of time for that even if the sample rate is slower?
Title: Re: accurate Moteino battery voltage monitoring
Post by: perky on February 14, 2017, 09:06:39 PM
I think the dummy reads are necessary because of 'common mode' settling times, it requires a ceratin number of ADC clocks to stabalize the internal references before a sample can be taken accurately. Whether that can be done at a much faster rate that normal sampling and still be accurate I don't know.
Mark.
Title: Re: accurate Moteino battery voltage monitoring
Post by: ChemE on February 15, 2017, 07:54:55 AM
My first reading is the only one that is throw away.  The second and subsequent readings are all within one integer of each other.  I'll check later this morning if the same is true at faster and faster ADC clocks.  But for certain I am getting a faster true reading at 1MHz than I was at 125kHz.
Title: Re: accurate Moteino battery voltage monitoring
Post by: ChemE on February 15, 2017, 11:31:18 AM
I'm running into a hard limit it seems.  No matter what I try, I cannot get an accurate measurement within 100us of powering up the ADC.  Once that 100us has elapsed, I can sample at 4MHz and get accurate results every time in around 4us per measurement, but measurements taken inside that 100us are inaccurate.
Title: Re: accurate Moteino battery voltage monitoring
Post by: emjay on February 16, 2017, 02:55:54 PM
@ChemE,

What is the cap value hung on Aref?
Title: Re: accurate Moteino battery voltage monitoring
Post by: ChemE on February 16, 2017, 04:21:34 PM
@ChemE,

What is the cap value hung on Aref?

I'm not sure I understand the question but I don't have anything connected to Aref.  I'm measuring against the internal bandgap voltage.
Title: Re: accurate Moteino battery voltage monitoring
Post by: emjay on February 17, 2017, 07:15:35 AM
@ChemE,

Isn't this a standard Moteino?  Sorry, the thread is so long to plough all the way through.
Title: Re: accurate Moteino battery voltage monitoring
Post by: perky on February 17, 2017, 08:35:55 AM
I'm not sure I understand the question but I don't have anything connected to Aref.  I'm measuring against the internal bandgap voltage.
I'm not sure about the 328P, but the bandgap voltage may well be multiplexed onto Aref first. If that's the case Aref will have an output impedance which will combine with the 100nF cap on Aref to form an RC constant. If by not settling for 100us you mean values you get appear to be much higher than they should be during that time then this could well be the cause.

Edit: According to the datasheet block diagram, the bandgap voltage is multiplexed onto Aref. Also there is a bandgap reference startup time as well which is 40us typical.

Mark.
Title: Re: accurate Moteino battery voltage monitoring
Post by: ChemE on February 17, 2017, 08:45:14 AM
@ChemE,

Isn't this a standard Moteino?  Sorry, the thread is so long to plough all the way through.

Yes, I was doing this testing on a standard Moteino so that it would be useful to everyone here.  I've never attached anything to Aref except a multimeter probe but that could just be my own ignorance.  Is it expected that Aref is attached to a capacitor?
Title: Re: accurate Moteino battery voltage monitoring
Post by: emjay on February 17, 2017, 08:52:48 AM
@ChemE,

Ok, then if you have a look at the Moteino schematic you will see a cap hung off Aref for noise reduction.
Perky is correct - when switching on the internal reference, it can only rise as fast as that cap allows.
You can reduce the cap value (and hence the lag) somewhat without noise on Vref becoming too much of a problem.

Title: Re: accurate Moteino battery voltage monitoring
Post by: ChemE on February 17, 2017, 08:57:51 AM
Ah interesting.  Another instance where a chemical engineering education is unhelpful :)  So a smaller cap *might* be a means of further reducing the power consumption in that a battery voltage could be read faster provided it wasn't so much smaller as to make the line noisy.  Interesting, thanks gents.
Title: Re: accurate Moteino battery voltage monitoring
Post by: perky on February 17, 2017, 09:01:07 AM
There's also the bandgap startup time to consider (40us typical, 70us max), that'll combine with the RC constant and could explain your 100us settling time.
Mark.
Title: Re: accurate Moteino battery voltage monitoring
Post by: perky on February 17, 2017, 09:18:56 AM
This Aref settling time may well have implications for low power. Those wishing to do fast ADC reads on wakeup and then go back to sleep straight away may have to do a 2 stage wakeup and use a timer to time the 100us settling time:

1) Wake up from deep sleep
2) Start bandgap and mux onto Aref
3) Start timer to interrupt after 100us
4) Go to sleep with only timer clock running
5) Wake up from timer interrupt and read ADC
6) Go back to deep sleep

Mark.
Title: Re: accurate Moteino battery voltage monitoring
Post by: ChemE on February 17, 2017, 09:55:37 AM
I follow you.  This strategy vs. cooling my heels for 100us may well be testable via my ultracapacitor.  Given that sensing battery voltage is a pretty fundamental part of most battery powered nodes, I plan to do some further investigating to see if some extra coulombs can be squeezed out.