Raspberry Pi SPI Basics

SPI is a fast four-wire bus that uses a dedicated chip-select line per device, making it well suited to high-speed peripherals like ADCs and displays.

What Is SPI?

SPI, short for Serial Peripheral Interface, is a synchronous communication protocol that the Raspberry Pi uses to talk to fast peripherals. Unlike I2C, which shares one pair of wires among every device through unique addresses, SPI dedicates one clock line, two data lines, and a separate chip-select (CS) line to each device. The Pi drives the clock and picks which peripheral is 'listening' at any moment by pulling that peripheral's chip-select line low, so devices don't need an address at all — they simply respond whenever their own CS line is active.

  • MOSI (Master Out, Slave In): data sent from the Pi to the peripheral
  • MISO (Master In, Slave Out): data sent from the peripheral back to the Pi
  • SCLK: the clock signal that keeps both sides in sync
  • CE0 / CE1 (chip enable, also called chip select): one dedicated line per connected device
  • Full-duplex operation — data can be sent and received in the same clock cycle
  • Typical clock speeds run from a few hundred kHz up to tens of MHz, well beyond I2C's usual 100-400 kHz

SPI vs I2C

AspectI2CSPI
Wires2 (SDA, SCL) shared by all devices4 minimum, plus 1 chip-select per device
AddressingEach device has a unique bus addressNo addresses — the device is chosen via its CS line
Typical speed100 kHz to 400 kHz (up to ~3.4 MHz Fast Mode+)A few MHz up to tens of MHz
Wiring as devices growSimple — just tap into the same two wiresMore pins needed — one extra CS wire per device
Common usesSensors, RTCs, small OLED displaysADCs/DACs, SD cards, TFT/e-paper displays, flash chips

Wiring and Enabling SPI

The Raspberry Pi's primary SPI bus (SPI0) uses physical pin 19 for MOSI (GPIO10), pin 21 for MISO (GPIO9), pin 23 for SCLK (GPIO11), and two chip-select lines: pin 24 for CE0 (GPIO8) and pin 26 for CE1 (GPIO7) — enough to wire up two independent SPI devices without extra hardware. SPI is disabled by default; enable it with sudo raspi-config under Interface Options > SPI > Yes, or non-interactively with sudo raspi-config nonint do_spi 0, then reboot. Finally install the Python library with sudo apt install -y python3-spidev.

Talking to an SPI Device in Python

In Python, the spidev library gives you an SpiDev object representing one bus/device pair. Call .open(bus, device) where bus is almost always 0 and device is 0 or 1 depending on which CE line you wired up. Set max_speed_hz to something your peripheral's datasheet supports, and set mode (0-3) to match the clock polarity and phase it expects. The core method, xfer2(list_of_bytes), shifts your bytes out on MOSI while simultaneously shifting bytes in on MISO, returning a list the same length as what you sent — even if you only care about the reply, you still need to send filler bytes to generate the clock pulses that pull the response out.

Example

import spidev

spi = spidev.SpiDev()
spi.open(0, 0)          # bus 0, chip-select CE0
spi.max_speed_hz = 1350000
spi.mode = 0

def read_channel(channel):
    # MCP3008 command: start bit, single-ended mode, channel number
    command = [1, (8 + channel) << 4, 0]
    reply = spi.xfer2(command)
    value = ((reply[1] & 3) << 8) | reply[2]
    return value  # 0-1023

try:
    raw = read_channel(0)
    voltage = raw / 1023 * 3.3
    print(f"Raw: {raw}  Voltage: {voltage:.2f}V")
finally:
    spi.close()

Example

import spidev

spi = spidev.SpiDev()
spi.open(0, 1)          # bus 0, chip-select CE1
spi.max_speed_hz = 500000
spi.mode = 0

READ_STATUS_REGISTER = 0x05

reply = spi.xfer2([READ_STATUS_REGISTER, 0x00])
status_register = reply[1]
print(f"Status register: {status_register:#010b}")

spi.close()
Note: SPI has four common 'modes' (0-3) describing when data is sampled relative to the clock edge — using the wrong mode is the most frequent reason an SPI device stays silent, so always check the mode your peripheral's datasheet requests. Chip-select lines are also active low: the Pi pulls a device's CE pin low to select it and high to release it, and spidev handles this automatically as long as you open the matching device number.

Exercise: Raspberry Pi I2C and SPI

Which statement correctly compares the wiring of I2C and SPI on a Raspberry Pi?