The SPI Bus is a synchronous communication protocol used to transfer data between a microcontroller and other devices, such as sensors, displays, memory, and peripherals.
Unlike other protocols, the SPI bus uses multiple communication lines, allowing for a high transfer speed and exceptional flexibility.
The SPI port is primarily used for its high data transmission capacity. For this reason, you will find it in devices that require a large amount of data per second, such as storage devices (memories, SD) and displays.
If you don’t know what the SPI bus is or need more help, check out these entries:
The SPI bus in the ESP32
The ESP32, ESP32-S2, and ESP32-S3 have four SPI controllers, while the ESP32-C3 has three.
Its use in the Arduino environment is very similar to what we would find in a conventional Arduino. The functionalities are defined in the SPI.h
library, under the SPIClass
object.
void setup() {
// Initialize SPI communication
SPI.begin();
}
The biggest confusion we will have is with the pins and their denominations. But, we have the advantage that in the case of the ESP32, we can reassign the pins.
If we look at the ESP32, ESP32-S2, and ESP32-S3 have four controllers, called SPI0, SPI1, SPI2, and SPI3.
- SPI0 and SPI1 are used for communication with Flash memory. So we don’t touch them.
- SPI2 and SPI3 are free for the user.
This leaves two free SPI controllers to use (one in the ESP32-C3).
On the other hand, SPI2 is referred to as HSPI and SPI3 is referred to as VSPI. What do the H and V mean? Absolutely nothing, they are identical in characteristics.
In fact, search the internet, there are funny questions and answers about what H and V mean (I like the one about Henry and Victor).
In the case of the ESP32
SPI | MOSI | MISO | SCK | CS |
---|---|---|---|---|
HSPI | GPIO 13 | GPIO 12 | GPIO 14 | GPIO 15 |
VSPI | GPIO 23 | GPIO 19 | GPIO 18 | GPIO 5 |
In the case of the ESP32-S3
SPI | MOSI | MISO | SCK | CS |
---|---|---|---|---|
HSPI | GPIO 35 | GPIO 37 | GPIO 37 | GPIO - |
VSPI | GPIO 11 | GPIO 13 | GPIO 12 | GPIO 10 |
But the same, I would take care of defining them manually.
SPIClass vspi = SPIClass(VSPI);
MySPI.begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_SS);
The constants VSPI and HSPI are integers that are defined in the Arduino Core. They are different for each variant of the ESP32, so use the constant instead of a number.
Model | HSPI | VSPI |
---|---|---|
ESP32 | 1 | 3 |
ESP32-S2 | 2 | 3 |
ESP32-S3 | 2 | 3 |
ESP32-C3 | 1 | 3 |
How to use SPI in ESP32 in the Arduino environment
Using the SPI bus in the ESP32 in the Arduino environment is very similar to doing so in a conventional Arduino. Here are some examples.
Sending Data
byte dataToSend = 0xAA;
byte receivedData;
digitalWrite(SS, LOW); // Lower CS/SS line to select the device
receivedData = SPI.transfer(dataToSend); // Send and receive data
digitalWrite(SS, HIGH); // Raise CS/SS line to end communication
Using multiple SPI in the ESP32
As we have said, the ESP32, ESP32-S2, and ESP32-S3 have two SPI controllers, so we can create two simultaneous device networks.
#include <SPI.h>
#define HSPI 2 // 2 for S2 and S3, 1 for S1
#define VSPI 3
// replace with the pins you want to use
const int HSPI_MISO = 0;
const int HSPI_MOSI = 0;
const int HSPI_SCLK = 0;
const int HSPI_SS = 0;
const int VSPI_MISO = 0;
const int VSPI_MOSI = 0;
const int VSPI_SCLK = 0;
const int VSPI_SS = 0;
SPIClass vspi = SPIClass(VSPI);
SPIClass hspi = SPIClass(HSPI);
void setup()
{
vspi.begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_SS);
hspi.begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_SS);
}
void loop()
{
delay(1000); // do nothing
}