SPI (Serial Peripheral Interface) is a synchronous, full-duplex, 4-wire communication bus used to connect microcontrollers to high-speed peripherals like TFT displays, SD cards, and ADCs. Unlike asynchronous protocols, SPI uses a dedicated clock line to synchronize data transfer, allowing it to push significantly higher data rates—often between 1 MHz and 50 MHz—over short distances. If you are asking what SPI protocol means for your workbench, it is the default choice when you need to move large blocks of data quickly, provided your wiring runs are under a meter.

The Physical Layer: Wires, Speeds, and Bus Mechanics

SPI operates on a master-slave (or controller-peripheral) architecture. The master generates the clock signal and initiates all transfers. To understand the physical layer, you must look at the four shared lines that make up the bus mechanics.

Table 1: SPI Bus Mechanics and Specifications
ParameterSPI SpecificationPractical Bench Limits
Wires4 shared (SCK, MOSI, MISO) + 1 CS per deviceMinimum 4 wires; scales linearly with device count due to CS lines
SpeedTypically 1 MHz to 10 MHzUp to 50+ MHz for short, well-terminated PCB traces; 8 MHz is a safe default for jumper wires
AddressingNone (Hardware Chip Select routing)Limited only by available MCU GPIO pins for CS lines
DistanceNot strictly defined by standard< 1 meter on breadboards; highly dependent on bus capacitance and clock speed
DuplexFull-duplexMaster and slave can transmit simultaneously on MOSI and MISO

Which Protocol Fits Your Project?

Choosing between SPI, I2C, and UART depends entirely on your constraints regarding distance, speed, and device count.

Table 2: Protocol Selection Matrix
CriteriaSPII2CUART
Best ForHigh-speed data (Displays, SD cards)Low-speed sensors, many devices on 2 wiresLong-distance, point-to-point telemetry
Max Speed10 - 50 MHz100 kHz (Standard) to 3.4 MHz (High-Speed)115,200 baud typical (up to 1-3 Mbps)
Max Distance< 1 meter (unshielded)< 1 meter (highly capacitance limited)15+ meters (RS-485 physical layer)
Device CountLow (requires 1 CS pin per device)High (up to 127 via software addressing)1-to-1 (unless multiplexed)

Physical Wiring Requirements: Level Shifters and Pull-Ups

A common mistake when wiring SPI is applying I2C rules to an SPI bus. SPI data lines (MOSI, MISO, SCK) are push-pull, not open-drain. Therefore, they do not require pull-up resistors to function. Adding pull-ups to SPI data lines will only increase bus capacitance and degrade your high-frequency signal edges.

Wiring Tip: The CS Pull-Up Exception
While data lines don't need pull-ups, the Chip Select (CS) line absolutely does. When an ESP32 or Arduino resets, its GPIO pins briefly float before initializing. If a peripheral's CS line floats low during this boot sequence, the peripheral may activate and enter an undefined state. Always place a 10kΩ pull-up resistor between the CS line and VCC to keep the peripheral deselected during MCU boot.

Level Shifting: The ESP32 operates at 3.3V logic. If you are connecting it to a 5V SPI device (like an older ILI9341 display or a 5V logic ADC), you must use a level shifter. Do not rely on internal clamping diodes for high-speed SPI; the current spikes will destroy the ESP32's GPIO over time. Use a dedicated IC like the TXS0108E (for bidirectional MISO/MOSI) or a CD4050 (for unidirectional SCK/MOSI/CS).

The Classic Failures: CS Clashes, Missing Pull-Ups, and Baud Mismatches

Debugging SPI requires understanding how it fails. When makers transition from I2C, they often look for an address clash. SPI doesn't use software addresses; it uses individual Chip Select wires. The SPI equivalent of an address clash is a CS routing clash—wiring two peripherals to the same CS pin, or failing to manage CS states in software, causing two devices to drive the MISO line simultaneously and short-circuit their output buffers.

The second classic failure is a missing pull-up on the CS line, as mentioned above. If your SD card works perfectly until you press the ESP32 reset button, and then fails to mount on the next boot, your CS line is floating during reset.

The third and most insidious failure is a baud mismatch combined with Clock Polarity/Phase (CPOL/CPHA) errors. SPI defines four modes based on whether the clock idles high or low (CPOL) and whether data is sampled on the leading or trailing edge (CPHA).

  • Mode 0: CPOL=0, CPHA=0 (Clock idles LOW, sample on RISING edge). Most common.
  • Mode 3: CPOL=1, CPHA=1 (Clock idles HIGH, sample on FALLING edge).

If your master is configured for Mode 0 but the peripheral requires Mode 3, the master will sample the data exactly one half-cycle off, resulting in shifted bits and garbage data. Always verify the CPOL/CPHA timing diagram in the peripheral's datasheet.

Minimal Working Exchange and Sniffing the Bus

Below is a minimal working example reading a MAX31855 thermocouple amplifier using an ESP32. The MAX31855 is a receive-only (MISO) device, which simplifies the wiring.

Table 3: ESP32 to MAX31855 SPI Wiring
ESP32 DevKit V1 PinMAX31855 Module PinWire Color (Suggestion)
3V3VCCRed
GNDGNDBlack
GPIO 18 (SCK)SCK / CLKYellow
GPIO 19 (MISO)SO / DOOrange
GPIO 5 (CS)CSGreen
#include <SPI.h>

// Pin definitions for ESP32 DevKit V1
const int CS_PIN = 5;
const int SCK_PIN = 18;
const int MISO_PIN = 19;

void setup() {
  Serial.begin(115200);
  
  // Initialize SPI with explicit pin mapping (ESP32 allows software routing)
  SPI.begin(SCK_PIN, MISO_PIN, -1, CS_PIN); // -1 for MOSI since MAX31855 is read-only
  pinMode(CS_PIN, OUTPUT);
  digitalWrite(CS_PIN, HIGH); // Deselect device
  
  Serial.println("MAX31855 SPI Initialized.");
}

void loop() {
  uint32_t raw_data = 0;
  
  // Pull CS LOW to start transfer
  digitalWrite(CS_PIN, LOW);
  delayMicroseconds(1); // Allow line to settle
  
  // Read 32 bits (4 bytes) from the sensor
  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
  for (int i = 0; i < 4; i++) {
    raw_data <<= 8;
    raw_data |= SPI.transfer(0x00); // Send dummy byte to clock in MISO
  }
  SPI.endTransaction();
  
  // Pull CS HIGH to end transfer
  digitalWrite(CS_PIN, HIGH);
  
  // Process data (simplified for example)
  if (raw_data & 0x7) {
    Serial.println("Sensor fault detected.");
  } else {
    int16_t temp_raw = (raw_data >> 18) & 0x3FFF;
    if (temp_raw & 0x2000) temp_raw |= 0xC000; // Sign extension
    float temp_c = temp_raw * 0.25;
    Serial.printf("Temperature: %.2f C\n", temp_c);
  }
  
  delay(1000);
}

How to Sniff and Debug the Bus

When your code compiles but returns zeros or 0xFF, you need to look at the physical signals. Do not use a standard multimeter; SPI toggles too fast. Instead, use a logic analyzer. A standard 24MHz 8-channel Saleae clone (approx. $12 on Amazon) paired with the open-source PulseView (sigrok) software is the industry standard for bench debugging.

  1. Connect the analyzer's ground to your circuit ground.
  2. Connect channels 0-3 to CS, SCK, MOSI, and MISO.
  3. Set the sample rate to at least 4x your SPI clock speed (e.g., if SPI is 4 MHz, sample at 16 MHz or 24 MHz).
  4. Use PulseView's SPI protocol decoder. Verify that the CS line dips LOW before the SCK line starts toggling. If CS stays HIGH, your MCU isn't asserting the pin. If the decoder outputs garbage, check your CPOL/CPHA decoder settings against the datasheet.
Safety Caveat: Never connect a logic analyzer directly to an SPI bus that is galvanically tied to mains voltage (e.g., inside a smart thermostat or AC inverter). Use a digital isolator like the ISO7741 between the high-voltage SPI bus and your PC's USB logic analyzer to prevent destroying your computer's motherboard.

Frequently Asked Questions

What SPI speed should I use for long wire runs?

SPI was designed for on-PCB communication, not long cables. Wire capacitance rounds off the sharp square-wave edges of the SCK signal. If you must run SPI over 50cm of ribbon cable, drop your baud rate to 1 MHz or 500 kHz. For runs over 1 meter, abandon standard SPI and use RS-485 transceivers (like the MAX485) to convert the SPI signals to differential pairs, or switch to an I2C bus with active terminators.

What SPI mode is my device using if the datasheet doesn't say?

If the manufacturer omitted the timing diagram, default to SPI Mode 0 (CPOL=0, CPHA=0), as it is used by roughly 80% of SPI sensors and SD cards. If Mode 0 returns shifted or inverted data, hook up your logic analyzer and observe the SCK line at idle. If SCK idles HIGH, you need Mode 2 or 3. If it idles LOW, you need Mode 0 or 1. You can then toggle the CPHA setting in your SPISettings until the decoded bytes match expected register IDs.

What SPI pins can I change on the ESP32?

Unlike the Arduino Uno, which has fixed hardware SPI pins (11, 12, 13), the ESP32 features an internal GPIO Matrix. This allows you to route the SPI peripheral signals to almost any digital GPIO pin on the chip. However, for maximum reliability and speeds above 20 MHz, stick to the default VSPI pins (SCK=18, MISO=19, MOSI=23, CS=5) or HSPI pins (SCK=14, MISO=12, MOSI=13, CS=15), as these are optimized for high-frequency signal routing on the silicon die. For deeper architectural details, refer to the Espressif SPI Master API documentation.