yahboom
HomeLearn
Solution
Blog
Online Store
About Us
EN/中文
ESP32 Core Board📖
1. ESP32 Introduction
  • 1. ESP32S3 Overview
  • 2. Environment Setup Introduction
  • 3. Dev Board Introduction
2. ESP-IDF Development Tutorial
1. Before Development
  • 1. Environment Setup (Windows)
  • 2. Environment Setup (Linux)
  • 3. Build and Flash
2. Basic Peripherals
  • 1. LED Control
  • 2. Button Detection
  • 3. Peripheral Interrupts
  • 4. ESP_TIMER
  • 5. GPTIMER
  • 6. Watchdog Timer
  • 7. DMA
  • 8. ADC
  • 9. PWM Breathing LED
  • 10. RGB LED Effects
3. Serial Communication and Storage System
  • 1. Serial UART Communication Experiment
  • 2. I2C_OLED Display Experiment
  • 3. SPI Bus Communication Experiment
  • 4. PSRAM External Memory Experiment
  • 5. Flash Read and Write Experiment
  • 6. USB Emulated Mass Storage Experiment
4. FreeRTOS operating system
  • 1.FreeRTOS Core Concepts Theory
  • 2.Task Creation and Management
  • 3.Queue
  • 4.Binary Semaphore
  • 5.Mutex
  • 6.Event Groups
  • 7.Software Timer
  • 8.Task Scheduler
  • 9.Low Power Mode
  • 10.Deadlock
  • 11.Priority Inversion
5. Network Protocols and Wireless Communication
  • 1. WIFI Network Basics
  • 2. WIFI STA Mode
  • 3. WIFI AP Mode
  • 4. UDP Client Experiment
  • 5. UDP Server Experiment
  • 6. TCP Client Experiment
  • 7. TCP Server Experiment
  • 8. Socket Programming Basics
  • 9. HTTP Client Experiment
  • 10. HTTP Server Experiment
  • 11. MQTT IoT Communication Protocol
  • 12. WIFI OTA Upgrade
  • 13. Bluetooth Fundamentals
  • 14. Bluetooth Slave Mode
  • 15. Bluetooth Master Mode
6. Audio Applications
  • 1.I2S Microphone Recording and U-Disk Playback
  • 2.I2S Audio Playback Experiment
  • 3.Repeater Experiment
7. Xiaozhi AI Voice
  • 1. Burn Xiaozhi Firmware
  • 2. Network and Configuration
  • 3. AI Agent Settings
  • 4. Program Analysis
  • 5. Free Chat
3. Arduino Development Course
1. Before Development
  • 1. Environment Setup
  • 2. Build and Flash
2. Basic Peripherals
  • 1. LED Control
  • 2. Button Detection
  • 3. Peripheral Interrupts
  • 4. ESP_TIMER
  • 5. GPTIMER
  • 6. Watchdog Timer
  • 7. ADC
  • 8. PWM Breathing LED
  • 9. RGB LED Effects
3. Serial Communication and Storage System
  • 1. Serial UART Communication
  • 2. I2C OLED Display
  • 3. SPI Bus Communication
  • 4. Flash Read and Write
  • 5. USB Emulated Mass Storage
4. Network Protocols and Wireless Communication
  • 1. WIFI Network Basics
  • 2. WIFI STA Mode
  • 3. WIFI AP Mode
  • 4. UDP Server Experiment
  • 5. UDP Client Experiment
  • 6. TCP Client Experiment
  • 7. TCP Server Experiment
  • 8. HTTP Client Experiment
  • 9. HTTP Server Experiment
  • 10. MQTT IoT Communication Protocol
  • 11. WIFI OTA Upgrade
  • 12. Bluetooth Fundamentals
  • 13. Bluetooth Slave Mode
  • 14. Bluetooth Master Mode
5. Audio Applications
  • 1.I2S Microphone Recording and U-Disk Playback
  • 2.I2S Audio Playback Experiment
  • 3.Repeater Experiment
4. MicroPython Development Course
1. Before Development
  • 1. Environment Setup
  • 2. Build and Flash
  • 3. Thonny IDE
2. Basic Peripherals
  • 1. LED Control
  • 2. Button Detection
  • 3. Peripheral Interrupts
  • 4. TIMER_IT
  • 5. Watchdog Timer
  • 6. ADC
  • 7. PWM Breathing LED
  • 8. RGB LED Effects
3. Serial Communication and Storage System
  • 1. Serial UART Communication Experiment
  • 2. I2C_OLED Display Experiment
  • 3. SPI Bus Communication Experiment
  • 4. Flash Read and Write Experiment
  • 5. Print Storage
4. Network Protocols and Wireless Communication
  • 1. WIFI Network Basics
  • 2. WIFI STA Mode
  • 3. WIFI AP Mode
  • 4. UDP Client Experiment
  • 5. UDP Server Experiment
  • 6. TCP Client Experiment
  • 7. TCP Server Experiment
  • 8. HTTP Client Experiment
  • 9. HTTP Server Experiment
  • 10. MQTT
  • 11. Bluetooth Fundamentals
  • 12. Bluetooth Slave Mode
  • 13. Bluetooth Master Mode
5. Audio Applications
  • 1. I2S Audio Playback Experiment
  • 2. Repeater Experiment
Download
  • Code
  • Hardware_Info
  • 3D_Model_File
  • Software_Tools
  • VMware
  • VM_File
Download ZIP

Welcome to ESP32 Core Board repository

3. SPI Bus Communication

SPI Bus Communication Experiment


SPI Bus Communication Experiment1. SPI Bus Communication Overview2. Core Concepts2.1 SPI Four-Wire Signals2.2 SPI Modes (CPOL & CPHA)2.3 Full-Duplex Characteristic2.4 SPI Modes Summary2.5 Arduino Master vs ESP-IDF Slave3. Hardware Dependencies4. Project Architecture and Flow5. Source Code5.1 Master — SPI Initialization and Transfer5.2 Slave — DMA Buffer and Initialization5.3 Slave — Blocking Wait for Transfer6. Operation Flow6.1 Compile and Flash6.2 Normal Phenomena6.3 Verification Methods7. Common Issues


1. SPI Bus Communication Overview

SPI (Serial Peripheral Interface) is a four-wire full-duplex synchronous serial bus (SCK/MOSI/MISO/CS), with speed far exceeding UART and I2C.

This experiment uses two ESP32-S3 boards to build SPI master-slave communication: the master sends strings via SPIClass (Arduino API), and the slave receives and replies via spi_slave driver (ESP-IDF Native API), demonstrating SPI full-duplex transmission, manual CS control, and DMA buffer configuration.

Why two boards are needed: A single Arduino cannot simultaneously act as both master and slave on the same SPI bus, hardware peripheral architecture does not support it.

The most intuitive way to verify the complete SPI transmit/receive process is:

Board A as master, Board B as slave, send and receive data to/from each other, and observe the serial port print results.

Typical Application Scenarios:

Application TypeExamples
High-speed peripheralsTFT/OLED screens, SD cards, SPI Flash
SensorsHigh-precision ADC/DAC, IMU gyroscope
Inter-board communicationDual MCU high-speed data exchange
Display driversePaper ink screen, LED matrix

2. Core Concepts

2.1 SPI Four-Wire Signals

SignalDirection (Master perspective)Function
SCKOutputClock, generated by master
MOSIOutputMaster Out Slave In — master sends to slave
MISOInputMaster In Slave Out — slave sends to master
CSOutputChip select, active low to select target slave

2.2 SPI Modes (CPOL & CPHA)

SPI has 4 modes, determined by CPOL (Clock Polarity) and CPHA (Clock Phase):

ModeCPOLCPHASCK Idle LevelSampling Edge
000LowRising edge
101LowFalling edge
210HighFalling edge
311HighRising edge

This example uses Mode 0 (CPOL=0, CPHA=0), SCK idle low level, sampling on rising edge. Both master and slave must be set to the same mode.

2.3 Full-Duplex Characteristic

During each SPI clock pulse, two things happen simultaneously: the master outputs 1 bit on MOSI while sampling 1 bit on MISO. Therefore, for every byte the master sends, it inevitably receives one byte — even if the slave didn't prepare meaningful data. This is not a bug, it's a hardware characteristic.

Key slave constraint: Because the master controls the clock, the slave must have the reply data filled into tx_buf before the master initiates transmission. Once CS goes low and SCK starts running, the slave has no choice — each clock cycle it must drop one bit onto MISO.

2.4 SPI Modes Summary

SPI has 4 modes (determined by CPOL and CPHA). This experiment uses SPI_MODE0: SCK idle is low level, data is sampled on the first edge (rising edge). Both master and slave modes must match.

2.5 Arduino Master vs ESP-IDF Slave

 Master (Arduino)Slave (ESP-IDF Native)
APISPIClass + spi.transfer()spi_slave_initialize() + spi_slave_transmit()
ControllerSPI3_HOSTSPI2_HOST
DMAAutomatic managementManual declaration DRAM_ATTR + 4-byte alignment

3. Hardware Dependencies

This experiment requires two ESP32-S3 boards, one flashed with master program, one with slave program.

Master pins:

PinPeripheralConfigurationDescription
GPIO4SCKSPI clock outputConnected to slave GPIO4
GPIO5MOSIMaster outputConnected to slave GPIO5
GPIO6MISOMaster inputConnected to slave GPIO6
GPIO2CSManual chip selectConnected to slave GPIO2 (active low)
GNDGNDCommon ground between master and slaveConnected to slave GND

Board-to-board wiring

Slave pins: Identical to master, connected one-to-one.

ESP32-S3 SPI Hardware Features:

FeatureParameter
Number of SPI controllers4 (SPI0/SPI1 occupied by Flash/PSRAM, SPI2/SPI3 available for user)
Operating modesMaster / Slave
Maximum clock frequency80MHz (master mode), 20MHz (slave mode)
Data width1/2/4/8 wire (Standard/DUAL/QUAD/OCTAL)
FIFO depth64 bytes (independent TX/RX)
DMA supportYes (slave must place buffer in DRAM with 4-byte alignment)
GPIO mappingAny GPIO configurable as SPI pin via IO MUX
SPI modes0/1/2/3 (CPOL + CPHA combination), this experiment uses MODE0

Requires two ESP32-S3 boards, 4 Dupont wires connecting SCK/MOSI/MISO/CS, plus one GND wire for common ground.


4. Project Architecture and Flow

​x
[Master] setup()
  ├─ SPI.begin(SCK, MISO, MOSI, -1)    // -1 = manual CS control
  ├─ pinMode(CS, OUTPUT); CS=HIGH       // Idle: release slave
  └─ Toggle CS 3 times to verify wiring

[Master] loop()
  ├─ Construct "Hello N from Master!"
  ├─ CS=LOW → beginTransaction → Loop transfer(BUF_SIZE bytes) → endTransaction → CS=HIGH
  └─ Print TX and RX results via serial

[Slave] setup()
  ├─ spi_slave_initialize(SPI2_HOST, ...)  // Configure bus + slave interface
  └─ Pre-fill tx_buf = "Slave Received, over"

[Slave] loop()
  ├─ Block waiting for master transmission (spi_slave_transmit)
  ├─ Print TX/RX content
  └─ Construct next reply based on received content → Loop

5. Source Code

Source Code Location: Source code → Arduino → 2.Serial communication → 3. SPI → SPI_Master → SPI_Master.ino

5.1 Master — SPI Initialization and Transfer

Using manual CS control to precisely control chip select timing before and after transfer.

xxxxxxxxxx
SPIClass spi(1);  // SPIClass(1) = SPI3_HOST

void setup() {
  spi.begin(PIN_SCK, PIN_MISO, PIN_MOSI, -1);  // -1 = no hardware CS
  pinMode(PIN_CS, OUTPUT);
  digitalWrite(PIN_CS, HIGH);  // Idle: don't select slave
}

void loop() {
  digitalWrite(PIN_CS, LOW);                    // ① Select slave
  spi.beginTransaction(SPISettings(100000, MSBFIRST, SPI_MODE0));
  for (int i = 0; i < BUF_SIZE; i++)
    rx[i] = spi.transfer(tx[i]);                // ② Full-duplex TX/RX
  spi.endTransaction();
  digitalWrite(PIN_CS, HIGH);                   // ③ Release slave
}

Each call to spi.transfer(tx_byte) completes 8 SCK clock cycles: sending 8 bits to MOSI while sampling 8 bits from MISO.

5.2 Slave — DMA Buffer and Initialization

DMA buffers must be in internal DRAM with 4-byte alignment.

xxxxxxxxxx
static uint8_t DRAM_ATTR tx_buf[64] __attribute__((aligned(4)));
static uint8_t DRAM_ATTR rx_buf[64] __attribute__((aligned(4)));

void setup() {
  spi_bus_config_t bus_cfg = {};
  bus_cfg.mosi_io_num = PIN_MOSI;
  bus_cfg.miso_io_num = PIN_MISO;
  bus_cfg.sclk_io_num = PIN_SCK;

  spi_slave_interface_config_t slv_cfg = {};
  slv_cfg.mode = 0;               // SPI_MODE0
  slv_cfg.spics_io_num = PIN_CS;

  spi_slave_initialize(SPI2_HOST, &bus_cfg, &slv_cfg, SPI_DMA_CH_AUTO);
  strcpy((char*)tx_buf, "Slave Received, over");  // Pre-fill first reply
}

DRAM_ATTR places the array in internal DRAM (DMA can only access internal RAM, not PSRAM). __attribute__((aligned(4))) ensures 4-byte alignment, otherwise DMA triggers hardware exceptions.

5.3 Slave — Blocking Wait for Transfer

spi_slave_transmit() blocks the current task until the master initiates transfer or timeout.

xxxxxxxxxx
void loop() {
  memset(rx_buf, 0xAA, BUF_SIZE);   // Fill with marker value

  spi_slave_transaction_t t = {};
  t.length    = BUF_SIZE * 8;       // Unit is bits! 64 bytes = 512 bits
  t.tx_buffer = tx_buf;
  t.rx_buffer = rx_buf;

  esp_err_t ret = spi_slave_transmit(SPI2_HOST, &t, pdMS_TO_TICKS(3000));

  // Prepare next reply based on received content
  snprintf((char*)tx_buf, BUF_SIZE, "I got: %s", (char*)rx_buf);
}

t.length unit is bits, not bytes — this is the most commonly miswritten field in spi_slave_transaction_t. The 0xAA fill pattern for rx_buf allows visual inspection of how many bytes the master actually sent.


6. Operation Flow

6.1 Compile and Flash

Arduino Flash Process: See 1. Before Development → 2. Build and Flash.

  1. Connect the two boards pin-to-pin according to the pin table with Dupont wires, must share common ground

  2. Compile and flash SPI_Master.ino and SPI_Slave.ino to the respective boards

6.2 Normal Phenomena

Master serial monitor (115200 bps) prints every second:

xxxxxxxxxx
[M] TX: Hello 0 from Master!
[M] RX: Slave Received, over
[M] TX: Hello 1 from Master!
[M] RX: I got: Hello 1 from Master!

SPI master print

xxxxxxxxxx
--- [SLAVE] ---
  bits=512  bytes=64  strlen=20
  RX: [Hello 1 from Master!]
  TX: [I got: Hello 0 from Master!]
  Next TX: [I got: Hello 1 from Master!]
--- [SLAVE] ---
  bits=512  bytes=64  strlen=20
  RX: [Hello 2 from Master!]
  TX: [I got: Hello 1 from Master!]
  Next TX: [I got: Hello 2 from Master!]

SPI slave print

6.3 Verification Methods

OperationExpected Result
Power on both boardsMaster RX receives slave reply
Remove any one signal wireMaster RX is all 0 or garbled
Master and slave SPI modes don't matchData byte offset or all wrong

7. Common Issues

PhenomenonCauseSolution
Master RX is all 0xAASlave not running or CS not connectedConfirm slave is powered on, check CS wiring
Master RX data misalignedSPI mode mismatchBoth master and slave use SPI_MODE0
Slave spi_slave_transmit timeoutCS or SCK wiring brokenUse multimeter to check each wire
Slave DMA exceptionBuffer not aligned or not in DRAMConfirm DRAM_ATTR + __attribute__((aligned(4)))
Garbage bytes in dataDupont wires too long causing signal reflectionLower SCK frequency or shorten Dupont wires
I2C OLED Display
Flash Read and Write

COMPANY

  • About us
  • Team Style
  • Blog

LEARNING & EXPLORATION

  • Tutorials
  • Edge AI hardware
  • Educational robots
  • Embedded intelligent hardware

WHERE TO BUY

  • Yahboom Online Store
  • Amazon
  • Alibaba
  • AliExpress
  • Mercado

TECHNOLOGY SUPPORT

  • Email: support@yahboom.com

BE A DISTRIBUTOR

  • Email: sales@yahboom.com
QR Code
QR Code

Copyright © 2017-2026 Yahboom. All Rights Reserved.

EN/中文