SPI on AVR-based Arduino boards
AVR processors support SPI over the ICSP connector. Many mirror the connections over pins D10-13.
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.
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.
Each bit in the Control Register controls a specific aspect of SPI. For each bit, there is a symbolic
SPCR – SPI Control Register
The usual way to set a single bit is to use the symbol as a shift count. Consider:
SPIE: SPI Interrupt Enable
SPE: SPI Enable
DORD: Data Order
MSTR: Master/Slave Select
CPOL: Clock Polarity
CPHA: Clock Phase
SPCR = 1 << SPE | 1 << MSTR
This enables the SPI in master mode.
A program can get current information about the SPI by reading from the Status Register. Three bits are defined:
SPSR – SPI Status Register
SPIF: SPI Interrupt Flag
WCOL: Write Collision Flag
SPI2X: Double SPI Speed Bit
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
This transmits the value in variable x over SPI:
SPSR – SPI Data Register
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
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.
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
This example uses processor interrupts to do the data transfer. In the loop()
it checks to see if the buffer has been filled.