PyRaspBeta

MCP3008 ADC (SPI)

The MCP3008 is an 8-channel, 10-bit analog-to-digital converter in a DIP-16 package. It costs $4 and is the classic way to give a Raspberry Pi analog inputs: the Pi has no ADC of its own, so a potentiometer, an LDR or a soil probe is read through this chip over four SPI wires, turning a voltage into a number from 0 to 1023. The analog inputs primer explains why that is needed in the first place.

MCP3008 ADC (SPI)

Pins

PinWhat it isType
CH0Analog input 0 (pin 1)io
CH1Analog input 1 (pin 2)io
CH2Analog input 2 (pin 3)io
CH3Analog input 3 (pin 4)io
CH4Analog input 4 (pin 5)io
CH5Analog input 5 (pin 6)io
CH6Analog input 6 (pin 7)io
CH7Analog input 7 (pin 8)io
DGNDDigital ground (pin 9)ground
CSChip select, active low (pin 10)io
DINSerial data in, from MOSI (pin 11)io
DOUTSerial data out, to MISO (pin 12)io
CLKSerial clock, from SCLK (pin 13)io
AGNDAnalog ground (pin 14)ground
VREFReference voltage (pin 15)io
VDDSupply 2.7–5.5 V (pin 16)power

CH0–CH7 are the analog inputs; the wiper of a pot or the middle of a divider goes to one of them. VDD and VREF both go to 3V3 — VREF sets the conversion range and VDD powers the logic — and AGND and DGND join at the Pi's ground. CLK, DIN, DOUT and CS are the SPI side: the Pi's SCLK, MOSI, MISO and CE0.

Wiring it in circuit.py

A potentiometer on channel 0, using the Pi's hardware SPI pins:

circuit.py
from wiring import *

pi = Pi()

pot = Potentiometer(10000)
adc = MCP3008()

pi.V3_3 >> pot.pin3
pot.pin1 >> pi.GND
pot.wiper >> adc.ch0

pi.V3_3 >> adc.vdd
adc.vdd >> adc.vref
adc.agnd >> pi.GND
adc.dgnd >> pi.GND
pi.SCLK >> adc.clk
pi.MISO >> adc.dout
pi.MOSI >> adc.din
pi.CE0 >> adc.cs

The knob + ADC kit is this circuit pre-wired: it exposes vdd, gnd, clk, dout, din and cs, and the pot sits on channel 0.

Driving it in main.py

main.py
from gpiozero import MCP3008
from time import sleep

knob = MCP3008(channel=0)

while True:
    print(f"{knob.value:.3f}  {knob.voltage:.2f} V  raw {knob.raw_value}")
    sleep(0.5)

value is the reading divided by VREF (0.0–1.0), voltage is the input in volts and raw_value is the code from 0 to 1023. Pass differential=True to read a channel against its neighbour instead of ground.

Electrical notes

  • Supply is 2.7–5.5 V, but power it from 3V3. At 5 V the chip's digital output swings to 5 V, which the SPI pins must not see; VREF may still be 3.3 V, since it only sets the conversion range.
  • 10 bits over VREF: code = 1024 × Vin ÷ VREF. With VREF on 3V3 that is one step of about 3.2 mV.
  • The model adds the datasheet's errors: a smooth bow of up to 1 LSB across the range (integral non-linearity) plus Gaussian noise of 0.5 LSB σ by default. Both are datafeed knobs; offset and gain errors are not modelled.
  • It converts up to about 200 kSPS at 5 V (75 kSPS at 2.7 V), draws 425 µA, and answers in SPI mode 0. The datasheet's other mode, 3, is not modelled: a driver that asks for it gets a warning and a reply shifted by one bit.
  • Leave unused channels grounded: a floating input reads whatever its neighbour last held.
  • VREF at or below 0.25 V reads 0, which is a handy test — an unwired reference gives all-zero codes.

Simulator vs real hardware

  • SPI is decoded at bit level: after CS goes low the chip waits for a start bit, the single-ended/differential bit and three channel bits, samples, then shifts out a null bit, the 10-bit result MSB first and the same bits LSB first — exactly as the datasheet's timing diagram, so gpiozero, spidev and hand-rolled drivers all work.
  • The eight channels are also differential pairs (CH0–CH1, CH2–CH3, …), so MCP3008(channel=0, differential=True) reads CH0 minus CH1 like the real chip.
  • Conversions are instant: no sample rate, no minimum clock, no droop. On hardware, reading faster than the sample rate starts overlapping conversions.
  • gpiozero's MCP3008 uses spidev (port 0, device 0 → CE0) in the simulator. For a different chip select, wire it and drive the transfer yourself.

Going deeper

Further reading