The Raspberry Pi is a powerhouse for digital logic, networking, and Linux-based processing, but it has one glaring hardware omission: it lacks native analog-to-digital conversion. If you want to read a potentiometer, an LDR, a soil moisture probe, or an MQ gas sensor, you cannot plug them directly into the GPIO header. You must use an external ADC for Raspberry Pi. The industry-standard solution is the ADS1115, a 16-bit, 4-channel I2C ADC that offers vastly superior precision and lower noise than the older 10-bit MCP3008 SPI alternative.
This guide walks through wiring the ADS1115 to a Raspberry Pi 4 or 5, writing robust Python code with hardware fault handling, and debugging the most common I2C communication failures you will encounter on the bench.
Project Spec Sheet & Parts List
| Parameter | Specification |
|---|---|
| Difficulty Rating | Intermediate (Requires I2C config and Python environment setup) |
| Target Board Variant | Raspberry Pi 4 Model B (4GB/8GB) or Raspberry Pi 5 (40-pin header) |
| ADC Module | Adafruit ADS1115 16-Bit ADC Breakout (Product ID: 1085) or generic equivalent |
| Communication Protocol | I2C (Inter-Integrated Circuit) |
| Resolution | 16-bit (0 to 32767 raw values) |
| Operating Voltage | 3.3V DC (Critical for Pi GPIO safety) |
| Estimated Cost | $15 - $22 USD (Breakout + Pi accessories) |
| Time to Complete | 30 Minutes |
Required Materials
- Microcomputer: Raspberry Pi 4 or 5 running Raspberry Pi OS (Bookworm or newer).
- ADC Breakout: ADS1115 16-bit I2C ADC module. (Ensure it is the ADS1115, not the 12-bit ADS1015).
- Test Sensor: 10kΩ linear potentiometer or an analog joystick module.
- Wiring: Female-to-female jumper wires, breadboard.
- Resistors: 2x 4.7kΩ pull-up resistors (only required if using a raw IC or a breakout lacking onboard pull-ups; Adafruit breakouts include them).
Wiring the ADS1115 to Raspberry Pi GPIO
The ADS1115 communicates via I2C, which requires only two shared data lines (SDA and SCL) plus power and ground. The Raspberry Pi 4 and 5 share the same I2C pinout on the primary 40-pin header.
Pin Mapping Table
| ADS1115 Pin | Raspberry Pi GPIO (Physical Pin #) | Function / Notes |
|---|---|---|
| VDD | Pin 1 (3.3V Power) | Power supply. Must be 3.3V. |
| GND | Pin 6 (Ground) | Common ground reference. |
| SCL | Pin 5 (GPIO 3 / SCL) | I2C Serial Clock. |
| SDA | Pin 3 (GPIO 2 / SDA) | I2C Serial Data. |
| ADDR | Pin 6 (Ground) | Address select. Tie to GND for default I2C address 0x48. |
| ALRT | Not Connected | Comparator alert (unused for basic polling). |
| A0 | Potentiometer Wiper | Analog Input Channel 0. |
Wiring the Potentiometer: Connect one outer leg of the 10kΩ potentiometer to Pi 3.3V (Pin 1), the other outer leg to Pi GND (Pin 6), and the middle wiper pin to the ADS1115 A0 pin.
Python Code: Reading Analog Voltage with Error Handling
Before running the code, ensure your I2C interface is enabled via sudo raspi-config (Interface Options > I2C > Yes) and install the required Adafruit Blinka libraries:
sudo apt update
sudo apt install python3-pip i2c-tools
pip3 install --break-system-packages adafruit-circuitpython-ads1x15
The following Python script targets the Raspberry Pi 4/5 running standard Raspberry Pi OS. It initializes the I2C bus, catches hardware-level connection faults, and continuously polls Channel 0.
import time
import board
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
# Define I2C bus using default Pi SCL and SDA pins
i2c = busio.I2C(board.SCL, board.SDA)
try:
# Initialize the ADS1115 ADC at default address 0x48
ads = ADS.ADS1115(i2c)
# Configure analog input on physical pin A0
chan = AnalogIn(ads, ADS.P0)
# Optional: Set the gain to match your voltage range.
# GAIN_ONE means the full-scale range is +/- 4.096V.
# Since Pi is 3.3V, GAIN_ONE provides excellent resolution.
ads.gain = 1
except FileNotFoundError as e:
print(f'I2C Bus Error: {e}')
print('Fix: I2C is likely disabled. Run sudo raspi-config and enable I2C.')
exit(1)
except ValueError as e:
print(f'Hardware Address Error: {e}')
print('Fix: ADS1115 not found at 0x48. Check SDA/SCL wiring and ADDR pin.')
exit(1)
print('ADC initialized successfully. Reading Channel A0...')
while True:
try:
# Read the raw 16-bit integer and the calculated voltage
raw_val = chan.value
voltage = chan.voltage
print(f'Raw ADC: {raw_val:>5} | Voltage: {voltage:>5.3f} V')
except OSError as e:
print(f'I2C Read Fault: {e} - Check for loose jumper wires.')
time.sleep(0.25)
Debugging: I2C Errors and Faulty Readings
When working with an ADC for Raspberry Pi, I2C bus errors are the most common point of failure. If your script crashes or returns static values, follow this diagnostic path.
The First 3 Things to Check When It Fails
- Run the I2C Detection Tool: Open a terminal and type
sudo i2cdetect -y 1. You should see a grid with48highlighted. If the grid is empty, your wiring is wrong or I2C is disabled in the OS. - Verify VDD Voltage: Use a multimeter to measure between the ADS1115 VDD and GND pins. It must read ~3.3V. If it reads 5V, immediately disconnect power before you fry the Pi's BCM chip.
- Check the ADDR Pin State: The ADDR pin dictates the I2C address. If it is left floating, the address will drift. Ensure it is firmly soldered or jumpered to GND for address
0x48.
Ranked Causes for Exact Error Strings
FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'Cause 1: I2C is disabled in
raspi-config. (Most Likely)Cause 2: You are running the script inside a Docker container or virtual environment without passing the
--device /dev/i2c-1 flag.Fix: Run
sudo raspi-config, navigate to Interface Options, enable I2C, and reboot.
ValueError: No I2C device at address: 0x48Cause 1: SDA and SCL wires are swapped. (Most Likely)
Cause 2: The ADDR pin is tied to VDD instead of GND (shifting the address to 0x49).
Cause 3: Missing pull-up resistors on SDA/SCL lines (only applies to raw chips, not Adafruit breakouts).
Fix: Swap SDA/SCL. Run
i2cdetect -y 1 to find the actual address and update the Python code to ADS.ADS1115(i2c, address=0x49) if necessary.
Extending and Simplifying Your ADC Build
Once you have a single channel reading reliably, you will likely want to scale the system. Here is how to adapt the hardware.
Extending: Daisy-Chaining Multiple ADCs
The ADS1115 has an ADDR pin that allows you to change its I2C address, meaning you can connect up to four ADS1115 modules to a single Raspberry Pi I2C bus, yielding 16 analog channels. Simply wire the ADDR pin on the second module to VDD (Address 0x49), the third to SDA (0x4A), and the fourth to SCL (0x4B). Initialize them in Python by passing the address argument to the constructor.
Simplifying: Using an Analog HAT
If you want to avoid breadboard wiring and pull-up resistor calculations entirely, look into an Analog Zero HAT or the Adafruit ADS1x15 Learning Guide for pre-assembled shields. These plug directly over the 40-pin header, route the analog traces to onboard screw terminals, and handle the 3.3V logic shifting automatically. For permanent installations in enclosures, a HAT saves hours of debugging loose Dupont connectors.
Frequently Asked Questions
Can I use the Raspberry Pi internal temperature sensor instead of an external ADC?
No. The Raspberry Pi SoC contains an internal thermal sensor for monitoring CPU die temperature, but this sensor is not exposed to the GPIO header or accessible for external analog measurements. To read external thermistors (like the NTC 10k) or analog temperature ICs (like the LM35), you absolutely must use an external ADC for Raspberry Pi.
Why does my 16-bit ADC for Raspberry Pi max out at 3.3V when it is rated for 5V?
While the ADS1115 chip can accept up to 5.5V on its VDD pin, the Raspberry Pi GPIO is strictly limited to 3.3V. Because I2C data lines (SDA/SCL) are pulled up to VDD, powering the ADC with 5V will push 5V back into the Pi's 3.3V logic pins, risking catastrophic silicon damage. Therefore, you must power the breakout at 3.3V. With a 3.3V VDD, your maximum safe analog input voltage on channels A0-A3 is also capped at 3.3V. If you need to read a 5V sensor, use a voltage divider (e.g., two 10kΩ resistors) to step the sensor output down to 3.3V before it hits the ADC pin.
Is the MCP3008 SPI ADC better than the ADS1115 I2C ADC for Raspberry Pi projects?
It depends on your application. The MCP3008 uses SPI, which is faster and better for high-frequency audio sampling or reading 8 channels simultaneously at high speeds. However, it only offers 10-bit resolution (1024 steps) and requires more GPIO pins (MISO, MOSI, SCLK, CE0). The ADS1115 uses I2C (only 2 pins), offers 16-bit resolution (32768 steps), and includes an internal programmable gain amplifier (PGA). For 90% of DIY sensor projects (soil moisture, light levels, battery voltage monitoring), the ADS1115 is the superior choice due to its precision and simpler wiring. For further reading on Pi hardware interfaces, consult the Raspberry Pi Official Configuration Documentation.






