Cautions In Using ESP32 ADC

 Cautions-in-Using-ESP32-ADC

ESP32 series has been popular these days, and I have made a lot of ESP32-related boards, but, there actually some problems we encountered, the most problem is its ADC.

ESP32 series (ESP32/S2/S3/C3...) has 2 SAR(Successive Approximation Register) ADC with 12 bits, with 3.3V power supply. In one application, I need to A/D some small& sensitive signals, I found its ADC was not precise, so I checked its ADC result, with Arduino IDE.

I used the analogReadMilliVolts() provided by ESP32 producer espressif, Its detailed explanation at:
https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/adc.html
analogReadMilliVolts
int vol_direct = analogReadMilliVolts(ADC_PIN);
The result seems not good, with average error 45mV, and Variance (with excel:=varp())2535.
analogReadMilliVolts-Result

ESP32-AD-Error
Most A/D error takes place when the voltage is close to 0 or 3.3V. But even near voltage 2V, the max error is up to 100 mV.

The same method for ESP32-S3 and ESP32-C3:
ESP32-S3-AD-Error

ESP32-C3-AD-Error

For both the S3 and C3, the most error happens at 2.5~3V, the max voltage error is up to 250mV and 500 mV. That is, they can not be used for most applications that need a previse ADC.

As a contrast, I measured the RP2040 and Atmega328P:
● RP2040, average error 8.4mA, with variance 13; max error 15mV at about 2.7V;
RP2040-AD-Error

 Atmega328P, average error 16 mV, with variance 372; max error 50mV;
Atmega328p-AD-Error

So, with Arduino IDE:
 
Average error(mV)
Error Variance
Max error(mV)
Points with max error
ESP32
45
2535
150
0V~0.1V/3.2V~3.3V
ESP32-S3
37
5573
250
3V
ESP32-C3
200
24746
500
2.7V
RP2040
8
13
15
2.7V
Atmega328P
16
372
55
4.9V~5V

It shows that compares to RP2040/ Atmega328P, the ESP32/ ESP32S3 ADC accuracy is worse. If you have to use them, do not make it works near zero or full voltage.

Do not trust the result of ESP32-C3.

Besides, the ESP32 producer espressif provides a calibration method in its default IDF development with esp_adc_cal_raw_to_voltage():
Check the source here.
esp_adc_cal_raw_to_voltage

I use the adcx_get_raw() to A/D the signal, and then the adc_cal_raw_to_voltage() to calibrate it. the code:
 while (1) {
        uint32_t adc_reading = 0;
        //Multisampling
        for (int i = 0; i < NO_OF_SAMPLES; i++) {
            if (unit == ADC_UNIT_1) {
                adc_reading += adc1_get_raw((adc1_channel_t)channel);
            } else {
                int raw;
                adc2_get_raw((adc2_channel_t)channel, width, &raw);
                adc_reading += raw;
            }
        }
        adc_reading /= NO_OF_SAMPLES;
        //Convert adc_reading to voltage in mV
        uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
        printf("Raw: %d\tVoltage: %dmV\n", adc_reading, voltage);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
Its output:
ESP32-AD-Error-with-Calibration-in-IDF

The average error is 12, with variance 2440, max error is up to 150mV, still not good. But if we only set it working in 0.1~3.1V, the result is much better:
ESP32-AD-Error-with-Calibration-in-IDF-in-0_1-3_2V

Its average error is 18 mV, with variance 53, max error 30 mV, even better than that with Atmega328P.
 
Average error(mV)
Error Variance
Max error(mV)
Points with max error
ESP32
45
2535
150
0V~0.1V/3.2V~3.3V
ESP32-S3
37
5573
250
3V
ESP32-C3
200
24746
500
2.7V
RP2040
8
13
15
2.7V
Atmega328P
16
372
55
4.9V~5V
ESP32(with official calibration)
12
2440
150
0V~0.1V/3.2V~3.3V
ESP32 in 0.1V~3.2V(with official calibration)
18
53
30
2.5V

So, my conclusion:
1. Do not trust ESP32 C3 ADC;
2. If you need to use ESP32 ADC, use the espressif official SDK (I used v4.4, do not tested the latest version) esp_adc_cal_raw_to_voltage() for calibration; and avoid to use ESP32 ADC at 0~0.1V and 3.1~3.3V. With these notes, the ESP32 ADC can be good same as that with Atmega328P;
3. RP2040 ADC the best.

If you have any further questions about the ESP32 ADC, please contact service@makerfabs.com.wink

Comments