ESP32 analogRead attenuation and accuracy

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
Post Reply
User avatar
liudr
Posts: 211
Joined: Tue Oct 17, 2017 5:18 am

ESP32 analogRead attenuation and accuracy

Post by liudr » Mon Feb 21, 2022 4:00 am

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.

KJM
Posts: 158
Joined: Sun Nov 18, 2018 10:53 pm
Location: Sydney AU

Re: ESP32 analogRead attenuation and accuracy

Post by KJM » 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.

User avatar
liudr
Posts: 211
Joined: Tue Oct 17, 2017 5:18 am

Re: ESP32 analogRead attenuation and accuracy

Post by liudr » Mon Feb 21, 2022 8:19 pm

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.

KJM
Posts: 158
Joined: Sun Nov 18, 2018 10:53 pm
Location: Sydney AU

Re: ESP32 analogRead attenuation and accuracy

Post by KJM » Mon Feb 21, 2022 10:59 pm

Check the graph about half way down the page https://randomnerdtutorials.com/esp32-p ... nce-gpios/

User avatar
scruss
Posts: 360
Joined: Sat Aug 12, 2017 2:27 pm
Location: Toronto, Canada
Contact:

Re: ESP32 analogRead attenuation and accuracy

Post by scruss » 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

User avatar
liudr
Posts: 211
Joined: Tue Oct 17, 2017 5:18 am

Re: ESP32 analogRead attenuation and accuracy

Post by liudr » Fri Mar 04, 2022 10:33 pm

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.

davef
Posts: 811
Joined: Thu Apr 30, 2020 1:03 am
Location: Christchurch, NZ

Re: ESP32 analogRead attenuation and accuracy

Post by davef » Fri Mar 04, 2022 10:37 pm


Pivert
Posts: 5
Joined: Fri Aug 10, 2018 1:00 pm

Re: ESP32 analogRead attenuation and accuracy

Post by Pivert » Sun Aug 28, 2022 10:02 am

Also check this excellent article about accuracy of the ESP32 ADC

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

Post Reply