The SPI Interface

SPI (Serial Peripheral Interface) is a serial, bus based, hardware interface for connecting peripheral devices. It provides higher bandwidth than would be possible with an i2c interface. Bitmapped displays often use the SPI interface.

The Raspberry Pi has two SPI buses which together can drive up to 5 devices. I2C interfaces are disabled by default. To activate them add the following lines to /boot/config.txt and reboot:

Bus Config Line
0 dtparam=spi=on
1 (uncommon) dtoverlay=spi1-3cs

The SPI interface can be accessed via Linux devices. When everything is properly configured, you should see a subset of the following Linux devices.

Linux device bus pins Chip Select (CS) pin
/dev/spidev0.0 SPI0 MOSI/MISO/CLK SPI0 CS0
/dev/spidev0.1 SPI0 MOSI/MISO/CLK SPI0 CS1
/dev/spidev1.0 SPI1 MOSI/MISO/CLK SPI1 CS0
/dev/spidev1.1 SPI1 MOSI/MISO/CLK SPI1 CS1
/dev/spidev1.2 SPI1 MOSI/MISO/CLK SPI1 CS2

The table below shows where to find the SPI bus interface on the Pi's header.

Description BCM Pin Pin BCM Description
01 02
02 03 04
03 05 06
04 07 08 14
09 10 15
SPI1 CS1 17 11 12 18 SPI1 CS0
27 13 14
22 15 16 23
17 18 24
SPI0 MOSI 10 19 20
SPI0 MISO 09 21 22 25
SPI0 CLK 11 23 24 08 SPI0 CS0
00 27 28 01 SPI0 CS1
05 29 30
06 31 32 12
13 33 34
SPI1 MISO 19 35 36 16 SPI1 CS2
26 37 38 20 SPI1 MOSI
39 40 21 SPI1 CLK

To connect am spi device you usually need to connect the following pins:

Because of their proximity it is very common to use pins: 17-24 together with /dev/spidev0.0 to attache an spi device

Python

In Python you get access to SPI via the spidev library1.

A simple class wrapping this interface looks like this:

import spidev
import RPi.GPIO as GPIO
    
class SpiDevice(object):

    def __init__(self, device, port, dc_pin, reset_pin, max_speed_hz, transfer_size):
        self._dc = dc_pin
        self._rst = reset_pin
        if self._dc is not None:
            GPIO.setup(self._dc, GPIO.OUT)
        if self._rst is not None:
            GPIO.setup(self._rst, GPIO.OUT)
        self.reset()
        self._spi = spidev.SpiDev()
        self._spi.open(device, port)
        self._spi.cshigh = False
        self._spi.max_speed_hz = max_speed_hz = 1000000

    def reset(self):
        if self._rst is not None:
            GPIO.output(self._rst, GPIO.LOW)  # Reset device
            GPIO.output(self._rst, GPIO.HIGH)  # Keep RESET pulled high

    def write_data(self, data: bytes):
        if self._dc is not None:
            GPIO.output(self._dc, GPIO.HIGH)
        i = 0
        n = len(data)
        tx_sz = self._transfer_size
        while i < n:
            # This should accept bytes
            self._spi.writebytes(list(data[i:i + tx_sz]))
            i += tx_sz

    def write_cmd(self, data: bytes):
        if self._dc is not None:
            GPIO.output(self._dc, GPIO.LOW)
        # print ("DATA", len(data), list(data))
        self._spi.writebytes(list(data))

TODO: example for reading data from SPI interface

Note:


  1. sudo apt install python3-spidev