SPI (Serial Peripheral Interface) is a fast synchronous communication bus running on four wires: MOSI and MISO (the data in each direction), SCK (the clock) and CS (the select). One device acts as the controller (historically called the master) and talks to one peripheral at a time, activating it by pulling that peripheral’s dedicated CS line low. The exchange is full-duplex, the controller sending and receiving at the same time.

SPI wiring: one controller and two peripherals. The three wires MOSI, MISO and SCK are shared in a single bundle, each peripheral gets its own CS line, and the GND rails are tied together.

How does it work?

The three wires MOSI, MISO and SCK are shared by every device. Each peripheral, on the other hand, gets its own CS line: adding a device means adding a select wire. There is no addressing, then. The controller picks who it talks to through the CS pin it pulls low. How many peripherals, at most? The protocol imposes no limit, and the ceiling is the number of CS pins available on the controller, which is to say the GPIO budget. In return for that extra wire per peripheral, SPI offers high throughput, well suited to graphic displays, SD cards and converters, over very short distances. At that scale no termination resistor is needed.

On the wire

SPI timing diagram: CS goes low first, then eight SCK clock pulses, with the MOSI and MISO bytes travelling at the same time in full duplex, before CS goes back high.

The controller first pulls the targeted peripheral’s CS low, then beats out eight clock pulses on SCK: on each pulse a bit leaves on MOSI and a bit comes back on MISO. The exchange is simultaneous, which is what full duplex means. CS goes back high at the end. Exactly when the bits are sampled depends on the SPI mode (clock polarity and phase, numbered 0 to 3). Putting it to work is covered in SPI on Arduino for Arduino, SPI on the ESP32 for the ESP32 and SPI in MicroPython for MicroPython.

Pitfalls

Forgetting to assert CS. As long as a peripheral’s CS line is not pulled low, that peripheral ignores the bus. An exchange without a prior select produces nothing at all.

Adding peripherals without counting wires. Unlike I2C, which stacks devices onto two wires by address, SPI demands one more CS pin per peripheral: past a handful of devices, the pin budget becomes a criterion in its own right.

Picking the wrong SPI mode. Clock polarity and phase mismatched to the device: the wiring is right, but the data arrives shifted or empty. The mode is read from the device’s datasheet and set in the library.

See also