57  SPI Protocol

Key Concepts
  • SPI (Serial Peripheral Interface): A four-wire synchronous serial bus using MOSI, MISO, SCLK, and CS lines; faster than I²C but requires a separate CS line per slave
  • MOSI (Master Out Slave In): The data line from the master to the slave device
  • MISO (Master In Slave Out): The data line from the slave to the master device
  • SCLK (Serial Clock): The clock signal generated by the master that synchronises data transfer
  • CS (Chip Select): An active-low signal from the master that enables a specific slave device; one CS line required per slave
  • SPI Mode: The combination of clock polarity (CPOL) and clock phase (CPHA) settings; must match between master and slave (4 modes: 0, 1, 2, 3)
  • Full-Duplex Operation: SPI transfers data simultaneously in both directions (MOSI and MISO active at the same time) in every clock cycle

57.1 In 60 Seconds

SPI (Serial Peripheral Interface) is a 4-wire, full-duplex synchronous protocol using MOSI, MISO, SCLK, and one chip-select (SS) line per slave device. It achieves speeds of 10+ Mbps – much faster than I2C – making it ideal for high-throughput peripherals like SD cards, displays, and ADCs. The trade-off is more wires: each additional slave needs its own SS line, and there is no standardized addressing or acknowledgment mechanism.

57.2 Learning Objectives

By the end of this chapter, you will be able to:

  • Explain SPI Architecture: Identify the four-wire structure (MOSI, MISO, SCK, SS) and describe the role of each signal in full-duplex data transfer
  • Configure SPI Modes: Select the correct clock polarity (CPOL) and phase (CPHA) combination for a given device datasheet
  • Construct SPI Wiring: Connect multiple slave devices to a single master using individual chip-select lines
  • Distinguish Protocol Trade-offs: Compare SPI, I2C, and UART across speed, pin count, device capacity, and duplex mode to justify the best choice for a given application
  • Diagnose SPI Faults: Identify the root cause of mode mismatch, chip-select conflicts, and signal-integrity problems from observed symptoms
  • Implement SPI Code: Build and configure Arduino/ESP32 firmware to communicate with SD cards and displays using the SPI library

SPI (Serial Peripheral Interface) is a fast communication method that connects a main controller to sensors and displays using four wires. Think of it as a one-on-one conversation where the controller picks which device to talk to by tapping it on the shoulder. SPI is faster than I2C but uses more wires, so it is great when speed matters.

“When I need to go FAST, I use SPI,” said Max the Microcontroller. “It can do over 10 Mbps – way faster than I2C’s 400 kHz! That is why SD cards, color displays, and high-speed ADCs use SPI.”

“SPI has four wires,” explained Sammy the Sensor. “MOSI sends data from Max to me, MISO sends data from me back to Max, SCLK is the shared clock, and SS is my personal select wire. When Max pulls my SS line low, it means ‘Sammy, you are up!’ and I start responding.”

Lila the LED noticed a trade-off. “The cool thing is SPI is full-duplex – Max can send and receive data at the SAME time. But the downside is each device needs its own SS wire. With 10 sensors, Max needs 10 extra wires just for chip selects!”

“So here is the rule of thumb,” said Bella the Battery. “Use SPI when you need speed – reading from an SD card, driving a fast display, or sampling audio data. Use I2C when you have lots of slow sensors and want minimal wiring. And use UART for simple two-device connections like a GPS module. Each protocol has its sweet spot!”

57.3 Prerequisites

Before diving into this chapter, you should be familiar with:


57.4 SPI Overview

SPI (Serial Peripheral Interface) is a high-speed, full-duplex synchronous protocol developed by Motorola.

No official standard - implementations vary slightly between manufacturers.

57.4.1 Characteristics

Feature Value
Wires 4+ wires (SCLK, MOSI, MISO, + 1 SS per slave)
Topology Multi-point (star)
Sync/Async Synchronous (SCLK = clock)
Duplex Full-duplex (simultaneous send/receive)
Speed Up to 10+ Mbps (much faster than I2C)
Distance <1 meter (short cables, same PCB)
Devices Unlimited (limited by SS pins available)
Master/Slave Single master, multiple slaves

SPI’s speed advantage over I2C comes from the absence of pull-up resistors and their RC time constant limitation.

For a 10 cm PCB trace with 50 pF capacitance (typical for SPI slave input), driven by push-pull output (20 Ω source impedance):

\[t_r = 2.2 \times R_{source} \times C_{load} = 2.2 \times 20 \times 50 \times 10^{-12} = 2.2 \text{ ns}\]

This allows clock frequencies up to: \[f_{max} = \frac{0.35}{t_r} = \frac{0.35}{2.2 \times 10^{-9}} = 159 \text{ MHz}\]

For I2C with 4.7 kΩ pull-up and same 50 pF load: \[t_r = 2.2 \times 4700 \times 50 \times 10^{-12} = 517 \text{ ns}\] \[f_{max} = \frac{0.35}{517 \times 10^{-9}} = 677 \text{ kHz}\]

This explains why SPI routinely runs at 10-80 MHz while I2C maxes out at 400 kHz (standard) or 3.4 MHz (high-speed with active pull-ups). With the parameters above, SPI is ~235× faster than standard I2C; in general the speed ratio scales with the pull-up resistance value and is driven entirely by the RC time constant of the open-drain pull-up network.

Try It: SPI vs I2C Rise Time Calculator

57.5 SPI Signals

SPI uses four dedicated lines between master and slave. Figure 57.1 shows the four signals, and Figure 57.2 shows how a single master connects to multiple slaves using shared data lines with individual chip-select lines.

SPI signal diagram showing four lines: MOSI for master output slave input, MISO for master input slave output, SCK for clock signal, and SS/CS for slave select chip enable
Figure 57.1: SPI signal lines showing MOSI, MISO, SCK, and SS connections
SPI Bus architecture diagram showing one master connected to multiple slave devices sharing MOSI, MISO, and SCLK lines with individual chip-select lines per slave
Figure 57.2: SPI Bus Architecture with Multiple Slaves

Signal names (vary by manufacturer):

Function Alternative Names
SCLK SCK, CLK (Serial Clock)
MOSI SDI, DI, SI (Master Out Slave In)
MISO SDO, DO, SO (Master In Slave Out)
SS CS, CE (Slave Select / Chip Select)

SCLK (Serial Clock):

  • Clock signal from master
  • Slaves synchronize to this clock

MOSI (Master Out, Slave In):

  • Data from master to slave
  • Master writes, slaves read

MISO (Master In, Slave Out):

  • Data from slaves to master
  • Slaves write, master reads

SS (Slave Select):

  • Active LOW (usually)
  • Master pulls LOW to select specific slave
  • Separate SS line for each slave

57.6 SPI Modes

SPI has 4 modes based on clock polarity (CPOL) and phase (CPHA). Figure 57.3 illustrates how each combination of CPOL and CPHA determines when data is sampled relative to the clock edge.

SPI clock polarity CPOL and phase CPHA timing diagram showing four modes: mode 0 CPOL=0 CPHA=0, mode 1 CPOL=0 CPHA=1, mode 2 CPOL=1 CPHA=0, mode 3 CPOL=1 CPHA=1 with data sampling points
Figure 57.3: SPI clock mechanism and timing showing clock polarity and phase
Mode CPOL CPHA Clock Idle Data Sampled
0 0 0 LOW Rising edge
1 0 1 LOW Falling edge
2 1 0 HIGH Falling edge
3 1 1 HIGH Rising edge

CPOL (Clock Polarity):

  • 0 = Clock idle state is LOW
  • 1 = Clock idle state is HIGH

CPHA (Clock Phase):

  • 0 = Data sampled on leading edge (first transition)
  • 1 = Data sampled on trailing edge (second transition)

Most common: Mode 0 and Mode 3

Important: Master and slave must use same mode!


57.7 SPI Data Transfer

Full-duplex simultaneous transfer:

     SS   ____                        ________
              \______________________/

   SCLK   ___   _   _   _   _   _   _   _   ___
             \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/

   MOSI   ====X===X===X===X===X===X===X===X=====
          (Master sends data to slave)

   MISO   ====X===X===X===X===X===X===X===X=====
          (Slave sends data to master)

          Bit:  7   6   5   4   3   2   1   0

Process:

  1. Master pulls SS LOW (select slave)
  2. Master generates clock pulses on SCLK
  3. On each clock pulse:
    • Master outputs bit on MOSI
    • Slave outputs bit on MISO
    • Both sides shift data simultaneously
  4. After 8 (or 16) bits, transaction complete
  5. Master pulls SS HIGH (deselect slave)

Data transmitted MSB first (most significant bit first) - can be configured.


57.8 Arduino/ESP32 SPI Example

#include <SPI.h>

// SS (Chip Select) pin
#define SS_PIN 5

void setup() {
  Serial.begin(115200);

  // Initialize SPI
  SPI.begin();

  // Configure SS pin
  pinMode(SS_PIN, OUTPUT);
  digitalWrite(SS_PIN, HIGH);  // Deselect

  Serial.println("SPI Initialized");
}

void loop() {
  // Begin transaction BEFORE asserting CS (required by Arduino SPI library)
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));

  // Select slave
  digitalWrite(SS_PIN, LOW);

  // Transfer data (sends 0xAA, receives slave's response simultaneously)
  byte response = SPI.transfer(0xAA);

  // Deselect slave BEFORE ending transaction
  digitalWrite(SS_PIN, HIGH);
  SPI.endTransaction();

  Serial.print("Sent: 0xAA, Received: 0x");
  Serial.println(response, HEX);

  delay(1000);
}

Wiring (ESP32 default SPI pins):

ESP32 GPIO 18 (SCLK) -> Slave SCLK
ESP32 GPIO 23 (MOSI) -> Slave MOSI
ESP32 GPIO 19 (MISO) -> Slave MISO
ESP32 GPIO 5  (SS)   -> Slave SS/CS
ESP32 GND            -> Slave GND

Common SPI devices:

  • SD card modules
  • TFT/OLED displays
  • NRF24L01 radio modules
  • ADXL345 accelerometer
  • MCP3008 ADC

Practical Tips

Choosing the Right SPI Mode:

  1. Check device datasheet - Look for CPOL/CPHA or explicit mode number
  2. Try Mode 0 first - Works with ~80% of SPI devices
  3. Try Mode 3 second - If Mode 0 fails (some displays, Ethernet)
  4. Modes 1 and 2 rare - Only specific industrial/legacy devices

Common Mode Assignments:

  • SD Cards: Mode 0 (CPOL=0, CPHA=0)
  • TFT Displays: Mode 0 or Mode 3
  • ADXL345: Mode 3 (CPOL=1, CPHA=1)
  • NRF24L01: Mode 0
  • W5500 Ethernet: Mode 0

Debugging Mode Issues:

  • Symptom: Garbled data, bits shifted
  • Solution: Try different modes (SPI_MODE0 through SPI_MODE3)
  • Test: Send known byte (0xAA = 10101010), verify response

57.9 Hands-On Lab: SD Card Reader

Objective: Read/write files to SD card via SPI.

#include <SPI.h>
#include <SD.h>

#define SD_CS 5  // Chip Select pin

void setup() {
  Serial.begin(115200);

  if (!SD.begin(SD_CS)) {
    Serial.println("SD card initialization failed!");
    return;
  }
  Serial.println("SD card initialized");

  // Write to file
  File file = SD.open("/test.txt", FILE_WRITE);
  if (file) {
    file.println("Hello from ESP32!");
    file.close();
    Serial.println("File written");
  }

  // Read from file
  file = SD.open("/test.txt");
  if (file) {
    Serial.println("\nFile contents:");
    while (file.available()) {
      Serial.write(file.read());
    }
    file.close();
  }
}

void loop() {}

57.10 Knowledge Check: SPI Signal Integrity

Scenario: Your data logger uses an SPI flash memory (Winbond W25Q128) rated for 133 MHz clock. Tests at 80 MHz work reliably (98% success rate), but at 133 MHz you see 40% corruption. A logic analyzer reveals clock signal overshoot (+5.8V on 3.3V logic) and ringing (+/-0.8V oscillations lasting 12 ns).

Think about:

  1. Why do PCB traces behave differently at 133 MHz vs 10 MHz?
  2. What physical phenomena cause the overshoot and ringing?

Key Insight: At high frequencies, transmission line effects dominate PCB design. A 10 cm trace at 133 MHz becomes an antenna:

  • Signal wavelength: lambda = c/f = (3x10^8 m/s) / (133x10^6 Hz) = 2.26 meters
  • Critical length: lambda/10 = 22.6 cm (your trace is 10 cm -> significant effects)
  • Fast edge time: ~2 ns (10%-90% rise) creates harmonics up to 500 MHz

Root causes:

  • Impedance mismatch: 50 ohm PCB trace -> 10 ohm chip pin creates reflection coefficient Gamma = (10-50)/(10+50) = -0.67 (67% negative reflection)
  • Reflected wave: Bounces back toward source, interfering with forward signal (ringing)
  • Overshoot: Reflected wave adds to forward wave (constructive interference)

Solutions:

  1. Series termination: 22-33 ohm resistor at source dampens reflections
  2. Shorter traces: Reduce to <5 cm (<lambda/40 at 133 MHz)
  3. Controlled impedance: Design 50 ohm traces (width/height ratio)
  4. Ground plane: Continuous plane under signal reduces loop inductance

Verify Your Understanding:

  • Why does this matter more at 133 MHz than 10 MHz? Because lambda/10 at 10 MHz = 3 meters (trace is insignificant). At 133 MHz, lambda/10 = 22 cm (trace is significant fraction).
  • Calculate required series resistor: Source impedance (5 ohm) + resistor (27 ohm) = 32 ohm approximately equal to 50 ohm trace impedance (minimizes reflections).

57.11 Protocol Comparison for IoT

Understanding SPI in isolation is only half the story. Every IoT design involves choosing the right protocol for each peripheral. The table below summarizes the primary wired protocols covered in this module.

57.11.1 When to Use Each Protocol

Protocol Best For Avoid When
RS-232 GPS modules, serial debugging, industrial legacy systems Multiple devices on same bus, high speed needed
I2C Multiple low-speed sensors (temp, humidity, pressure), displays, EEPROMs High-speed data transfer (video, audio), long cables
SPI High-speed sensors, SD cards, displays, radio modules Pin count is limited, long-distance communication

57.11.2 Detailed Comparison

Wired protocol selection flowchart showing decision paths to choose between SPI, I2C, UART, RS-485, and CAN Bus based on device count, speed, distance, and duplex requirements
Figure 57.4: Wired Protocol Selection Decision Flowchart

57.11.3 Practical Trade-offs

I2C Advantages:

  • Only 2 wires (minimal pins)
  • Easy to add devices (just connect to bus)
  • Addressable (up to 112 devices)
  • Bidirectional on same wire

I2C Disadvantages:

  • Slower than SPI
  • Pull-up resistors required
  • Address conflicts possible
  • Limited cable length

SPI Advantages:

  • Very fast (10+ Mbps)
  • Full-duplex (simultaneous send/receive)
  • Simple, no addressing
  • No pull-up resistors needed

SPI Disadvantages:

  • More wires (4+ pins)
  • Separate SS for each slave (pin intensive)
  • No multi-master capability
  • No flow control
Protocol Selection Guide

Choose UART when:

  • Point-to-point communication (2 devices)
  • Serial debugging or console needed
  • GPS module, Bluetooth HC-05/HC-06
  • Cable lengths up to 15 meters

Choose I2C when:

  • Multiple devices (2-112 on same bus)
  • Limited pins (only 2 wires available: SDA, SCL)
  • Low-to-medium speed OK (< 400 kHz)
  • Sensors, displays, EEPROMs, RTCs

Choose SPI when:

  • High speed required (1-10+ Mbps)
  • Enough pins available (4+ wires)
  • SD cards, TFT displays, fast sensors
  • Full-duplex needed (simultaneous TX/RX)

Real-World Examples:

  • Weather station: I2C (BME280, OLED display on same bus)
  • Data logger: SPI (SD card for fast writes)
  • GPS tracker: UART (GPS module + serial debug)
  • Robot: Mixed (I2C for sensors, SPI for displays, UART for debug)

57.12 Quiz: SPI and Protocol Comparison


Interactive: SPI Communication Protocol

Interactive Animation: This visualization is under development.

57.13 Decision Framework: SPI vs I2C vs UART

Choosing the right wired protocol is one of the first design decisions in any embedded IoT project. The wrong choice leads to either inadequate performance or unnecessary wiring complexity.

57.13.1 Quick Decision Table

Question SPI I2C UART
How many devices? 1-4 (limited by SS pins) 1-112 (bus addressing) 1 (point-to-point)
Need speed >1 Mbps? Yes (10+ Mbps) No (max 3.4 MHz, usually 400 kHz) No (max ~1 Mbps)
Board space tight? No (4+ wires) Yes (2 wires) OK (2 wires)
Full-duplex needed? Yes (simultaneous TX/RX) No (half-duplex) Yes (separate TX/RX)
Distance >1 meter? No No Yes (RS-485: up to 1200 m)
Need acknowledgment? No (no ACK mechanism) Yes (ACK/NACK per byte) No (unless added in software)

57.13.2 Worked Example: Weather Station Design

A weather station needs to connect these peripherals to an ESP32:

Peripherals:
  1. BME280 (temperature/humidity/pressure) - supports I2C and SPI
  2. SSD1306 OLED display (128x64) - supports I2C and SPI
  3. SD card module (data logging) - SPI only
  4. GPS module (NEO-6M) - UART only
  5. Wind speed sensor (pulse counter) - GPIO (not a bus protocol)

Analysis:

Peripheral I2C SPI UART Best Choice Why
BME280 Supported Supported No I2C Low data rate (14 bytes per read), saves 2 pins vs SPI
SSD1306 OLED Supported (slow) Supported (fast) No SPI Display refresh at I2C 400 kHz takes ~23 ms per frame (1024 bytes × 9 bits/byte / 400 kHz); SPI at 8 MHz takes ~1 ms (~22× faster)
SD card No Required No SPI SD cards only support SPI (and native SD interface)
GPS No No Required UART GPS modules output NMEA sentences over serial

Pin allocation:

I2C bus (2 pins):     GPIO21 (SDA), GPIO22 (SCL) -> BME280
SPI bus (3 pins):     GPIO18 (SCK), GPIO23 (MOSI), GPIO19 (MISO)
  SD card SS:         GPIO5
  OLED SS:            GPIO15
  OLED DC (data/cmd): GPIO4
UART (2 pins):        GPIO16 (RX), GPIO17 (TX) -> GPS

Total pins used: 10 out of 34 available GPIO

Why not put everything on I2C? The OLED display would bottleneck. At I2C 400 kHz, writing 1 KB of display data takes ~23 ms (1,024 bytes × 9 bits/byte ÷ 400,000 bps). The SD card does not support I2C at all. The GPS module outputs continuous serial data that would block the I2C bus if it were somehow connected.

Why not put everything on SPI? The BME280 would waste 2 pins (SS + the SPI bus is already used by 2 other devices). Since BME280 reads are infrequent (every few seconds) and tiny (14 bytes), I2C is perfectly adequate and saves wiring.

Try It: SPI Transfer Time Calculator

Common Pitfalls

A sensor expecting SPI Mode 0 (CPOL=0, CPHA=0) connected to a master configured for Mode 3 will produce corrupted data. Fix: always check the sensor’s datasheet for the required SPI mode and configure the master to match before testing.

High SPI clock speeds (> 10 MHz) on PCB traces longer than 10 cm cause signal integrity issues (ringing, reflections). Fix: add a series resistor (33–100 Ω) on the SCLK line near the driver and reduce clock speed for long traces or off-board connections.

The CS line must be low before the first SCLK edge for the slave to latch data correctly. Some implementations assert CS mid-transaction. Fix: verify CS assertion timing with an oscilloscope or logic analyser before relying on SPI data integrity.

57.14 Summary

This chapter covered SPI (Serial Peripheral Interface) protocol and protocol comparison:

  • Four-wire interface (SCLK, MOSI, MISO, SS) enables high-speed full-duplex communication
  • SPI modes (0-3) define clock polarity and phase - must match between master and slave
  • Chip select (SS/CS) lines enable multi-slave configurations with separate select per device
  • Speed advantage: 10+ Mbps vs I2C’s 400 kbps, ideal for SD cards, displays, and fast sensors
  • Trade-off: More pins (4+ wires) vs I2C’s 2 wires, no multi-master, no addressing
  • Protocol selection: Use SPI for high-throughput peripherals (SD cards, displays), I2C for multi-sensor buses, UART for serial-output modules (GPS, cellular modems)

57.15 What’s Next

Having mastered SPI and wired protocol selection, explore these complementary topics:

Topic Chapter Description
UART and RS-232 UART and RS-232 Point-to-point serial communication for GPS modules, debug consoles, and cellular modems
Wired Fundamentals Wired Communication Fundamentals Signal types, timing diagrams, and topology concepts underlying all wired protocols
I2C Protocol I2C Protocol The 2-wire alternative to SPI for multi-sensor buses with hardware addressing
Wired Communication Overview Wired Communication Overview Module overview covering all wired IoT protocols and when to apply each
Network Physical Layer Wired Ethernet Ethernet standards and physical-layer considerations for wired IoT infrastructure
Layered Network Models OSI and TCP/IP Models How SPI and other link-layer protocols fit within the full networking stack