Investigating the SPI driver

Posted on February 14, 2015

We left off with the hardware being hooked up but no software to run our project. I wanted to test the SPI hardware and the best way to do so is with a loopback test. After using my favorite search engine I found a post called SPI-Python: Hardware SPI for RasPi from Python by Louis Thiery. He had an interesting article on how to interface an Arduino with a RasPi. I wasn’t interested in that (right now) but I was curious about the spidev_test program that he used to verify his setup. However, the instructions didn’t work for me due URLs I couldn’t get to and a test program that wouldn’t compile because of differences in the header files.

Modifying the Code

On my Raspberry Pi I created a directory in which to load the source file and then I got the original source from the Linux source tree.

mkdir spidev_test
wget https://raw.githubusercontent.com/torvalds/linux/master/Documentation/spi/spidev_test.c

I now had the tester source file in my directory. It’s a simple matter to compile it.

gcc spidev_test.c -o spidev_test

Uh oh, I get a few error messages:

spidev_test.c: In function ‘transfer’:
spidev_test.c:60:13: error: ‘SPI_TX_QUAD’ undeclared (first use in this function)
spidev_test.c:60:13: note: each undeclared identifier is reported only once for each function it appears in
spidev_test.c:61:5: error: ‘struct spi_ioc_transfer’ has no member named ‘tx_nbits’
spidev_test.c:62:18: error: ‘SPI_TX_DUAL’ undeclared (first use in this function)
spidev_test.c:63:5: error: ‘struct spi_ioc_transfer’ has no member named ‘tx_nbits’
spidev_test.c:64:13: error: ‘SPI_RX_QUAD’ undeclared (first use in this function)
spidev_test.c:65:5: error: ‘struct spi_ioc_transfer’ has no member named ‘rx_nbits’
spidev_test.c:66:18: error: ‘SPI_RX_DUAL’ undeclared (first use in this function)
spidev_test.c:67:5: error: ‘struct spi_ioc_transfer’ has no member named ‘rx_nbits’
spidev_test.c: In function ‘parse_opts’:
spidev_test.c:172:12: error: ‘SPI_TX_DUAL’ undeclared (first use in this function)
spidev_test.c:175:12: error: ‘SPI_TX_QUAD’ undeclared (first use in this function)
spidev_test.c:184:12: error: ‘SPI_RX_DUAL’ undeclared (first use in this function)
spidev_test.c:186:12: error: ‘SPI_RX_QUAD’ undeclared (first use in this function)
spidev_test.c: In function ‘main’:
spidev_test.c:204:18: error: ‘SPI_IOC_WR_MODE32’ undeclared (first use in this function)
spidev_test.c:208:18: error: ‘SPI_IOC_RD_MODE32’ undeclared (first use in this function)

After some investigation the culprit turns out to be my spidev.h header file. The constants mentioned above don’t exist in that file. I am using Linux raspberrypi 3.18.7+ and as of that distribution those constants are not there. When I check the file on github the commit log says that the new revision implements a couple of new modes for DMA controlled SPI. Ah, well I don’t care about that so I’ll just comment out references to those constants.

As an aside, unless you are doing a lot of SPI reads (or writes) you probably don’t need a DMA interface.

The last thing is the change the name of the device file from /dev/spidev1.1 to /dev/spidev0.0

Once the references were commented out and the device file updaed it compiled fine. Now, on to the test.

Testing the Loopback

The first thing I need to do is to connect the loopback. This is very simple since I’m using a breadboard and the Adafruit T-Cobbler Plus. I just put a jumper from the MOSI (Master Out Slave In) to MISO (Master In Slave Out). Now we’re ready to run the code!

To run the code I used the sudo utility since accessing hardware directly is not normally allowed in Linux. I ran the code and observed the output.

pi@raspberrypi:~/spidev_test$ sudo ./spidev_test

This is what I saw. It works!

spi mode: 0x0
bits per word: 8
max speed: 500000 Hz (500 KHz)

FF FF FF FF FF FF
40 00 00 00 00 95
FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF FF FF FF FF
DE AD BE EF BA AD
F0 0D

A Complication

When I was working with the SPI interface I was pushing on it really hard and after awhile it didn’t show up when I rebooted. I first noticed this after I had done an update to my system using the apt-get two-step.

sudo apt-get update
sudo apt-get upgrade

The best way to fix it is to use raspi-config to always enable the SPI interface. I’m going to be a heavy user of SPI so I don’t see why I wouldn’t want to do this. The SPI interface controls are located under the “8 Advanced Options” entry. Once chosen select “A6 SPI”. It will then ask you if you want to enable the SPI interface and if you want to load the kernel module. Yes to both questions. Save it and after a reboot you should see the driver when you issue an lsmod

pi@raspberrypi:~$ lsmod
Module                  Size  Used by
snd_bcm2835            21342  0
snd_pcm                93100  1 snd_bcm2835
snd_seq                61097  0
snd_seq_device          7209  1 snd_seq
snd_timer              23007  2 snd_pcm,snd_seq
snd                    67211  5 snd_bcm2835,snd_timer,snd_pcm,snd_seq,snd_seq_device
spi_bcm2708             6018  0
uio_pdrv_genirq         3666  0
uio                     9897  1 uio_pdrv_genirq

Now I have the SPI available whenever I start up my Pi.

What’s Next

Now that I’ve got the software test working I want to write some code to send information to my 4-Wire-Intefaced 20-Port LED Display Driver and I/O Expander (MAX6957) and light an LED.