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.