What Is SPI (Serial Peripheral Interface)?
Last updated 19 August 2026 · 7 min read
Direct Answer
SPI (Serial Peripheral Interface) is a synchronous, full-duplex serial bus that uses a shared clock and separate data lines to let one controller communicate with one or more peripheral devices at high speed, typically over four signals: SCLK, MOSI, MISO, and CS.
Detailed Explanation
SPI is built around four signals:
- SCLK (Serial Clock): generated by the controller, sets the bit rate.
- MOSI (Controller Out, Peripheral In): carries data from controller to peripheral.
- MISO (Controller In, Peripheral Out): carries data from peripheral to controller.
- CS (Chip Select): one per peripheral; the controller drives it low to address a specific device.
Because SPI is full-duplex, a controller can shift data out on MOSI and read data in on MISO during the same clock cycle. There is no addressing scheme on the bus itself; device selection is handled entirely by which CS line is asserted, which is why each peripheral typically needs its own.
Newer controller and peripheral datasheets increasingly label MOSI/MISO as SDO (Serial Data Out) and SDI (Serial Data In) instead, since "controller/peripheral" replaced the older master/slave naming in most vendor documentation. The signals are functionally identical either way, but check which naming convention a specific datasheet uses before wiring: SDO on one chip connects to SDI on the other, the same cross-connection rule UART's TX/RX follows.
SPI Modes: Clock Polarity and Phase (CPOL/CPHA)
Clock polarity (CPOL) and clock phase (CPHA) together define one of four SPI "modes," which determine when the clock idles and which clock edge data is sampled on. Both controller and peripheral must be configured to the same mode, and a mismatch is one of the most common sources of "SPI isn't working" bugs (see Common Mistakes below for a worked example of exactly this failure).
| Mode | CPOL | CPHA | Clock idles | Data sampled on |
|---|---|---|---|---|
| 0 | 0 | 0 | Low | Rising (leading) edge |
| 1 | 0 | 1 | Low | Falling (trailing) edge |
| 2 | 1 | 0 | High | Falling (leading) edge |
| 3 | 1 | 1 | High | Rising (trailing) edge |
Mode 0 is the most commonly used default across embedded peripherals, but this varies by device family. Always confirm the required mode from the specific peripheral's datasheet rather than assuming mode 0 will work: some peripherals (many EEPROMs and flash chips) support two modes, others accept only one.
Multi-Device Topologies: Independent Chip Select vs Daisy-Chain
The standard way to put multiple peripherals on one SPI bus is a shared SCLK/MOSI/MISO with an independent CS line per device (sometimes called a "star" or "independent-slave" topology). The controller asserts exactly one CS at a time, and only that device drives MISO. This is the configuration assumed by most SPI peripherals and requires one controller GPIO per device.
A smaller number of peripheral families support daisy-chain mode instead: shift-register ICs like the 74HC595, and some SPI-compatible ADC and LED-driver chains, wire MISO of one device into MOSI of the next so all devices share a single CS and SCLK, and the controller shifts data through the entire chain as one long shift register. Daisy-chaining trades GPIO count (one CS regardless of chain length) for a longer total transfer per device addressed and firmware that must know the exact chain length and bit ordering. Confirm daisy-chain support in the specific peripheral's datasheet first: it is not a universal SPI feature, and wiring MISO-to-MOSI between devices that don't support it will not work.
Maximum Clock Speed
SPI clock rate is set by the controller and is generally limited by whichever is slower: the peripheral's maximum rated SCLK frequency (from its datasheet, commonly a few MHz to tens of MHz depending on the device) or the signal integrity of the physical connection. Short, well-routed PCB traces can usually run at or near a peripheral's rated maximum; longer traces, cables, or connectors between boards introduce ringing and reflections that force a lower practical speed than the datasheet maximum suggests. Always verify the achieved clock rate against the peripheral's rated maximum, and derate further for any off-board or cabled connection.
Practical Examples
A typical use case is reading a sensor: an SPI accelerometer is wired with SCLK, MOSI, and MISO shared with other SPI devices on the same bus, and its own dedicated CS line back to a GPIO pin on the microcontroller. The firmware drives CS low, shifts out a register-read command on MOSI while clocking, reads the response on MISO, then releases CS high.
An SPI NOR flash chip (common for firmware storage or a filesystem partition) typically operates in mode 0 or mode 3, both of which read correctly on a flash device that samples data mid-bit-cell regardless of clock idle state. The two modes are not universally interchangeable across all peripheral families, though, so the datasheet's stated mode(s) should still be confirmed rather than assumed from this common case. A read command is issued as an opcode byte followed by a 24- or 32-bit address, then the controller clocks out don't-care bytes on MOSI while reading the requested data back on MISO.
Flash memory chips, SD cards (in SPI mode), display controllers, and many ADCs/DACs all commonly use SPI because of its simplicity and speed compared to a shared-bus protocol.
Design Considerations
- Trace length and signal integrity: at higher clock rates (tens of MHz), keep SCLK/MOSI/MISO traces short and length-matched, and watch for ringing caused by an unmanaged trace impedance on long traces or cables.
- Number of available CS lines: each additional SPI peripheral consumes one more GPIO in a standard independent-CS topology, which can become a constraint on pin-limited microcontrollers. Daisy-chain-capable peripherals reduce this to one CS for the whole chain, at the cost of a longer transfer and stricter chain-length bookkeeping in firmware. If only a point-to-point link to a single device is needed, UART avoids the CS-line question entirely, at the cost of the throughput SPI provides.
- Mode compatibility: confirm CPOL/CPHA against the peripheral's datasheet before wiring anything. Getting this wrong is the single most common cause of garbled SPI reads.
- Pull-ups on CS: an idle (unselected) CS line should be pulled high so the peripheral doesn't see spurious activity during power-up, before the controller's GPIO has been configured as an output.
- Clock speed vs physical connection: a peripheral's rated maximum SCLK frequency assumes a clean, short connection. Cabled or connector-based links (as opposed to a short on-board trace) commonly need a lower clock rate than the datasheet maximum to read reliably.
- Choosing between SPI, I2C, and UART: each protocol suits a different scenario. For a structured protocol-selection guide covering all three, see SPI vs I2C vs UART: which to use.
- SPI on Raspberry Pi: for enabling SPI0 via device tree overlay and using it from Python with spidev (including clock rate considerations and mode configuration), see Raspberry Pi GPIO Interfacing.
- SPI driver development: writing SPI drivers that hold up in production, with correct mode configuration, DMA or interrupt handling, and proper error recovery, is part of the embedded firmware services Zeus Design's software team provides for microcontroller-based designs.
Common Mistakes
- Forgetting that MISO is high-impedance (not driven) when a peripheral's CS is not asserted. Without a pull-up, an idle bus can read noise.
- Sharing one CS line across multiple devices that don't support daisy-chaining, which causes bus contention on MISO since SPI has no built-in bus arbitration. Only one device may drive MISO at a time.
- Mismatched SPI mode between controller and peripheral. Getting CPOL or CPHA wrong typically produces reads that all return 0xFF even when a logic analyser shows MISO activity, because the MCU is sampling on the wrong clock edge. See the SPI CPOL/CPHA troubleshooting thread for a worked diagnosis example.
- Running the clock faster than the peripheral's datasheet maximum, which works intermittently on the bench but fails in production temperature ranges.
- Assuming a daisy-chain-capable peripheral's chain length is fixed in hardware. Firmware typically has to know the exact number of devices in the chain to shift the correct total bit count, so adding or removing a device without updating firmware silently misaligns every device's data.
Frequently Asked Questions
- Is SPI faster than I2C?
- Yes. SPI typically runs from a few MHz up to tens of MHz, well beyond I2C's standard 100 kHz–1 MHz range, because SPI uses dedicated data lines instead of a shared bus with arbitration overhead.
- How many devices can share one SPI bus?
- As many as you have free chip-select (CS) lines for, since each peripheral needs its own CS signal. Some peripherals support daisy-chaining, but a unique CS per device is the standard approach.
References
Related Questions
What Is I2C (Inter-Integrated Circuit)?
I2C is a two-wire serial bus for addressing multiple peripherals over shared SDA/SCL lines. Learn how addressing, speed grades, and pull-up resistors work.
What Is UART (Universal Asynchronous Receiver-Transmitter)?
UART sends serial data asynchronously over TX and RX with no shared clock. Learn how framing, baud rate, RS-232 voltage levels, and common UART pitfalls work.
SPI vs I2C vs UART: Which Protocol Should You Use?
SPI suits high-speed transfers, I2C minimises pins for multi-device buses, and UART suits point-to-point links. Learn which to choose for your embedded design.
What Is a Microcontroller (MCU)?
A microcontroller (MCU) combines a CPU, flash, RAM, and peripherals on one chip. Learn how MCUs work and how they differ from microprocessors and FPGAs.
What Is Controlled Impedance PCB Design, and Why It Matters?
Controlled impedance PCB design shapes trace geometry so a trace presents a specific, predictable impedance. Here's when you need it and how.
How to Interface Sensors and Peripherals with Raspberry Pi GPIO
Interface sensors and peripherals with Raspberry Pi GPIO: 3.3 V limits, level shifting, I2C/SPI/UART device tree configuration, lgpio API, and i2cdetect.