Go Down

Topic: Delay in analogRead after switching pin (Read 2906 times) previous topic - next topic

dc42

Several users of the forum have hit the problem that if you do an analogRead from a pin driven from a high impedance source, and you previously read a different pin, then the value returned by analogRead is wildly inaccurate. I suggest the following changes:

- declare a new variable "static unsigned int analogReadDelay = 100;" in wiring_analog.c

- modify analogRead to call "delayMicroseconds(analogReadDelay)" between setting the multiplexer and starting the conversion (there is already a commented-out "delay(1);" call in the code at this location, see wiring_analog.c(64))

- add new function "void setAnalogReadDelay(unsigned int amount){ analogReadDelay = amount; }". Most users won't need to call this function, but it can be used to increase or reduce the delay if needed.

- fix the bug that "delayMicroseconds(0)" delays for a very long time instead of a minimal time, so that "setAnalogReadDelay(0)" works properly.

Possible improvements on this scheme:

1. Make the delay call only if a different pin was read last time.

2. Allow the delay to be set on a per-pin basis.

I have suggested 100 microseconds as the default delay, but other folks may have a better idea of what is needed e.g. when reading from a LM35 temperature sensor.

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

johnwasser

Perhaps copying this section from the ATmega datasheet would cover the problem of people using high impedance sources:

"The ADC is optimized for analog signals with an output impedance of approximately 10 k? or less. If such a source is used, the sampling time will be negligible. If a source with higher imped- ance is used, the sampling time will depend on how long time the source needs to charge the S/H capacitor, with can vary widely. The user is recommended to only use low impedance sources with slowly varying signals, since this minimizes the required charge transfer to the S/H capacitor."
Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

dc42

johnwasser, I know what the datasheet says, but do you really expect everyone using a source with an impedance greater than 10K to buffer the signal? I would hazard a guess that a majority, or at least a substantial minority, of Arduino users connect sources with an impedance >10K to analog input pins. The forum is full of posts in which users have connected temperature sensors (other than thermocouples), LDRs, and phototransistors (with pullup resistors > 10k) to the analog input pins. It's simply not necessary to buffer the signal when reading a *slowly varying* signal such as provided by these types pof sensor, provided that sufficient delay is allowed between setting the mux and initiating the conversion.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

CrossRoads

Doesn't reading an input twice & ignoring the first read usually solve the problem?
Things like temperatures aren't changing all that  fast.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

retrolefty

#4
Aug 18, 2011, 06:56 pm Last Edit: Aug 18, 2011, 07:19 pm by retrolefty Reason: 1
There is also analogRead() inaccuracies after one first changes the reference source for the ADC function (to external Aref pin, to band-gap, etc). Typically the first value returned is pretty much garbage and somewhere it was recommended to do a 'dummy' read before performing a valid analogRead() function. I think this might also be independent of if the analog voltage has < 10k source impedenace, or which analog channel was last read from, but not positive about that.

I've always considered the AVR's built-in 10 bit ADC function as very handy and useful, but not to be confused with instrumentation quality ADC devices. My current favorite is the TI ADS1115 16 bit I2C, 2 diff or 4 SE channels, five programmable input ranges, built in comparitor with digital output pin, works with either 3.3 or 5vdc systems, up to 860SPS, has internal reference voltage source, small as a baby asprin. Lot of bang for a $15 break-out module.
 http://www.ti.com/lit/ds/symlink/ads1115.pdf
 
http://www.ebay.com/itm/230619695873?ssPageName=STRK:MEWAX:IT&_trksid=p3984.m1423.l2649

Lefty


dc42

Crossroads,

Yes, reading the pin twice and discarding the first reading does usually solve the problem. But many users facing this situation don't know they need to do that.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

dc42

I've just seen YET ANOTHER post relating to this problem, see http://arduino.cc/forum/index.php/topic,69742.0.html. That's the 4th post I've seen by a user experiencing this problem, and I only joined the forum about 2 weeks ago. Anything that's causing this much trouble for Arduino users needs to be addressed, preferably in the software, or failing that in the documentation.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

CrossRoads

Sure, but then how would we run up our post counts ;)

= vs == also comes a lot.

Very many posters just dive in & ask questions without browsing the playground first; if they did that first (or were even aware that it exists it seems) that would resolve a lot of things.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

retrolefty


I've just seen YET ANOTHER post relating to this problem, see http://arduino.cc/forum/index.php/topic,69742.0.html. That's the 4th post I've seen by a user experiencing this problem, and I only joined the forum about 2 weeks ago. Anything that's causing this much trouble for Arduino users needs to be addressed, preferably in the software, or failing that in the documentation.


Well it is certainly a balancing act. We see many inexperienced people having trouble reading even simple push button switches using digitalRead() because they don't yet understand the concept of a 'floating input pin'. Does that mean the digitMode command should automatically enable the internal pull-up resistor when set to input mode?  I would think that trying to make the analogRead function fool proof for all possible problems would either be not effective or hamper the basic performance of the function.

Still a very interesting topic. I recall a year or so ago where Coding Badly was helping me work out a method such that an arduino sketch could actually measure the voltage value of it's Vcc pin without any external wiring or components. Very useful function if you wish to have 'dynamic' calibration/correction capabilities, where you might be running on battery voltage which decreases voltage over time.

Lefty

dc42

Crossroads, my aim is indeed to reduce your post counts! :D (that wouldn't be such a bad thing, because I find the forum to be rather slow in responding compared to other sites). The = vs == issue is a defect in the C language, which we can't do much about (although good C/C++ programmers generally turn on enough compiler warnings to pick up accidental use of = where == was intended).

Lefty, not enabling pullups when they are needed is an issue of understanding basic electronics, not a limitation of the chip. But the need for a delay between switching pins and reading the ADC is a feature of the microcontroller. That is why I think it deserves to have a workaround built in to the Arduino software.

I'm going to experiment with various analogue signal source resistances to see what delay is needed.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

robtillaart

Quote

- fix the bug that "delayMicroseconds(0)" delays for a very long time instead of a minimal time, so that "setAnalogReadDelay(0)" works properly.

reported some time ago - http://code.google.com/p/arduino/issues/detail?id=576 -  

Fix proposed - http://arduino.cc/forum/index.php/topic,68383.msg504892.html#msg504892 -



I do not prefer the delay as a solution. I would rather encapsulate the analog port in a class that supports asynchronuous behaviour, a bit of

void AnalogPort[pin].request();
boolean AnalogPort[pin].ready();
int AnalogPort[pin].read();


In that way you can do something usefull while waiting for the conversion.


Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

retrolefty

Quote
I'm going to experiment with various analogue signal source resistances to see what delay is needed.


A worthwhile effort I would say. You might consider using two analog inputs as best case source impedance wired to ground and +5vdc respectively, and then a third analog input pin could be your source impedance pin under test.

Lefty

dc42

OK, this is the test setup I used:

Pin A0 connected to GND via resistance R
Pin A1 connected to +5 via resistance R
Read and store A0 10 times in a tight loop, then send the values to the serial port, then delay. Repeat for A1. Then start again.

Ideally I'd have read a pin driven by a variable voltage in case the above doesn't give worst-case conditions. I may try that when I have more time.

Using the standard Arduino software:

With R=10K: the readings are stable, 0 and 1023 every time.
With R=100K: the +5 pin sometimes reads as low as 1017 the first time, otherwise it is 1023. The GND pin always reads zero.
With R=1M: the GND pin may read as high as 345 on the first reading but reads 0 by the 4th reading. The 5v pin may read as low as 664 on the first reading but reads 1022 by the 5th reading, and often never reaches 1023 even on the 10th reading.

Using the 1M resistors, I tried inserting the delayMicroseconds call that I propose. With 150 microseconds delay, the 0v pin always reads zero and the +5v pin usually reads 1023 (occasionally 1022). With 120 microseconds delay, the readings are less consistent.

Using the 100K resistors, with a delay of 10us the readings were consistently 0 and 1023. With 5 microseconds they were 0 and 1022 or 1023.

I measured the time taken by an analogRead call (without extra delay) at around 110 microseconds.

Conclusion:

- The effect of high source resistance is worse when reading +5v than when reading 0v.
- If my mcu is typical, inserting a delay of 10us would give reliable results with source resistance of up to 100K or a little more.
- At 1M source resistance, the delay needs to be increased to 150us.
- If instead of adding the delay you read the pin several times, the time taken to obtain a stable and correct reading can be much longer. For example, 5 readings @ 110us each totalling 550us, vs. 1 reading @ 260us including the 150us delay. Or 2 readings at 110us each totalling 220us, vs. 1 reading at 120us including 10us delay.

If my suggestion is adopted, I suggest making the default delay 10us, with a recommendation to set the delay higher if the source resistance is >100k. This default delay adds less than 10% to the time taken by a call to analogRead.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

CrossRoads

"I find the forum to be rather slow in responding"
Well, I do the best I can 8) when I'm not at work or designing things or building things or writing code or teaching fencing classes or deleting spam posts ...
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Go Up