Skip to content

What is an ADC?

An ADC (Analog-to-Digital Converter) reads a real-world voltage on a pin and converts it to a number your code can use. The ESP32-S3’s built-in ADC measures voltages between 0V and ~3.1V and outputs an integer from 0 to 4095.

Digital GPIO pins only tell you HIGH or LOW — on or off. But many sensors output varying voltages. Potentiometers, light sensors, analog microphones, flex sensors, soil moisture probes, and temperature sensors all produce continuous analog signals. The ADC is how your code reads those in-between values and turns them into data you can work with.

The ESP32-S3 ADC has 12-bit resolution, which means 2¹² = 4,096 possible values (numbered 0 to 4095). Each step represents approximately 0.8 mV. When the ADC returns 2048, the input voltage is roughly 1.65V — halfway between 0V and 3.3V. When it returns 0, the pin is at 0V. When it returns 4095, the pin is at ~3.1V.

const int sensorPin = 1; // GPIO 1, an ADC1 pin
void setup() {
Serial.begin(115200);
}
void loop() {
int raw = analogRead(sensorPin); // uncalibrated: 0–4095
int mV = analogReadMilliVolts(sensorPin); // calibrated: actual millivolts
Serial.print("Raw: ");
Serial.print(raw);
Serial.print(" | Voltage: ");
Serial.print(mV);
Serial.println(" mV");
delay(200);
}

The ESP32-S3 has two ADC units with 10 channels each (20 total):

UnitGPIO PinsChannels
ADC1GPIO 1–1010
ADC2GPIO 11–2010

Attenuation controls the maximum voltage the ADC can measure. The default (11 dB) covers the full 0–3.1V range. Lower attenuation gives better accuracy over a narrower range.

SettingArduino ConstantMeasurable Range
0 dBADC_0db0 – 950 mV
2.5 dBADC_2_5db0 – 1250 mV
6 dBADC_6db0 – 1750 mV
11 dBADC_11db0 – 3100 mV (default)

If your signal never goes above 1V, using ADC_0db gives you better precision across that range:

analogSetPinAttenuation(1, ADC_0db); // GPIO 1: high accuracy 0–950 mV

The ESP32-S3’s ADC becomes inaccurate above approximately 2750 mV. Past this point, readings compress and stop tracking the actual voltage linearly. At ~3100 mV the output saturates at 4095 — the ADC can’t distinguish 3.1V from 3.3V.

The good news: the ESP32-S3 is much better than the original ESP32 near 0V. The S3 can accurately read voltages very close to ground, while the original ESP32 had a dead zone below ~100 mV.

Practical guideline: Keep input signals between 0V and 2.9V at 11 dB attenuation for reliable results. Expect accuracy within ±30 mV across this range after factory calibration.

Potentiometer (volume knob / position control). Connect the wiper (middle pin) to an ADC1 pin, outer pins to 3.3V and GND. analogRead() gives you the knob position as 0–4095.

Light sensor (LDR). Wire the LDR in a voltage divider with a fixed resistor (10kΩ is common). The ADC reads the changing voltage as light levels shift.

Battery voltage monitoring. LiPo batteries (3.0–4.2V) exceed the ADC’s 3.1V limit. Use a resistor voltage divider — two equal resistors (e.g., 100kΩ each) halve the voltage so 4.2V becomes 2.1V at the ADC pin. Scale the reading back in code:

int mV = analogReadMilliVolts(1);
float batteryV = (mV / 1000.0) * 2.0; // 2.0 = divider ratio

Any analog sensor outputting 0–3.1V — soil moisture, flex sensors, gas sensors, force-sensitive resistors — can be read directly on an ADC1 pin.

Average multiple samples. A single ADC read can be noisy. Reading 16–64 samples and averaging gives much more stable values:

int readAvg(int pin, int samples) {
long sum = 0;
for (int i = 0; i < samples; i++) {
sum += analogReadMilliVolts(pin);
}
return sum / samples;
}

Add a 100 nF capacitor. Solder or place a small ceramic capacitor between your ADC input pin and GND. This filters out high-frequency noise at the hardware level and is recommended by Espressif.

Know when to use an external ADC. The built-in ADC is great for potentiometers, approximate battery levels, and anything where ±2–5% accuracy is fine. For precision measurement (current sensing, load cells, scientific instruments), use an external ADC like the ADS1115 — a 16-bit I2C module (~$4 breakout) with 65,536 levels of resolution and excellent linearity. The tradeoff: the ADS1115 maxes out at 860 samples/second versus ~100,000 for the built-in ADC.

FeatureESP32-S3
Resolution12-bit (0–4095)
ADC1 pins (WiFi-safe)GPIO 1–10
ADC2 pins (no WiFi)GPIO 11–20
Default voltage range0 – 3.1V (11 dB attenuation)
Accuracy (calibrated)±30 mV in usable range
Non-linear above~2750 mV
Best functionanalogReadMilliVolts(pin)
Max sample rate~100,000 samples/sec

Robojax — step-by-step walkthrough of ADC pins, potentiometer wiring, analogRead() code, and a live Serial Monitor demo. About 12 minutes.