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

int vol_direct = analogReadMilliVolts(ADC_PIN);

The result seems not good, with average error 45mV, and Variance (with excel:=varp())2535.

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:

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;

 

Atmega328P, average error 16 mV, with variance 372; max error 50mV;

 

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.

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:

 

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:

 

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