SPI on AVR-based Arduino boards

AVR processors support SPI over the ICSP connector. Many mirror the connections over pins D10-13.

Missing slave

The Arduino libraries provide the SPIClass to use SPI in master mode. But if you are developing a device that will run as a SPI slave, you need to find another way. The sample code here shows a solution.

Hardware registers

There are circuits built into the AVR chips that react when a program reads or writes to certain constant memory addresses. They are described in the datasheet. The libraries in the Arduino IDE contain symbolic definitions for those constant addresses.

Three registers are used for the SPI interface.

SPCR – SPI Control Register

Each bit in the Control Register controls a specific aspect of SPI. For each bit, there is a symbolic value: The usual way to set a single bit is to use the symbol as a shift count. Consider:

SPCR = 1 << SPE | 1 << MSTR

This enables the SPI in master mode.

SPSR – SPI Status Register

A program can get current information about the SPI by reading from the Status Register. Three bits are defined: SPIF indicates a transfer of one byte has been completed. If so, a program can receive and send another byte. This is how it could be checked:
if ( SPSR & 1 << SPIF )
{
// Read and write a byte
}

SPSR – SPI Data Register

This transmits the value in variable x over SPI:

SPDR = x;

This reads a value from SPI into x:

x = SPDR;

Note that different shift registers are used for reading and writing so that the seemingly incorrect:

SPDR = x;
x = SPDR;

actually changes the value of x. When a program writes to SPSR, the value is transmitted over SPI. When a program reads from SPSR, a value that is received is returned.

Sample sketches

Polling

This sample code runs SPI in slave mode. It interrogates the SPI status register in the loop(). If status register indicates that the last transfer is complete, the sketch reads and writes a byte.

Interrupt

This example uses processor interrupts to do the data transfer. In the loop() it checks to see if the buffer has been filled.