Skip to content
Frank Bauernöppel edited this page Jan 10, 2019 · 19 revisions

SPI = serial peripheral interface

SPI masters

The SoC has three SPI master peripherals: SPI0, SPI1, and SPI2. SPI0 is the most powerful one; SPI1, SPI2 and UART1 are combined as grouped together as Auxiliary peripherals. For details, see hardware docs.

With dtoverlay=spi0-hw-cs.dtbo in config.txt SPI0 is available on the expansion header at the following pins:

GPIO pin expansion header pin SPI0 signal comment
GPIO11 23 SCLK serial clock
GPIO9 21 MISO master in, slave out
GPIO10 19 MOSI master out, slave in
GPIO8 24 CE0 chip enable for device 0
GPIO7 26 CE1 chip enable for device 1
25 GND ground

checking SPI presence

pi@raspberrypi:~ $ ls -l /dev/spi*
crw-rw---- 1 root spi 153, 0 Mar 20 20:26 /dev/spidev0.0
crw-rw---- 1 root spi 153, 1 Mar 20 20:26 /dev/spidev0.1
pi@raspberrypi:~ $ ls -l /sys/class/spidev/spidev*   
lrwxrwxrwx 1 root root 0 Mar 20 20:29 /sys/class/spidev/spidev0.0 -> ../../devices/platform/soc/3f204000.spi/spi_master/spi0/spi0.0/spidev/spidev0.0
lrwxrwxrwx 1 root root 0 Mar 20 20:29 /sys/class/spidev/spidev0.1 -> ../../devices/platform/soc/3f204000.spi/spi_master/spi0/spi0.1/spidev/spidev0.1

testing SPI with spiloop

spiloop is a tool in the meta-rpi layer. If not already included in your image, you can build it by executing on the build host in a bitbake shell

bitbake spiloop

and using a package server or network login and scp to copy it to your RasPi.

On a running RasPi execute command

spiloop -d /dev/spidev0.0 -i 16 -v

with all header pins unconnected. You will see a pattern like:

tx: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
rx: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
tx: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 
rx: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
tx: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02

...

i.e. a 0x00 byte is always received on MISO pin regardless of what was sent from MOSI pin.

Connect a wire between MOSI and MISO pins (see above) on the expansion header and repeat the test. Now, the output is like:

tx: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
rx: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
tx: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 
rx: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 
tx: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 
rx: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 

...

The wire created a loopback and the output on MOSI is read as input on MISO.

testing SPI with spidev_test

spidev_test is a similar tool distributed with the Linux kernel sources. It is easy to download, compile and use. On a running RasPi enter:

wget https://raw.githubusercontent.com/raspberrypi/linux/rpi-4.4.y/Documentation/spi/spidev_test.c
gcc -o spi_test spi_test.c
./spidev_test -h

using SPI from a C program

Note that /dev/spidev0.0 denotes SPI bus 0 device 0 (which toggles CE0) and /dev/spidev0.1 is SPI bus 0 device 1 (which toggles CE1).

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <fcntl.h>

int main()
{
  int rc;
  int fd = open("/dev/spidev0.0", O_RDWR);
  if(fd < 0 ) {
    perror("open spi device");
    return -1;
  }

  static struct spi_ioc_transfer tr;
  uint8_t rx[5];
  uint8_t tx[5];
  tr.tx_buf = (unsigned long)tx;
  tr.rx_buf = (unsigned long)rx;
  tr.len = 5;
  tr.speed_hz = 1000000;
  tr.bits_per_word = 8;
  memset( tx, 0xF0, 5 );
  for(;;) {
    rc = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    if(rc < 0 ) {
      perror("send message");
      return -1;
    }
    sleep(1);
  }
  close(fd);
}

using SPI from a kernel module

MCP251x CAN bus driver

further reading