ESP32 In MicroPython: Analog Input
Written by Mike James & Harry Fairhead   
Tuesday, 17 October 2023
Article Index
ESP32 In MicroPython: Analog Input
Calibration
How Fast?

Analog input is the way to interface many sensors. This extract is from Programming the ESP32 in MicroPython, part of the I Programmer Library and it shows you how to get accurate readings from the on board ADC.

Programming the ESP32in MicroPython

By Harry Fairhead & Mike James

esppython360

Buy from Amazon.

Contents

       Preface

  1. The ESP32 – Before We Begin
  2. Getting Started
  3. Getting Started With The GPIO 
  4. Simple Output
  5. Some Electronics
  6. Simple Input
  7. Advanced Input – Interrupts
  8. Pulse Width Modulation
       Extract:
    PWM And The Duty Cycle
  9. Controlling Motors And Servos
  10. Getting Started With The SPI Bus
  11. Using Analog Sensors
       Extract:
    Analog Input
  12. Using The I2C Bus
       Extract
    : I2C, HTU21D And Slow Reading 
  13. One-Wire Protocols
  14. The Serial Port
  15. Using WiFi
     Extract:
    WiFi 
  16. Sockets
     Extract:
    Client Sockets
     Extract:
    SSL Client Sockets
  17. Asyncio And Servers
     Extract:
    Asyncio ***NEW!
  18. Direct To The Hardware
     Extract:
    Using Hardware Registers 

<ASIN:187196282X>

The ESP32 has a wide range of analog capabilities. It has two A-to-D converters (ADCs) and two D-to-A converters (DACs) connected to specific GPIO pins. In addition, it has a set of capacitive input lines which can be used as touch sensors.

ESP32 ADC

The ESP32 has two 12-bit onboard ADCs, ADC1 supports 8 channels and ADC2 supports 10 channels. The only problem is that the WiFi uses one of the two channels, ADC2, and hence its use is best avoided unless you turn WiFi off or use it only when the WiFi is inactive.

The GPIO lines that can be used by the ADC are fixed. ADC 1 can use GPIO32 to 39 and ADC 2 can use GPIO 0, 2, 4, 12-15 and 25-27. In practice not all of these lines can be used. Of the 8 ADC1 channels only 6 are available on development boards. So even though the hardware seems to offer 18 ADC inputs this is actually reduced to six that are easy to use:

  • GPIO 32 ADC1_CH4 Hall Sensor

  • GPIO 33 ADC1_CH5 Hall Sensor

  • GPIO 34 ADC1_CH6 Input Only

  • GPIO 35 ADC1_CH7 Input Only

  • GPIO 36 ADC1_CH0 Input Only

  • GPIO 39 ADC1_CH3 Input Only

GPIO 36 and 39 are also used to read the built-in Hall sensor, see later, and are also best avoided.

The ADC is a successive approximation converter. You don't need to know how it works to use it, but it isn't difficult to understand. The input voltage is compared to a standard voltage, VREF. First a voltage equal to VREF/2 is generated and the input voltage is compared to this. If it is lower then the most significant bit is a 0 and if it is equal or greater then the most significant bit is a 1. At the next step the voltage generated is VREF/2+VREF/4 and the comparison is repeated to generate the next bit. Successive approximation converters are easy to build, but they are slow.

The ESP32 ADC uses a reference voltage that is generated on-chip and varies between 1000mV and 1200mV. Since 2018 ESP32 chips have the reference voltage burned into the eFuse memory and this makes calibration a matter of reading the value and using it to correct the result. The easiest way to discover if the device you are using has calibration data is to use espefuse.py which is installed along with esptool.py and can be used to read and write the eFuse memory. This is a non-volatile write-once memory that you can use to record small amounts of configuration data, but it is better to avoid using it with MicroPython as there is no easy-to-use interface. It can also damage the ESP32 if you change the wrong bits as once set to 1 a bit cannot be changed back to 0. To discover the calibration data use:

python espefuse -p COM6 adc_info

replacing COM6 with the serial port that the ESP32 is connected to. If no calibration data is available you will see:

ADC VRef calibration: None (1100mV nominal)

and the best you can do is assume the middle value for the reference voltage. If there is calibration data you will see a single point calibration:

ADC VRef calibration: 1149mV

and you might also see a two-point calibration for each channel:

ADC readings stored in efuse BLK3:
    ADC1 Low reading  (150mV): 306
    ADC1 High reading (850mV): 3153
    ADC2 Low reading  (150mV): 389
    ADC2 High reading (850mV): 3206

If you want to automate the correction you can read the eFuse memory directly from MicroPython:

from machine import mem32
def getVCal():
    VC=(mem32[0x3FF5_A010]>>8)& 0x1F
    if(VC & 0x10 ):
        VC=-(VC & 0x0F)
    return 1100+VC*7
print(getVCal())

The calibration value is stored as a 5-bit sign-magnitude value in increments of seven and as an offset from 1100 – the middle of the range. The calibration is used by MicroPython to get a more accurate result.



Last Updated ( Tuesday, 17 October 2023 )