SPI: Serial Peripheral Interface
SPI is a synchronous board-level serial bus used when an MCU needs fast, simple communication with peripherals such as ADCs, DACs, displays, flash memories, shift registers, radios, and SD cards. One controller provides the clock. Selected peripherals shift data in and out at the same time.
SPI is fast because it is simple. The tradeoff is that SPI has no universal addressing, no universal command format, and no built-in acknowledgement. The wiring and timing are generic; the transaction meaning comes from each device data sheet.
Learning Objectives
By the end of this lesson, you should be able to:
- identify SCK, MOSI, MISO, chip select, supply, and ground connections;
- explain full-duplex shifting and dummy bytes;
- choose the correct clock polarity and phase from a data sheet;
- calculate transfer time from SPI clock frequency and bits transferred;
- design a shared SPI bus with one chip-select line per peripheral;
- debug mode errors, bus contention, floating MISO, and signal-integrity problems.
Core Idea: The Controller Owns The Clock
SPI is synchronous. The controller starts a transaction by asserting a chip-select signal, then toggles SCK. On each clock cycle, one bit moves from controller to peripheral on MOSI and one bit moves back on MISO.
Many older data sheets say master and slave. Newer documents often use controller and peripheral. The signals are the same.
SPI Signals
| Signal | Direction | Purpose |
|---|---|---|
| SCK | controller to peripheral | serial clock |
| MOSI | controller to peripheral | controller data output |
| MISO | peripheral to controller | peripheral data output |
| CS, SS, or nCS | controller to peripheral | selects one device, usually active LOW |
| GND | shared reference | required for logic-level signaling |
Some vendors use alternate names: COPI for controller-out peripheral-in, CIPO for controller-in peripheral-out, and SDO/SDI from the device point of view. Always map names from the data sheet before wiring.
Full-Duplex Shifting
SPI shift registers exchange bits simultaneously. Even a read operation requires the controller to transmit something, often a dummy byte, because clock pulses are created only while the controller sends.
For many sensors, the first byte is a command or register address. The meaningful response appears in the next byte or next several bytes. The first returned byte may be dummy data.
Clock Polarity And Phase
SPI has four common modes. They are defined by clock polarity CPOL and clock phase CPHA.
| Mode | CPOL | CPHA | Idle SCK | Capture edge, common wording |
|---|---|---|---|---|
| 0 | 0 | 0 | LOW | first edge, rising |
| 1 | 0 | 1 | LOW | second edge, falling |
| 2 | 1 | 0 | HIGH | first edge, falling |
| 3 | 1 | 1 | HIGH | second edge, rising |
The mode must match the peripheral data sheet. If the mode is wrong, data may look shifted by one bit, unstable, or completely wrong. Do not rely on "mode 0 usually works" when the data sheet specifies another mode.
Transfer Time
SPI throughput is set by SCK and by protocol overhead.
$$
t_{bits} = \frac{N_{bits}}{f_{SCK}}
$$
For a 16-bit register read that sends an 8-bit command and receives 16 data bits, many devices require 24 clock cycles:
$$
t = \frac{24}{8,MHz} = 3,us
$$
Real transaction time also includes chip-select setup time, chip-select hold time, firmware overhead, and any required delay between command and data.
Multiple Devices On One Bus
SCK, MOSI, and often MISO are shared. Each peripheral gets its own chip-select line.
Only one chip-select should be active at a time unless the hardware is intentionally designed for a special daisy-chain or broadcast case. If two peripherals drive MISO at once, the bus is electrically contended and data is corrupted.
Electrical Design Rules
- Keep SPI traces short on a PCB, especially at high SCK rates.
- Route SCK cleanly; it is the signal most likely to cause timing and ringing issues.
- Use series damping resistors near the driver when edges are fast and traces are long enough to ring.
- Confirm that all devices use compatible I/O voltage.
- Keep chip-select HIGH during reset until firmware configures the peripheral.
- Check whether MISO is high impedance when CS is inactive.
- Avoid long off-board SPI cables; use a robust physical layer when distance or noise is significant.
Firmware Transaction Pattern
uint8_t spi_transfer(uint8_t out);
void cs_low(void);
void cs_high(void);
uint16_t read_register16(uint8_t reg) {
uint8_t hi;
uint8_t lo;
cs_low();
(void)spi_transfer(0x80u | reg); /* command byte: read selected register */
hi = spi_transfer(0x00u); /* dummy output clocks in high byte */
lo = spi_transfer(0x00u); /* dummy output clocks in low byte */
cs_high();
return ((uint16_t)hi << 8) | lo;
}
This code is a generic pattern, not a universal command format. Real devices define read/write bits, address size, dummy cycles, byte order, and CS timing in their own data sheets.
Worked Example: Reading A 12-Bit ADC
Suppose an SPI ADC requires 3 command bits, 1 null bit, and 12 data bits. The controller clocks 16 bits total at 2 MHz.
$$
t = \frac{16}{2,MHz} = 8,us
$$
If the ADC must be sampled at 10 kS/s, the sample period is:
$$
T_s = \frac{1}{10000} = 100,us
$$
An 8 us transfer fits easily, but firmware must still leave time for chip-select timing, interrupt latency, processing, and other bus users.
Practical Debug Checklist
- Confirm supply voltage and I/O level compatibility.
- Verify SCK, MOSI, MISO, CS, and GND mapping from the device data sheet.
- Keep all chip-selects HIGH except the target device.
- Confirm CPOL, CPHA, bit order, word length, and maximum SCK.
- Start with a slow SCK, then increase after the transaction is correct.
- Use a logic analyzer to inspect CS, SCK, MOSI, and MISO together.
- Check whether the first returned byte is dummy data.
- Confirm that inactive peripherals release MISO.
Common Mistakes
- Swapping MISO and MOSI because names are read from opposite device perspectives.
- Leaving a chip-select LOW between transactions.
- Selecting two peripherals at the same time.
- Using the wrong SPI mode.
- Reading the first dummy byte as real data.
- Clocking faster than the peripheral or board layout can support.
- Forgetting pull-ups or default states for chip-select during reset.
- Trying to run SPI over a long cable in a noisy machine.
Summary
SPI is a fast synchronous bus where the controller selects one peripheral, generates SCK, and exchanges one bit in each direction per clock cycle. Correct SPI design depends on matching the data sheet mode and timing, controlling chip-select lines carefully, avoiding MISO contention, and validating signal quality at the actual clock rate.
Further Reading
- Motorola SPI Block Guide for the original SPI concepts.
- Microchip and STMicroelectronics SPI peripheral reference manual chapters.
- Texas Instruments application notes on SPI timing and signal integrity.
- Device data sheets for MCP320x ADCs, W25Q flash memories, and common display controllers.
Mind Map
Previous: UART
Next: I2C: Inter-Integrated Circuit