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. SPI 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
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:
transfer_size
must be <=4096max_speed_hz
the internally available frequencies are shown below. It is usually best to pick the highest frequency the works reliably with a device. 8 Mhz (which will map to 7.8MHz) is usually a good guess.
sudo apt install python3-spidev
↩︎