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
Plan SPI Applications: Translate timing, chip-select, and mode requirements into test steps before wiring SD cards, displays, and sensors
For Beginners: The SPI Protocol
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.
Sensor Squad: The Speed Demon!
“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:
I2C Protocol: Comparison with I2C helps understand when to choose SPI
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
Putting Numbers to It
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 a 20 Ω push-pull output, the edge rises much faster than an I2C pull-up line:
Case
Calculation
Result
SPI rise time
2.2 × 20 Ω × 50 pF
2.2 ns
SPI maximum clock estimate
0.35 ÷ 2.2 ns
159 MHz
I2C rise time with 4.7 kΩ pull-up
2.2 × 4,700 Ω × 50 pF
517 ns
I2C maximum clock estimate
0.35 ÷ 517 ns
677 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.
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.
Figure 57.1: SPI signal lines showing MOSI, MISO, SCK, and SS connections
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.
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:
Signal
What you should see
Direction during the byte
SS/CS
Goes LOW before the first clock and HIGH after the byte
Master selects exactly one peripheral
SCLK
Eight clock pulses for one 8-bit byte
Master provides timing
MOSI
One bit is presented for each clock edge
Master sends command/data to the peripheral
MISO
One bit is returned at the same time
Peripheral sends status/data back to the master
Bit order
Usually bit 7 first, then down to bit 0
Check the peripheral datasheet
Process:
Master pulls SS LOW (select slave)
Master generates clock pulses on SCLK
On each clock pulse:
Master outputs bit on MOSI
Slave outputs bit on MISO
Both sides shift data simultaneously
After 8 (or 16) bits, transaction complete
Master pulls SS HIGH (deselect slave)
Data transmitted MSB first (most significant bit first) - can be configured.
57.8 Arduino/ESP32 SPI Example
Use the timing diagrams and transfer calculator first. This sketch is optional for learners who have an ESP32 and an SPI peripheral ready to test.
Optional ESP32 SPI Build Checklist
Stage
What to verify
Success evidence
Choose clock mode
Match CPOL/CPHA from the peripheral datasheet
Logic analyzer idle level and sample edge match the datasheet.
Keep CS high at idle
Configure the chip-select pin as output and deselect the device
Peripheral does not drive MISO until selected.
Start a transaction
Set clock speed, bit order, and SPI mode before pulling CS low
Clock and data timing are stable for the whole byte.
Transfer a known byte
Send a test pattern such as 0xAA
MOSI alternates bits; MISO returns a repeatable response.
End cleanly
Pull CS high before releasing the bus
MISO goes inactive and another SPI device can be selected safely.
ESP32 wiring reference:
ESP32 pin
SPI signal
Peripheral pin
GPIO 18
SCLK
SCLK
GPIO 23
MOSI
MOSI / SDI / DIN
GPIO 19
MISO
MISO / SDO / DOUT
GPIO 5
SS / CS
CS
GND
Ground
GND
Common SPI devices:
SD card modules
TFT/OLED displays
NRF24L01 radio modules
ADXL345 accelerometer
MCP3008 ADC
Practical Tips
Choosing the Right SPI Mode:
Check device datasheet - Look for CPOL/CPHA or explicit mode number
Try Mode 0 first - Works with ~80% of SPI devices
Try Mode 3 second - If Mode 0 fails (some displays, Ethernet)
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.
Optional SD Card Reader Workflow
Stage
Student action
Evidence to record
Inspect module
Confirm the SD breakout voltage and level shifting
Module is safe for 3.3 V ESP32 logic.
Wire SPI lines
Connect SCLK, MOSI, MISO, CS, 3.3 V, and GND
Card initializes only when the correct CS pin is used.
Start slowly
Use a conservative SPI clock first
Initialization succeeds before speed tuning.
Write a test file
Create a short text file
Directory listing shows the new file.
Read it back
Reopen the file and compare content
Read text matches the written text exactly.
Common failure interpretation:
Symptom
Likely cause
First fix
Initialization fails
Wrong CS pin, weak power, or bad card format
Recheck CS wiring and format the card as FAT32.
Reads work but writes fail
Card locked, brownout, or file-system issue
Check card lock switch and power stability.
Random corruption
Clock too fast or long jumper wires
Lower SPI clock and shorten wiring.
57.10 Knowledge Check: SPI Signal Integrity
Understanding Check: SPI Signal Integrity at High Speeds
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:
Why do PCB traces behave differently at 133 MHz vs 10 MHz?
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:
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
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
Quiz Questions
57.12.1 Review Practice
Interactive: SPI Communication Protocol
Use this quick mode visualizer before wiring a real peripheral. Set the CPOL and CPHA values from a datasheet and compare the clock idle state and sampling edge with what you would expect to see on a logic analyzer.
Show code
viewof spi_mode_cpol = Inputs.select([0,1], {label:"CPOL: clock polarity",value:0,format: d => d ===0?"0 - clock idles LOW":"1 - clock idles HIGH"})viewof spi_mode_cpha = Inputs.select([0,1], {label:"CPHA: clock phase",value:0,format: d => d ===0?"0 - sample on leading edge":"1 - sample on trailing edge"}){const mode = spi_mode_cpol *2+ spi_mode_cpha;const idle = spi_mode_cpol ===0?"LOW":"HIGH";const leading = spi_mode_cpol ===0?"rising":"falling";const trailing = spi_mode_cpol ===0?"falling":"rising";const sample = spi_mode_cpha ===0? leading : trailing;const shift = spi_mode_cpha ===0? trailing : leading;returnhtml`<div style="font-family:Arial,sans-serif;background:#f8fbfd;border-left:4px solid #16A085;border-radius:8px;padding:16px;"> <div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-bottom:12px;"> <div style="background:white;border:1px solid #d8e2ea;border-radius:8px;padding:12px;text-align:center;"> <div style="font-size:0.8em;color:#5f7280;text-transform:uppercase;letter-spacing:.05em;">SPI Mode</div> <div style="font-size:2em;font-weight:700;color:#17364f;">${mode}</div> </div> <div style="background:white;border:1px solid #d8e2ea;border-radius:8px;padding:12px;text-align:center;"> <div style="font-size:0.8em;color:#5f7280;text-transform:uppercase;letter-spacing:.05em;">Clock Idle</div> <div style="font-size:2em;font-weight:700;color:#17364f;">${idle}</div> </div> <div style="background:white;border:1px solid #d8e2ea;border-radius:8px;padding:12px;text-align:center;"> <div style="font-size:0.8em;color:#5f7280;text-transform:uppercase;letter-spacing:.05em;">Sample Edge</div> <div style="font-size:2em;font-weight:700;color:#16A085;">${sample}</div> </div> </div> <svg viewBox="0 0 760 170" style="width:100%;max-width:760px;display:block;margin:auto;background:white;border:1px solid #d8e2ea;border-radius:8px;"> <text x="24" y="30" font-size="15" font-weight="700" fill="#17364f">What to check on the logic analyzer</text> <line x1="90" y1="${spi_mode_cpol ===0?118:58}" x2="150" y2="${spi_mode_cpol ===0?118:58}" stroke="#17364f" stroke-width="4"/> <polyline points="150,${spi_mode_cpol ===0?118:58} 150,${spi_mode_cpol ===0?58:118} 230,${spi_mode_cpol ===0?58:118} 230,${spi_mode_cpol ===0?118:58} 310,${spi_mode_cpol ===0?118:58} 310,${spi_mode_cpol ===0?58:118} 390,${spi_mode_cpol ===0?58:118} 390,${spi_mode_cpol ===0?118:58} 470,${spi_mode_cpol ===0?118:58} 470,${spi_mode_cpol ===0?58:118} 550,${spi_mode_cpol ===0?58:118}" fill="none" stroke="#17364f" stroke-width="4"/> <text x="24" y="92" font-size="14" fill="#5f7280">SCLK</text> <line x1="${sample === leading ?150:230}" y1="42" x2="${sample === leading ?150:230}" y2="136" stroke="#16A085" stroke-width="3" stroke-dasharray="6 5"/> <line x1="${sample === leading ?310:390}" y1="42" x2="${sample === leading ?310:390}" y2="136" stroke="#16A085" stroke-width="3" stroke-dasharray="6 5"/> <text x="${sample === leading ?160:240}" y="52" font-size="13" font-weight="700" fill="#16A085">sample ${sample} edge</text> <text x="570" y="78" font-size="14" font-weight="700" fill="#17364f">Shift: ${shift} edge</text> <text x="570" y="104" font-size="14" font-weight="700" fill="#17364f">Sample: ${sample} edge</text> </svg> <p style="margin:12px 0 0;color:#5f7280;font-size:0.9em;">If the master and peripheral disagree on either CPOL or CPHA, every byte can be shifted or sampled at the wrong time.</p> </div>`;}
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:
Peripheral
Interface options
What it does
BME280 temperature/humidity/pressure sensor
I2C or SPI
Sends a few sensor bytes every few seconds.
SSD1306 OLED display
I2C or SPI
Needs larger screen-refresh transfers.
SD card module
SPI only
Logs measurements quickly to storage.
GPS module (NEO-6M)
UART only
Streams NMEA text sentences continuously.
Wind speed sensor
GPIO pulse input
Counts pulses rather than using a bus protocol.
Analysis:
Peripheral
Best bus
Student-friendly reason
BME280 sensor
I2C
One slow sensor read only needs a few bytes, so saving pins matters more than speed.
SSD1306 OLED
SPI
A full screen update is much larger than a sensor read; SPI keeps refreshes responsive.
SD card
SPI
The common breakout module expects SPI, and logging benefits from the higher data rate.
GPS module
UART
GPS modules continuously stream text sentences over serial, so UART is the natural fit.
Pin allocation:
Function
ESP32 pins
Connected device
Pins used
I2C bus
GPIO21 (SDA), GPIO22 (SCL)
BME280
2
SPI shared bus
GPIO18 (SCK), GPIO23 (MOSI), GPIO19 (MISO)
SD card and OLED
3
SD card chip select
GPIO5
SD card CS
1
OLED chip select
GPIO15
OLED CS
1
OLED data/command
GPIO4
OLED DC
1
UART
GPIO16 (RX), GPIO17 (TX)
GPS
2
Total
10 of 34 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.
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.
2. Running SPI at Maximum Clock Speed on Long PCB Traces
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.
3. Not Asserting CS Low Before the First Clock Edge
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.13.3 Label the Diagram
57.13.4 Code Challenge
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: