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.

These four sketches are structurally identical to the MSB-first variants, with one critical difference: LSBFIRST is passed to SPISettings instead of MSBFIRST. This means bit 0 — the least significant bit — is transmitted first on MOSI, inverting the bit sequence that appears on the wire. The clock mode, clock speed, sent byte, and wiring all remain exactly the same. Loading an LSB sketch back-to-back with its MSB counterpart on a logic analyzer instantly shows the waveform reversal.

What Changes with LSBFIRST

The byte being transmitted in all four sketches is 0x62, which in binary is 0110 0010.
Bit OrderTransmission Sequence (bit 7 → bit 0)MOSI Waveform
MSBFIRST0, 1, 1, 0, 0, 0, 1, 0Low, High, High, Low, Low, Low, High, Low
LSBFIRST0, 1, 0, 0, 0, 1, 1, 0Low, High, Low, Low, Low, High, High, Low
Only the MOSI line changes — MISO reception is also LSB-first, so the received byte is automatically re-assembled in the correct order by the ATmega328P hardware before being returned by SPI.transfer(). No additional bit-reversal in software is needed.

Mode 0 — CPOL=0, CPHA=0

Clock idles LOW; data sampled on the rising edge. Bit 0 of 0x62 is the first bit clocked out on MOSI.
SPI_Echo_LSB_Mode0.ino
#include <SPI.h>

/*
Pin Description: 
CS  - Chip Select         : Pin-> 10
MOSI- Master Out/Slave In : Pin-> 11
MISO- Master In/Slave Out : Pin-> 12
SCK - Clock Signal        : Pin-> 13
*/

/*
Logic Analyser:
CH0: SCK
CH1: Enable/Chip Select
CH2: MOSI
CH3: MISO
*/


#define CS 10     //Chip Select, Here no Slave is used but logic analyser need Enable signal to decoded the message.

byte ClockSpeed = 100000; //1MHz: Arduino Support upto 16MH. Keep it within the sampling rate of Logic Analyser as well. 

byte sentValue = 0x62;

byte receivedValue;

void setup() {

  Serial.begin(9600);  //Serial mode is used to print the received value in MISO, in case, the logic analyser is not present.

  pinMode(CS, OUTPUT); //Define the Chip Select Pin to Output (Master --> Slave)
  digitalWrite(CS, HIGH);   // Keep slave deselected, usually teh CS is active low (We need to check the slave datasheet for this information.)

  SPI.begin();

}

void loop() {

  SPI.beginTransaction(SPISettings(ClockSpeed, LSBFIRST, SPI_MODE0));
  digitalWrite(CS, LOW);          // Select slave 
  receivedValue = SPI.transfer(sentValue);
  digitalWrite(CS, HIGH);         // Deselect slave

  SPI.endTransaction();           // Release the SPI bus

  Serial.print("Received Value: ");
  Serial.println(receivedValue, HEX);

  delay(1000);

}

Mode 1 — CPOL=0, CPHA=1

Clock idles LOW; data sampled on the falling edge. The bit sequence on MOSI is the same LSB-first order as Mode 0 — only the sampling edge shifts.
SPI_Echo_LSB_Mode1.ino
#include <SPI.h>

/*
Pin Description: 
CS  - Chip Select         : Pin-> 10
MOSI- Master Out/Slave In : Pin-> 11
MISO- Master In/Slave Out : Pin-> 12
SCK - Clock Signal        : Pin-> 13
*/

/*
Logic Analyser:
CH0: SCK
CH1: Enable/Chip Select
CH2: MOSI
CH3: MISO
*/


#define CS 10     //Chip Select, Here no Slave is used but logic analyser need Enable signal to decoded the message.

byte ClockSpeed = 100000; //1MHz: Arduino Support upto 16MH. Keep it within the sampling rate of Logic Analyser as well. 

byte sentValue = 0x62;

byte receivedValue;

void setup() {

  Serial.begin(9600);  //Serial mode is used to print the received value in MISO, in case, the logic analyser is not present.

  pinMode(CS, OUTPUT); //Define the Chip Select Pin to Output (Master --> Slave)
  digitalWrite(CS, HIGH);   // Keep slave deselected, usually teh CS is active low (We need to check the slave datasheet for this information.)

  SPI.begin();

}

void loop() {

  SPI.beginTransaction(SPISettings(ClockSpeed, LSBFIRST, SPI_MODE1));
  digitalWrite(CS, LOW);          // Select slave 
  receivedValue = SPI.transfer(sentValue);
  digitalWrite(CS, HIGH);         // Deselect slave

  SPI.endTransaction();           // Release the SPI bus

  Serial.print("Received Value: ");
  Serial.println(receivedValue, HEX);

  delay(1000);

}

Mode 2 — CPOL=1, CPHA=0

Clock idles HIGH; data sampled on the falling (leading) edge. SCK sits high before CS asserts, then transitions on the first clock pulse with MOSI already presenting bit 0.
SPI_Echo_LSB_Mode2.ino
#include <SPI.h>

/*
Pin Description: 
CS  - Chip Select         : Pin-> 10
MOSI- Master Out/Slave In : Pin-> 11
MISO- Master In/Slave Out : Pin-> 12
SCK - Clock Signal        : Pin-> 13
*/

/*
Logic Analyser:
CH0: SCK
CH1: Enable/Chip Select
CH2: MOSI
CH3: MISO
*/


#define CS 10     //Chip Select, Here no Slave is used but logic analyser need Enable signal to decoded the message.

byte ClockSpeed = 100000; //1MHz: Arduino Support upto 16MH. Keep it within the sampling rate of Logic Analyser as well. 

byte sentValue = 0x62;

byte receivedValue;

void setup() {

  Serial.begin(9600);  //Serial mode is used to print the received value in MISO, in case, the logic analyser is not present.

  pinMode(CS, OUTPUT); //Define the Chip Select Pin to Output (Master --> Slave)
  digitalWrite(CS, HIGH);   // Keep slave deselected, usually teh CS is active low (We need to check the slave datasheet for this information.)

  SPI.begin();

}

void loop() {

  SPI.beginTransaction(SPISettings(ClockSpeed, LSBFIRST, SPI_MODE2));
  digitalWrite(CS, LOW);          // Select slave 
  receivedValue = SPI.transfer(sentValue);
  digitalWrite(CS, HIGH);         // Deselect slave

  SPI.endTransaction();           // Release the SPI bus

  Serial.print("Received Value: ");
  Serial.println(receivedValue, HEX);

  delay(1000);

}

Mode 3 — CPOL=1, CPHA=1

Clock idles HIGH; data sampled on the rising (trailing) edge. The combination of LSB-first bit order and Mode 3 timing produces the most visually distinct waveform compared to the standard MSB-first Mode 0 baseline.
SPI_Echo_LSB_Mode3.ino
#include <SPI.h>

/*
Pin Description: 
CS  - Chip Select         : Pin-> 10
MOSI- Master Out/Slave In : Pin-> 11
MISO- Master In/Slave Out : Pin-> 12
SCK - Clock Signal        : Pin-> 13
*/

/*
Logic Analyser:
CH0: SCK
CH1: Enable/Chip Select
CH2: MOSI
CH3: MISO
*/


#define CS 10     //Chip Select, Here no Slave is used but logic analyser need Enable signal to decoded the message.

byte ClockSpeed = 100000; //1MHz: Arduino Support upto 16MH. Keep it within the sampling rate of Logic Analyser as well. 

byte sentValue = 0x62;

byte receivedValue;

void setup() {

  Serial.begin(9600);  //Serial mode is used to print the received value in MISO, in case, the logic analyser is not present.

  pinMode(CS, OUTPUT); //Define the Chip Select Pin to Output (Master --> Slave)
  digitalWrite(CS, HIGH);   // Keep slave deselected, usually teh CS is active low (We need to check the slave datasheet for this information.)

  SPI.begin();

}

void loop() {

  SPI.beginTransaction(SPISettings(ClockSpeed, LSBFIRST, SPI_MODE3));
  digitalWrite(CS, LOW);          // Select slave 
  receivedValue = SPI.transfer(sentValue);
  digitalWrite(CS, HIGH);         // Deselect slave

  SPI.endTransaction();           // Release the SPI bus

  Serial.print("Received Value: ");
  Serial.println(receivedValue, HEX);

  delay(1000);

}

When to Use LSBFIRST

The vast majority of SPI peripherals — sensors, displays, memory chips, ADCs — specify MSB-first transmission in their datasheets. MSBFIRST should be your default.Use LSBFIRST only when the slave device’s datasheet explicitly states that the least significant bit is transmitted first. Common examples include certain shift registers and some older serial DACs. The datasheet will typically show a timing diagram labeling the first bit shifted in as “D0” or “LSB” rather than “D7” or “MSB”.Mismatched bit order is a silent failure. If the master sends MSB-first but the slave expects LSB-first (or vice versa), the received byte will be a bit-reversed version of the intended value. The SPI transaction will complete without errors, the Serial Monitor will show a plausible hex value, and no exception will be thrown — making this one of the harder bugs to diagnose without a logic analyzer. Always verify the MOSI waveform bit-by-bit against the expected binary value of 0x62 (0110 0010) when bring-up fails.
LSBFIRST is implemented entirely in the ATmega328P SPI hardware — the DORD bit in the SPCR register controls transmission order. No extra wiring, additional shift registers, or software bit-reversal routines are required. Switching between MSBFIRST and LSBFIRST is a single-argument change in SPISettings(...) and takes effect immediately on the next SPI.beginTransaction() call.
Compare these sketches side by side with the SPI MSB-First Echo Sketches to see exactly how the MOSI waveform changes when bit order is reversed. For a deeper understanding of how CPOL and CPHA interact with bit order, see SPI Modes and Timing.

Build docs developers (and LLMs) love