Language: EN

esp32-adc

How to use the ADC analog inputs in an ESP32

All ESP32 models come with two ADCs (analog-to-digital converter) SAR (Successive Approximation Register) of 12 bits, referred to as ADC1 and ADC2.

With a resolution of 12 bits, a resolution of 3.3 volts / 4096 units, is equivalent to 0.8 mV per step. Additionally, we can programmatically configure the resolution of the ADC and the channel range.

The maximum allowable voltage is 3.3V. Although many GPIOs of the ESP32 are 5V tolerant, the ADC is not. So do not apply more than 3.6V to a pin used as an analog input, or you will damage the ADC.

The number of pins will depend on the model of ESP32 we are using. For example, the ESP32 has 18 pins, organized as follows,

  • ADC1 connected to 8 GPIOs (32-39)
  • ADC2 connected to 10 GPIOs (0, 2, 4, 12-15, and 25-27)

While an ESP32-S3 has 20 analog pins, organized as,

  • ADC1 connected to 10 GPIO (1-10)
  • ADC2 connected to 10 GPIO (11-20)

Moreover, depending on your development board, not all may be available on your board. When in doubt, consult the documentation for your specific model. read more

Very important, ADC2 is used by the Wi-Fi module, so we cannot use the ADC2 pins when Wi-Fi is enabled. If your project requires Wi-Fi, use only the ADC1 pins.

How to Read the Analog Input of the ESP32

Under the Arduino environment, reading an analog input on the ESP32 is exactly the same as how we would do it on a “conventional” Arduino.

We simply have to use the function analogRead(GPIO). It accepts as its only argument the pin number to which the sensor is connected.

For example, this is how we would read the analog value from pin A0 and display it over the serial port,

void setup() 
{
  Serial.begin(9600);
}

void loop() 
{
  int sensorValue = analogRead(A0);
  Serial.println(sensorValue);
  delay(100);
}

Otherwise, the operation is similar to the analog inputs in Arduino. We can read voltages and resistances or potentiometers.

More Useful Functions

In addition to the normal functionality that we would find in a “normal” Arduino, the ESP32 offers these additional functions,

// Set the sample bits and resolution.
// Can be a value between 9 (0 – 511) to 12 bits (0 – 4095).
// Default resolution: 12 bits.
analogReadResolution(resolution);

// Set the sample bits and resolution.
// Can be a value between 9 (0 – 511) to 12 bits (0 – 4095).
// Default resolution: 12 bits.
analogSetWidth(width);

// Set the number of cycles per sample.
// Default value: 8. Range: 1 to 255.
analogSetCycles(cycles);

// Set the number of samples in the range.
// Has the effect of increasing sensitivity.
// Default value: 1 sample.
analogSetSamples(samples);

// Set the divisor for the ADC clock.
// Default value: 1. Range: 1 to 255.
analogSetClockDiv(attenuation);

// Set the input attenuation for all ADC pins.
// Default value: ADC_11db.
// Accepted values:
// - ADC_0db: no attenuation
// - ADC_2_5db: extended attenuation
// - ADC_6db: extended attenuation
// - ADC_11db: extended attenuation
analogSetAttenuation(attenuation);

// Set the input attenuation for the specified pin.
// Default value: ADC_11db.
// Attenuation values are equal to the previous function.
analogSetPinAttenuation(pin, attenuation);

// Attach a pin to the ADC (also clears any other analog mode that may be active).
// Returns a TRUE or FALSE result.
adcAttachPin(pin);

// Starts an ADC conversion on the associated pin bus.
// Checks if the conversion on the pin's ADC bus is currently in progress.
// Returns TRUE or FALSE.
// Gets the conversion result: returns a 16-bit integer.
adcStart(pin);
adcBusy(pin);
adcEnd(pin);

ADC Attenuation Values

To perform the measurement, the ESP32 compares the voltage we want to measure with a reference value Vref that, by design, is 1.1V.

To allow measuring a range of higher voltages, the ESP32 employs a variable gain attenuation circuit. (at -11dB, which is the default value to measure up to 3.3V).

The behavior of the ADC of the ESP32 in its different variants has never been one of its strong points. See below ‘ADC Precision’. Therefore, the manufacturer recommends some “optimal” values for the voltages we can measure with the ADC.

ESP32 Attenuation Values

AttenuationPreferred voltage range
ADC_ATTEN_DB_0100 mV ~ 950 mV
ADC_ATTEN_DB_2_5100 mV ~ 1250 mV
ADC_ATTEN_DB_6150 mV ~ 1750 mV
ADC_ATTEN_DB_11150 mV ~ 2450 mV

ESP32-S3 Attenuation Values

AttenuationPreferred voltage range
ADC_ATTEN_DB_0100 mV ~ 950 mV
ADC_ATTEN_DB_2_5100 mV ~ 1250 mV
ADC_ATTEN_DB_6150 mV ~ 1750 mV
ADC_ATTEN_DB_11150 mV ~ 2450 mV

Precision of the ADC in the ESP32

Much has been said, and not for the better, about the precision of the ADC of the ESP32. The truth is that, traditionally, it is not one of the strong points of the ESP32.

However, many of the things that have been said are no longer valid today, and apply only to the “normal” ESP32 (not to S2, S3… etc).

The problem with the ESP32 is that, as mentioned before, the ESP32 compares with an internal Vref value of 1.1V. However, the boards come with different variations that make that 1.1V actually range from 1.0 to 1.2V.

On the other hand, at -11dB, the default attenuation value to measure up to 3.3V, the attenuation circuit introduces a strongly nonlinear behavior.

That is to say, the response we have looks somewhat like this. Quite messy when we operate at -11dB.

esp32-adc-response

It is possible to calibrate the ESP32 to improve the behavior of the ADC. Here you have a good repository that explains how to calibrate it easily GitHub - e-tinkers/esp32-adc-calibrate.

However, what is usually not mentioned is that since 2019, the ESP32s come factory pre-calibrated and the code was changed to add a software correction. Therefore, the behavior is considerably better.

On the other hand, in the case of the ESP32-S3, the situation is different. This model includes an internal hardware calibration chip, so the response of the ESP32-S3 looks something like this.

esp32-s3-adc-response

Which is much better than what we had in the old ESP32 (without version).

Finally, even in the old model, the importance of the lack of precision of the ESP32 should be relativized, depending on what you truly need in your project.

That is, if you want the ADC, for example, to read a potentiometer and change the brightness of an LED, or the speed of a motor, it will probably work perfectly even if it is not calibrated.

If you need a really precise measurement, you probably should not use the ADC “as is” from any processor, neither the ESP32 nor a “conventional” Arduino.

In that case, you can either perform an ADC calibration or use a high-precision ADC like the AD1115 that we saw in this entry 16-bit analog input with Arduino and ADC ADS1115



References: