OC
OceanRemote
Low-code IoT platform
Back to Troubleshooting Hub

Pico W ADC Inaccurate Reading

Your Raspberry Pi Pico W's analog-to-digital converter readings are inaccurate, noisy, or non-linear. The values fluctuate or don't match expected voltages. This guide covers 12-bit ADC calibration, voltage reference issues, input impedance, and noise filtering techniques.

Last updated: April 22, 2026 | 12 min read

Symptoms

  • ADC readings fluctuate even with stable input voltage
  • NTC thermistor temperature readings jump around or show wrong values
  • Voltage divider readings don't match calculated values
  • ADC values at 0V are not zero
  • ADC values at 3.3V are not 4095
  • Readings change when WiFi is active
  • Different ADC channels give different readings for same input voltage

Common Causes

  1. Internal ADC Temperature Drift RP2040's ADC reference voltage drifts with temperature
  2. Noisy Power Supply ADC uses 3.3V rail as reference; noise directly affects readings
  3. High Source Impedance RP2040 ADC requires source impedance <10k for accurate readings
  4. WiFi/RF Interference CYW43439 WiFi chip creates noise on ADC during transmission
  5. Missing Input Filtering No capacitor on ADC input to filter high-frequency noise
  6. ADC Channel Crosstalk Switching between channels without settling time
  7. ADC Not Calibrated Factory calibration may be off by 2-5%

Pico W ADC Specifications

Specification Value Note
Resolution ()12-bit Effective ~10.5 bits due to noise
Input Voltage Range ()0V to 3.3V Exceeding 3.3V may damage ADC
Reference Voltage ()3.3V Same as board 3.3V rail ()
Input Impedance ()~100k Requires source impedance <10k
Sample Rate ()Up to 500 ksps Arduino default ~50 ksps
ADC Channels ()3 GPIO29 is VSYS sense
DNL ()1 LSB typical Can cause non-linearity ()
INL ()2 LSB typical Can cause offset errors ()

Pico W ADC is less accurate than ESP32's ADC. Expect 2-5% error without calibration.

Step-by-Step Fixes

1. Add Capacitor on ADC Input

Filter high-frequency noise with a capacitor:

// Hardware fix - Add capacitor between ADC pin and GND
// Connect 0.1F  ceramic capacitor
// Place as close as possible to the ADC pin
//
// For noisy environments, add 1F-10F capacitor in parallel
//
// Wiring:
// GPIO26   Capacitor (+)  GND
//                 
//                  Sensor output

2. Use Lower Source Impedance

RP2040 ADC requires source impedance <10k:

  • For voltage dividers, use resistors <10k
  • For NTC thermistors, use 10k pull-down
  • For potentiometers, use 10k pot
  • Add op-amp buffer for high-impedance sources
//  WRONG - High impedance 
// 100k and 100k divider  50k source impedance (too high)
//
//  CORRECT - Low impedance 
// 10k and 10k divider  5k source impedance (good)
//
// Voltage divider for battery monitoring:
const float R1 = 10000.0;  // 10k 
const float R2 = 10000.0;  // 10k

3. Average Multiple Samples

Reduce noise by averaging readings:

float readADC_Average {
  long sum = 0;
  for  {
    sum += analogRead(pin);
    delayMicroseconds;  // Allow ADC to settle
  }
  return sum / samples;
}

// Use median filter for spike rejection
float readADC_Median {
  int values[samples];
  for  {
    values[i] = analogRead(pin);
    delayMicroseconds;
  }
  // Sort array
  for  {
    for  {
      if  {
        int temp = values[i];
        values[i] = values[j];
        values[j] = temp;
      }
    }
  }
  // Return median
  return values[samples / 2];
}

4. Add Settling Time After Channel Switch

ADC needs time to charge internal capacitor when switching channels:

//  WRONG - Reading multiple channels too fast
int val1 = analogRead;
int val2 = analogRead;  // Immediate read - may be inaccurate
int val3 = analogRead;

//  CORRECT - Add settling time between reads
int val1 = analogRead;
delayMicroseconds;  // Allow ADC to settle
int val2 = analogRead;
delayMicroseconds;
int val3 = analogRead;

5. Calibrate ADC with Known Voltages

Measure actual voltage reference and calculate correction factor:

// Calibration procedure
void calibrateADC() {
  // Measure actual 3.3V pin voltage with multimeter
  // Let's say you measure 3.28V 
  const float ACTUAL_VREF = 3.28;  // Replace with your measured value
  const float IDEAL_VREF = 3.3;
  const float CALIBRATION_FACTOR = ACTUAL_VREF / IDEAL_VREF;
  
  // Apply calibration to all readings
  int raw = analogRead;
  float voltage =  * 3.3 * CALIBRATION_FACTOR;
  
  // For NTC thermistors, calibrate at two points 
  // Adjust Beta value or add offset in OceanRemote dashboard
}

6. Reduce WiFi Interference

WiFi transmission creates noise on ADC:

  • Stop ADC readings during WiFi transmission, or average over longer periods
  • Use separate 3.3V regulator for ADC
  • Add ferrite bead on 3.3V line to ADC
  • Reduce WiFi TX power
  • Take ADC readings when WiFi is idle
// Take ADC readings when WiFi is not transmitting
unsigned long lastWiFiActivity = 0;

void loop() {
  // Check if WiFi is idle
  if  == WL_CONNECTED && 
      millis() - lastWiFiActivity > 100) {
    // Take stable ADC reading
    int adc = readADC_Average;
    lastWiFiActivity = millis();
  }
  
  // WiFi activity happens here
  // ...
}

7. Use External ADC

For high accuracy requirements, use external ADC:

  • ADS1115 16-bit, 4 channels, I2C, 0.01% accuracy
  • MCP3008 10-bit, 8 channels, SPI
  • MAX11606 10-bit, 2/4/8 channels, I2C
  • External ADCs have dedicated reference voltage, not affected by Pico W's noisy 3.3V rail
// Example with ADS1115 
#include 

Adafruit_ADS1115 ads;

void setup() {
  Serial.begin;
  ads.begin();
  ads.setGain;  // 4.096V range
}

void loop() {
  int16_t results = ads.readADC_SingleEnded;
  float voltage = results * 0.000125;  // 4.096V / 32768 = 0.125mV per bit
  Serial.print; Serial.println;
}

Pico W ADC Channels

ADC Channel GPIO Physical Pin Notes
ADC0 GPIO26 31 Primary analog input ()
ADC1 GPIO27 32 Secondary analog input ()
ADC2 GPIO28 34 Third analog input ()
ADC3 ()N/A N/A ()Measures 3.3V rail , use for reference. Use to calibrate other ADC channels. Connect to VSYS via resistor divider? Not for general use. Measuring internal temperature sensor? RP2040 has no internal temp sensor. ADC3 is connected to internal voltage reference? It may be used to measure VDDA/3? Not recommended for beginners. Stick with GPIO26-28.

Prevention Tips

  • Add 0.1F capacitor between ADC pin and GND
  • Use source impedance <10k for accurate readings
  • Average 16-64 samples to reduce noise
  • Add 1-10ms settling time when switching ADC channels
  • Calibrate ADC with known voltage reference
  • Use external ADC for high accuracy applications
  • Keep analog signals away from WiFi antenna and digital lines

Related Issues

Frequently Asked Questions

Q: Why is Pico W ADC less accurate than ESP32?

A: Pico W's RP2040 has a simpler ADC with no dedicated voltage reference. The ADC uses the same 3.3V rail that powers the WiFi chip, which introduces noise. ESP32 has better ADC with more filtering and calibration.

Q: How much error should I expect from Pico W ADC?

A: Without calibration: 2-5% error . With averaging and calibration: 0.5-1% error possible. For NTC thermistors, use OceanRemote's offset calibration to correct readings.

Q: Can I use the internal ADC for temperature sensing ?

A: Yes, but with limitations. NTC thermistors are acceptable for temperature monitoring within 1-2C accuracy. For high accuracy , use external ADC or DS18B20 digital sensor. OceanRemote's offset calibration can compensate for ADC inaccuracies.

Still having ADC issues? Contact Support or return to the Troubleshooting Hub.