Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/manish04-mu/TheEmbeddedInsights/llms.txt

Use this file to discover all available pages before exploring further.

Every SPI transfer is governed by two one-bit parameters — CPOL (Clock Polarity) and CPHA (Clock Phase) — that together define exactly when data is driven onto the bus and when it is sampled. Choosing the wrong combination means your master samples bits on the wrong clock edge, producing corrupted bytes, all-zero reads, or apparently random data. Before writing a single line of code, look up the required mode in your slave’s datasheet and configure SPISettings to match.

CPOL — Clock Polarity

CPOL controls the idle state of SCK — the voltage level the clock line rests at when no transaction is in progress (i.e., while CS is HIGH).
  • CPOL = 0 — SCK idles LOW. The first clock edge of a transaction is a rising edge.
  • CPOL = 1 — SCK idles HIGH. The first clock edge of a transaction is a falling edge.
Getting CPOL wrong is immediately visible on a logic analyzer: the clock will appear inverted, with the wrong resting level between transactions.

CPHA — Clock Phase

CPHA controls when data is sampled relative to the clock transitions within an active transaction.
  • CPHA = 0 — Data is sampled on the leading (first) clock edge of each bit period and driven on the trailing edge. The master and slave must present their data bits before the first active edge.
  • CPHA = 1 — Data is driven on the leading clock edge and sampled on the trailing (second) edge of each bit period.
Combined with CPOL, this gives four possible relationships between the clock waveform and the data lines — the four SPI modes.

The Four Modes

ModeCPOLCPHAClock Idle StateData Sampled OnArduino Constant
000LOWRising edgeSPI_MODE0
101LOWFalling edgeSPI_MODE1
210HIGHFalling edgeSPI_MODE2
311HIGHRising edgeSPI_MODE3
Mode 0 is by far the most common default. The majority of SPI sensors, ADCs, and flash memory devices specify CPOL=0, CPHA=0. If a slave datasheet doesn’t explicitly state a mode, try SPI_MODE0 first.

Setting the Mode in Arduino

The Arduino SPI library encapsulates clock speed, bit order, and mode into an SPISettings object passed to SPI.beginTransaction(). The transaction API ensures the bus is configured correctly before the first SPI.transfer() call and releases it cleanly afterward. All sketches in this series use a clock speed of 100,000 Hz (100 kHz) — well within the Arduino UNO’s 16 MHz maximum and comfortably below the typical logic analyzer’s sampling rate ceiling. Mode 0 — CPOL=0, CPHA=0, MSBFIRST (most common)
#include <SPI.h>

#define CS 10
byte clockSpeed = 100000;
byte sentValue  = 0x62;
byte receivedValue;

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

void loop() {
  SPI.beginTransaction(SPISettings(clockSpeed, MSBFIRST, SPI_MODE0));
  digitalWrite(CS, LOW);
  receivedValue = SPI.transfer(sentValue);
  digitalWrite(CS, HIGH);
  SPI.endTransaction();
}
Mode 1 — CPOL=0, CPHA=1, MSBFIRST
SPI.beginTransaction(SPISettings(100000, MSBFIRST, SPI_MODE1));
digitalWrite(CS, LOW);
receivedValue = SPI.transfer(sentValue);
digitalWrite(CS, HIGH);
SPI.endTransaction();
Mode 2 — CPOL=1, CPHA=0, MSBFIRST
SPI.beginTransaction(SPISettings(100000, MSBFIRST, SPI_MODE2));
digitalWrite(CS, LOW);
receivedValue = SPI.transfer(sentValue);
digitalWrite(CS, HIGH);
SPI.endTransaction();
Mode 3 — CPOL=1, CPHA=1, MSBFIRST
SPI.beginTransaction(SPISettings(100000, MSBFIRST, SPI_MODE3));
digitalWrite(CS, LOW);
receivedValue = SPI.transfer(sentValue);
digitalWrite(CS, HIGH);
SPI.endTransaction();
The only difference between each snippet is the SPISettings arguments — the CS assertion/deassertion pattern and SPI.endTransaction() call remain identical across all four modes.

Choosing a Mode

Check the slave device’s datasheet. Look for a section titled “SPI Interface”, “Serial Interface”, or “Timing Diagram”. The datasheet will either state the mode number directly (e.g. “supports SPI Mode 0 and Mode 3”) or provide CPOL and CPHA values in the electrical characteristics table. Map those values to the table above to find the correct Arduino constant.
The master will sample each incoming bit on the wrong clock edge. In practice this produces one of three symptoms: all bytes read back as 0x00 or 0xFF, a fixed bit-shifted version of the expected value (e.g., every byte appears rotated by one bit), or seemingly random data that changes between reads. A logic analyzer makes the problem obvious — if the idle level of SCK contradicts the CPOL setting you can spot it instantly on the waveform.
Yes. Call SPI.endTransaction() to release the bus, then call SPI.beginTransaction() again with a new SPISettings object containing the updated mode. This is common when a single Arduino master communicates with two different slave devices that require different SPI modes — each transaction simply re-configures the bus before asserting that slave’s CS line.
// Communicate with slave A (Mode 0)
SPI.beginTransaction(SPISettings(100000, MSBFIRST, SPI_MODE0));
digitalWrite(CS_A, LOW);
SPI.transfer(dataA);
digitalWrite(CS_A, HIGH);
SPI.endTransaction();

// Communicate with slave B (Mode 3)
SPI.beginTransaction(SPISettings(100000, MSBFIRST, SPI_MODE3));
digitalWrite(CS_B, LOW);
SPI.transfer(dataB);
digitalWrite(CS_B, HIGH);
SPI.endTransaction();

Build docs developers (and LLMs) love