This page documents a newer SPI library, released in Arduino 1.0.6 and Teensyduino 1.20, with beginTransaction() and endTransaction(). These new transaction functions prevent SPI bus conflicts, so their use it recommended for all new projects.

Hardware Requirements

SPI Library: DigitalPotControl Example

SPI has 4 signals: SS, SCK, MOSI, MISO. SCK is a clock signal. Master Out Slave In (MOSI) sends data from the SPI master to one or more slaves. Master In Slave Out (MISO) is how slaves send data back to the master. To talk to only one of several slaves, the Slave Select (SS) pin is used. Thus, some chips need only 3 or even 2 of these signals; a display, for example, will use MOSI but not MISO, as it is an output only device.

Multiple SPI devices use the same SPI SCK, MISO and MOSI signals but each device will need it's own SS pin.

Signal

Function

Teensy2.0

Teensy++2.0

Teensy3.0/3.1

Teensy 3.0/3.1Alternate

SS

Select Device

0

20

10

SCK

Clock

1

21

13

14

MOSI

Data Output

2

22

11

7

MISO

Data Input

3

23

12

8

Arduino automatically defines "SS", "SCK", "MOSI", and "MISO" as the pin
numbers for the selected board. Teensy 3.0 and 3.1 can use an alternate set of SPI pins; see below.

Call this function first, to initialize the SPI hardware. The SCK, MOSI and MISO pins are initialized. You should manaully
configure the SS pin.

SPI.usingInterrupt(interrupt)

If your program will perform SPI transactions within an interrupt, call this function
to register the interrupt number or name with the SPI library. This allows beginTransaction()
to prevent usage conflicts.

SPI.beginTransaction(SPISettings(clockspeed, MSBFIRST, SPI_MODE0))

Begin using the SPI bus. Normally this is called before asserting the chip select
signal. The SPI is configured to use the clock, data order
(MSBFIRST or LSBFIRST) and data mode (SPI_MODE0, SPI_MODE1, SPI_MODE2, or SPI_MODE3).
The clock speed should be the maximum speed the SPI slave device can accept.

digitalWrite(SSpin, level)

Most SPI devices define a transfer of multiple bytes. You need to write
the SS pin before the transfer begins (most chips use LOW during the transfer)
and write it again after the last byte, to end the transfer.
See below for more SS pin details.

SPI.transfer(data)

Transmit a byte from master to slave, and simultaneously receive a byte from slave to master.
SPI always transmits and receives
at the same time, but often the received byte is ignored. When only reception is needed,
0 or 255 is transmitted to cause the reception.

SPI.endTransaction()

Stop using the SPI bus. Normally this is called after de-asserting the chip select,
to allow other libraries to use the SPI bus.

Example Program

This example can be opened from the menu: File > Examples > SPI > DigitalPotControl.
The code here is an abreviated version. See the example for comments describing
the required hardware and other details.

Any digital pin can be used for a SS (slave select) signal. The SPI library does not
control the SS signals, because devices differ on when this is used, whether it is held low for multiple transfers or for each individual transfer, and so on. Control SS with digitalWrite().

However, the SS pin must either be configured as an output, or if it is an input, it must
remain low during the SPI transfer. Unconfigured pins default to input, and a pin with
no signal can easily "float" to random voltages due to electrical noise. Always configure
the SS pin as an output, or make sure it remains low.

Most SPI devices are designed to work together with others, where SCK, MISO, and MOSI
are shared. Each chip needs a separate SS signal. Only the selected chip will
communicate. The others ignore SCK and MOSI, and avoid driving MISO when they are
not selected.

The SPI protocol allows for a range of transmission speeds ranging from 1Mhz to 100MHz. SPI slaves vary in the maximum speed at which they can reliably work. Slower speeds are usually needed when 5 volt signals are converted to 3 volts using only resistors. Together with the capacitance associated with the wire and pins,
resistors can distort the pulses on the wire, requiring slower speeds.

Very long wires may also require slower speeds. When using long wires (more than
25 cm or 1 foot), a 100 ohm resistor should be placed between the Teensy's pin and
the long wire.

Most SPI chips transfer data with the MSB (most significant bit) first, but LSB first is also used by some devices.

The serial clock can be either normally high or normally low (clock polarity), and data can be sent on the rising or falling clock edge (clock phase). The four combinations of clock phase and polarity are expressed as the clock mode, numbered 0 to 3 (more on clock modes). Most SPI chips are designed to work with either mode 0 or mode 3.

If all the SPI slaves in a project use mode 0, MSB first, and work at the default 4MHz clock speed, you don't need to set any SPI options. If any use non default setting, then define this for all SPI devices you are using.

A common problem used to be that different SPI devices needed different, incompatible settings. Your sketch had to take care of saving and restoring the SPI settings before communicating with each SPI device. If any SPI device was accessed from an interrupt, this could result in data corruption if another SPI device was communicating at the time.

With the new SPI library, configure each SPI device once as an SPISettings object. Also, if that device will be called from an interrupt, say so with SPI.usingInterrupt(interruptNumber). To communicate with a specific SPI device, use SPI.beginTransaction which automatically uses the settings you declared for that device. In addition, it will disable any interrupts that use SPI for the duration of the transaction. Once you are finished, use SPI.endTransaction() which re-enables any SPI-using interrupts.

Used by older versions of the SPI library, this method was not interrupt safe and depended on your sketch doing low-level SPI configuration management.

SPI speed was set indirectly, as a function of the Teensy clock, with SPI.setClockDivider(divider). SPI_CLOCK_DIV2 was the fastest option. This meant that code running on a 16MHz Teensy 2 and a 96MHz Teensy 3.1 would set the SPI speed differently to achieve same actual speed for the device.

SPI bit order was set with SPI.setBitOrder(LSBFIRST), and SPI.setBitOrder(MSBFIRST) to set it back to the default.

The SPI library defaults to mode 0. If a different mode
was needed, SPI.setDataMode(mode) was used.

Sometimes, the SPI pins are already in use for other tasks when an SPI device is added to a project. If that task is simply a digital pin, or an analog input, it is usually better to move that to another pin so that the hardware SPI can be used. Sometimes though, the conflicting pin cannot be moved. The Audio Adapter, for example, uses some of the SPI pins to talk to the Audio DAC over I2S. For this case, Teensy 3.0 and 3.1 provide an alternate set of SPI pins.

The main SPI pins are enabled by default. SPI pins can be moved to their alternate position with SPI.setMOSI(pin), SPI.setMISO(pin), and SPI.setSCK(pin). You can move all of them, or just the ones that conflict, as you prefer. The pin must be the actual alternate pin supported by the hardware, see the table above; you can't just assign any random pin.

You should be aware that libraries sometimes have to move SPI pins. (The Audio Library is an example). If you add an SPI device yto your project and it does not work, check whether the library has moved the pins and if so, use the same pins the library does.

If all else fails, the SPI protocol can be emulated ("bit-banged") in software. This has the advantage that any convenient pins can be used, and the disadvantage that it is much, much slower and prevents your sketch from doing useful work meanwhile.

The SPI library only supports SPI master mode, where it selects the chip to communicate
and the master drives SCK and MISO, and receives on MISO.

SPI slave devices do the opposite. They way for a master to select them, and they
receive the SCK and MOSI signals from the master and transmit on MISO. Virtually all
chips controlled by SPI are slave devices.

The SPI port can work in slave mode, which may be useful if Teensy should appear as
a SPI device to be controlled by another Teensy or other board. The SPI library
does not support slave mode.

Apart from this AVR example, is there an Arduino library which supports slave mode?