ESP32/Wires on the board/28. SPI and chip select
No board required

This one is about the wire, not the chip. Nothing below changes with the board you picked, which is why the chip and language switches are not on it. They come back on the ESP32 pages this one sits underneath.

Wires on the board · 28 of 81

SPI and chip select

SPI shares three wires between every device and gives each one a private pin to say "I mean you". That buys it about a hundred times the speed of I2C and costs it a pin per device — the whole trade, in one sentence.

/esp32/spi-and-chip-select · any board · 9 min read

Add devices, then pull two chip selects low at once. Nothing on the bus objects, which is the point.

Three shared wires, one private one each
3 + 3 = 6 pins
Devices on the bus3
The TFT display is selected, and it is the only one. The other 2 devices hold MISO in high impedance — electrically not there. Same three wires, 6 pins in total, and it will run at 40 MHz where I2C is doing 400 kHz.

Three shared wires and one private one

  • SCK — the clock, always driven by the master.
  • MOSI — master out, slave in.
  • MISO — master in, slave out.
  • CS (or SS, or NSS) — one per device, active low.

While a device's CS is high it holds MISO in high impedance: electrically not connected. Pull one CS low and that device joins the bus. That is the entire addressing scheme, and it lives in copper rather than in the protocol.

Nothing here checks anything

SPI has no addresses, no acknowledgement, no error detection and no defined speed. The master clocks bits out; a bit comes back on every clock whether or not anybody is there. Read a disconnected SPI device and you get 0xFF or 0x00 — a perfectly valid byte from nothing at all.

Two chip selects low is two outputs fighting. One device pushes MISO high while another pulls it low. There is no arbitration to save you the way there is on I2C, because MISO is push-pull, not open-drain. The master reads whichever wins and both parts get hot. Exactly one CS may be low at a time.

A floating CS is the same bug wearing a disguise. A pin that has not been set to OUTPUT and driven high is at the mercy of the room, and a device that decides it is selected will join in the middle of someone else's transfer. Drive every CS high in setup(), before anything else touches the bus.

Duplex, and why displays like it

Every clock tick sends a bit and receives a bit at the same time. There is no turnaround, no ACK, no per-byte overhead: a byte is eight clocks, full stop. At 40 MHz that is 5 MB/s, against roughly 40 kB/s for I2C at 400 kHz.

That is why an SPI screen redraws instantly and the same panel over I2C wipes visibly down the display, and why SD cards and flash chips are SPI without exception.

Modes, which is the one setting people get wrong

Two bits describe when data is valid: clock polarity (idle high or low) and clock phase (sample on the first edge or the second). Four combinations, called mode 0 to mode 3. Almost everything is mode 0; a few displays are mode 3.

Wrong mode does not error. It returns bytes, shifted by one bit, which is why "garbage but structured" is the symptom.

#include <SPI.h>
#define CS_DISPLAY 5
#define CS_SD      15

void setup() {
  pinMode(CS_DISPLAY, OUTPUT);  digitalWrite(CS_DISPLAY, HIGH);
  pinMode(CS_SD,      OUTPUT);  digitalWrite(CS_SD,      HIGH);
  SPI.begin();
}

uint8_t readReg(uint8_t cs, uint8_t reg) {
  SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
  digitalWrite(cs, LOW);
  SPI.transfer(reg | 0x80);          // top bit: read, on most parts
  uint8_t v = SPI.transfer(0x00);    // clock out a dummy byte to clock one in
  digitalWrite(cs, HIGH);
  SPI.endTransaction();
  return v;
}

beginTransaction matters as soon as two devices want different speeds or modes — it applies that device's settings and locks the bus for the duration.

Choosing between the two

Registers, settings, a sensor read a few times a second: I2C, two pins, done. Anything with a frame buffer or a filesystem behind it: SPI, and pay the pins.

Running out of chip selects is a real constraint on small boards, and the answers are the ordinary ones — a shift register to make more outputs, or an I2C expander to make them somewhere else.

Where this goes next

The same three wires with the ESP32's HSPI and VSPI behind them, and what to do when you run out of chip selects.

SPI

Edit this page — content/esp32/spi-and-chip-select.mdx

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse ESP32 on the forum