Page 1 of 1

ESP32 analogRead attenuation and accuracy

Posted: Mon Feb 21, 2022 4:00 am
by liudr
I read from here that there are several attenuation levels of the ADC:

https://docs.micropython.org/en/latest/ ... conversion

On the other hand, random nerd tutorials has a different set of ranges with the same attenuation levels:

https://randomnerdtutorials.com/esp32-e ... cropython/

ESP32 MP doc:
ADC.ATTN_11DB: 11dB attenuation (150mV - 2450mV)

Random nerd:
ADC.ATTN_11DB — the full range voltage: 3.3V

My tests show that Random nerd is possibly correct. The results are a bit off. My supply measures 3.29V so I'm only 0.3% less than 3.3V. But my readout is 0.16V less than my Fluke meter. This isn't from the 2.45V vs 3.3V I think.

So I read further on ESP32 MP doc:
ADC.read_uv()¶

This method uses the known characteristics of the ADC and per-package eFuse values - set during manufacture - to return a calibrated input voltage (before attenuation) in microvolts. The returned value has only millivolt resolution (i.e., will always be a multiple of 1000 microvolts).

The calibration is only valid across the linear range of the ADC. In particular, an input tied to ground will read as a value above 0 microvolts. Within the linear range, however, more accurate and consistent results will be obtained than using read_u16() and scaling the result with a constant.
So this ADC.read_uv(), it doesn't exist in 1.17 firmware. I tried 1.18. It's not there either. i wonder if this is just an issue with the document maybe copy-pasted from pyboard. The call class ADC(pin, *, atten) also doesn't work. It only takes 1 parameter. So under the current scenario, is there any way to read voltages more accurately? Thanks.

Here is another reference from sparkfun saying a 0.2V discrepancy. My issue isn't the 0.2V. I have a voltage divider with 510K/100K to read 12V battery voltages. That scaling makes 0.2V scale to over 1V of difference. I wish I could make more accurate reading using factory calibration.

Re: ESP32 analogRead attenuation and accuracy

Posted: Mon Feb 21, 2022 7:41 am
by KJM
I've wound up the voltage at the analog inputs of several ESP32s set to ATTN_11DB over the years. I found the max 4095 count is reached at around 3.13v on my Fluke87.

Re: ESP32 analogRead attenuation and accuracy

Posted: Mon Feb 21, 2022 8:19 pm
by liudr
KJM wrote:
Mon Feb 21, 2022 7:41 am
I've wound up the voltage at the analog inputs of several ESP32s set to ATTN_11DB over the years. I found the max 4095 count is reached at around 3.13v on my Fluke87.
So maybe the high and low ends of the voltage range doesn't go linear enough. What about the mid section like say 2V? Is 2V represented by 2/3.3*4096?

Thanks.

Re: ESP32 analogRead attenuation and accuracy

Posted: Mon Feb 21, 2022 10:59 pm
by KJM
Check the graph about half way down the page https://randomnerdtutorials.com/esp32-p ... nce-gpios/

Re: ESP32 analogRead attenuation and accuracy

Posted: Tue Feb 22, 2022 4:59 am
by scruss
liudr wrote:
Mon Feb 21, 2022 4:00 am
So this ADC.read_uv(), it doesn't exist in 1.17 firmware. I tried 1.18. It's not there either. i wonder if this is just an issue with the document maybe copy-pasted from pyboard. The call class ADC(pin, *, atten) also doesn't work. It only takes 1 parameter. So under the current scenario, is there any way to read voltages more accurately? Thanks.
It came out after 1.18, so is in the nightlies:

Code: Select all

from machine import ADC, Pin
import os

print(os.uname())
a=ADC(Pin(33))
a.atten(ADC.ATTN_11DB)
print(a.read_uv()/1e6)
which gives:

Code: Select all

(sysname='esp32', nodename='esp32', release='1.18.0', version='v1.18 on 2022-02-22', machine='ESP32 module with ESP32')
0.142

Re: ESP32 analogRead attenuation and accuracy

Posted: Fri Mar 04, 2022 10:33 pm
by liudr
scruss wrote:
Tue Feb 22, 2022 4:59 am
liudr wrote:
Mon Feb 21, 2022 4:00 am
So this ADC.read_uv(), it doesn't exist in 1.17 firmware. I tried 1.18. It's not there either. i wonder if this is just an issue with the document maybe copy-pasted from pyboard. The call class ADC(pin, *, atten) also doesn't work. It only takes 1 parameter. So under the current scenario, is there any way to read voltages more accurately? Thanks.
It came out after 1.18, so is in the nightlies:

Code: Select all

from machine import ADC, Pin
import os

print(os.uname())
a=ADC(Pin(33))
a.atten(ADC.ATTN_11DB)
print(a.read_uv()/1e6)
which gives:

Code: Select all

(sysname='esp32', nodename='esp32', release='1.18.0', version='v1.18 on 2022-02-22', machine='ESP32 module with ESP32')
0.142
Thanks and sorry for the delay. So is this method more accurate than the legacy method? I'll give it a test on a dev board myself when I get some time.

Re: ESP32 analogRead attenuation and accuracy

Posted: Fri Mar 04, 2022 10:37 pm
by davef

Re: ESP32 analogRead attenuation and accuracy

Posted: Sun Aug 28, 2022 10:02 am
by Pivert
Also check this excellent article about accuracy of the ESP32 ADC

https://w4krl.com/esp32-analog-to-digit ... -accuracy/