Lesson 73: SPI Communication
Learn SPI fundamentals, signal lines, clock modes, and practical master-slave data transfer flow.
Progress indicator
Lesson 73 of 73
Learning Objectives
- Understand SPI architecture and why it is fast for peripherals.
- Know MOSI/MISO/SCK/SS line roles in real transfers.
- Understand mode, clock, and bit-order settings clearly.
- Read transaction flow from CS low to CS high safely.
- Avoid common SPI wiring and configuration mistakes.
Concept Explanation
What is SPI
SPI (Serial Peripheral Interface) is a synchronous communication protocol between a controller (master) and peripherals (slaves).
It is commonly used when you need faster transfers than I2C and simple wiring logic.
SPI Communication Basics
Master controls timing with the SPI clock. Data is shifted bit-by-bit on each clock edge. SPI is usually full-duplex: sending and receiving happen together.
Master vs Slave Concept
- Master starts transaction and sets clock.
- Slave responds only when its CS/SS is active.
- One master can control multiple slaves using separate CS pins.
SPI Signal Lines (MOSI, MISO, SCK, SS)
MOSI: Master sends data to slave.MISO: Slave sends data back to master.SCK: Master clock signal.SS/CS: Slave-select line (active LOW in most cases).
SPI Data Transfer Process
- Master configures SPI transaction settings.
- Master pulls target CS LOW.
- Master clocks out bits on MOSI while reading bits on MISO.
- Master sets CS HIGH to end frame/command.
SPI Clock and Speed
Clock speed is set in SPISettings(clock, bitOrder, mode). Start at safe speed and increase gradually after communication is stable.
SPI Modes Explained
Modes combine clock polarity (CPOL) and phase (CPHA). Common names: SPI_MODE0 to SPI_MODE3. Master and slave mode must match.
When to Use SPI
- Displays, flash memory, ADC/DAC chips, high-speed sensors.
- When deterministic timing is important.
- When short wires and higher data rate are acceptable design choices.
Example Code
This example runs one-byte SPI transfer with explicit transaction and CS control.
#include <SPI.h>
const int CS_PIN = 5;
byte txValue = 0x3A;
void setup() {
Serial.begin(115200);
pinMode(CS_PIN, OUTPUT);
digitalWrite(CS_PIN, HIGH);
SPI.begin(); // Initialize SPI bus pins and hardware
}
void loop() {
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(CS_PIN, LOW); // Select slave
byte rxValue = SPI.transfer(txValue); // Full-duplex transfer
digitalWrite(CS_PIN, HIGH); // Deselect slave
SPI.endTransaction();
Serial.print("TX=0x");
Serial.print(txValue, HEX);
Serial.print(", RX=0x");
Serial.println(rxValue, HEX);
delay(500);
}Example Code Explanation
SPI.begin()enables SPI peripheral and default pin mapping.SPI.beginTransaction(...)applies mode, speed, and bit order.- CS LOW selects the slave before transfer.
SPI.transfer(txValue)sends TX byte and receives RX byte simultaneously.- CS HIGH finalizes current SPI frame.
SPI.endTransaction()releases bus config context safely.- Serial output confirms transmitted and received values.
What Happens Inside
- Master writes outgoing byte into SPI shift register.
- Clock pulses move bits out/in one edge at a time.
- Slave shift register responds with return bits over MISO.
- Master assembles received bits into final RX byte.
- CS deactivation ends command frame for selected slave.
Common Mistakes with SPI
- Wrong SPI mode (CPOL/CPHA mismatch) causing garbage data.
- CS not handled correctly (left LOW too long or toggled incorrectly).
- Clock too fast for slave or wiring quality.
- MOSI/MISO swapped in wiring.
Best Practices for SPI
- Always use transaction APIs for shared SPI bus safety.
- Set each slave CS HIGH by default; activate one slave at a time.
- Start slow clock (e.g., 1 MHz), then tune upward after validation.
- Use Serial logging and logic analyzer when debugging unstable transfers.
Try it now
Open the simulator workspace and step through SPI transaction and chip-select flow.