GPIO (General Purpose Input/Output) pins are fundamentally digital, acting as binary switches that read or write discrete HIGH and LOW voltage states, though microcontrollers often route separate Analog-to-Digital Converter (ADC) circuits to specific GPIO pads to measure continuous voltages. If you treat a purely digital pin as an analog input without configuring the internal hardware multiplexer, your code will only read binary 0s and 1s, or worse, floating noise. Conversely, attempting to output a smooth, variable voltage from a standard digital GPIO will fail, as the silicon can only physically connect the pin to the VCC rail or Ground.
Think of a standard digital GPIO pin like a basic toggle light switch—it only has two physical states: fully ON or fully OFF. An analog signal, by contrast, is like a dimmer switch that can stop at any continuous point along the dial. Understanding this distinction dictates everything from how you wire a sensor to how you configure your microcontroller's registers.
The Silicon Reality: How Digital GPIO Actually Works
At the silicon level, a standard GPIO pad is connected to a CMOS push-pull inverter. When you set a pin to HIGH, a P-channel MOSFET connects the pin to the microcontroller's VCC (e.g., 3.3V or 5V). When you set it to LOW, an N-channel MOSFET connects it to Ground (0V). There is no physical mechanism inside a standard GPIO block to output 1.8V or 2.4V directly.
So, where does the "analog" capability come from? Microcontrollers feature a dedicated peripheral called an ADC. The ADC is a completely separate block of silicon that measures voltage by charging an internal capacitor and timing the discharge. The microcontroller uses an internal analog multiplexer (mux)—essentially a microscopic rotary switch—to route specific, designated GPIO pads away from the digital buffer and into the ADC peripheral. This is why you cannot just read an analog voltage on any pin; you must use the pins physically wired to the ADC mux on your specific board.
Worked Example: Reading a 10k Potentiometer on an ESP32-S3
Let's look at a real-world numeric example using an ESP32-S3-WROOM-1 module and a Bourns 3386P 10kΩ trimpot. The ESP32-S3 features a 12-bit ADC, meaning it divides the input voltage range into 4,096 discrete digital steps (from 0 to 4095).
Assume we configure the ADC reference voltage to 3.3V. The resolution per step is:
3.3V / 4095 = 0.000805V (or 0.805 mV per step)
If you turn the potentiometer wiper to output exactly 1.65V, the ADC hardware measures this and returns a digital integer to your code:
1.65V / 0.000805V = 2049
// ESP32 Arduino Core ADC Configuration
#include
const int potPin = 1; // GPIO 1 is routed to ADC1_CHANNEL_1 on ESP32-S3
int adcValue = 0;
float voltage = 0.0;
void setup() {
Serial.begin(115200);
analogReadResolution(12); // Set 12-bit resolution (0-4095)
}
void loop() {
adcValue = analogRead(potPin);
// Convert digital steps back to voltage
voltage = adcValue * (3.3 / 4095.0);
Serial.printf("Raw ADC: %d | Voltage: %.2f V\n", adcValue, voltage);
delay(250);
}
analogReadMilliVolts() function in the ESP32 Arduino Core v2.x/v3.x, which applies Espressif's factory-stored eFuse calibration data to correct the raw reading, rather than doing the raw math yourself.
Where You Meet This in Practice: PWM vs. True Analog
The most common confusion in embedded electronics is mistaking Pulse Width Modulation (PWM) for an analog output. When you use the Arduino analogWrite() function to fade an LED, you are not actually outputting an analog voltage. You are outputting a digital square wave that toggles between 0V and 5V (or 3.3V) at a high frequency, typically 490 Hz or 980 Hz.
If you set analogWrite(pin, 127) on a 5V Arduino Uno R4, the pin is not outputting 2.5V. It is outputting 5V for 50% of the time, and 0V for the other 50%. Because the switching happens nearly 1,000 times per second, the human eye's persistence of vision integrates the light pulses, making the LED appear to be running at half brightness. If you connect a multimeter set to DC Volts on that same pin, the meter's internal low-pass filter will average the square wave and display ~2.5V, further tricking beginners into thinking the GPIO is generating a true analog voltage.
What this changes in a real circuit: If you try to use a PWM pin to drive an analog audio amplifier or a precision DC motor controller that expects a smooth 0-5V control signal, you will inject massive amounts of high-frequency digital switching noise into your circuit. To get a true analog voltage output, you must either use a microcontroller with a dedicated DAC (Digital-to-Analog Converter) peripheral—like the ESP32's 8-bit DAC on GPIO 25/26, or the Arduino Zero's 10-bit DAC—or build a hardware RC low-pass filter to smooth the PWM square wave into a DC voltage.
Frequently Asked Questions About GPIO and Analog Signals
Can I output a true analog voltage from a standard digital GPIO pin?
No. A standard digital GPIO pin can only physically connect to VCC or Ground. To output a true, continuous analog voltage, your microcontroller must have a dedicated DAC (Digital-to-Analog Converter) peripheral routed to that specific pin. For example, the Raspberry Pi Pico (RP2040) has no internal DAC, meaning it cannot output true analog voltage natively; you must use an external DAC chip like the MCP4725 over I2C, or filter a PWM signal through a resistor-capacitor network.
Why does my digital GPIO pin read random values when nothing is connected?
This is known as a "floating pin." Because a digital GPIO input has extremely high impedance (often >100 MΩ), it acts like an antenna, picking up electromagnetic interference from nearby AC wiring, switching power supplies, or even your body. The voltage hovers in the undefined transition region (e.g., 1.2V on a 3.3V system), causing the digital buffer to rapidly toggle between 0 and 1. To fix this, you must provide a defined DC path by enabling the microcontroller's internal pull-up or pull-down resistors in software, or by wiring an external 10kΩ resistor to VCC or GND.
Are Raspberry Pi GPIO pins analog or digital?
The GPIO header on the Raspberry Pi 4 and Pi 5 is strictly 3.3V digital. The Broadcom SoCs used in these single-board computers do not include an internal ADC peripheral routed to the GPIO header. If you need to read an analog sensor (like a photoresistor or an analog temperature probe) on a Raspberry Pi, you must wire an external ADC integrated circuit, such as the ADS1115 (16-bit, I2C) or the MCP3008 (10-bit, SPI), between your sensor and the Pi's digital pins.






