Loading header...

SPI — Serial Peripheral Interface

SPI is the protocol you reach for when you need speed. SD cards, TFT displays, ADC chips, flash memory, and shift registers all use SPI. It is synchronous (has a shared clock), full-duplex (sends and receives at the same time), and far faster than UART or I²C.


The Core Idea — Master Controls the Clock

In UART, both sides have their own clocks and agree on speed in advance. SPI is different — there is one master device that generates the clock, and one or more slave devices that follow it.

The master decides exactly when each bit is sent. Slaves have no say — they just respond when the master clocks them.

flowchart LR classDef master fill:#dbeafe,stroke:#2563eb,color:#1e3a5f classDef slave fill:#dcfce7,stroke:#16a34a,color:#14532d classDef wire fill:#fef9c3,stroke:#ca8a04,color:#713f12 M["Master\n(your microcontroller)\ngenerates the clock\ndecides when to talk"]:::master S["Slave\n(sensor, SD card, display...)\nfollows the clock\nresponds when selected"]:::slave M -- "SCK → (clock pulses)" --> S M -- "MOSI → (data out)" --> S S -- "MISO ← (data back)" --> M M -- "SS̄ → (select this slave)" --> S

Four wires:

Wire Full name Direction What it does
SCK Serial Clock Master → Slave Clock pulses from master
MOSI Master Out Slave In Master → Slave Data from master to slave
MISO Master In Slave Out Slave → Master Data from slave back to master
SS̄ Slave Select (active LOW) Master → Slave Tells one specific slave it is being talked to

Full-Duplex — Sending and Receiving at the Same Time

SPI is full-duplex: on every clock pulse, the master sends one bit on MOSI and the slave sends one bit back on MISO — simultaneously. Both sides are shifting their data out at the same time.

Think of it like two people sliding pieces of paper across a table at the same moment — one goes left, one goes right, both happen at the same time.

sequenceDiagram participant M as Master participant S as Slave Note over M,S: SS̄ pulled LOW — slave is selected M->>S: Clock pulse 1 — MOSI bit 7 (MSB) S->>M: Clock pulse 1 — MISO bit 7 (MSB) M->>S: Clock pulse 2 — MOSI bit 6 S->>M: Clock pulse 2 — MISO bit 6 M->>S: Clock pulse 3 — MOSI bit 5 S->>M: Clock pulse 3 — MISO bit 5 M->>S: Clock pulses 4–7 — remaining bits S->>M: Clock pulses 4–7 — remaining bits M->>S: Clock pulse 8 — MOSI bit 0 (LSB) S->>M: Clock pulse 8 — MISO bit 0 (LSB) Note over M,S: SS̄ pulled HIGH — slave deselected Note over M,S: Master has sent 1 byte. Slave has sent 1 byte. At the same time.

If you only want to write (e.g. sending a command to a display), ignore whatever comes back on MISO.
If you only want to read (e.g. reading a sensor value), send a dummy byte (all zeros) on MOSI just to generate the clock pulses.


Slave Select — Choosing Who to Talk To

SS̄ is active LOW — pull it LOW to activate a slave, HIGH to deactivate it. Each slave needs its own SS̄ line going back to the master.

flowchart TD classDef master fill:#dbeafe,stroke:#2563eb,color:#1e3a5f classDef slave fill:#dcfce7,stroke:#16a34a,color:#14532d classDef bus fill:#fef9c3,stroke:#ca8a04,color:#713f12 M["Master MCU"]:::master BUS["Shared bus\nSCK, MOSI, MISO\n(all slaves connected to same 3 wires)"]:::bus S0["Slave 0\nSD Card\nSS̄0 from master"]:::slave S1["Slave 1\nDisplay\nSS̄1 from master"]:::slave S2["Slave 2\nADC Chip\nSS̄2 from master"]:::slave M --> BUS BUS --> S0 BUS --> S1 BUS --> S2 M -- "SS̄0 (LOW = talking to SD card)" --> S0 M -- "SS̄1 (LOW = talking to display)" --> S1 M -- "SS̄2 (LOW = talking to ADC)" --> S2

How a SPI Transaction Works — Step by Step

flowchart TD classDef step fill:#dbeafe,stroke:#2563eb,color:#1e3a5f classDef warn fill:#fee2e2,stroke:#dc2626,color:#7f1d1d A["Pull SS̄ LOW\n→ Slave wakes up and listens"]:::step B["Master starts generating clock pulses on SCK"]:::step C["On each clock pulse:\n• Master shifts next bit out on MOSI\n• Slave shifts its bit out on MISO\n• Both happen at the same moment"]:::step D["After 8 clock pulses: 1 full byte exchanged\nRepeat for more bytes if needed"]:::step E["Pull SS̄ HIGH\n→ Transaction complete, slave goes idle"]:::step F["Never leave SS̄ LOW between transactions\nor the slave stays in a confused state"]:::warn A --> B --> C --> D --> E --> F

Clock Modes — CPOL and CPHA

SPI has 4 modes that define exactly which edge of the clock the data is sampled on. Every SPI device has a specific mode it needs — you must match it.

flowchart TD classDef m0 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f classDef m1 fill:#dcfce7,stroke:#16a34a,color:#14532d classDef m2 fill:#fef9c3,stroke:#ca8a04,color:#713f12 classDef m3 fill:#fee2e2,stroke:#dc2626,color:#7f1d1d M0["Mode 0 (most common)\n──────────────────────\nClock starts LOW\nData captured on the RISING edge\nSD cards, most sensors use this"]:::m0 M1["Mode 1\n──────────────────────\nClock starts LOW\nData captured on the FALLING edge"]:::m1 M2["Mode 2\n──────────────────────\nClock starts HIGH\nData captured on the FALLING edge"]:::m2 M3["Mode 3\n──────────────────────\nClock starts HIGH\nData captured on the RISING edge\nSome thermocouple chips, some displays"]:::m3 M0 --> M1 --> M2 --> M3

[!TIP] When a datasheet does not mention which mode, try Mode 0 first. It works for the majority of SPI devices.


Reading from a Sensor — The Full Picture

Here is what actually happens when you read a temperature value from an SPI sensor:

sequenceDiagram participant M as Master (MCU) participant S as Slave (Sensor) M->>S: Pull SS̄ LOW (select this sensor) M->>S: Send command byte over MOSI (e.g. "read temperature register") S->>M: Slave receives command (MISO sends back dummy data — ignore it) Note over M,S: Sensor now knows what you want M->>S: Send dummy byte (0x00) on MOSI just to generate 8 clock pulses S->>M: Slave sends temperature value back on MISO M->>S: Pull SS̄ HIGH (done — release the slave) Note over M: Master now has the temperature value

SPI vs UART vs I²C

UART SPI I²C
Wires 3 4 + 1 per slave 2 + GND
Speed Up to ~1 Mbps Up to 20+ Mbps 100 kHz – 1 MHz
Devices on bus 1-to-1 only 1 master, many slaves Up to 127
Duplex Full Full (both directions at once) Half
Best for Debug, GPS, GSM SD cards, displays, ADCs Sensors, RTC, EEPROM

Common SPI Devices

Device What it does SPI Mode
SD / microSD card Mass storage Mode 0
ILI9341 / ST7789 TFT colour display Mode 0
MCP3204 4-channel 12-bit ADC Mode 0
MAX31855 Thermocouple sensor Mode 1 or 3
W25Q32 External flash memory Mode 0
74HC595 Shift register (output expander) Mode 0

Practical Tips

  • Always pull SS̄ LOW before sending, HIGH after — never leave a transaction open
  • Wrong mode = wrong data — if you read garbage from a sensor, try changing the clock mode
  • MISO needs a pull-up resistor if the slave might tri-state its MISO (leaves it floating) — add a 10kΩ resistor to VCC
  • One SS̄ pin per slave — SPI does not have addresses like I²C, so the SS̄ wire is the only way to select a device

Previous: ← UART
Next: I²C — Inter-Integrated Circuit →