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

Fluctuating ADC with stabilized source #2070

Closed
supersjimmie opened this issue May 30, 2016 · 132 comments
Closed

Fluctuating ADC with stabilized source #2070

supersjimmie opened this issue May 30, 2016 · 132 comments

Comments

@supersjimmie
Copy link

supersjimmie commented May 30, 2016

I supply the ADC with a stable voltage, supplied by a separate LM1117 3.3V with 100uF capacitor a resistor voltage divider. The LM1117 will provide 3.3V regardless of the load of the ESP's own voltage regulator, the capacitor takes away any noise and the 2 resistors make a fixed voltage suitable to be read by the ADC.
(GND for both the ESP and the LM1117 are connected)

Then, based on this article, I tried to add more stability to the readings:
https://www.quora.com/Why-is-a-little-delay-needed-after-analogRead-in-Arduino
So I do subsequent readings and only use the last one. I even do it 3 times instead of 2, and then only use the last one because that one is supposed to be stable.

#define ANALOGPIN A0;
...
analog = analogRead(ANALOGPIN);
delay(1);
analog = analogRead(ANALOGPIN);
analog = analogRead(ANALOGPIN);
Serial.print(F("Stablized Analog pin: "));
Serial.println(analog);

Readings are done and stored every minute.

The ADC reading has 2 fluctuations, a slow drift and spikes.
This show the ADC output:
analogRead fluctuations

This has been tested with the mentioned 'external' 3.3V regulator and with the 3.3V output from the ESP itself. I also tried with or without the subsequent readings. I don't really mind the spikes because I can add some code to flatten those, but the "long" wave-like fluctuation makes it all useless.

(I need this to read an MQ135 sensor.)

Using current core stable and Arduino IDE 1.6.9.

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@supersjimmie
Copy link
Author

Full code, when logging to the IDE's Serial Plotter:

#include <Arduino.h>
void setup() {
  Serial.begin(115200);
}

void loop() {
  int A;
  A = analogRead(A0);
  A = analogRead(A0);
  Serial.println(A);
  delay(60000);
}

I've had this code running for a few hours on a ESP with only the 2 resistors on the A0, one connected to Gnd and one connected to an LM1117 3.3v output.

@igrr
Copy link
Member

igrr commented Jun 1, 2016

I've set up a circuit to test this, so far I'm getting readings within 1 LSB of average. The thing will run for a few hours, and I'll post a graph by end of day.

Here's my schematic, for the record:
adc_test_1
ESP8266 is mounted on a test board, which is powered by a SY8088 dc/dc step-down regulator. 3.3V to ADC input is supplied by another identical board, which doesn't have an ESP on it (so the regulator is only loaded by ADC divider).

@igrr
Copy link
Member

igrr commented Jun 1, 2016

No drift, just random noise mostly within 1 LSB:

adc_test

@supersjimmie
Copy link
Author

Strange, had it running on a separate ESP (NodeMCU), which is powered through USB, and the ADC powered like this:
connection
Yesterday it kept going up and down about 10, currently it runs smooth.

@supersjimmie
Copy link
Author

supersjimmie commented Jun 7, 2016

@igrr , I think I made some progress.
I've done several tests:

  • with 2 different 'external' 3.3V power sources or with the 3.3V line from my NodeMCU board,
  • with one or two subsequent analogRead calls,
  • intervals ranging from 100ms to 60s,
  • two different nodeMCU boards,
  • with or without some WiFi related libraries loaded and connect/webclient calls.
    In all cases it kept jumping up and down with a difference of about 10.

Then I noticed that after a reset, it was stable for only a few seconds.
So that made me think about the fact that even without any WiFi library loaded and without any WiFi.begin(), the modules are still using their last save Wifi settings.
So I added #include <ESP8266WiFi.h> and in the setup I just called WiFi.disconnect() and then it was totally rock stable!

Then I added the WiFi.begin(..) again and it got unstable.

So this issue is related to WiFi.

@ibaranov-cp
Copy link

ibaranov-cp commented Jun 9, 2016

To me, this looks like the power draw from WiFi is distorting the onboard ADC.
This is honestly not too surprising, and unless there is an on-board external reference input, it is difficult to combat in software. Perhaps an I2C attached external ADC would serve your purposes if you need actual precision?
The onboard 10bit ADC is most likely a SAR type (simplest and cheapest).
So, if it is possible to control sample timing, giving the ADC more time to do its job may also help.

@supersjimmie
Copy link
Author

Using an 'external' adc is not an option for my setup, simply because I don't have any empty usable digital pins left on the module. How could I control the sample timing?

@supersjimmie
Copy link
Author

supersjimmie commented Jun 11, 2016

Until now I have this as a work-around to do a reading every minute:

void loop() {
  unsigned long starttime = millis();
  WiFi.disconnect();
  delay(10);  // allow a short time to disconnect wifi
  Serial.println(analogRead(A0));
  WiFi.begin(ssid, password);
  while ((WiFi.status() != WL_CONNECTED)) {  // wait for connect wifi
    delay(500);
  }
  delay(60000-(millis()-starttime));  // make loop time 60 sec
}

Only this introduces another issue, that the ESP doesn't always (re)connect to wifi causing it to hang.

@supersjimmie
Copy link
Author

supersjimmie commented Jun 15, 2016

I have the issue with 3 NodeMCU boards, so I tried to find out if it was perhaps related to the small power regulator on those board. Instead of powering over usb or with an external 5V powersupply to the Vin pin, I now used a LM1117 3.3V reguator to supply to the 3.3V of the board. (thus bypassing the small onboard voltage regulator)
This still gives the same jumpy values.

@Gorkde
Copy link

Gorkde commented Jun 16, 2016

Same problem for me see:

http://bbs.espressif.com/viewtopic.php?f=66&t=2286&p=7367#p7367
https://www.mikrocontroller.net/topic/399791#4616103

Even tried battery powered and entire Board shielded with foil.
Definitive the transmitting is causing this

After wifi.disconnect() the reading is ok!
In the Beginnin good readings then fluctuating

@Gorkde
Copy link

Gorkde commented Jun 16, 2016

Btw as for me I also have no pins for external ADC which probably would be the best choice.

@Gorkde
Copy link

Gorkde commented Jun 16, 2016

Isn't there a way to check if wifi is transmitting and poll the ADC when it's not?

@arizzi
Copy link

arizzi commented Jun 17, 2016

same problem here... is there a way to "pause" the wifi radio without really disconnecting?

@arizzi
Copy link

arizzi commented Jun 17, 2016

@supersjimmie
Copy link
Author

supersjimmie commented Jun 17, 2016

Simply tested that.
Doing WiFi.forceSleepBegin(100); disconnects indeed, but it seems to be buggy because it never reconnects anymore. I needed to add WiFi.forceSleepWait() after the analogRead(). Then it has to re-connect (re-associate?) wifi, which takes 4-5 seconds. So any subsequent code that needs a connection will fail...

The resulting analogRead looks stable.

@Gorkde
Copy link

Gorkde commented Jun 27, 2016

Another Thing I noticed.... When using Blynk App in my sketch and doing Blynk.Write every 100ms it seems to be stable as well so the unstability might be just when Wifi starts or stops transmitting.

@Gorkde
Copy link

Gorkde commented Jun 28, 2016

I also noticed it just starts getting wrong readings once it seems the WIFI connection has been established the first time (some seconds after powerup).

It then gets wrong radings in the range 1-7 above (always!) the correct reading with seldom a correct reading in between.

If I put AIN to GND I get readings 0-1 which schould be normal but as soon as the connection is established the readings are 0-7 where most of them are in the 5-7 range.

I now used a sketch to read for some time and only use the lowest reading which works but is VERY slow because as soon as I sample readings for less than around 100ms it seems to miss the seldom correct (low) readings and I get wrong ones sometimes in my result.

int ReadAIN()
{
  int Ergebnis = analogRead(0);

  for (int i = 0 ; i < 50 ; i++)
  {
    int Messung = analogRead(0);
    if (Messung < Ergebnis)
    {
      Ergebnis = Messung;
    }
    delay(2);
  }
  return (Ergebnis);
}

BTW... I also use the same voltage regulator, maybe a problem with that one (LM1117V33)?

I also found this (09bb758) and would like to try if that's solving my problen but don't know how. Just integrating it in my sketch doresn't seem to work. Any advice?

REMARK: If the ESP has established a connection once it automatically will after powerup so you will see this problen only if the ESP has been connected before or if it gets connected by WiFi.begin() command

Closed my other Issue since it's the same as this.

@supersjimmie
Copy link
Author

supersjimmie commented Jun 30, 2016

@Gorkde I think that code fails on rom_i2c_writeReg_Mask? I cannot find where that should come from, probably something that only existed in older SDK?

@igrr I have tested it with the latest GIT version, which includes SDK 1.5.4. In the rellease notes of that SDK is a note about a fix of analogread:
8. Revised the issue that API system_adc_read and system_get_vdd33 may return wrong value.
But no luck it still does exacly the same.

@Gorkde
Copy link

Gorkde commented Jun 30, 2016

@supersjimmie:

I wrote that piece of code to make my sketch work until the issue is fixed.

When I do analogread I found the readings always go up from the correct reading.

Therefore I wrote a read function that samples readings an just uses the lowest of them because that's the correct reading.

But as I said, it's just for the time being until the issue is fixed.

Maybe this is an hardware issue of the modules we have or the voltage regulator?

Which one do you use?
Will buy another one for testing purposes but I really don't think that's the reason.

@Gorkde
Copy link

Gorkde commented Jul 4, 2016

Did some further investigation.

When printing in Serial plotter it's easy to see the readings are +/-1 which should be normal but once the Wifi is enabled and connected it seems to have a constant minimal positive voltage offset that's causing the problem (no longterm fluctuations fir me, they probably are Vcc related).

So I get 6 +/-1 from then on most of the time.

Tried some Capacitors (100nF and/or 10uF) soldierd directly to Vcc/GND, as well GPIO0, GPIO2, GPIO15 to GND. Same readings.

Therfore I really don't think thats a voltage regulator issue, maybe defective Modules or really some kind of bug in ADC.

@igrr
Did you test with 12E? Do you have 12F that you could test?

@Others
Which Voltage regulator do you use?
Which ESP module do you use? 12E or 12F or other?

@igrr
Copy link
Member

igrr commented Jul 4, 2016

I tested with an ESP8266 mounted onto a test board, I can repeat with a NodeMCU which has ESP12F on it. Could you please post your sketch so that our tests happens in the same conditions?
Thanks.

@Gorkde
Copy link

Gorkde commented Jul 4, 2016

ADC is Grounded and reading should be 0/1

Once I do WiFi.disconnect() every reading is ok again.

// ***** Print ADC Reading *****
#include <ESP8266WiFi.h>

void setup()
{
  Serial.begin(115200);
  WiFi.begin(ssid, pass);
}

void loop()
{
  int ReadingADC = analogRead(0);
  Serial.println(ReadingADC);
  delay(200);
}

readings

@Gorkde
Copy link

Gorkde commented Jul 4, 2016

I mounted my ESP on a pcb along with 100nF (also tried 10uF additional) which is plugged in my breadboard.

Voltage is supported by a LM1117V33 with 100nF input and 10uF or 470uF at the output (tried all possible means). VCC of the ESP is connected by a switch (tried with direct connection as well, same result). Also tried on a seperate Breadboard with no other Hardware than Voltage regulator ESP and Caps.

While testing I also noticed the ESP-VCC drops from 3.3V to 3.2 or even 3.0 (at random for each start) as I apply VCC to the ESP (no matter what, the voltage regulator cannot get it up again). Even with very big capacitors directly at ESP-VCC and Voltage regulator directly at the ESP the Voltage drops.

My Voltage regulator is supplied by an 1A power adapter which I tried setting to lower or higher voltage. Doesen't change anything. Also the input voltage doesn't break in below 7V so that's not the problem. Tried another power adapter as well, no change.

The Voltage regulator is rated 800mA so either the ESP is drawing more than that (which shouldnt be the case) or there's some other thing going on that I can't locate with my means of measuring.

But as soon as WiFi connects the voltage goes up to normal 3.3V again.

So at the mysterious voltage drop before connecting I get correct readings (also when ADC is not Grounded but set to any voltage like 0,5V) but when WiFi connects and VCC gets to normal the reading starts getting an offset.

I got no parts here to try ESP12E or another voltage regulator but ordered them. This will take 3 at least 3 weeks until they arrive.

@Gorkde
Copy link

Gorkde commented Jul 4, 2016

For what I can measure the ESP draws around 20-70mA

@lrmoreno007
Copy link
Contributor

Have you tried with a simple condenser?

@RudyFiero
Copy link

The noise is not random and does not average around the true value. So a capacitor will not necessarily provide the correct result. If it were consistent then it would be easier to compensate for the deviations.

@leon-v
Copy link

leon-v commented Sep 13, 2017

My findings for this were that the internal WiFi circuitry is coupling to the ADC reference of the ADC.
most of the solutions here changed the behavior of the WiFi, which would change what the ADC did, but were not a reliable solution because the chip would just use current at other times..
This is why the system_adc_fast_read() required you to disable interrupts and turn off Wifi.

I might try use it without turning off Wifi and computing the results...

Also, why is the minimum value the correct one? All my tests show that the highest one is the correct one. Unless my LiPo batter really is dropping to 2.3V and up to 3.7V :-p

Note: I am not using Arduino. I use the ESP8266_NONOS_SDK_V2.0.0

I will try to look for some way to interrupt the ic when its not drawing current, like the start of an incoming WiFi packet, assuming its synchronous.
Any one got any idea on this?

Or Does anyone know how the WiFi circuity can be properly decoupled from the ADC?

@leon-v
Copy link

leon-v commented Sep 14, 2017

OK.. My ideas worked with varying degrees if failure..
My first idea was to use system_phy_set_max_tpw() to make WiFi use less current.. Which sort of worked, but made other things unstable.

I next tried to use wifi_status_led_install() to toggle a pin based on activity, then only used the ADC when that pin was low.. Which again worked, but not as well as i would have expected if that was the issue.

So i tried to hold the CH_PD pin low, which helped a lot, since my design was toggling GPIO14 next to CH_PD, there was noise coupling onto CD_PD and the IC was slowing or stuttering for a bit which was one issue.

I then thought "what if my big fat capacitor does need to be closer to the module?"
I had it in line with short feed wires, but that doesn't seem to be enough.
Putting a big capacitor right on the VCC and GND of the module fixed my issue.
And i must say i am surprised at how much decoupling the ESP8266 needed.
Or maybe i created a resonant circuit ?

Anyway.. My statement above was wrong. And i did have supply decoupling issues.

@timmclaurin
Copy link

I think it is a hardware problem due to the floating nature. It is like we need a clean reference via a diode... Not saying it can't be accomplished via software just over my head. ;/

@devyte
Copy link
Collaborator

devyte commented Oct 17, 2017

Closing this, because so far I don't really see a possible action within the core. If that changes, please open a new issue with the relevant details, and reference this one.

@dynek
Copy link

dynek commented Aug 24, 2018

So everyone gave up having a stabilised ADC on the ESP8266?
I have tried everything I read in this thread and nothing helped.
Even worse, flashing same code gives different values each time, also if I power it off and on again, different values (jumping from 600-ish to 700-ish).

@leon-v
Copy link

leon-v commented Aug 24, 2018

My issues were related to interrupts firing and sleep states. From memory, when I put the ADC conversion code inside a task, instead of an interrupt handler, all was OK. And I added proper decoupling capacitors. The ones I was using were not small enough.

@dynek
Copy link

dynek commented Aug 24, 2018

2018-08-24 at 10 49 pm

setup is made of

WiFi.disconnect();
wifi_set_sleep_type(NONE_SLEEP_T);

and reading analog in loop

float analog = 0;
analog = analogRead(A0);
delay(1);
analog = analogRead(A0);
analog = analogRead(A0);
Serial.println(analog);
Serial.print(" ");
delay(1000);

@timmclaurin
Copy link

Yeah, I gave up and used an external adc. I only needed one input, too. Super sad. looking for a different chip to produce my product. Amazing insight in this thread, but we need a stable pin with wifi on.

@devyte
Copy link
Collaborator

devyte commented Aug 25, 2018

Not really given up, just stopped discussing for a while.
As a side note, my own experience with the esp12e is not as described here, at least as far as I've noticed. For me it's pretty stable, and I'm reading over wifi via webserver.

@dynek
Copy link

dynek commented Aug 27, 2018

This was from an ESP-07 and I can't seem to find a way to have "not too bad" results :-|

@dynek
Copy link

dynek commented Sep 12, 2018

OK got something not too bad with a 0.1uF cap between the ADC and GND... not perfect but much better so far.

@timmclaurin
Copy link

timmclaurin commented Sep 12, 2018 via email

@dynek
Copy link

dynek commented Sep 12, 2018

2018-09-12 at 9 27 pm

As I said not perfect but better. Readings fluctuate less and if I power off and on the device I have close to identical results. It wasn't the case before.

@dynek
Copy link

dynek commented Sep 12, 2018

Just removed one of the cap to use an external antenna instead:
https://www.esp8266.com/viewtopic.php?p=35604

And it seems to also improve things... There are still weird results though:
2018-09-12 at 9 39 pm

@dynek
Copy link

dynek commented Sep 18, 2018

Just gave an ADS1115 a try and it's damn stable :-)

@wzaggle
Copy link

wzaggle commented Oct 11, 2018

I finally got pretty stable results using...

extern "C" {
    #include "user_interface.h"
}

int getAnalog() {
    unsigned int total = 0;
    wifi_set_opmode(NULL_MODE);
    system_soft_wdt_stop();
    ets_intr_lock( ); 
    noInterrupts();
    total = system_adc_read();
    interrupts();
    ets_intr_unlock(); 
    system_soft_wdt_restart();
    return total;
}

aminurmi added a commit to aminurmi/LandXcape_WemosD1Pro that referenced this issue Apr 27, 2020
…sor values is taken -> see esp8266/Arduino#2070,

	Updated to ESP 2.6.3 version for the .bin file
aminurmi added a commit to aminurmi/LandXcape_WemosD1Pro that referenced this issue May 3, 2020
…e logFileSplitSize (which is currently set to 9kb) -> meaning log file grows up to 11kb and is then shortend to 9kb and so on

Bin File: ESP8266 Arduino Board Config updated to 2.7.0
Internal: Moved back to readable hmtl sites within code (enough ram availble)
System: LogFiles reworked for better readablity with a uniform timeStamp at the beginning
BugFix: Starting Robi although not within the given Mow from to timeframe
Sensor readings: Reduced to 70 to take the smallest one -> see bug: esp8266/Arduino#2070
Sensor readings: Update frequency set to every 3 sec instead of previous 5 sec
@BEMBELmotorsport
Copy link

After a lot of research i found out that the flucuating reading on pin A0 only appears if delay is used in the code. If timing is done with a non blocking pattern, the readings of pin A0 are stable.

Here are my code examples and the resulting values

Using delay:

#include <Arduino.h>
#include <ESP8266WiFi.h>


constexpr unsigned long kIntervalAnaloReadMS { 50 };


void setup() {

    // Start serial connection
    Serial.begin(115200);

    // Connect WiFi - use your own wifi ssid and password
    WiFi.begin("****", "****");

    // wait for WiFi to connect
    while (WiFi.status() != WL_CONNECTED) {
        delay(50);
    }
    
}


void loop() {

    // Print time and current voltage of Pin A0
    Serial.print(millis());
    Serial.print(',');
    Serial.println(analogRead(A0));

    // Wait
    delay(kIntervalAnaloReadMS);

}

Using a non blocking pattern:

#include <Arduino.h>
#include <ESP8266WiFi.h>


constexpr unsigned long kIntervalAnaloReadMS { 50 };


void setup() {

    // Start serial connection
    Serial.begin(115200);

    // Connect WiFi - use your own wifi ssid and password
    WiFi.begin("****", "****");

    // wait for WiFi to connect
    while (WiFi.status() != WL_CONNECTED) {
        delay(50);
    }
    
}


void loop() {

    // Initialize time referece of last reading to 0 on startup
    static unsigned long t_last_reading_ms { 0 };

    // Check if time intervall is elapsed
    if ((millis() - t_last_reading_ms) >= kIntervalAnaloReadMS) {

        // Update time reference of last reading
        t_last_reading_ms = millis();

        // Print time and current voltage of Pin A0
        Serial.print(millis());
        Serial.print(',');
        Serial.println(analogRead(A0));

    }
    
}

The resulting values:
analogValues

I hope this can be useful for you

@BetaAthe
Copy link

BetaAthe commented Dec 16, 2023

Adding to this: Yielding for some time before reading pin A0 also results in more stable readings.

void loop(void) {
  unsigned long loop_time = millis();

  // Yielding for 100ms
  while(millis()-loop_time<100){
    yield();
  }
  Serial.println(analogRead(A0));

  // Wait with delay
  delay(1000);
}

@matik001
Copy link

matik001 commented Aug 4, 2024

@BetaAthe Thank You, I love you
I tried huge capacitors, I also didn't have any blocking sleep in code. I even though about switching esp32, but this fixed the issue completely

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

No branches or pull requests