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 name | GPIO |
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 |
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 name | GPIO |
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
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 name | Display 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
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 name | MCP3201 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
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 name | Name | MAX6675 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.
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 name | Device name | Device pin # |
P2 | 5.0V | Vin | JP3-4 |
P24 | SPI0_CE0 | FSYNC | JP3-12 |
P19 | SPI0_MOSI | SDATA | JP3-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.
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.