Home ArduinoArduino Tutorials Tutorial: Arduino Serial Peripheral Interface (SPI)

Tutorial: Arduino Serial Peripheral Interface (SPI)

by shedboy71

Serial Peripheral Interface (SPI) is a communication protocol used to transfer data between microcontrollers and peripheral devices like sensors, SD cards, displays, and more.

It is faster than I2C and uses a master-slave architecture.

This tutorial explains how SPI works, its implementation on Arduino, and provides practical examples.

Table of Contents

1. What Is SPI?

SPI is a synchronous serial communication protocol that uses four main lines:

  1. MOSI (Master Out Slave In): Data sent from master to slave.
  2. MISO (Master In Slave Out): Data sent from slave to master.
  3. SCK (Serial Clock): Clock signal controlled by the master.
  4. SS (Slave Select): Selects which slave device to communicate with.

Key Features:

  • Full-duplex: Data can be sent and received simultaneously.
  • Fast Communication: Suitable for high-speed data transfer.
  • Multiple Slaves: Can connect several slave devices with unique SS pins.

2. How Does SPI Work?

  1. The master generates a clock signal on the SCK line.
  2. Data is sent via MOSI (from master) or MISO (from slave).
  3. The master selects the target slave device using the SS line.
  4. The master and slave exchange data bits on every clock pulse.

3. Setting Up SPI on Arduino

Master Device

The master initiates communication and controls the clock.

Slave Device

The slave responds to the master’s requests and sends data when addressed.

4. Arduino SPI Library

The SPI library simplifies SPI communication in Arduino. You can include it in your project as follows:

#include <SPI.h>

4.1 SPI.begin()

  • Initializes the SPI bus.
  • Use on the master device.

4.2 SPI.transfer(data)

  • Sends data from the master to the slave and simultaneously receives data from the slave.
  • Returns the received byte.

4.3 SPI.end()

  • Disables the SPI bus.

5. SPI Pin Configuration

Board MOSI MISO SCK SS
Arduino Uno 11 12 13 10
Arduino Mega 51 50 52 53
Arduino Nano 11 12 13 10

6. Practical Examples

6.1 Communicating Between Two Arduinos

Master Code

#include <SPI.h>

const int ssPin = 10;

void setup() {
  pinMode(ssPin, OUTPUT);
  digitalWrite(ssPin, HIGH);  // Ensure slave is not selected
  SPI.begin();                // Initialize SPI as master
  Serial.begin(9600);
}

void loop() {
  digitalWrite(ssPin, LOW);           // Select slave
  byte receivedData = SPI.transfer(42); // Send data and receive response
  digitalWrite(ssPin, HIGH);          // Deselect slave

  Serial.print("Received: ");
  Serial.println(receivedData);
  delay(1000);
}

Slave Code

#include <SPI.h>

const int ssPin = 10;

void setup() {
  pinMode(ssPin, INPUT);
  SPI.begin();  // Initialize SPI as slave
  SPI.setBitOrder(MSBFIRST); // Set bit order (default)
}

void loop() {
  if (digitalRead(ssPin) == LOW) {
    byte data = SPI.transfer(0); // Respond with dummy data
    SPI.transfer(data + 1);      // Return data incremented by 1
  }
}

6.2 Interfacing with an SPI Sensor

Use an SPI temperature sensor (e.g., MCP3008).

#include <SPI.h>

const int csPin = 10;

void setup() {
  pinMode(csPin, OUTPUT);
  digitalWrite(csPin, HIGH);  // Deselect sensor
  SPI.begin();
  Serial.begin(9600);
}

void loop() {
  digitalWrite(csPin, LOW);                // Select sensor
  SPI.transfer(0b00000001);                // Start bit
  byte highByte = SPI.transfer(0b10000000); // Send configuration bits
  byte lowByte = SPI.transfer(0);          // Read data
  digitalWrite(csPin, HIGH);               // Deselect sensor

  int value = ((highByte & 0x03) << 8) | lowByte; // Combine bytes
  Serial.print("Sensor Value: ");
  Serial.println(value);

  delay(500);
}

6.3 Controlling an SPI Display

Control an SPI OLED or LCD display (e.g., SSD1306).

  1. Install Adafruit SSD1306 Library:
    • Go to Tools > Manage Libraries and search for “Adafruit SSD1306.”
  2. Connect the Display:
    • Connect MOSI, SCK, CS, and DC to appropriate pins.
  3. Code Example:
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define CS_PIN 10

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &SPI, OLED_RESET, DC, CS_PIN);

void setup() {
  if (!display.begin(SSD1306_I2C_ADDRESS, CS_PIN)) {
    Serial.println("OLED initialization failed");
    while (1);
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Hello, SPI Display!");
  display.display();
}

void loop() {
  // Empty
}

7. Best Practices for Using SPI

  1. Use Pull-Up Resistors:
    • Use pull-up resistors on the SS lines to prevent floating states.
  2. Select the Correct Mode:
    • SPI devices operate in different modes (clock polarity and phase). Refer to the device datasheet to configure the correct mode using:
      SPI.setDataMode(SPI_MODE0);
      
  3. Handle Shared Buses:
    • If multiple slaves share the SPI bus, ensure only one slave is active at a time by managing the SS lines.
  4. Monitor Clock Speed:
    • Use SPI.setClockDivider() to adjust the speed based on the slave device’s requirements.
  5. Debug with Serial Monitor:
    • Print transmitted and received data to verify communication.

Conclusion

SPI is a versatile and high-speed communication protocol, ideal for connecting Arduino with various peripherals.

By using the built-in SPI library, you can simplify communication and focus on building your project.

This tutorial provided an introduction to SPI, its functions, and practical examples like Arduino-to-Arduino communication, interfacing with a sensor, and controlling a display.

For more details, visit the official Arduino SPI reference.

 

You may also like