Raspberry Pi SPI

SPIDEV0

The most well-known SPI device uses GPIOs 7--11, and exists on all models of the Pi, including the early 26-pin ones.

Since around 2015-02-24, the raspi-config program does the necessary changes to configuration when we want to enable the first SPI device, spidev0.

If relevant, the spi-bcm2708 will be un-blacklisted and added to /etc/modules.

Then in /boot/config.txt, this line is added or uncommented:

dtparam=spi=on

The signal lines in use are the following ones:

RP.P1#R-Pi nameGPIO
P26 SPI1_CE1 GPIO 7
P24 SPI1_CE0 GPIO 8
P21 SPI1_MISO GPIO 9
P19 SPI1_MOSI GPIO 10
P23 SPI1_SCLK GPIO 11

SPIDEV1

There exists a second SPI master, with 3 device-select lines, on the later models of Raspberry Pi, with 40 pins. This uses GPIOs 16--21, allocated as follows:

RP.P1#R-Pi nameGPIO
P36 SPI1_CE2 GPIO 16
P11 SPI1_CE1 GPIO 17
P12 SPI1_CE0 GPIO 18
P35 SPI1_MISO GPIO 19
P38 SPI1_MOSI GPIO 20
P40 SPI1_SCLK GPIO 21

To enable this, add entries in /boot/config.txt as follows

dtparam=spi=on
dtoverlay=spi1-3cs

This allows up to 5 different SPI devices to operate from the Raspberry Pi without requiring extra hardware. The following device files now appear in /dev:

crw-rw---- 1 root spi 153, 0 Mar  5 09:39 /dev/spidev0.0
crw-rw---- 1 root spi 153, 1 Mar  5 09:39 /dev/spidev0.1
crw-rw---- 1 root spi 153, 4 Mar  5 09:39 /dev/spidev1.0
crw-rw---- 1 root spi 153, 3 Mar  5 09:39 /dev/spidev1.1
crw-rw---- 1 root spi 153, 2 Mar  5 09:39 /dev/spidev1.2

Small LCD display

I have been able to send data to the small graphical 84 by 48 display from Sparkfun, using the SPI output lines.

RP.P1#R-Pi nameDisplay name Display pin #
P17 3.3V VCC 1
P24 SPI0_CE0 SCE 3
P18 GPIO24 RST 4
P22 GPIO25 D/C 5
P19 SPI0_MOSI DN(MOSI) 6
P23 SPI0_SCLK SCLK 7
P20 GND GND 2

My code uses the /dev/spidev0.0 for the data channel, and the two GPIO lines 24 and 25 (using /dev/mem type access) for the reset and data/command selection bits. I get by with using write(2), since the display is write-only.

Source files are here: mgraf1.tar.gz

MCP3201 ADC

With a view to making a new interface to the wind sensors, where there is an analog input for the direction and a counting, digital, input for the speed, I connected an MCP3201, 12-bit ADC.

The device is connected to the R.Pi as follows:

RP.P1#R-Pi nameMCP3201 name pin #
P24 SPI0_CE0 SCE 5
P23 SPI0_SCLK SCLK 7
P21 SPI0_MISO DO 6
P17 3.3V VCC 8
P17 3.3V VR+ 4
P20 GND GND 1
P20 GND Vi- 2
Vi+ 3

Pin 3 is analog input, this has been buffered using half of a LMC6482IN to give the desired low source resistance.

The code for reading this is fairly simple; open the /dev/spidev0.0, set the mode (0), number of bits (8), and the speed (100kHz), then read the data, and interpret it.

Source file is here: rpot.c

MAX6675 and MAX31855

These are other fairly simple SPI read-only device, that reads the voltage from a thermocouple and returns the corresponding temperature in degrees Celsius. MAX6675 is obsolete and replaced by the MAX31855, but they both have the same general interface.

The MAX31855 devices I have here are on breakout-boards, with screw-terminal or plug connections for the thermocouple.

The device is connected to the R.Pi as follows:

RP.P1#R-Pi nameNameMAX6675 pin #Thermocouple
P26 SPI0_CE1 /CS 6
P23 SPI0_SCLK SCK 5
P21 SPI0_MISO SO 7
P17 3.3V VCC 4
P20 GND GND 1
P20 GND T- 2 Red (Alumel lead)
T+ 3 Yellow (Chromel lead)

The thermocouple, SEN-00251 from Hobbytronics.co.uk or Sparkfun (same part number both places) is connected to the pins T- and T+, and T- is also connected to GND, as per the datasheet.

This thermocouple assembly has the two cores extended out, one is given red sheathing, the other is yellow. The wires are not easy to solder, so I have used a screw-on connector. Red is negative, T-, to pin 2; while the yellow is the positive, T+, to pin 3.

Programming is very similar to what is done for the MCP3201 (mode 0 bitcount 8 speed 100kHz) -- this device returns 16 bits of data, where 12 bits are the temperature, and a couple of the others are framing and status info.

Some C code for reading the MAX31855 is here: max31855-160110.tar.gz. We use the IOC_MESSAGE ioctl here, to read all 32 bits in one go. These bits are are data and status-info on such things as whether the thermocouple is connected properly and not shorted to ground or positive voltage.

AD9837

Like the display-unit above, this device is also of a write-only nature, in that it only receives data on the MOSI line, and doesn't even have MISO connected. The interesting difference here is that the AD9837 wants data in 16-bit packages, so instead of using plain write(2) which only deliver 8 bits per CS cycle, we use the ioctl(SPI_IOC_MESSAGE) call insted, where several octets can be written and read in any combination, possibly without cycling the Chip Select line.

The device uses SPI mode 2, Clock polarity idle Low, and Latch going Low to High. (CPOL=0, CPHA=1). Otherwise it is much the same: data is 8 bits, MSB first, Speed 100 kHz is fine.

The device is mounted on a circuit board with a 16 MHz oscillator and a filter circuit; this assembly is made by Sparkfun and they call it the Sparkfun MiniGen Shield. Though it is designed to match an Arduino Pro Mini, the connection footprint is essentially the same as a 24-pin wide DIP, with two rows of 12 pins, only a few of which are actually connected to anything. And it comes readily configured for use with 3.3V which is the perfect match for the Raspberry Pi.

RP.P1#R-Pi nameDevice nameDevice pin #
P2 5.0V Vin JP3-4
P24 SPI0_CE0 FSYNC JP3-12
P19 SPI0_MOSI SDATAJP3-11
P23 SPI0_SCLK SCLK JP3-9
P20 GND GND JP3-2

As the AD9837 expects 16-bit data values, the following function does the necessary work to write all these in one go:


#include <stdint.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>


int write16(int fd, uint16_t bits16)
{
    int rvv;
    struct spi_ioc_transfer sit[1];
    uint8_t items[2];

    items[0] = (bits16 >> 8) & 0xFF;
    items[1] = bits16 & 0xFF;

    sit[0].tx_buf = (uintptr_t) items;
    sit[0].rx_buf = (__u64) 0;
    sit[0].len = 2;
    sit[0].speed_hz = 100000;
    sit[0].bits_per_word = 8;
    sit[0].delay_usecs = 0;
    sit[0].cs_change = 0;

    rvv = ioctl(fd, SPI_IOC_MESSAGE(1), sit);
    return(rvv);
}

The example Source files are here: ad9837-prog.tar.gz where the resulting program can take arguments either a frequency in Hz or a musical note in standardized notation where 'A 4' will be at the reference 440 Hz, and then set the ad9837 to emit a sinusoid at this frequency.

The AD9835 in the older signal-generator product from Sparkfun, now retired is very similar in programming. Hook-up is rather more involved, with the need for 7.5 V power to the on-board regulators, and buffering of MOSI, SCK and SCE through 74LS244s to make the signals 5V.

Microchip 4131-103

This device contains an electronic version of a potentiometer, with 129 steps (0x00 to 0x80 inclusive). Like other SPI devices, it has SCLK, SCE, and the data lines, but this is read/write but with the added complexity that the data line is bidirectional: MISO and MOSI are combined into one.

The resistor element works as a 10 kilo-ohm potentiometer with three connections: the wiper, the low end B, and the high end A. It is limited to voltages between the GND and Vcc connections on the chip, that would be 0V and +5V, but when used with the AD9835 it can work as a variable attenuator on its output. The idea is to be able to use this combination as a signal generator.

The definitions in /usr/include/linux/spi/spidev.h includes a code for 3wire SPI, which is what this is.


Valid XHTML 1.0 Transitional