The ESP-12F ADC pin appears to consistently read higher values at times when the processor is not as busy. I worked around this by taking the average of multiple reads, and discarding any averages where the number of samples varied dramatically from expectations.
I’m using an ESP-12F and a TEMT6000 module to measure brightness in an area that also has PWM-modulated LED lighting. I have an AMS1117 providing pretty consistent 3.3V to the circuit and it draws about 41mA. The ESP doesn’t have hardware PWM, so I’m suing the software version with analogWrite(), and I have the PWM frequency set down to about 200Hz because that seems to resolve some flickering issues.
I’m using MQTT (PubSubClient) and the AutoConnect library in my project. I take a brightness measurement every 5 seconds, and, if the resulting value has changed since the previous measurement, I publish the result to a related MQTT topic.
I’m using a 10k/4.7k voltage divider to step down the output of the TEMT6000 module to 1.055V. This circuit switches a separate 12V source that drives the LEDs, and that switching is optically isolated.
ADC analogRead() averaging with PWM LEDs
Because the LEDs turn on and off repeatedly to give the effect of dimming, I sample the ADC pin repeatedly for two PWM wavelengths (100Hz) and average the results. This seems to work out pretty well and is reasonably consistent. I get typically about 45 samples during that time in production. I’ll refer to this average in this post as “the value” or “the brightness” — it’s not an instantaneous value, but an average of several samples. This value is scaled to 0-1000 to approximate the number of mV read. I yield() inside of the sample loop as well.
Stability Techniques Already Employed
I have a 0.1uF tantallum across the ADC pin and GND, and when I sample the ADC pin, I do it twice in a row, ignoring the first sample, because I read somewhere that the first sample can be a bit inconsistent sometimes.
From time to time I observed pretty erratic ADC fluctuations, notably right after start-up, and then periodically throughout the day. I haven’t taken the time to figure out if there’s a larger pattern here, but while I was debugging this I started writing out the number of samples actually taken when calculating the brightness value. That’s when I discovered a positive correlation between samples taken and brightness value.
The PWM duty cycle is consistent, as is the length of time I take samples for each reading. In this graph, I was doing some extra serial communication, so the number of samples per 100Hz period is lower than the ~45 or so I consistently get in production.
I used my KORAD KA3005P to feed 0.05V to the ADC pin for this test. Note that a value of 61 is usually read when the number of samples is lower than 40, but that value goes up to 68 when the number of samples if over 70. I ruled out a math error — each individual reading does in fact average 68 when more samples are taken.
Although I wasn’t able to correlate things like WiFi status with this variation, my guess is that the power used for wireless communication is affecting the ADC readings — when the ESP12F isn’t very busy and can take more samples in the allotted time, then the voltage it reads is a tiny bit higher (~7mV). It’s not a lot, but when you values you expect to see only range 1-60 or so, then it’s significant.
I still haven’t nailed down the exact problem, and I’m not sure I even want to spend the time doing that if this work-around works out, but here’s how I chose to resolve this:
- I’ve added some code that compares the number of samples actually taken to the number of samples I expect (those that provide a more consistent result).
- If this “expected sample count” value is zero, then I’ll let the circuit operate normally, and report out the number of samples taken with each reading. This will allow me to figure out how many samples to expect in production.
- When the “expected sample count” value is greater than zero, I basically just ignore the reading and pretend it hasn’t changed from the previous reading.
This seems to do a great job of smoothing out these erratic ADC fluctuations and providing more consistent brightness readings for my application. I hope others will find this helpful, too, and I’ll update here if I decide to look into it further.