Introduction

Serial Peripheral Interface (SPI) is a synchronous serial communication protocol commonly used in microcontrollers and embedded systems. On Arduino boards, SPI enables fast, efficient communication with various external peripherals such as sensors, memories and wireless communication modules. This protocol is appreciated for its simplicity, speed and flexibility.

How it works

The SPI link is synchronous, which means that transmission requires the clock given before transmission.

It’s a full-duplex link, which means that you can listen to what you’re transmitting while sending bits.

It’s not an exclusive link: the circuits communicate according to a master-slave scheme, where the master takes care of all communication. Several slaves can coexist on the same bus, in which case selection of the recipient is made via a dedicated line between master and slave called chip select, as shown in the diagram below:

SPI has lines labeled “MOSI”: Master Output Slave Input, generated by the master, lines labeled “MISO”: Master Input Slave Output, generated by the slave, and a clock line (SCK: SPI Serial Clock).

 

These three lines are connected to their respective lines on one or more slaves. Slaves are identified by their CS (Chip Select) line signal.

SPI pin on Arduino board

On Arduino boards, the pins dedicated to SPI vary according to the board model. For example, on an Arduino Uno, the SPI pins are :

  • MISO: Pin 12
  • MOSI: Pin 11
  • SCK: Pin 13
  • SS: Pin 10 (or any other user-configured pin)

Writing to SPI

Arduino simplifies the use of SPI with its SPI.h library. Here’s a basic example of how to use this library to communicate with an SPI device:

#include <SPI.h>

void setup() {
  // Initialize SPI communication
  SPI.begin();
  // Configure SS pin as output
  pinMode(10, OUTPUT);
}

void loop() {
  // Activate slave by setting SS to LOW
  digitalWrite(10, LOW);
  
  // Send data byte to SPI device
  byte dataSent = 0x42;
  byte dataReceived = SPI.transfer(dataSent);
  
  // Disable slave by setting SS to HIGH
  digitalWrite(10, HIGH);
  
  // Wait before retransmitting
  delay(1000);
}

The following program sends byte 42 via the SPI wires.

SPI reading

If you want to read the values on the SPI of the Arduino board :

#include <SPI.h>

// Set the SS (Slave Select) pin
const int slaveSelectPin = 10;

void setup() {
  // Initialize serial communication to display results
  Serial.begin(9600);

  // Set SS pin as output
  pinMode(slaveSelectPin, OUTPUT);

  // Initialize SPI communication
  SPI.begin();

  // Optional: Set SPI parameters
  SPI.setClockDivider(SPI_CLOCK_DIV16); // Divide clock by 16 (1 MHz for a 16 MHz clock)
  SPI.setDataMode(SPI_MODE0); // SPI mode 0
  SPI.setBitOrder(MSBFIRST); // Bit order: MSB first
}

void loop() {
  // Activate slave by setting SS to LOW
  digitalWrite(slaveSelectPin, LOW);

  // Send a read request to the SPI device
  byte requestByte = 0x00; // Example of request (may vary depending on device)
  byte receivedValue = SPI.transfer(requestByte);

  // Disable slave by setting SS to HIGH
  digitalWrite(slaveSelectPin, HIGH);

  // Display received value in serial monitor
  Serial.print("Value received: ”);
  Serial.println(receivedValue);

  // Wait before reading again
  delay(1000);
}

Conclusion

If you’d like to know more about the communications buses available on Arduino, we’ve written courses on UART and I2C.

If you’d like to apply what you’ve seen in this course, you can read our course on RFID, which uses the SPI link to operate.