The direct answer to what SPI phase (CPHA) means: it dictates whether the receiving device samples the data line on the leading (first) or trailing (second) edge of the clock pulse. Combined with Clock Polarity (CPOL), which sets the idle state of the clock, these two parameters create the four distinct SPI modes (Mode 0 through 3). If your microcontroller and peripheral disagree on the SPI phase, you will read garbage data or zeros, regardless of how perfectly your wiring is routed.

This primer breaks down the physical layer, maps the exact clock phase matrices, and provides a bench-tested debugging framework for when the bus refuses to talk.

SPI Bus Mechanics and Physical Layer Rules

Serial Peripheral Interface (SPI) is a synchronous, full-duplex, master-slave bus. Unlike multi-master buses, SPI relies on dedicated hardware lines for every transaction. Below is the foundational mechanics table for standard 4-wire SPI.

Parameter SPI Specification Practical Bench Limits
Wires 4 (MOSI, MISO, SCK, CS/SS) Adds 1 CS wire per target device
Speed (Baud) 1 MHz to 50+ MHz Reliably 1-10 MHz on breadboards; >20 MHz requires PCB trace routing
Addressing None (Hardware Chip Select) No software address clashes; limited by available GPIO pins for CS
Distance Intra-board (< 1 meter) Keep traces under 10cm for >10 MHz to avoid signal ringing
Duplex Full-Duplex MISO and MOSI shift simultaneously on every clock edge
Physical Wiring & Pull-Up Callout: A common mistake for makers migrating from I2C is adding pull-up resistors to SPI lines. Do not use pull-ups on MOSI, MISO, or SCK. SPI uses push-pull drivers, not open-drain. However, you must place a 10kΩ pull-up resistor on every CS (Chip Select) line to VCC. During MCU boot, GPIO pins often float or glitch before initializing as outputs; a floating CS line can accidentally activate a peripheral, causing it to drive the MISO line and crash the entire bus.

The Four SPI Modes: Clock Phase and Polarity Matrix

To successfully exchange data, the master and slave must agree on the clock's idle state (CPOL) and the sampling edge (CPHA). According to the Analog Devices SPI Guide, misinterpreting the datasheet's timing diagram is the number one cause of SPI integration failure.

SPI Mode CPOL (Polarity) CPHA (Phase) Clock Idle State Data Sampled On Data Shifted On
Mode 0 0 0 Low Rising (Leading) Falling (Trailing)
Mode 1 0 1 Low Falling (Trailing) Rising (Leading)
Mode 2 1 0 High Falling (Leading) Rising (Trailing)
Mode 3 1 1 High Rising (Trailing) Falling (Leading)

Why does CPHA=1 exist? When CPHA is 0, the slave must place the first bit on MISO before the first clock edge, meaning the slave prepares data as soon as CS goes low. When CPHA is 1, the first clock edge is used to shift (prepare) the data, and the second edge is used to sample it. This gives the slave peripheral a full half-clock cycle to fetch the first byte from its internal registers before the master reads it.

Protocol Selection: When to Choose SPI Over I2C or UART

Not every sensor needs the speed of SPI. Here is how the bus mechanics dictate your protocol choice based on distance, speed, and device count.

Criterion SPI I2C UART
Best For High-speed data (SD cards, TFT displays, ADCs) Many low-speed sensors on limited GPIO Point-to-point off-board comms (GPS, Cellular)
Max Speed 50+ MHz 3.4 MHz (High-Speed Mode) ~5 Mbps (practical limit on MCUs)
Distance Limit < 30 cm (without differential transceivers) < 1 meter (at 100 kHz) 15 meters (RS-232) / 1200m (RS-485)
Device Count 1 Master, N Slaves (Requires N Chip Select wires) 1 Master, up to 127 Slaves (2 shared wires) Strictly 1-to-1 (without multiplexing)

Classic Failures: Debugging Phase Mismatches and Bus Errors

When your logic analyzer shows a blank MISO line or your serial monitor prints 0xFF repeatedly, you are likely facing one of three classic SPI failures.

  1. The Phase/Polarity Mismatch: You configured Mode 0, but the sensor requires Mode 1. Fix: Check the sensor datasheet's timing diagram. If the data changes on the falling edge but is read on the rising edge, you need CPHA=1. Toggle through Modes 0-3 in your SPISettings until valid data appears.
  2. Baud Rate Mismatch & Signal Ringing: You set the clock to 20 MHz on a breadboard with 10cm jumper wires. The wire inductance causes the square wave to ring, crossing the logic threshold multiple times per edge. The slave reads this as a dozen extra clock pulses. Fix: Drop the baud rate to 1 MHz to verify communication. For high-speed PCB designs, add 33Ω series termination resistors near the master's MOSI and SCK pins to dampen reflections.
  3. Address Clash vs. CS Clash (Missing Pull-Up): I2C suffers from software address clashes; SPI suffers from hardware CS clashes. If two SPI devices share the MISO line and one lacks a pull-up on its CS pin, it may wake up during MCU boot and permanently drive MISO low, blocking all other devices. Fix: Measure the CS pins with a multimeter during boot. Ensure every CS line has a 10kΩ pull-up to VCC.

How to Sniff and Debug the Bus: Do not guess; use a logic analyzer. Tools like the Saleae SPI Protocol Analyzer or the open-source Sigrok/PulseView software allow you to decode the hex bytes in real-time. When debugging, look closely at the setup and hold times—the microseconds between the CS line going low and the first SCK edge. If your MCU toggles CS and immediately fires the clock, you may violate the peripheral's required setup time (often 50ns to 100ns). Insert a 1-microsecond delay in your code after pulling CS low before initiating the SPI transfer.

Minimal Working Exchange: ESP32 to MAX31865 (Mode 1)

The MAX31865 RTD-to-Digital converter is a classic example of a device that strictly requires SPI Mode 1 (CPOL=0, CPHA=1) or Mode 3. Attempting to read it in Mode 0 will yield corrupted temperature registers. Below is a minimal, bench-verified exchange using the ESP32.

Physical Wiring Table

ESP32 DevKit v1 GPIO MAX31865 Breakout Pin Notes
GPIO 23 (MOSI) SDI Master Out, Slave In
GPIO 19 (MISO) SDO Master In, Slave Out
GPIO 18 (SCK) SCK Clock (Max 5MHz for MAX31865)
GPIO 5 (CS) CS Requires 10kΩ pull-up to 3.3V
3V3 Vin / VDD MAX31865 is 3.3V logic
GND GND Common ground required

ESP32 Arduino Core Code

This code initializes the bus with the correct SPI phase (Mode 1), reads the configuration register (0x00), and writes a Vbias enable command. For deeper ESP32 hardware abstraction details, refer to the Espressif ESP32 SPI Master Documentation.

#include <SPI.h>

// Pin Definitions
#define MAX_CS 5

// MAX31865 Registers
#define REG_CONFIG 0x00
#define CONFIG_BIAS 0x80 // Vbias enable bit

void setup() {
  Serial.begin(115200);
  pinMode(MAX_CS, OUTPUT);
  digitalWrite(MAX_CS, HIGH); // Deselect immediately

  // Initialize SPI bus
  SPI.begin();
  
  // Delay to allow peripheral power stabilization
  delay(100);
  
  // Write to Config Register to enable Vbias
  // SPI Mode 1: CPOL=0, CPHA=1. Max clock 5MHz.
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE1));
  digitalWrite(MAX_CS, LOW);
  delayMicroseconds(1); // Respect CS setup time
  
  // Send Write command (Address | 0x80) and Data
  SPI.transfer(REG_CONFIG | 0x80); 
  SPI.transfer(CONFIG_BIAS);
  
  digitalWrite(MAX_CS, HIGH);
  SPI.endTransaction();
  
  Serial.println("MAX31865 Vbias enabled via SPI Mode 1.");
}

void loop() {
  // Read Config Register back to verify phase alignment
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE1));
  digitalWrite(MAX_CS, LOW);
  delayMicroseconds(1);
  
  SPI.transfer(REG_CONFIG); // Read command (Address & 0x7F)
  byte configVal = SPI.transfer(0x00); // Clock out the data
  
  digitalWrite(MAX_CS, HIGH);
  SPI.endTransaction();
  
  Serial.print("Config Register: 0x");
  Serial.println(configVal, HEX);
  
  delay(2000);
}

If your serial monitor outputs Config Register: 0x80 (or 0x82 depending on 2/3/4-wire RTD configuration), your SPI phase, polarity, and wiring are perfectly aligned. If you read 0x00 or 0xFF, drop your baud rate to 250kHz and verify your CS pull-up resistor.