From the article machine.Pin, it has been discussed using a microcontroller pin to import and export data and in the article I2C bus communication which uses the machine.I2C class to communicate between devices. Now let’s take a look at the machine.SPI class, another form of communication that has been recognized for its speed and is commonly used with a graphics display (esp8266/esp32 article) or SD-Card reader (esp8266, esp32article).
SPI
SPI, or Serial Peripheral Interface bus protocol, is a form of bus communication based on serial communication. By dividing the work into the side of the communication controller and devices that are communicated through at least 3 signal lines, which are:
- SCK is the clock cable is used to control the transmission of data between them.
- MOSI is the line outputs the data from the communication controller to the communication device.
- MISO is the line receives data from the devices it communicates with.
Compared with I2C communication, it is found that in I2C bus systems, SDA serves both receiving and transmitting data. And every device on the bus will have an identification number for reference. When there is data in the line but not its number, it doesn’t have to send or receive data. Instead, SPI has separate communication lines for receiving and transmitting and assigning it to active or inactive often relies on an on/off pin with the device it communicates with. Therefore, SPI devices have more than 3 pins for connection, but I2C only needs 2. But with a separate line design for receiving and transmitting, the communication speed of SPI is higher than I2C, but the faster it affects the distance of the signal cable as well.
Micropython supports both hardware and software SPI in two separate classes, machine.SPI and machine.SoftSPI. The structure of the two classes is as shown in Figures 1 and 2.
From Figures 1 and 2, both classes have the same function and constant structure. The difference is that machine.SPI supports hardware and machine.SoftSPI supported by software operation. In the perspective of speed, we cannot confirm which one is faster in all cases. But having the hardware to use makes programming easier, and when Micropython is available in both cases, we often choose that if there is hardware, use the hardware first. If not enough, use the rest of the pins to do software work.
Calling the SPI and SoftSPI classes is done by importing them from the machine:
from machine import SPI
or
from machine import SoftSPI
When the class is successfully imported, the next step is to create an object for a reference medium to a communication bus with the following constructor. The communication speed depends on the cable distance and device support, and for hardware SPI, no pin numbering is required. Just assign the communication channel number as mentioned in the article machine.Pin, for example, when used with esp32 it can be either 1 or 2 to select either the HSPI or VSPI pin set.
object = SoftSPI( baudrate=speed, polarity=1, phase=0, sck=machine.Pin(SCK), mosi=machine.Pin(MOSI), miso=machine.Pin(MISO))
object = SPI(number, baudrate=speed, polarity=0, phase=0)
If you want to change the communication speed or baudrate, you can execute the command init() in the following format. The maximum communication speed that can be supported is 80MHz.
object.init( baudrate=speed )
When the communication is finished, it needs to be canceled with the following command.
object.deinit()
The command to send n bytes of data to the destination device has the following format:
object.write( n_bytes )
The command to read data has the following form of usage: the first command reads the specified n bytes of data from the bus. But in the 2nd form, the difference is set to read a maximum of n bytes, and if the data is found to match the end data or as defined in x it will stop reading data. (but reads no more than n bytes)
data = object.read( n )
data = object.read( n, x )
If you want to read and store it in the reserved byte memory which is reserved and reused, has a higher speed, has to create data and reserve memory to be stored in a new buffer or variable every time like in read( ) command.
object.readinto( buf )
object.readinto( buf, x )
From the above read instruction pattern, the byte memory reservation must be performed first using the following reserving form:
buf = bytearray( reserve_bytes )
The last group of commands is the command sends data to the bus and stores the result in a buffer as the following usage patterns
object.write_readinto( output, buffer )
object.write_readinfo( output_buffer, buffer )
Conclusion
From this article, we will find that using SPI in both hardware and software mode is not complicated because it only commands and reads data. As for how to operate an external module, it is necessary to study the details of that module and how to use it. We expect this article to continue to be an educational resource for everyone. Finally, have fun with programming.
If you want to talk with us, feel free to comment below!!
References
- Micropython, Quick reference for esp8266
- Micropython, Quick reference for esp32
- Micropython, Class SPI
(C) 2020-2021, By Jarut Busarathid and Danai Jedsadathitikul
Updated 2021-10-24