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.
- 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.
Add another function called: AnalogChannelDelay( Channel, Delay )
If this function is NOT called then ...
the AnalogRead() function performs "as-is".
This gives us 100% backward compatibility.
If the AnalogChannelDelay( Channel, Delay ) function is called then ...
SAVE the "Delay" value in an AnalogChannelDelays array that is indexed by "Channel".
When it is time to do an AnalogRead() then ...
Delay X microseconds per the AnalogChannelDelays array.
This will allow me to adjust each analog channel with the delay needed per that Channel's resistance.
CH 0 with 10K = 0 usec delay
CH 1 with 100K = 10 usec delay
CH 2 with 1Meg = 150 usec delay
Sending a Delay value = 0 makes that Channel work normally, ie no delay.