Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple analog reads mess up ADC on Arduino UNO #334

Open
webondevices opened this issue Nov 28, 2016 · 25 comments
Open

Multiple analog reads mess up ADC on Arduino UNO #334

webondevices opened this issue Nov 28, 2016 · 25 comments

Comments

@webondevices
Copy link

webondevices commented Nov 28, 2016

There is a well-known problem with the Arduino UNO ADC (very likely affects other boards as well) that multiple analogRead() performed on different pins with no delay won't give enough time for the ADC to "cool down" and measurements will be completely wrong.

I discovered this issue while trying to make the LM35 temp sensor and an LDR measure correctly in the same circuit with the Johnny-Five library but they only work independently but not together.

In the Arduino community there are two solutions (hacks) to this:

  • add a couple of ms delay between measurements on different pins
  • perform two analogRead() on the same pin, dump the first and keep the second

I modified the StandardFirmata sketch by adding the dummy analogRead before the actual Firmata read and it solved all my problems:

dummyRead = analogRead(analogPin);
Firmata.sendAnalog(analogPin, analogRead(analogPin));
@webondevices webondevices changed the title Multiple analog reads messes up ADC on Arduino UNO Multiple analog reads mess up ADC on Arduino UNO Nov 28, 2016
@soundanalogous
Copy link
Member

That's strange because the analogRead code in Arduino blocks until the read has finished but I guess this doesn't account for an ADC channel change which can take a few microseconds.

The issue here is that the delay time is likely unique per microcontroller architecture (Firmata is supported on architectures other than AVR). I'm not sure how long a dummy read takes vs the minimum delay required to switch an ADC channel on a given microcontroller architecture. Until I have that data it's difficult to determine how to proceed.

@soundanalogous
Copy link
Member

It may actually be most effective to stagger reads, so instead of reading all analog inputs in one shot, stagger them, one read per iteration of the main loop, with the first read occurring at the sampling interval, assuming that all reads could occur within the sampling interval. This would not incur any additional delays. The only problem would be if the loop time is < the necessary channel change duration.

@webondevices
Copy link
Author

It's clear that the issue is not with the software implementation as the code blocks until the read has finished. This is most likely an issue with the ADC.

I wanted to highlight this thread on the Arduino forum where they are discussing this issue in a bit more detail:

http://forum.arduino.cc/index.php?topic=69675.0

@webondevices
Copy link
Author

@soundanalogous , I'm currently writing a book on Johnny-Five and some of my examples have multiple analog sensors running the same time. I see no progress here so I have no other choice than to just provide the reader a link to my Github to download my modified StandardFirmata file.

Does the license allow me to publish a modified version of the StandardFirmata on my GitHub?

Also, is this really the best option I have?

@soundanalogous
Copy link
Member

Why don't you submit a PR with your modified StandardFirmata file and we can go from there. I'm working on several Firmata issues in my limited spare time and this one isn't high priority for me at the moment.

@soundanalogous
Copy link
Member

I'd really like to see a solution that doesn't involve delays, but I can help walk you through it if you are willing to put in some work.

@jguille2
Copy link

jguille2 commented Jan 3, 2017

Hi,
I would like to share a comment with us(excuse me if it is not opportune).

I use StandardFirmata to read multiple analog inputs with Snap4Arduino. I only have had troubles with LM35 sensor. Reading it alone is ok... but when I read another pin (activing reporting) then its readings are wrong. The value of the other measurements affect the reading value. With an oscilloscope, you can see the noise of another signal.

Several people (with more knowledge than me in electronics) insist that the problem is in the soft (firmata)... but I think that the problem is in the conjunction (this sensor with our reading frequency).

Take a look at this LM35 info. Putting a 75Ω Resistor and a 1µF Capacitor between ground and signal pins, the noise disappears and the measurement returns to be stable (again independent of other measures

@webondevices
Copy link
Author

webondevices commented Jan 3, 2017

@jguille2 , thanks for the input! I have tested these. I don't think the issue only happens because of the LM35 sensor. I have inconsistencies in the readings without that however the scale is definitely not that bad. I have tested this with a water sensor and an LDR in the same circuit. The change in the water sensor don't seem to affect the reading on the LDR, however the LDR can change the water sensor reading from 810 to 940.

On the other hand the resistor and capacitor have fixed my temperature sensor reading!

I wonder if my voltage divider circuit for the LDR misses a component that would fix my readings on that side as well?

Anyway, I'm going to close my pull request for now until we get to the end of this.

@jguille2
Copy link

jguille2 commented Jan 4, 2017

Ok, let's continue...

As I said, 'electronic people' insists me that LM35 is ok... and the problem is in firmata. Really, reading speed seems to cause side effects... at least in some devices. But if we can manage this with the hardware connections... the problem disappears... and we only have to document it.

I do not want to get away from this issue ... but I try to talk about a feature that might arrange this problem ... and I also needed in other scenes.

I would like to have two reading methods: the actual (turning on/of reporting) and an alternative making single readings.
I try to explain this with some examples...

  • The reporting method is perfect when you are continuously following a digital pin with very few changes (arduino only sends pin changes... and we check continuously the var value). But on the other hand., if I want to read an analog pin with a low frequency, arduino will continue sending values with a high speed.
  • A method of single mesurements is the opposite. Better to analog inputs: less readings, less sendings... and not noise.

Can we have two methods to read pins? Maybe two different functions... or maybe a config var to choose the method.

Thanks for your patience... I know I'm asking a lot...

Joan

@soundanalogous
Copy link
Member

@jguille2 see this proposal, it includes a way to read a single analog pin value. That way the user can control the rate at which it's read. The downside is the latency will be twice that of using reporting (due to the round trip communication over the transport). I may actually break that proposal out into multiple features including:

  • ANALOG_READ_REQUEST: request a single analog pin value
  • DIGITAL_READ_REQUEST: request a single digital pin value

@soundanalogous
Copy link
Member

I linked to the wrong proposal, that one is actually related, but this is the proposal I meant to link to: firmata/protocol#59

@jguille2
Copy link

jguille2 commented Jan 4, 2017

Thanks Jeff,

Very interesting for me this proposal. If firmata keeps reporting method and adds a single reading method... it will be perfect. We'll choose the best method for each case.

The latency increase will not be a problem in some scenarios. And I think this will fix the problem of some sensors (like LM35)... and they must work with the alternative method.

I'll be waiting to test these changes.

Thank you very much for your great work!! I love firmata.

My best wishes for this new 2017!

Joan

@soundanalogous
Copy link
Member

@webondevices were you able to resolve this issue with hardware?

@webondevices
Copy link
Author

@soundanalogous , sorry for not sharing my results earlier.

The proposed solution in this article seems to have to solved my problem:
https://heliosoph.wordpress.com/2012/03/21/connecting-an-arduino-with-a-lm35-temperature-sensor-special-issues/

Unfortunately, I don't have enough hardware knowledge to understand why this fixes the problem but the added resistor + capacitor combo have stabilised my readings.

@jguille2
Copy link

Hi @soundanalogous ,

I think this can be closed, because it wasn't a general analog reading issue... and I think the problem with the lm35 has a hardware workaround.
I only want to know if the proposal to have single readings is still alive.

Thanks,
Joan

@soundanalogous
Copy link
Member

@jguille2 that proposal is still alive but relatively low priority. What I may enable before that is the ability to query a single analog pin value, however I have not yet drafted a proposal for that feature.

@jguille2
Copy link

Thanks @soundanalogous for all your work!

This ability to query a single analog/digital pin would be great.

Joan

@senadj
Copy link

senadj commented Oct 6, 2017

I am using customized "firmata" for my arduino UNO and I am hitting the same problem with LM35 and another Hall-effect sensor.
I found that readings are stable as long as I use this order in a loop:

  1. pin19: AnalogRead(Hall)
  2. pin18: AnalogRead(LM35)
  3. send serial data (+delay 15ms)

If I swap steps 1 and 2 then LM35 sensor data is floating somewhere down 30% and up to 180% above correct value. I say "correct", but even with stable readings, LM35 output shows almost 25% lower value when used together with Hall sensor (compared to being alone).
But If I move LM35 to pin14 and leave Hall on pin19, that value is only 5% lower.
With my code I can swap readings order on the fly, and this issue is consistently reproduced.

@soundanalogous soundanalogous reopened this Oct 7, 2017
@soundanalogous
Copy link
Member

soundanalogous commented Oct 7, 2017

@senadj have you tried adding a small delay after each analogRead? Also how often are you reading the analog pins? Every iteration of loop() or every 19ms (the default Firmata analog sampling frequency)?

@senadj
Copy link

senadj commented Oct 7, 2017

I did just now (using 5,10,25,125ms). Now read order does not matter - in both cases LM35 sensor readouts floats. It seems the problem got worse, no stable reads anymore.

I checked my code again and realized I did not use delay call before. This is how it went:
I was doing both analogReads one after another. Then serial write and waiting for serial buffer flush. Then repeat this sequence (in a loop) if more than 100ms have passed from last start of previous iteration.

Inserting dummy analogRead before the "real" one seems to fix the problem independently of sensor read order. That way I get read stability plus read values are identical to when using LM35 only.
Putting delay between readouts doesn't change anything in this case.
And considering all this, I am not sure if adding capacitor and resistor to LM35 as mentioned above is really needed.

@soundanalogous
Copy link
Member

So if you need to call analogRead more than once, you need a dummy call to analogRead before each subsequent call to analogRead?

// do you need to do this?
analogRead(HALL_PIN); // dummy read
byte hallPinVal = analogRead(HALL_PIN);
analogRead(LM35_PIN); // dummy read
byte lm35PinVal = analogRead(LM35_PIN);
Serial.write(data...);
// or is this sufficient
// no dummy read for initial analog sensor
byte hallPinVal = analogRead(HALL_PIN);
analogRead(LM35_PIN); // dummy read only for additional analog sensors
byte lm35PinVal = analogRead(LM35_PIN);
Serial.write(data...);

@senadj
Copy link

senadj commented Oct 8, 2017

Your second example is sufficient in my case. But you should use int datatype to store 10bit readouts (hallPinVal and lm35PinVal).

I would guess only particular sensors benefit from dummy analogRead operations.

@soundanalogous
Copy link
Member

For StandardFirmata I would need a very generic solution since the firmware doesn't know anything about connected analog sensors, it only knows how many analogReads to make per sampling interval. Currently it makes them one after another with no delay and no dummy reads. So one solution is to add a dummy read before each subsequent call if there are more than 1 analogReads queue'd up.

@lkasari
Copy link

lkasari commented Jun 13, 2018

I've done dozens of Arduino projects but have never run into this problem until now. Currently I'm doing a rather large project which polls all 16 analog inputs of an Arduino Mega repeatedly. I was reading them all with only a single 1mS delay in the main loop and was noticing several odd analog reading problems, especially with A14 and A15. After looking at the comments in this thread I did two things. First I put a delay of 1mS between each read, and second I put all the reads in order, from 0 to 15. All the problems went away. I'm not sure putting the reads in order helped or not, but it didn't hurt.

I agree this is a bit of a kludge, but I was able to rewrite the main loop so it can still get all the analog inputs and deal with its other tasks in a timely manner.

Thanks for your comments. They helped a lot.

@MoutatsuLai
Copy link

MoutatsuLai commented Jan 2, 2024

  1. The problem of sampling twice to get the correct value.
    Is it related to the fact that Input MUX switching requires 25 ADC Clocks?
    adc_first_med

  2. ADC reading value error problem
    Dragon Knight_1123
    I think the problem is the impedance at the input and the PCB trace capacitance.
    A.General situation
    If the resistance and capacitance values ​​are small enough, the MCU internal capacitance (14pF) can be fully charged within 13.5 ADC clock cycles and the correct value can be sampled.
    B. Error situation (CDS photocell or other high impedance sensor)
    If the resistance value is too high, after 13.5 ADC Clocks, the value of the capacitor that is not fully charged will be sampled.
    This should be the cause of the error.

Open Music Labs - ATmega ADC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants