In addition to the known and disclosed problem with linearity, there is also a considerable problem with noise.
With a pot connected and not moving, readings vary +/- 5%. A large cap (47uF) across the input makes no difference.
Essentially this ADC appears to be useless except for the most gross measurements.
Am I missing something?
Hello Daniel, unfortunately what you said is true.
The ESP32 ADC in non-linear and fails in accuracy.
It’s quite frustrating having a 12 bit ADC if its accuracy is so bad and it has so much noise.
For accurate measurements it’s definitely not recommend to use…
If what you are trying to measure is approximately 1/2 of the supply voltage, say a battery with a 10K/10K resistor divider this might be of help. Create another 10K/10K resistor divider between the 3.3v supply and ground and measure it with another ADC input. The result will be the value the ADC thinks is 1/2 of the supply voltage. Use that to correct the battery voltage reading. See below:
#define REF_mV 3300 // mV
// Read & return the battery voltage in milliVolts.
// Both the battery & supply voltages are halved
// using resistor dividers. This is done to get the ADC
// values in mid-range because of the non-linearities
// at the upper range.
// Get the reference supply voltage / DIV_VALUE
REF_ADC = analogRead(REF_PIN);
// Get the battery voltage / DIV_VALUE
BAT_ADC = analogRead(BAT_PIN);
// Calculate and return the battery voltage in milliVolts
return ((BAT_ADC * REF_mV) / REF_ADC);
Thanks for sharing that. That can be very useful for our readers.
We need to try that and see our results.
A few technical details may complement this discussion:
Analog to Digital Converter (by Espressif)
In particular, take a look at the following sections:
- Minimizing Noise
- ADC Calibration
I’ve read through that, unfortunately the calibration step is non-trivial and is required for each individual ESP32. The voltage divider method described above does reduce the resolution some but is as accurate as the 3.3v supply voltage. It is also generally limited to the lower two thirds of the ADC input range. Not ideal but simple to implement and generally good enough in many cases.