What Is the SPI Protocol?
In the world of embedded systems, communication protocols are the neural pathways. When you need to read simple temperature data once per second, a slower protocol like I2C is perfect. But when you need to stream continuous pixels to a 320x240 color TFT screen or read data blocks from an SD card, you need serious throughput. That is where SPI shines.
Unlike I2C or UART, SPI is a synchronous, full-duplex protocol. "Synchronous" means it relies on a shared clock line to synchronize sender and receiver, removing the need for strict baud rates. "Full-duplex" means data flows in both directions simultaneously. There is no software addressing overhead; devices are addressed using physical Chip Select wires, maximizing performance.
- SPI communication protocol enables synchronous full-duplex high-speed data exchange.
- Master devices generate clock signals to coordinate peripheral device transmissions.
- Chip select lines physically activate target peripherals to enable bus communication.
Understanding the 4 Wire Bus Lines
A standard SPI interface relies on exactly four signals. Let's break down what each line does:
- SCK (Serial Clock): Generated strictly by the Master device. This square-wave clock signal synchronizes the shifting and sampling of data bits. The bus speed is defined by this clock frequency.
- MOSI (Master Out Slave In): The data line carrying bits from the Master to the Slave peripheral. (Also sometimes called SDI — Serial Data In, or COPI — Controller Out Peripheral In).
- MISO (Master In Slave Out): The data line carrying bits from the Slave to the Master. (Also sometimes called SDO — Serial Data Out, or CIPO — Controller In Peripheral Out).
- CS / SS (Chip Select / Slave Select): An active-LOW control line driven by the master. When pulled LOW, the specific slave chip is activated and its MISO pin is enabled. When HIGH, the slave ignores the clock and data lines, and tri-states (disconnects) its MISO line, allowing other slaves to share the bus.
Because SPI pins are driven with active push-pull transistors (rather than open-drain pull-up circuits like I2C), the rise and fall times are extremely fast. This physical difference is what allows SPI to scale to 10 MHz, 20 MHz, or even 80 MHz, whereas standard I2C is capped at 400 kHz or 1 MHz.
SPI Clock Modes: CPOL & CPHA
Unlike I2C where the clock format is rigidly standard, SPI is highly flexible. The master and slave must agree on when data bits are changed (shifted) and when they are read (sampled). This behavior is configured using two registers:
- CPOL (Clock Polarity): Defines the idle state of the clock line. CPOL = 0 means clock idles LOW; CPOL = 1 means clock idles HIGH.
- CPHA (Clock Phase): Defines on which clock transition the data is sampled. CPHA = 0 means data is sampled on the first edge (leading edge); CPHA = 1 means data is sampled on the second edge (trailing edge).
These two bits combine to create four distinct SPI Modes. If a microcontroller and a sensor are not set to the exact same mode, data will be offset by one bit or completely corrupted.
| SPI Mode | CPOL | CPHA | Clock Idle | Data Sample Edge |
|---|---|---|---|---|
| Mode 0 (Default) | 0 | 0 | LOW | Rising (Edge 1) |
| Mode 1 | 0 | 1 | LOW | Falling (Edge 2) |
| Mode 2 | 1 | 0 | HIGH | Falling (Edge 1) |
| Mode 3 | 1 | 1 | HIGH | Rising (Edge 2) |
Multi-Slave Topologies: Connecting Multiple Devices
When you have multiple SPI peripherals, you cannot simply wire all of them parallel like I2C because SPI does not use address packets. There are two primary layouts:
1. Independent (Star) Topology (Most Common)
In this layout, the SCK, MOSI, and MISO lines are completely shared among all devices. However, the master must have a dedicated physical Chip Select (CS) pin wired to each slave. To talk to Slave 1, the master pulls CS1 LOW and keeps CS2 and CS3 HIGH. This is simple, fast, and robust, but consumes one extra IO pin on the microcontroller for every slave added.
2. Daisy Chain Topology
If pins are limited, you can daisy chain the devices. The master's MOSI connects to Slave 1's input. Slave 1's output (MISO) connects directly to Slave 2's input, and so on. The final slave's MISO connects back to the master. All slaves share a single CS line. In this mode, the master shifts out a long continuous bitstream that flows through all devices sequentially like a large shift register. This saves pins but is slower and requires complex software handling.
SPI vs I2C vs UART
Choosing the right serial bus protocol is crucial. Let's compare SPI against the other popular options:
| Feature | SPI | I2C | UART |
|---|---|---|---|
| Wires Required | 4 (plus 1 per slave) | 2 (SDA, SCL) | 2 (TX, RX) |
| Max Speed | 50+ Mbps (Very Fast) | 400 kbps – 3.4 Mbps | 115.2 kbps (typical) |
| Duplex | Full Duplex | Half Duplex | Full Duplex |
| Addressing | Hardware (CS Pin) | Software (7/10-bit address) | None (Point-to-Point) |
| Acknowledge | None (Blind send) | Yes (ACK/NACK bit) | None (Parity bit optional) |
| Best For | High-speed displays, SD cards | Low-speed sensors, small PCBs | Computer-to-module links |
Arduino SPI Programming Tutorial
Arduino provides an extremely efficient `SPI` library that leverages the microcontroller's internal hardware SPI engine. Here is a practical example showing how to read a register from an SPI sensor (such as an ADXL345 accelerometer):
// Arduino SPI Sensor Reading Example
// SCK → Pin 13 (Uno) / Pin 52 (Mega)
// MISO → Pin 12 (Uno) / Pin 50 (Mega)
// MOSI → Pin 11 (Uno) / Pin 51 (Mega)
// CS → Pin 10 (Hardware Chip Select)
#include <SPI.h>
const int chipSelectPin = 10;
const byte READ_BYTE = 0x80; // SPI read bit mask
void setup() {
Serial.begin(9600);
// Configure Chip Select pin as active-HIGH output
pinMode(chipSelectPin, OUTPUT);
digitalWrite(chipSelectPin, HIGH); // De-assert CS (high)
// Initialize the hardware SPI bus
SPI.begin();
}
byte readRegister(byte regAddress) {
byte data = 0;
byte address = regAddress | READ_BYTE; // Combine address with read command
// Start SPI Transaction: 4MHz, MSB First, SPI Mode 3
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3));
digitalWrite(chipSelectPin, LOW); // Assert CS (enable slave)
SPI.transfer(address); // Send register address
data = SPI.transfer(0x00); // Send dummy byte to clock in the response
digitalWrite(chipSelectPin, HIGH); // De-assert CS (disable slave)
SPI.endTransaction(); // Release the SPI bus
return data;
}
void loop() {
byte deviceID = readRegister(0x00); // Read Device ID register (0x00)
Serial.print("Sensor Device ID: 0x");
Serial.println(deviceID, HEX);
delay(1000);
}Frequently Asked Questions
What is SPI and how does it work?
SPI is a synchronous, full-duplex serial protocol. The master drives a clock line (SCK) and asserts a Chip Select line (CS) LOW to activate a slave, then shifts bits out to the slave on MOSI while simultaneously shifting bits in from the slave on MISO.
What is the difference between SPI and I2C?
SPI uses 4 wires, requires a physical CS line per slave, and runs at high speeds (50+ Mbps) in full-duplex. I2C uses only 2 wires, supports multiple devices via software addressing, but is slower (typical limit 400kHz–1MHz) and half-duplex.
What are SPI CPOL and CPHA (SPI Modes)?
CPOL and CPHA define clock idle polarity and data sampling phase. They combine to form 4 modes (0, 1, 2, 3). If the master and slave do not match modes, data will become offset or entirely corrupted.
How do you connect multiple slaves to a single SPI master?
You can use Independent (Star) topology, which uses shared MOSI/MISO/SCK lines and a separate CS pin for each slave. Alternatively, you can use Daisy Chain topology where devices are connected in series, passing data through like a shift register.
Does SPI require pull-up resistors like I2C?
No, SPI uses push-pull active drivers which actively pull signals HIGH and LOW, enabling high speeds. Pull-ups are only recommended on the CS line to ensure the slave remains disabled during master startup.
Conclusion
SPI is the absolute workhorse of high-speed embedded communication. Whether you are building an MP3 player reading from an SD card, streaming frames to an LCD screen, or logging data from high-frequency sensors, understanding clock modes, topologies, and CS assertion is key to designing high-performance circuits.
📚 References & Sources
Related Resources
UART vs SPI vs I2C
A direct comparison of all three core serial protocols.
How I2C Works
Learn about I2C, the 2-wire software-addressed alternative to SPI.
How CAN Bus Works
Explore automotive-grade differential serial bus protocols.
How OLED Displays Work
Discover how displays render pixels over SPI/I2C connections.