How to use SPI on Torizon
Introduction
SPI (Serial Peripheral Interface) is a common interface for a variety of hardware peripherals that use SPI as a communication protocol. SPI devices operate in a master-slave relationship, where the master (the controller) starts the communication with the slave (which could be a sensor, display, or other peripheral), and the slave returns information.
Torizon inherits BSP characteristics, i.e. at its core, Torizon is a Linux operating system, as such some of the information here is general Linux knowledge, which you can find at SPI (Linux) article.
The main goal of this article is to help you with the usage of SPI devices in the context of containers. This article will cover the the two general ways to access peripherals. The method depends on your specific needs and the software support of your specific SPI device:
This article complies with the Typographic Conventions for Torizon Documentation.
Prerequisites
In order to take full advantage of this article, the following read is recommended:
- A computer on module with TorizonCore installed "Getting Started with TorizonCore").
- Basic understanding of SPI management in Linux.
- (Optional) An understanding of device tree overlays.
Considerations about User-Space access
The idea with user-space is to access and manipulate the SPI interface from your application code. This means you will usually work with the generic default SPIdev interface provided by the kernel via /dev
.
When working in user-space, keep in mind that:
- With user-space you take on the burden of the device's behavior. This means writing code to read, write and interpret data from your peripheral.
- This will lead to initial development overhead, however if your device lacks proper software support it may be your only option.
The positive point of this approach is that by writing your own code, it becomes easy to debug issues compared to some external drivers.
Considerations about Kernel-Space access
The idea here is to leverage device specific driver software that is either builtin or loaded into the Linux kernel as a kernel module.
Compared to user-space access:
- Software comes from open-source community or device manufacturer.
- Kernel-space software may have little to no documentation.
- This can lead to more difficult issues when it comes to debugging.
- Driver software is a part of the Kernel system rather than the application code.
- Errors/issues with the driver can affect the entire system.
- Method is not available if kernel-space software doesn't exist.
- You may have to write a Device Tree Overlay, which may not be trivial. Many drivers come with device-tree examples, which can help you with this task. To learn more about this, refer to Device Tree Customization article and Device Tree Customization Examples to learn more.
When it comes to kernel-space drivers, the approach is very similar to the one described for I2C peripherals at How to use I2C on Torizon.
In kernel-space you are able to access the device's data via the same /sys
entries from within a container. For example, if you are using a IIO driver, you should be able to find it at /sys/bus/iio/devices/
.
SPI usage with Containers
To grant the container access to SPI devices you can use bind mounts, but passing devices (using --device
) is better for security since you avoid exposing a storage device that may be erased by an attacker.
Adding --privileged
flag to any docker run
command gives the container full root access. So, do not use this in production since a container with full root access is insecure.
As mentioned at SPI (Linux), the SPI interfaces can be listed in /dev
directory by using the symlinks /dev/<module_family>-spi*
or directly /dev/spidev*
, like in the example below for colibri iMX8X.
# ls -la /dev/colibri-spi*
lrwxrwxrwx 1 root root 9 Jan 1 1970 /dev/colibri-spi-cs0 -> spidev0.0
lrwxrwxrwx 1 root root 9 Jan 1 1970 /dev/colibri-spi-cs1 -> spidev0.1
# ls -la /dev/spidev*
crw-rw-r-- 1 root spidev 153, 0 Jan 1 1970 /dev/spidev0.0
crw-rw-r-- 1 root spidev 153, 1 Jan 1 1970 /dev/spidev0.1
For Torizon, we must overcome an additional issue of how to provide a container access to SPI devices. We made an spidev group with id 52 to allow the users in this group to access SPI devices without root privileges. A similar group was added to Toradex's Debian base container (see here) so that non root users in this group may also enjoy the same benefit.
Knowing this when building a container image based off of a Toradex Debian container image you need just add the following to your Dockerfile
.
RUN groupadd --gid 52 spidev
: Only required if you are building a container from scratch.RUN usermod -a -G spidev torizon
: Required to allow the users in this group to access SPI devices without root privileges.
The command will add the Torizon user to the spidev group allowing access to SPI devices in /dev
without root privileges. Now you just need run your container with the appropriate --device
flag.
SPI example
This SPI example is a test sample of spidev in user space, provided in the Linux Kernel repository. You are going to use the VS Code extension for Torizon.
Follow the steps described at C/C++ Development and Debugging on TorizonCore Using Visual Studio Code to create a Single File C Projetc using VS Code extension for Torizon.
Paste the source code into the main c file.
Proceed with the following modifications in the torizon extension, regarding the explanation about (#user-space-container-access). Refer to C/C++ Development and Debugging on TorizonCore Using Visual Studio Code, to read more about Torizon Configuration.
- At devices configuration, add the SPI device which you are going to use. The tests were made with
/dev/colibri-spi-cs0
; - At buildcommands, at Custom Properties configuration, add the command
RUN usermod -a -G spidev torizon
. - At Custom Properties, add
appargs
with value-D
followed by the SPI device you are going to use. In this case-D /dev/colibri-spi-cs1
.
- At devices configuration, add the SPI device which you are going to use. The tests were made with
Build and deploy the application to the board by pressing
F5
. The final result that you are going to see at the container terminal is going to be like this:
...
spi mode: 0x0
bits per word: 8
max speed: 500000 Hz (500 kHz)
...