ESP32 SPI Tutorial Master Slave Communication Example

In this tutorial, we will learn to use SPI communication buses of ESP32. By using that, we will see how to perform master slave SPI communication with ESP32 boards using Arduino IDE. Furthermore, we will look into SPI pins, how to use multiple SPI bus interfaces supported by ESP32, and how to configure them.

esp32 spi communication tutorial with Arduino IDE

SPI Communication Introduction

SPI stands for serial peripheral interface. It is a serial Full duplex and synchronous interface. The synchronous interface means it requires a clock signal to transfer and receive data. The clock signal is synchronized between both master and slave. Unlike UART communication which is asynchronous, the clock signal controls when data is to be sent to the slave and when it should be ready to read.

Only a master device can control the clock and provide a clock signal to all slave devices. Data can not be transferred without a clock signal. Both master and slave can exchange data with each other.No address decoding are done.

SPI Connection Between Two Devices

Both Master and Slave can exchange data with each other on the rising and falling edge of the clock signal.  The Block diagram below shows interfacing with one Master and one Slave. SPI interface consists of either three or four signals. But generally, we will see a 4 wire interface, and the fourth wire is used to select a slave.

SPI communication interface

The functionality of each signal is given here.

  • SCLK or SCK pin: This signal provides a clock to Slaves and only Master can control clock signal. Note that this pin remains in an idle state. i.e. inactive or tri-state when no operation is carried out.
  • SS or CS:  This is known as a chip select or Slave select pin. This line selects the slave to which the Master wants to transfer data.
  • MOSI:  It is a unidirectional pin. This stands for Master output and Slave input pin. As its name suggests, this line is used to send data from master to slave.
  • MISO: This is known as Master input and a Slave output. This line is used to send data from the slave to the Master.

In short, in this communication protocol, devices exchange data in master/slave mode. The master device is mainly responsible for the initiation of the data frame. The master device also selects the slave device to which data need to be transferred. The chip select line is usually used to identify or select a particular slave device.

Whenever a master device read to transmit data to a slave or wants to receive data from the slave, the master does so by activating the clock signal from active low to active high state. Every master device sends data on the MOSI line and receives data through another line which is MISO. 

ESP32 SPI Communication Bus

The ESP32 has four SPi buses but only two are available to use and they are known as HSPI and VSPI. As we mentioned earlier, in SPI communication, there is always one controller (which is also known as a master) which controls other peripheral devices ( also known as slaves).

We can configure ESP32 either as a master or slave. We will see examples of each of them at the end of this article.

As mentioned earlier, SPI is a full-duplex communication that means both master and slave can data to each other simultaneously.

esp32 spi communication tutorial

We can use the ESP32 SPI controller to interface with many slave peripherals or devices such as SD cards, BME680, BME280, and any other sensor which provides data over SPI interface.

ESP32 SPI Pins

As discussed earlier, ESP32 has four SPI channels such as SPI0, SPI1, SPI2, and SPI3. But SPI0 and SP1 are not available to use. Because they are internally connected to communicate with the flash memory of the chip.

By default, ESP32 has two useable SPI communication channels SPI2 (HSPI) and SPI3 (VSPI) and the following table provides the default SPI pins for both channels. But if we can also map these pins to other GPIO pins also in Arduino or esp-idf.

SPI ChannelMOSI / SDIMISO / SDOSCK/CLKCS/SS
VSPIGPIO23 GPIO19GPIO18GPIO5
HSPIGPIO13GPIO12GPIO14GPIO15

Both VSPI and HSPI have separate bus signals. Hence, we can use them separately either as a master or slave. In controller mode, each bus can control up to three SPI devices or slaves.

Find ESP32 Board Default SPI Pins

Note: There are many types of ESP32 boards available. Your ESP32 board might have different default SPI pins. You can find information about default pins from their datasheet. But if default pins are not mentioned, we can find them using an Arduino sketch.

Copy the following code to Arduino IDE and upload it to your ESP32 board:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.print("MOSI Pin: ");
  Serial.println(MOSI);
  Serial.print("MISO Pin: ");
  Serial.println(MISO);
  Serial.print("SCK Pin: ");
  Serial.println(SCK);
  Serial.print("SS Pin: ");
  Serial.println(SS);  
}

void loop() {
  // put your main code here, to run repeatedly:
}

Make sure to select your board from Tool>Boards. After uploading the above code, open the serial monitor and click on the reset button of the ESP32 board:

ESP32 enable reset button

As soon as you press the enable/reset button, you will be able to see default SPI pin numbers on the serial monitor:

esp32 default spi pins

Use ESP32 SPI as a Master (Controller)

In this section, we will see how to use ESP32 SPI as a master to read data from a BME680 device which acts as a slave.

In the following schematic diagram, ESP32 connects with BME680 by using default SPI pins.

esp32 spi as a master
BME680ESP32
VCCVCC=3.3V
GNDGND
SCL (SCK for SPI)GPIO18
SDA (SDI / MOSI for SPI)GPIO23
SDO / MISOGPIO19
CSGPIO5

In the following example code, ESP32 acts as a master and gets BME680 sensor data over SPI communication. You can refer to this article for a complete guide of ESP32 with BME680:

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"


#define SEALEVELPRESSURE_HPA (1013.25)

//Adafruit_BME680 bme; // I2C
 Adafruit_BME680 bme(SS); // hardware SPI
 Adafruit_BME680 bme(SS, MOSI, MISO, SCK);

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println(F("BME680 async test"));

  if (!bme.begin()) {
    Serial.println(F("Could not find a valid BME680 sensor, check wiring!"));
    while (1);
  }

  // Set up oversampling and filter initialization
  bme.setTemperatureOversampling(BME680_OS_8X);
  bme.setHumidityOversampling(BME680_OS_2X);
  bme.setPressureOversampling(BME680_OS_4X);
  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
  bme.setGasHeater(320, 150); // 320*C for 150 ms
}

void loop() {
  // Tell BME680 to begin measurement.
  unsigned long endTime = bme.beginReading();
  if (endTime == 0) {
    Serial.println(F("Failed to begin reading :("));
    return;
  }
  Serial.print(F("Reading started at "));
  Serial.print(millis());
  Serial.print(F(" and will finish at "));
  Serial.println(endTime);

  Serial.println(F("You can do other work during BME680 measurement."));
  delay(50); // This represents parallel work.
  // There's no need to delay() until millis() >= endTime: bme.endReading()
  // takes care of that. It's okay for parallel work to take longer than
  // BME680's measurement time.

  // Obtain measurement results from BME680. Note that this operation isn't
  // instantaneous even if milli() >= endTime due to I2C/SPI latency.
  if (!bme.endReading()) {
    Serial.println(F("Failed to complete reading :("));
    return;
  }
  Serial.print(F("Reading completed at "));
  Serial.println(millis());

  Serial.print(F("Temperature = "));
  Serial.print(bme.temperature);
  Serial.println(F(" *C"));

  Serial.print(F("Pressure = "));
  Serial.print(bme.pressure / 100.0);
  Serial.println(F(" hPa"));

  Serial.print(F("Humidity = "));
  Serial.print(bme.humidity);
  Serial.println(F(" %"));

  Serial.print(F("Gas = "));
  Serial.print(bme.gas_resistance / 1000.0);
  Serial.println(F(" KOhms"));

  Serial.print(F("Approx. Altitude = "));
  Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
  Serial.println(F(" m"));

  Serial.println();
  delay(2000);
}

As you can see in the above code, we are using default SPI pins to initialize BME680 object.

 Adafruit_BME680 bme(SS); // hardware SPI
 Adafruit_BME680 bme(SS, MOSI, MISO, SCK);

Use ESP32 Custom SPI Pins

We can also easily define custom pins for any ESP32 SPI bus instead of using default pins. When we are using libraries of sensors in Arduino IDE, it is very easy to define custom pins. But later on, we will also see how to define custom pins in the ESP32 SPI library.

We can define custom pins by passing pin names to the library constructor as here we passed pin numbers to BM680 library constructor:

#define BME_SCK  25
#define BME_MISO 32
#define BME_MOSI 26
#define BME_CS 33

Adafruit_BME680 bme(BME_CS); // hardware SPI
Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK);

If you are not using any sensor library and you directly want to use SPI library, in that case, you can set the custom pins as follows. In the following code, we are using default pins for HSPI and custom pins for the VSPI bus.

#include <SPI.h>

#define VSPI_MISO   2
#define VSPI_MOSI   4
#define VSPI_SCLK   0
#define VSPI_SS     33

void setup()
{
vspi = new SPIClass(VSPI);
hspi = new SPIClass(HSPI);
  
 vspi->begin();
 vspi->begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_SS); //SCLK, MISO, MOSI, SS)
}

Use ESP32 SPI Master with Multiple SPI Slaves

In this section, we will see how to use ESP32 SPI Bus with multiple SPI slave devices. To use a single SPI master with multiple slaves, we require multiple chip select (CS) or slave select (SS) lines from the controller(master).

As you can see in the following diagram, there is one ESP32 SPI controller and two SPI slave devices are connected with it by using the same MOSI, MISO, and SCLK pins. But different chip select lines are used for each slave device such as CS1 and CS2.

esp32 spi single master multiple slave communication

In our Arduino sketch, we make the particular CS line active low to select the slave device we want to communicate with.

For example, if we want to communicate with SPI peripheral 2, we will select it by setting the CS2 line to active low. Moreover, we should also make sure all other chip select lines should be active high on the SPI bus. Hence, in the above example, CS1 should be active high and CS2 must be active low when we want to communicate with SPI peripheral 2.

In summary, when using multiple slave devices with a single SPI master controller, we can communicate with a single slave device at a time and other slave devices will be in an idle state. If we want to communicate with multiple SPI devices simultaneously, we need to use multiple SPI controllers.

Use Two ESP32 SPI Buses HSPI and VSPI simultaneously

As discussed earlier, ESP32 has two usable SPI buses that are HSPI and VSPI. We can use them separately. As you can see in the following diagram, we have two SPI peripherals connected with HSPI and VSPI.

esp32 multiple spi buses arduino ide

We have already seen default pins for HSPI and VSPI buses in the ESP32 SPI pins section. But we can use either default or custom pins for both.

Now let’s see how to configure, initialize and use HSPI and VSPI buses in Arduino sketch.

First, include the header file of ESP32 SPI Controller library.

#include <SPI.h>

Note: This library can configure ESP32 in master mode only. In the next section, we will see how to use ESP32 SPI as a slave and we install a separate ESP32 SPI slave library.

In SPI master library, SPIClass contains all function definitions to configure and use SPI buses. Create two objects of SPIClass with any name. Here, we have defined two objects with the names vpsi_controller and hspi_controller. and passed the names of both SPI controllers to a class constructor. One for each ESP32 SPI controller.

vspi_controller = new SPIClass(VSPI);
hspi_controller = new SPIClass(HSPI);

In last step, we created objects but SPIClass constructor only configured the SPI controller. To initialize and start SPI communication, call the begin() method on vspi_controller and hspi_controller objects. It will initialize and make controller ready to use on default SPI pins.

vspi_controller->begin();
hspi_controller->begin();

We can also pass custom pin numbers to begin() method if we want to use custom pins instead. For example:

#define VSPI_MISO   2
  #define VSPI_MOSI   4
  #define VSPI_SCLK   0
  #define VSPI_SS     33

  #define HSPI_MISO   26
  #define HSPI_MOSI   27
  #define HSPI_SCLK   25
  #define HSPI_SS     32

vspi->begin(VSPI_CLK, VSPI_MISO, VSPI_MOSI, VSPI_SS);
hspi->begin(HSPI_CLK, HSPI_MISO, HSPI_MOSI, HSPI_SS);

When we are using custom pins, we also need to declare CS/SS pins as output pins inside the setup().

pinMode(VSPI_SS, OUTPUT);
pinMode(HSPI_SS, OUTPUT);

You can refer to this ES32 SPI multiple bus example Arduino sketch. By using this sketch, we will perform SPI communication between two Arduino boards in the next section.

#include <SPI.h>

// Define ALTERNATE_PINS to use non-standard GPIO pins for SPI bus

#ifdef ALTERNATE_PINS
  #define VSPI_MISO   2
  #define VSPI_MOSI   4
  #define VSPI_SCLK   0
  #define VSPI_SS     33

  #define HSPI_MISO   26
  #define HSPI_MOSI   27
  #define HSPI_SCLK   25
  #define HSPI_SS     32
#else
  #define VSPI_MISO   MISO
  #define VSPI_MOSI   MOSI
  #define VSPI_SCLK   SCK
  #define VSPI_SS     SS

  #define HSPI_MISO   12
  #define HSPI_MOSI   13
  #define HSPI_SCLK   14
  #define HSPI_SS     15
#endif

static const int spiClk = 1000000; // 1 MHz

//uninitalised pointers to SPI objects
SPIClass * vspi = NULL;
SPIClass * hspi = NULL;

void setup() {
  //initialise two instances of the SPIClass attached to VSPI and HSPI respectively
  vspi = new SPIClass(VSPI);
  hspi = new SPIClass(HSPI);
  
  //clock miso mosi ss

#ifndef ALTERNATE_PINS
  //initialise vspi with default pins
  //SCLK = 18, MISO = 19, MOSI = 23, SS = 5
  vspi->begin();
#else
  //alternatively route through GPIO pins of your choice
  vspi->begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_SS); //SCLK, MISO, MOSI, SS
#endif

#ifndef ALTERNATE_PINS
  //initialise hspi with default pins
  //SCLK = 14, MISO = 12, MOSI = 13, SS = 15
  hspi->begin();
#else
  //alternatively route through GPIO pins
  hspi->begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_SS); //SCLK, MISO, MOSI, SS
#endif

  //set up slave select pins as outputs as the Arduino API
  //doesn't handle automatically pulling SS low
  pinMode(VSPI_SS, OUTPUT); //VSPI SS
  pinMode(HSPI_SS, OUTPUT); //HSPI SS

}

// the loop function runs over and over again until power down or reset
void loop() {
  //use the SPI buses
  vspiCommand();
  hspiCommand();
  delay(100);
}

void vspiCommand() {
  byte data = 0b01010101; // junk data to illustrate usage

  //use it as you would the regular arduino SPI API
  vspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
  digitalWrite(VSPI_SS, LOW); //pull SS slow to prep other end for transfer
  vspi->transfer(data);  
  digitalWrite(VSPI_SS, HIGH); //pull ss high to signify end of data transfer
  vspi->endTransaction();
}

void hspiCommand() {
  byte stuff = 0b11001100;
  
  hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
  digitalWrite(HSPI_SS, LOW);
  hspi->transfer(stuff);
  digitalWrite(HSPI_SS, HIGH);
  hspi->endTransaction();
}

ESP32 SPI Master Slave Communication Example

In this section, we will see an example to perform SPI communication between two ESP32 boards. We will configure one EPS32 as a master and another ESP32 as a slave.

We will transmit commands from the ESP32 controller to slave device to control its onboard LED. Master will transmit ‘0’ and ‘1’ with a delay of 1 second. ESP32 slave will receive it and turn on and off its onboard LED.

In the following examples, we have used HPSI bus and default pins for both master and slave. Take two ESP32 boards and make connections between them according to the table connection shown below:

ESP32 MasterESP32 Slave
MOSI (GPIO12)MOSI (GPIO12)
MISO (GPIO13)MISO (GPIO13)
SCLK (GPIO14)SCLK (GPIO14)
CS (GPIO15)CS (GPIO15)

ESP32 SPI Master Sketch

This Arduino sketch will transfer on and off bytes on SPI bus using the HSPI controller with a delay of one second.

#include <SPI.h>

// Define ALTERNATE_PINS to use non-standard GPIO pins for SPI bus

#ifdef ALTERNATE_PINS
  #define HSPI_MISO   26
  #define HSPI_MOSI   27
  #define HSPI_SCLK   25
  #define HSPI_SS     32
#else
  #define HSPI_MISO   MISO
  #define HSPI_MOSI   MOSI
  #define HSPI_SCLK   SCK
  #define HSPI_SS     SS
#endif

static const int spiClk = 1000000; // 1 MHz

//uninitalised pointers to SPI objects
SPIClass * hspi = NULL;

void setup() {
  //initialise instance of the SPIClass attached to HSPI
  hspi = new SPIClass(HSPI);
  
  //clock miso mosi ss
#ifndef ALTERNATE_PINS
  //initialise hspi with default pins
  //SCLK = 14, MISO = 12, MOSI = 13, SS = 15
  hspi->begin();
#else
  //alternatively route through GPIO pins
  hspi->begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_SS); //SCLK, MISO, MOSI, SS
#endif

  //set up slave select pins as outputs as the Arduino API
  //doesn't handle automatically pulling SS low
  pinMode(HSPI_SS, OUTPUT); //HSPI SS
}

// the loop function runs over and over again until power down or reset
void loop() {
  hspi_send_command();
  delay(100);
}

void hspi_send_command() {
  byte data_on = 0b00000001; // data 1 to turn on LED of slave
  byte data_off = 0b0000000; // data 0 to turn off LED of slave
  
  hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
  digitalWrite(HSPI_SS, LOW);
  hspi->transfer(data_on);
  digitalWrite(HSPI_SS, HIGH);
  hspi->endTransaction();

  delay(1000);
  
  hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
  digitalWrite(HSPI_SS, LOW);
  hspi->transfer(data_off);
  digitalWrite(HSPI_SS, HIGH);
  hspi->endTransaction();
  delay(1000);

}

How does Code work?

First, include the header file of the ESP32 SPI Controller library.

#include <SPI.h>

Next, define the pins for HSPI. Here, we have defined both default and custom pins. We will be using default pins in this example. But if you want to use custom pins instead, you can enable them by defining ALTERNATE_PINS with #define after #include <SPI.h>.

#ifdef ALTERNATE_PINS
  #define HSPI_MISO   26
  #define HSPI_MOSI   27
  #define HSPI_SCLK   25
  #define HSPI_SS     32
#else
  #define HSPI_MISO   MISO
  #define HSPI_MOSI   MOSI
  #define HSPI_SCLK   SCK
  #define HSPI_SS     SS
#endif

Define the clock speed for SPI bus and here we define it as 1MHz.

static const int spiClk = 1000000; // 1 MHz

Here, we have defined an object of class SPI class with the name hpsi. and passed the name of HSPI controller to a class constructor which will configure the controller.

SPIClass * hspi = NULL;  
hspi = new SPIClass(HSPI);

To initialize and start SPI communication, call the begin() method on hspi object. It will initialize and make the controller ready to use on default or custom pins.

  //clock miso mosi ss
#ifndef ALTERNATE_PINS
  //initialise hspi with default pins
  //SCLK = 14, MISO = 12, MOSI = 13, SS = 15
  hspi->begin();
#else
  //alternatively route through GPIO pins
  hspi->begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_SS); //SCLK, MISO, MOSI, SS
#endif

Inside the loop, we call hspi_send_command() function after every 100ms. This function will transmit ‘1’ and ‘0’ after every 1 second.

void hspi_send_command() {
  byte data_on = 0b00000001; // data 1 to turn on LED of slave
  byte data_off = 0b0000000; // data 0 to turn off LED of slave
  
  hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
  digitalWrite(HSPI_SS, LOW);
  hspi->transfer(data_on);
  digitalWrite(HSPI_SS, HIGH);
  hspi->endTransaction();

  delay(1000);
  
  hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
  digitalWrite(HSPI_SS, LOW);
  hspi->transfer(data_off);
  digitalWrite(HSPI_SS, HIGH);
  hspi->endTransaction();
  delay(1000);

}

ESP32 SPI Slave Sketch

As discussed earlier, SPI.h library configures ESP32 in master mode only or as a controller. To use ESP32 as a slave or a peripheral device, we need to install ESP32SPISlave library.

Install ESP32 SPI Slave library

Open Arduino IDE and click on Sketch > Library > Manage Libraries.

When you click on the manage libraries option, you will get this window. In this window write ‘ESP32SPISlave‘ in the search bar and press enter.

Select the highlighted library and click on install.

ESP32 SPI slave library Arduino IDE

Now copy the following Arduino sketch and upload it to ESP32 slave. The following code will read SPI data in blocking mode from a master. Based on data received from a controller, it will turn on and off onboard LED.

#include <ESP32SPISlave.h>

ESP32SPISlave slave;

static constexpr uint32_t BUFFER_SIZE {32};
uint8_t spi_slave_tx_buf[BUFFER_SIZE];
uint8_t spi_slave_rx_buf[BUFFER_SIZE];

#define LED 2
void setup() {
    Serial.begin(115200);
    delay(2000);
    pinMode(LED, OUTPUT);
    // begin() after setting
    // HSPI = CS: 15, CLK: 14, MOSI: 13, MISO: 12 -> default
    // VSPI = CS:  5, CLK: 18, MOSI: 23, MISO: 19
    slave.setDataMode(SPI_MODE0);
    slave.begin();
    // slave.begin(VSPI);   // you can use VSPI like this

    // clear buffers
    memset(spi_slave_tx_buf, 0, BUFFER_SIZE);
    memset(spi_slave_rx_buf, 0, BUFFER_SIZE);
}

void loop() {
    // block until the transaction comes from master
    slave.wait(spi_slave_rx_buf, spi_slave_tx_buf, BUFFER_SIZE);

    // if transaction has completed from master,
    // available() returns size of results of transaction,
    // and buffer is automatically updated
    char data;
    while (slave.available()) {
        // show received data
         Serial.print("Command Received: ");
         Serial.println(spi_slave_rx_buf[0]);
         data = spi_slave_rx_buf[0];
         slave.pop();
    }
    if(data == 1 )
    {
        Serial.println("Setting LED active HIGH ");
        digitalWrite(LED, HIGH);
    }
    else if(data == 0 )
    {
        Serial.println("Setting LED active LOW ");
        digitalWrite(LED, LOW);
    }
     Serial.println("");
}

How does Code Works?

First, include the header file of the ESP32 SPI peripheral or slave library.

#include <ESP32SPISlave.h>


Create an object of ESP32SPISlave class with the name of slave.

ESP32SPISlave slave;

Define buffers to store data received on the MOSI pin of ESP32 SPI slave.

static constexpr uint32_t BUFFER_SIZE {32};
uint8_t spi_slave_tx_buf[BUFFER_SIZE];
uint8_t spi_slave_rx_buf[BUFFER_SIZE];

Define a name for onboard LED with #define preprocessor directive. We will use this name to configure and control the onboard LED of ESP32.

#define LED 2

Initialize serial communication with a baud rate of 115200. We will use it to print data on the serial monitor that HSPI slave will receive.

  Serial.begin(115200);

Configure onboard LED of ESP32 as a digital output pin which is connected with GPIO2.

 pinMode(LED, OUTPUT);

Set the data mode on slave object.

slave.setDataMode(SPI_MODE0); 

To initialize and start HSPI, call the begin() method on hspi object. It will initialize and make the HSPI bus in salve mode ready to use on default pins.

slave.begin();

Clear the buffers and initialize them to zero.

memset(spi_slave_tx_buf, 0, BUFFER_SIZE);     
memset(spi_slave_rx_buf, 0, BUFFER_SIZE);  

Inside for loop, wait in blocking state until the data transaction comes from ESP32 master.

 slave.wait(spi_slave_rx_buf, spi_slave_tx_buf, BUFFER_SIZE); 

If the transaction has been completed from the master, available() returns size of results of transaction, and a buffer is automatically updated. After that, send the received byte to the serial monitor for display. Additionally, save this byte in a data variable.

 char data;   
 while (slave.available()) 
{         
// show received data          
Serial.print("Command Received: ");          
Serial.println(spi_slave_rx_buf[0]);          
data = spi_slave_rx_buf[0];         
 slave.pop();     
}

This if statement block checks if the data received is ‘1’, it will turn on the LED, and if it is ‘0’, it will turn off the LED. Also, it will print the LED status on the serial monitor.

if(data == 1 )    
 {         
Serial.println("Setting LED active HIGH ");         
digitalWrite(LED, HIGH);    
 }    
 else if(data == 0 )     
{         
Serial.println("Setting LED active LOW ");        
digitalWrite(LED, LOW);    
}   

After uploading Arduino sketches to both ESP32 boards, open the serial monitor of a slave device, you will get these messages on the serial monitor:

esp32 spi master slave communication between two boards

You will also see that the onboard LED of ESP32 slave will turn on and off with a delay of one second.

spi commuication between two esp32 using Arduino ide master slave

Video demo:

You may also like to read:

Other SPI tutorials:

14 thoughts on “ESP32 SPI Tutorial Master Slave Communication Example”

  1. Hello,

    Thank you for the tutorial.

    Hello,

    Thank you for the tutorial.

    I would appreciate your help. I am having an issue when I trying to compile the ESP32 SPI Slave Sketch:

    ESP32SPISlave.h:48:28: error: ‘SOC_SPI_MAXIMUM_BUFFER_SIZE’ was not declared in this scope .max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE,

    I tought it was an error associated to incompatibility between ESP32SPISLAVE library and my version of Arduino IDE (1.8.10). So, I download Arduino IDE 2.0.3 but the error still continues.

    I will be waiting for your response.

    Thanks.

    Reply
      • I didn’t need to install slave library, my library manager showed me it was already installed and it is the same version that you showed.

        Reply
        • Hello Microcontrollers Lab and AnaMariaR. Thanks for the tutorial.

          I have been trying to replicate the codes and I get the same error as AnaMariaR:

          ESP32SPISlave.h:48:28: error: ‘SOC_SPI_MAXIMUM_BUFFER_SIZE’ was not declared in this scope .max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE,

          Could you give me any advice to solve the problem? I would appreciate it a lot.

          Reply
  2. Hi, thank you for the tutorial

    One question, which are the pins that are finally used to interconnect the two ESP32? Because I used the default pins and they do not correspond to the ones I see in last picture and also I do not receive anything

    Reply
    • #define HSPI_MISO 12
      #define HSPI_MOSI 13
      #define HSPI_SCLK 14
      #define HSPI_SS 15

      I have used the above pins, sometimes it gets confusing to understand, it’s better to declare pins. I also faced some issue regarding pins assignment so went with above approach. Alternatively, if you want to know which pins has been used, print the pin variables defined in code

      Reply

Leave a Comment