Arduino — SPI

Serial Peripheral Interface (SPI) is a synchronous serial data protocol used by microcontrollers for communicating with one or more peripheral devices quickly over short distances. It can also be used for communication between two microcontrollers.

In an SPI connection, there is always a master device (usually a microcontroller) that controls the peripheral devices.

SPI uses the following four wires:

SCK − This is the serial clock driven by the master that synchronizes the data transmission.

MOSI − This is the master output/slave input driven by the master.

MISO − This is the master input/slave output driven by the master.

SS − This is the pin on each device that the master can use to enable/disable specific devices.

When a device’s Slave Select pin is low, it communicates with the master. When it’s high, it ignores the master. This allows you to have multiple SPI devices sharing the same MISO, MOSI, and CLK lines.

SPI has four modes of operations:

Mode 0 (the default) − Clock is low (CPOL = 0), and the data is sampled on the transition from low to high (leading edge) (CPHA = 0).

Mode 1 − Clock is low (CPOL = 0), and the data is sampled on the transition from high to low (trailing edge) (CPHA = 1).

Mode 2 − Clock is high (CPOL = 1), and the data is sampled on the transition from high to low (leading edge) (CPHA = 0).

Mode 3 − Clock is high (CPOL = 1), and the data is sampled on the transition from low to high (trailing edge) (CPHA = 1).

SPI Communication in Arduino

The following figure shows the pins in Arduino UNO which are used for SPI communication.

Image for post

Now, we’ll look at an example of SPI communication between two Arduinos. We’ll be configuring one Arduino as a master and another Arduino board as a slave. Following is the diagram for the connections between both the boards.

Note: The ground connection is common.

Image for post

Arduino SPI as a Master device

The Master unit sends ‘Hello World’ to the slave.

Image for post

Arduino SPI as a Slave

The slave device waits for the data, as soon as data arrives, the process variable becomes true indicating there is data in the buffer. In the main loop, we read this buffer and send it to the serial terminal.

Image for post

Image for post

Now let’s look at the functions that we used for the SPI communication between both boards.

  • SPI.begin() − This function initializes the SPI bus by setting SCK, MOSI, and SS to outputs, pulling SCK and MOSI low, and SS high.
  • SPI.setClockDivider(divider) − This sets the SPI clock divider relative to the system clock. On AVR based boards, the dividers available are 2, 4, 8, 16, 32, 64, or 128. The default setting is SPI_CLOCK_DIV4, which sets the SPI clock to one-quarter of the frequency of the system clock (5 Mhz for the boards at 20 MHz). The divider could be (SPI_CLOCK_DIV2, SPI_CLOCK_DIV4, SPI_CLOCK_DIV8, SPI_CLOCK_DIV16, SPI_CLOCK_DIV32, SPI_CLOCK_DIV64, SPI_CLOCK_DIV128).
  • SPI.transfer(val) − SPI transfer is based on simultaneously sending and receiving data: the received data is returned in receivedVal.
  • SPI.attachInterrupt(handler) − This function is called when a slave device receives data from the master.
  • SPI.beginTransaction(SPISettings(speedMaximum, dataOrder, dataMode)) − Initializes the SPI bus using the defined SPI settings where, speedMaximum is the clock, dataOrder(MSBFIRST or LSBFIRST) and dataMode is (SPI_MODE0, SPI_MODE1, SPI_MODE2, or SPI_MODE3).

Once you’ve compiled and uploaded the respective programs on both the boards, you’ll be able to see ‘Hello World’ on the serial monitor of the slave.

In this blog, we went through SPI communication in an Arduino board, its different modes of operations and saw a simple example that implemented the SPI communications protocol.