ESP32_Communication
ESP32_Communication
Table of Contents:
Introducing ESP32 SPI Communication Protocol
ESP32 SPI Peripherals
ESP32 SPI Pins
Using Custom ESP32 SPI Pins
ESP32 with Multiple SPI Devices
Multiple SPI Devices (same bus, different CS pin)
Using Two SPI Bus Interfaces (use HSPI and VSPI simultaneously)
This tutorial focus on programming the ESP32 using the Arduino core, so before proceeding,
you should have the ESP32 add-on installed in your Arduino IDE. Follow the next tutorial to
install the ESP32 on the Arduino IDE, if you haven’t already.
Installing the ESP32 Board in Arduino IDE (Windows, Mac OS X, and Linux
instructions)
Alternatively, you can also use VS Code with the PlatformIO extension to program your
boards using the Arduino core:
Getting Started with VS Code and PlatformIO IDE for ESP32 and ESP8266
(Windows, Mac OS X, Linux Ubuntu)
Introducing ESP32 SPI
Communication Protocol
SPI stands for Serial Peripheral Interface, and it is a synchronous serial data protocol used by
microcontrollers to communicate with one or more peripherals. For example, your ESP32
board communicating with a sensor that supports SPI or with another microcontroller.
In an SPI communication, there is always a controller (also called master) that controls
the peripheral devices (also called slaves). Data can be sent and received simultaneously.
This means that the master can send data to a slave, and a slave can send data to the master at
the same time.
You can have only one master, which will be a microcontroller (the ESP32), but you can have
multiple slaves. A slave can be a sensor, a display, a microSD card, etc., or another
microcontroller. This means you can have an ESP32 connected to multiple sensors, but the
same sensor can’t be connected to multiple ESP32 boards simultaneously.
SPI Interface
For SPI communication you need four lines:
You can use HSPI and VSPI to communicate with other devices. HSPI and VSPI have
independent bus signals, and each bus can drive up to three SPI slaves.
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-
spi-communication-arduino/
void loop() {
// put your main code here, to run repeatedly:
}
View raw code
Important: make sure you select the board you’re using in Tools > Board, otherwise, you
may not get the right pins.
After uploading the code, open the Serial Monitor, RST your board and you’ll see the SPI
pins.
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <SPI.h>
#define BME_SCK 25
#define BME_MISO 32
#define BME_MOSI 26
#define BME_CS 33
#define SEALEVELPRESSURE_HPA (1013.25)
void setup() {
Serial.begin(9600);
Serial.println(F("BME280 test"));
bool status;
// default settings
// (you can also pass in a Wire library object like &Wire2)
status = bme.begin();
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check
wiring!");
while (1);
}
Serial.println();
}
void loop() {
printValues();
delay(delayTime);
}
void printValues() {
Serial.print("Temperature = ");
Serial.print(bme.readTemperature());
Serial.println(" *C");
Serial.print("Pressure = ");
Serial.print(bme.readPressure() / 100.0F);
Serial.println(" hPa");
Serial.print("Humidity = ");
Serial.print(bme.readHumidity());
Serial.println(" %");
Serial.println();
}
View raw code
You can easily pass your custom SPI pins to the library constructor.
#define BME_SCK 25
#define BME_MISO 32
#define BME_MOSI 26
#define BME_CS 33
If you’re not using a library, or the library you’re using doesn’t accept the pins in the library
constructor, you may need to initialize the SPI bus yourself. In that case, you would need to
call the SPI.begin() method on the setup() and pass the SPI pins as arguments:
SPI.begin(SCK, MISO, MOSI, SS);
You can see an example of this scenario in this tutorial, in which we initialize an SPI LoRa
transceiver that is connected to custom SPI pins. Or this example showing how to use custom
SPI pins with a microSD card module.
To select the peripheral you want to communicate with, you should set its CS pin to LOW. For
example, imagine you have peripheral 1 and peripheral 2. To read from peripheral 1, make
sure its CS pin is set to LOW (here represented as CS_1):
digitalWrite(CS_1, LOW); // enable CS pin to read from peripheral 1
/*
use any SPI functions to communicate with peripheral 1
*/
Then, at same point, you’ll want to read from peripheral 2. You should disable peripheral
1 CS pin by setting it to HIGH, and enable peripheral 2 CS pin by setting it to LOW:
digitalWrite(CS_1, HIGH); // disable CS pin from peripheral 1
digitalWrite(CS_2, LOW); // enable CS pin to read from peripheral 2
/*
use any SPI functions to communicate with peripheral 2
*/
ESP32 Using Two SPI Bus Interfaces (Use HSPI and VSPI
simultaneously)
To communicate with multiple SPI peripherals simultaneously, you can use the ESP32 two
SPI buses (HSPI and VSPI). You can use the default HSPI and VSPI pins or use custom pins.
Briefly, to use HSPI and VSPI simultaneously, you just need to.
1) First, make sure you include the SPI library in your code.
#include <SPI.h>
2) Initialize two SPIClass objects with different names, one on the HSPI bus and another
on the VSPI bus. For example:
vspi = new SPIClass(VSPI);
hspi = new SPIClass(HSPI);
3) Call the begin() method on those objects.
vspi.begin();
hspi.begin();
You can pass custom pins to the begin() method if needed.
vspi.begin(VSPI_CLK, VSPI_MISO, VSPI_MOSI, VSPI_SS);
hspi.begin(HSPI_CLK, HSPI_MISO, HSPI_MOSI, HSPI_SS);
4) Finally, you also need to set the SS pins as outputs. For example:
pinMode(VSPI_SS, OUTPUT);
pinMode(HSPI_SS, OUTPUT);
Then, use the usual commands to interact with the SPI devices, whether you’re using a sensor
library or the SPI library methods.
You can find an example of how to use multiple SPI buses on the arduino-esp32 SPI library.
See the example below:
/* The ESP32 has four SPi buses, however as of right now only two of
* them are available to use, HSPI and VSPI. Simply using the SPI
API
* as illustrated in Arduino examples will use VSPI, leaving HSPI
unused.
*
* However if we simply initialize two instance of the SPI class for
both
* of these buses both can be used. However when just using these
the Arduino
* way only will actually be outputting at a time.
*
* Logic analyzer capture is in the same folder as this example as
* "multiple_bus_output.png"
*
* created 30/04/2018 by Alistair Symonds
*/
#include <SPI.h>
#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
#if !defined(CONFIG_IDF_TARGET_ESP32)
#define VSPI FSPI
#endif
void setup() {
//initialize two instances of the SPIClass attached to VSPI and
HSPI respectively
vspi = new SPIClass(VSPI);
hspi = new SPIClass(HSPI);
#ifndef ALTERNATE_PINS
//initialize 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
//initialize 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
// the loop function runs over and over again until power down or
reset
void loop() {
//use the SPI buses
spiCommand(vspi, 0b01010101); // junk data to illustrate usage
spiCommand(hspi, 0b11001100);
delay(100);
}
Wrapping Up
This article was a quick and simple guide showing you how to use SPI communication with
the ESP32 using the Arduino core—with the ESP32 acting as a controller (master).
In summary, the ESP32 has four SPI buses, but only two can be used to control peripherals,
the HSPI and VSPI. Most ESP32 have pre-assigned HSPI and VSPI GPIOs, but you can
always change the pin assignment in the code.
You can use the HSPI and VSPI buses simultaneously to drive multiple SPI peripherals, or
you can use multiple peripherals on the same bus as long as their CS pin is connected to a
different GPIO.
We didn’t dive deeply into examples, because each sensor, library, and case scenario is
different. But, now you should have a better idea of how to interface one or multiple SPI
devices with the ESP32.
For more detailed information about the SPI Master driver on the ESP32, you can check the
espressif official documentation.
We didn’t cover setting the ESP32 as an SPI slave, but you can check these examples.
We hope you find this tutorial useful. We have a similar article, but about I2C communication
protocol. Check it out on the following link:
ESP32 I2C Communication: Set Pins, Multiple Bus Interfaces and Peripherals
(Arduino IDE)
Learn more about the ESP32 with our resources:
Recommended Resources
Build a Home Automation System from Scratch » With Raspberry Pi, ESP8266, Arduino,
and Node-RED.
Home Automation using ESP8266 eBook and video course » Build IoT and home
automation projects.
Arduino Step-by-Step Projects » Build 25 Arduino projects with our course, even with no
prior experience!
ESP32 Datalogger: Download Data File via Web Server (Arduino IDE)