esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
16.05k stars 13.33k forks source link

Fluctuating ADC with stabilized source #2070

Closed supersjimmie closed 7 years ago

supersjimmie commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

No drift, just random noise mostly within 1 LSB:

adc_test

supersjimmie commented 8 years ago

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 commented 8 years ago

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

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 commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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

Gorkde commented 8 years ago

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

arizzi commented 8 years ago

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

arizzi commented 8 years ago

how about trying this: https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp#L366

supersjimmie commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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 (https://github.com/esp8266/Arduino/commit/09bb75874deb95c22b4c09e63b842fc1f89eebc3) 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 commented 8 years ago

@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 commented 8 years ago

@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 commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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

supersjimmie commented 8 years ago

My code is really simple:

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

char ssid[] = "SSID";             // SSID of network
char password[] = "password";          // Password of network

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
}

void loop() {
  Serial.println(analogRead(A0));
  delay(10000);
}

I have use both an external voltage regulator and the internal one, as mentioned in my previous postings. I am using two different NodeMCU boards. LoLin and some other. Problem persists, so that does not make any difference too.

supersjimmie commented 8 years ago

(sorry, by mistake I keep pushing the wrong button that closes the issue)

Gorkde commented 8 years ago

Haha! Read the Button before clicking it ;)

Gorkde commented 8 years ago

It seems I solved the Mystery for me.... I get stable 0 readings now with ADC grounded. Not even one 1 in between.

Will check further the next days since I often had things mysteriously working and then failing again...

What I did: 1) I did replace the Voltage regulator by another of the same kind. 2) I used another ESP-12F board (since the old one started failing for no reason. I didn't change the electronic and uploaded my sketch then it started resetting randomly with all kind of crazy reasons. I even reflashed the latest NONOS SDK but could'nt get it stable again) 3) I replaced the power plug by another one (I did try that one before and it had no effect, so this very surely was'nt the reason) 4) I used the shortest possible cable connection directly to the pins of the voltage regulator (which I did before as well)

So probably either the voltage regulator or the ESP were defective since the beginning I suppose. But I'm pretty sure I also tried exchanging the voltage regulator before.

But you never know, will see if I get wrong readings again tomorrow when working with it in more detail.... Wouldn't be the first time this happens.... Will let you know.

Gorkde commented 8 years ago

Crazy..... did further testing.... Now it's working when ADC is grounded but once I apply any voltage it's the same as before...

unbenannt

Gorkde commented 8 years ago

Just noticed before I got correct readings when WiFi was OFF. Now the correct readings are when WiFi is ON and I get wrong readings when its OFF....

So there must be some difference between the ESP I assume but they are from the same order.... Will see what my soon to arrive ESP12-E will do...

Gorkde commented 8 years ago

Also the ESP before did detect 1.08V as 1024 this one does so for 1.1V

Gorkde commented 8 years ago

Tried the same with my bought Wemos D1. Only external connections were 2 resistors as voltage divider for ADC (GND to 3.3V of Wemos D1) and the USB connection.

Same as with my hardware, so it's pretty sure no hardware issue.

unbenannt

Gorkde commented 8 years ago

@igrr In a similar Issue #338 you wrote: "So we have two groups of users, and two versions. One version works for one group, another works for the rest."

Which (topic and this section) seems to me somewhat related to our problem since

a) One of my modules did read correctly when WiFi was OFF and had a positive ADC offset when WiFi was ON b) The other module (same shipment) did read correctly when WiFi was ON and had a negative ADC offset when WiFi was OFF

(because of the negative offset it seems to read correctly when grounded since there's no way to get more negative than GND)

So could there be some relation?

(Btw... That voltage drop I reported earlier was my faulty measuring since my meters GND was too far away)

Gorkde commented 8 years ago

Exactly the same with the 12-E that arrived yesterday...

unbenannt

Gorkde commented 8 years ago

Anyone made any progress about this?

Gorkde commented 8 years ago

@igrr I totally forgot this can't be a voltage regulator issue since I already in the beginning did test my Wemos D1 clone with only 9V battery and no other connection than this and ADC to GND.

For testing I wrote a sketch that did blink the internal LED if the ADC is fluctuating. I also tried shielding the board with Aluminium foil that was connected to GND. Therefore the only possible cause besides a software issue could have been the ESP12F module. But I did rule that out because I tried and had the same issue.

Therefore could you look into this?

Maybe I could send some ESP module with that behavior if you need it for testing.

igrr commented 8 years ago

Our wrapper around the sdk function is pretty thin, so I don't think there is much room for improvement in Arduino code. I'll pass this on to the SDK team, but given the fact that this is still an issue after almost two years of SDK releases, I don't think much can be done.

Gorkde commented 8 years ago

Thanks. But since it doesn't seem to be a hardware issue I wonder why some people have that issue and others seem to not having that issue at all (like you).

supersjimmie commented 8 years ago

Back from holiday and a bit unhappy to see this issue still exists. Thanks @Gorkde and @igrr for keeping on top of this! I too was using different power sources so I don't think it's the lm1117.

As far as I can remember, my setup had most stable reading while wifi was inactive/off. When having the issue most readings are higher and only some are lower than the rest. Therefor I thought that the highest values should be correct. But now I understand that the lowest values are correct, so only a few...

I ony own 3 NodeMCU boards and a couple of lm1117's, anything you guys would like me to test?

Edit: maybe a strange thought, but it slightly looks like a lot of my wrong values are 32 off. That's one bit wrong, isn't it? That's not for all, but I noticed that many jumps are more-or-less the same difference.

Gorkde commented 8 years ago

As said I remembered I already tested with only battery connected at a WeMos clone, so it can't be the power.

Igrr said its working with his NodeMcu Board so could you test that one?

Doesn't NodeMcu have a different software than this ArduinoESP one? I think I saw another Github for that. If so and it works with that the issue must be in the ArduinoESP software right? They use the same SDK.

supersjimmie commented 8 years ago

I have only NodeMCU boards, which are just normal ESP chips on an easy board. So same chip(s) with same software.

supersjimmie commented 8 years ago

As I said yesterday, it looks like some kind of problem with the bit that stands for 32 decimal (6th bit). So I did a (0xFFDF & analogRead(A0)) to always set this bit to zero, only for testing. This seems to result in a less jumpy output, only now I cannot have values where that bit should have been '1'. This was just to see if it might have to do with that specific bit being the error... And so it seems!

gcarrieri commented 8 years ago

A little workaround to get right adc value and send data over wifi

dofile("config.lua")

retry = 0
data = ''
i = 0

function sendData()
if retry == 0 then wifi.sta.connect() end
  retry = retry + 1
  if retry < 20 then
    print(wifi.sta.status())
    if wifi.sta.status() ~= 5 then
        tmr.alarm(0, 500, 0, sendData)
    else
        local cu = net.createConnection(net.TCP, 0)
        cu:on("connection", function(cu) cu:send(data) end)
        cu:on("sent",function(cu) cu:close() end)
        cu:on("disconnection", function(cu) node.restart() end)
        cu:connect(server_port, server_ip)
    end
  end
end

tmr.alarm(0, 6000, tmr.ALARM_AUTO, function()
    data = data .. '|' .. adc.read(0)
    i = i + 1
    if (i > 9) then
        sendData()
    end    
end)
supersjimmie commented 8 years ago

Thanks @gcarrieri I don't speak lua, the essential part seems to be data = data .. '|' .. adc.read(0)? That just takes some kind of average? I don't understand it fully...

gcarrieri commented 8 years ago

sorry

tmr.alarm(0, 6000, tmr.ALARM_AUTO,

autostart every min the following func

    data = data .. '|' .. adc.read(0)
    i = i + 1
    if (i > 9) then
        sendData()
    end  

data is updated with adc.read(0) [ .. is string concat ] and every 10 times we call sendData

ex.: |818|817|816|818|817|817|816|818|817|817

if retry == 0 then wifi.sta.connect() end
  retry = retry + 1
  if retry < 20 then
    print(wifi.sta.status())
    if wifi.sta.status() ~= 5 then
        tmr.alarm(0, 500, 0, sendData)

first call try to connect, then for 20 times (500ms every time) or connected (~= 5) recall sendData

    else
        local cu = net.createConnection(net.TCP, 0)
        cu:on("connection", function(cu) cu:send(data) end)
        cu:on("sent",function(cu) cu:close() end)
        cu:on("disconnection", function(cu) node.restart() end)
        cu:connect(server_port, server_ip)

if connected, send data and restart (retry, data and i are reinitialized)

remember to disconnect wifi on start!! (wifi.sta.autoconnect(0))

Gorkde commented 8 years ago

I don't understand Lua either.

The crazy thing I had 2 ESP where the correct value was the High reading in general the after WIFI connection. But I tested another one where the correct reading was the lowest and the sparks down after WIFI connected.

My first attempt was to filter this out, read multiple times (100ms al least) and to generaly use the lowest reading. But since the other ESP behaved exactly the other way it works only with some ESP.

How did you filter that bit you suggest might be the problem? Do you have some example code?

Gorkde commented 8 years ago

@gcarrieri I don't understand how this solves the issue since I understand it reads multiple times if WIFI on, then sends the read data right? But this doesn't seem to change or correct the wrong readings? Maybe I didn't understood it correctly.

supersjimmie commented 8 years ago

@Gorkde how much do your correct/incorrect values differ on those two esp's? Are their differences simmilar and possibly also (about) the value of 1 specific bit (1/2/4/8/16/32/...)?

gcarrieri commented 8 years ago

@Gorkde it reads 10 times when WIFI is OFF, with WIFI off adc.read returns right values. After 10 times it connects to wifi and send data, then restart.

Gorkde commented 8 years ago

@supersjimmie They are pretty similar in Value as far as I remember. Habe a look at the graphs I posted above .

@gcarrieri Ok, so that is no workaround I could use a) because reconnect takes way too long for being useful in my project b) as I said I had ESP that had correct reading when Wifi was off, other had them when it was on only.

I suppose that thing about the wrong bit could be something to investigate. At least it would make sense.