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. Show
SPI Communication IntroductionSPI 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 DevicesBoth 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. The functionality of each signal is given here.
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. 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. 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 PinsAs 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.
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 PinsNote: 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:
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: As soon as you press the enable/reset button, you will be able to see default SPI pin numbers on the serial monitor: 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.
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:
As you can see in the above code, we are using default SPI pins to initialize BME680 object.
Use ESP32 Custom SPI PinsWe 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:
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.
Use ESP32 SPI Master with Multiple SPI SlavesIn 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. 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 simultaneouslyAs 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. 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.
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.
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.
We can also pass custom pin numbers to begin() method if we want to use custom pins instead. For example:
When we are using custom pins, we also need to declare CS/SS pins as output pins inside the setup().
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.
ESP32 SPI Master Slave Communication ExampleIn 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 SPI Master SketchThis Arduino sketch will transfer on and off bytes on SPI bus using the HSPI controller with a delay of one second.
How does Code work?First, include the header file of the ESP32 SPI Controller library.
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>.
Define the clock speed for SPI bus and here we define it as 1MHz.
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.
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.
Inside the loop, we call hspi_send_command() function after every 100ms. This function will transmit ‘1’ and ‘0’ after every 1 second.
ESP32 SPI Slave SketchAs 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 libraryOpen 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. 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.
How does Code Works?First, include the header file of the ESP32 SPI peripheral or slave library.
Define buffers to store data received on the MOSI pin of ESP32 SPI slave.
Define a name for onboard LED with #define preprocessor directive. We will use this name to configure and control the onboard LED of ESP32.
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.
Configure onboard LED of ESP32 as a digital output pin which is connected with GPIO2.
Set the data mode on slave object.
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.
Clear the buffers and initialize them to zero.
Inside for loop, wait in blocking state until the data transaction comes from ESP32 master.
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.
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.
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: You will also see that the onboard LED of ESP32 slave will turn on and off with a delay of one second. Video demo: You may also like to read:
Other SPI tutorials:
|