ESP32 analogRead is noisy or not linear: averaging, attenuation and ADC2

The ESP32 ADC is noisy and not perfectly linear, especially near 0 V and near full scale. Average several readings and stay in the middle of the range.

What the message means

The converter has noise and a curved response. Wi-Fi activity adds more noise, and ADC2 channels cannot be used while Wi-Fi runs on the classic ESP32.

Fix it in this order

  1. Take the average of 16 or more readings, or use a moving average.
  2. Set the attenuation with analogSetAttenuation or analogSetPinAttenuation so the signal sits in the middle of the range.
  3. Use an ADC1 pin (GPIO 32 to 39) if Wi-Fi is on. See the analogRead and Wi-Fi page.
  4. Add a capacitor of about 100 nF across the signal near the pin.
  5. Keep the sensor wires short and away from motor and Wi-Fi wiring.
  6. Use the calibration functions of your core, or an external ADC chip, if you need accuracy.

Why it happens

The ESP32 ADC is noisy and not linear, especially near 0 V and near the top of its range. On the classic ESP32, ADC2 pins also cannot be used while Wi-Fi is active, so use ADC1 pins such as 32 to 39.

float readAvg(int pin, int n = 16) {
  long s = 0;
  for (int i = 0; i < n; i++) s += analogRead(pin);
  return s / (float)n;
}
// analogSetPinAttenuation(pin, ADC_11db); // widest range, about up to 3.3 V

Example sketch: change pins and values for your own wiring. It has not been bench-tested on your hardware.

Average several samples, keep the signal away from the extremes, add a 100 nF capacitor at the pin, and calibrate against a multimeter if you need accuracy.

If you see this, do this

You seeDo this
Jumps by many countsAverage and add a capacitor.
Reads zero while Wi-Fi is onADC2 pin.

analogRead not working with Wi-Fi, ESP32 pinout.

Last reviewed: November 2026. These are the usual causes and the order that finds them fastest. Test on your own board; clones and cables differ.

Why this happens

The ESP32 ADC is a 12-bit converter, so raw readings run from 0 to 4095. Its input stage is built for a limited voltage window, and attenuation selects how much of the pin voltage reaches the converter. Near 0 V and near the top of the range the response bends away from a straight line, which is why a pin reading a sensor close to 0 V or 3.3 V looks wrong even when the wiring is fine.

Noise comes from three places: ripple on the 3.3 V rail, the radio drawing current in bursts, and a high-impedance source such as a large potentiometer or divider. Random noise falls roughly with the square root of the number of samples, so 16 samples cut it to about a quarter and 64 samples to about an eighth. Averaging removes noise but cannot remove the curve, which needs calibration.

How to confirm the cause

  • Tie the pin to a steady voltage, such as a divider from 3.3 V, and print 100 readings. The spread between the smallest and largest value is your noise in counts. A spread of a few counts is normal; a spread of hundreds points to supply or wiring trouble.
  • Repeat with Wi-Fi switched off. If the spread shrinks a lot, radio activity or its supply dip is the main source.
  • Connect the pin to GND, then to 3.3 V, and note the raw values. If the lowest reading is not zero or the highest is not near 4095, you are seeing the non-linear ends.
  • Feed in three known voltages from a divider and compare the result with a multimeter. If the error changes along the range, the curve is the cause, not noise.
  • Check the pin number. GPIO 0, 2, 4, 12 to 15 and 25 to 27 belong to ADC2, which the Wi-Fi driver uses on the classic ESP32.

Worked example

This sketch reports the minimum, maximum and average of 64 samples on GPIO 34 (an ADC1 pin). Change the pin for your board.

const int PIN = 34;
void setup() {
  Serial.begin(115200);
  analogSetPinAttenuation(PIN, ADC_11db);
}
void loop() {
  int lo = 4095, hi = 0; long sum = 0;
  for (int i = 0; i < 64; i++) {
    int r = analogRead(PIN);
    if (r < lo) lo = r;
    if (r > hi) hi = r;
    sum += r;
    delayMicroseconds(200);
  }
  Serial.printf("min %d max %d avg %.1f\n", lo, hi, sum / 64.0);
  delay(500);
}

Read the output as follows: if max minus min is under about 10 counts and the average still disagrees with your multimeter, calibration is the issue. If the spread is large, fix the supply and wiring first. Where your core provides analogReadMilliVolts(), it applies the calibration stored in the chip and is a better starting point than converting counts yourself.

Common mistakes

  • Averaging inside a tight loop with no gap between samples, so the samples are correlated and the noise is not reduced.
  • Measuring a signal that sits at 3.3 V or at 0 V and blaming the code for the flat or bent response.
  • Reading a high-resistance divider directly. Use lower resistor values, or add a 100 nF capacitor, so the sampling capacitor can charge.
  • Using an ADC2 pin and then wondering why the value is stuck once Wi-Fi starts.

If this did not fix it

  • Supply ripple: power the board from a better USB port or add a capacitor near the module.
  • Sensor output noise: add a low-pass filter (resistor plus capacitor) on the signal line.
  • Accuracy still not enough: an external ADC such as an I2C converter gives a cleaner result.