The Serial Peripheral Interface (SPI)

[Overview] [Bus Description] [Registers] [ISP]


The SPI (Serial Peripheral Interface) is a peripheral used to communicate between the AVR and other devices, like others AVRs, external EEPROMs, DACs, ADCs, etc. With this interface, you have one Master device which initiates and controls the communication, and one or more slaves who receive and transmit to the Master.

The core of the SPI is an 8-bit shift register in both the Master and the Slave, and a clock signal generated by the Master. Let's say the Master wants to send a byte of data (call it A) to the Slave and at the same time receive another byte of data from the Slave (call it B). Before starting the communication, the Master places A in its shift register, and the Slave places B in its shift register. (Figure 1-a). Then the Master generates 8 clock pulses, and the contents of the Master's shift register are transferred to the Slave's shift register and vice versa (Figure 1-b to 1-e). So, at the end of the clock pulses, the Master has completely received B, and the Slave has received A. As you can see, the transmission and reception occurs at the same time, so it is a full duplex data transfer.

The first image is the sate of the two devices before the transfer:

Bus Description

Before you can successfully communicate through the SPI, both the Master and Slave must agree on some clock signal settings. Details on how to configure this in the AVR will be discussed later.

Please note that not all AVRs have an SPI (you must check the particular datasheet). If your AVR doesn't have an SPI, you still can implement it in software (the details are not discussed here).

In an AVR, four signals (pins) are used for the SPI: MISO, MOSI, SCK and SS' (SS' means SS complemented). Here is a brief description of the function of each signal:

MISO (Master In Slave Out): the input of the Master's shift register, and the output of the Slave's shift register.

MOSI (Master Out Slave In): the output of the Master's shift register, and the input of the Slave's shift register.

SCK (Serial Clock): In the Master, this is the output of the clock generator. In the Slave, it is the input clock signal.

SS' (Slave Select): Since in an SPI setup you can have several slaves at the same time, you need a way to select which Slave you want to communicate to. This is what SS' is used for. If SS' is held in a high state, all Slave SPI pins are normal inputs, and will not receive incoming SPI data. On the other hand, if SS' is held in a low state, the SPI is activated. The software of the Master must control the SS'-line of each Slave.
If the SPI-device is configured as a Master, the behavior of the SS' pin depends on the configured data direction of the pin. If SS' is configured as an output, the pin does not affect the SPI. If SS' is configured as an input, it must be held high to ensure Master SPI operation. If the SS' pin is driven low, the SPI system interprets this as another Master selecting the SPI as a Slave and starting to send data to it. Having two SPI Masters is quite unusual, so the details of how to manage this are not discussed here (if you are curious, read the datasheet). So, if you want to keep your life simple, configure the Master's SS' pin as an output.

The following figures show a typical setup used with SPI:

A word of caution about the SPI pin names. MISO, MOSI, SCK and SS' are the names used by AVRs. Other devices may use a different set of names. You must check the data sheet of the particular device you are using to get them right.

What are the data directions of the SPI pins? It depends on the particular pin and on whether the SPI is set as a Master or Slave. In general, there are two possibilities. A pin is configured as an input regardless of the setting of the Data Direction Register of the port, or the pin must be configured by the user according to its function. The following table summarizes this:

Pin Direction, Master SPI Direction, Slave SPI
MOSI User defined Input
MISO Input User defined
SCK User defined Input
SS' User defined Input




(SPI Control Register)

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

SPIE (SPI Interrupt Enable) bit: Set SPIE to one if you want the SPI interrupt to be executed when a serial transfer is completed.

SPE (SPI Enable) bit: If you want to use the SPI, you must set this bit.

DORD (Data Order) bit: You can choose in which order the data will be transmitted. Set DORD to one to send the least significant bit (LSB) first. Set DORD to zero to send the most significant bit (MSB) first.

MSTR (Master/Slave Select) bit: Set MSTR to configure the AVR as a Master SPI device. Clear MSTR to configure it as a Slave.

CPOL (Clock Polarity) and CPHA (Clock Phase) bits: As stated previously, Master and Slave must agree on how to interpret the clock signal. The first thing to do is to configure which logic level the clock will be in when the SPI is idle. If CPOL is set to one, SCK is high when idle, and if CPOL is set to zero, SCK is low when idle. The second thing is to configure during which clock transition the data will be sampled. Set CPHA to sample the data on the trailing (last) edge, and clear CPHA to sample the data in the leading (first) edge.

So, there are four different ways of configuring the clock generation, which are known as 'SPI modes'. The following table summarizes the four SPI modes.

0 0 0 Leading (Rising) Edge
1 0 1 Trailing (Falling) Edge
2 1 0 Leading (Falling) Edge
3 1 1 Trailing (Rising) Edge

The following image shows figure 76 and 77 from the mega128 datasheet:

SPR1 and SPR2 (SPI Clock Rate Select) bits: The SPR bits configure the frequency of the clock signal. Since the Slave reads the clock from an input pin, the SPR bits have no effect on the Slave. The frequency of the SPI clock is related to the frequency of the AVR oscillator. The faster the SPI clock signal is, the faster the data trasfer will be, however, you must respect the maximum clock frequency specified by the Slave (as usual, read the datasheet). The following table summarizes the relationship between the SCK frequency and the SPR bits:

SPR1 SPR0 SCK frequency
0 0 fosc/4
0 1 fosc/16
1 0 fosc/64
1 1 fosc/128


(SPI Status Register)

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

SPIF (SPI Interrupt Flag) bit: This is a read only bit. It is set by hardware when a serial transfer is complete. SPIF is cleared by hardware when the SPI interrupt handling vector is executed, or when the SPIF bit and the SPDR register are read.

WCOL (Write Colision Flag) bit: This is a read only bit. The WCOL bit is set if the SPDR register is written to during a data transfer. The WCOL bit (and the SPIF bit) are cleared by first reading the SPI Status Register with WCOL set, and then accessing the SPI Data Register.

SPI2x (Double SPI Speed) bit: This feature is not implemented in all AVRs (check the particular data sheet). When this bit is set to one, the SPI speed will be doubled when the SPI is in Master mode.


(SPI Data Register)

The SPI Data Register is a read/write register used for data transfer between the Register File and the SPI Shift Register. Writing to the register initiates data transmission. Reading the register causes the Shift Register receive buffer to be read.

Finally, here is a code snippet to generate a data transfer between a Master and a Slave. Both Master and Slave are configured to send the MSB first and to use SPI mode 3. The clock frequency of the Master is fosc/16. The Master will send the data 0xAA, and the Slave the data 0x55.

Master code:

ldi r16,01011101b
out SPCR,r16
ldi r16,0xAA
out SPDR,r16
rjmp Wait
in SPDR,r16
; Set MOSI as output.
; Set SCK as output.
; Set SS' as output.
; Set SPI as a Master, with interrupt disabled,
; MSB first, SPI mode 3 and clock frequency fosc/16.
; Initiate data transfer.
; Wait for transmission to complete.
; The received data is placed in r16.

Slave code

ldi r16,01001100b
out SPCR,r16
ldi r16,0x55
out SPDR,r16
rjmp SPI_Receive
in r16,SPDR
; Set MISO as an output.
; Set SPI as a Slave, with interrupt disabled,
; MSB first and SPI mode 3.
; Send 0x55 on Master request.
; Wait for reception to complete.
; The received data is placed in r16.

SPI and In Circuit Programming (ISP)

The SPI interface is also used to program the AVR. If you want to program your AVR in-circuit and are using the SPI interface, a series resistor should be placed on each of the three dedicated lines to avoid 'driver contention' (see figure below). A driver contention is the situation you get if two outputs are connected together. For more details, see AVR application note No. 910.