Select the version of your OS from the tabs below. If you don't know the version you are using, run the command cat /etc/os-release
or cat /etc/issue
on the board.
Remember that you can always refer to the Torizon Documentation, there you can find a lot of relevant articles that might help you in the application development.
The Kernel Linux GPIO user space SysFS is deprecated and has been discontinued. On the other hand, the kernel config CONFIG_GPIO_SYSFS
is still enabled on our BSP as many customers still use it on their legacy applications - you can check it with zcat /proc/config.gz | grep CONFIG_GPIO_SYSFS
. Its use is discouraged and might be removed from mainline Linux after 2020 as can be seen on sysfs-gpio documentation. For GPIO access from userspace, the new char device API, also known as libgpiod, must be used.
The new user space API uses the /dev/gpiochip
devices through ioctl calls to manage GPIOs:
# ls /dev/gpiochip*
/dev/gpiochip0 /dev/gpiochip2 /dev/gpiochip4 /dev/gpiochip6
/dev/gpiochip1 /dev/gpiochip3 /dev/gpiochip5 /dev/gpiochip7
Each entry on the /dev/gpiochip
corresponds to a GPIO bank that the operating system has access to.
Even though Torizon is preferred for using libgpiod, it is also supported and can be used on Toradex BSP Layers and Reference Images for Yocto Project from the release 3.0b3 onwards. The userspace tools and libraries are included in our evaluation image. If you are looking for more general information on how to use the command-line tools and the C API as well, refer to GPIO (Linux).
Note: non-generic features such as GPIO power management keys, GPIO power off, GPIO LED, U-boot and others explained in GPIO (Linux) also work in TorizonCore.
Operating System in the Computer on Module:
To get the most out of this article and test things in practice, we recommend that you clone the torizon-samples repository to your computer:
$ cd ~
$ git clone https://github.com/toradex/torizon-samples.git
$ cd torizon-samples/gpio
Also, to build Container images for ARM architectures make sure to prepare your build environment according to the following article:
If you want to see things happening, hook up a LED (or a multimeter) and switch (and of course other components to interface with the TTL level from your SoM) to the GPIO pins:
For Colibri and Verdin, we leave it up to you to choose the pins.
Attention: The TTL level for Colibri and Apalis I/O is 3.3V and for Verdin is 1.8V. Do not apply 3.3V signals to Verdin I/O.
libgpiod library encapsulates the ioctl calls and data structures behind a straightforward API. Additionally, libgpiod project contains a set of command-line tools allowing access from shell scripts. These command-line tools can also be used to replace scripts that used the deprecated sysfs API directly.
For getting started with the libgpiod command-line tools let's exemplify some commands. We will use TorizonCore for testing with a pre-built container. We also provide optional instructions for you to re-build the container if you want.
Choose your SoM from the tabs below:
The Dockerfile below is built into the image torizonextras/arm64v8-gpiod: - Dockerfile Run the following command on the board terminal to download the image and mount the container for testing:
# docker run --rm -it --device /dev/gpiochip0 torizonextras/arm64v8-gpiod
The Dockerfile below is built into the image torizonextras/arm32v7-gpiod: - Dockerfile Run the following command on the board terminal to download the image and mount the container for testing:
# docker run --rm -it --device /dev/gpiochip0 torizonextras/arm32v7-gpiod
Note that in the docker run
command, the argument --device pass the char device from the GPIO bank that will be shared and accessed inside the container. You may specify that argument multiple times if access to different GPIO banks is required. Normally root user is required to access /dev/gpiochip devices. TorizonCore comes with udev rules which allow access for users part of the gpio group. Adding the torizon user to the group allows to also access GPIOs as a user from within the container. Use USER torizon
in your Dockerfile if you prefer running the container as non-root user, as exemplified in our sample Dockerfile.
After launching the container, you should be able to run, inside the container, any command explained in the section Command Line Tools on GPIO (Linux).
Some examples are provided in this chapter, illustrating how to use the C API from libgpiod. Pre-built containers are not provided, therefore you are encouraged to build your own, in which case you will need the optional dependencies. First, we will build and deploy the container. Then, we will explain and run the samples.
In this section, you will compile all the C examples and build a Container image to be easily deployed to the board. Choose your SoM from the tabs below:
Note: For the examples below we will use the multi-stage Docker build. It is a best practice and you are encouraged to understand how it is implemented.
The sample Dockerfile used is:
Assuming that you have cloned the torizon-samples as described in the optional dependencies, you can modify and re-build the image by yourself in your development PC.
First, we will build the container image.
$ docker build -f Dockerfile.arm64 -t <yourDockerHubUsername>/arm64v8-c-gpiod .
Upload the image generated in the command above to your Docker Hub:
$ docker login
$ docker push <yourDockerHubUsername>/arm64v8-c-gpiod
After that, on the board terminal, run the following command to pull the image from Docker Hub:
# docker pull <yourDockerHubUsername>/arm64v8-c-gpiod
The sample Dockerfile used is:
Assuming that you have cloned the torizon-samples as described in the optional dependencies, you can modify and re-build the image by yourself in your development PC.
First, we build the container image.
$ docker build -f Dockerfile.armhf -t <yourDockerHubUsername>/arm32v7-c-gpiod .
Upload the image generated in the command above to your Docker Hub:
$ docker login
$ docker push <yourDockerHubUsername>/arm32v7-c-gpiod
After that, on the board terminal, run the following command to pull the image from Docker Hub:
# docker pull <yourDockerHubUsername>/arm32v7-c-gpiod
Now you are ready to understand and run the samples documented at How to toggle a GPIO and Read GPIO Using Interrupt Driven Events. The sections below help you to run the mentioned examples using the previously built containers.
Run How to toggle a GPIO example using the previously built and deployed container. Choose your SoM from the tabs below:
This example uses the Apalis iMX8 GPIO3 - LSIO.GPIO0.IO12:
# docker run --rm -it --init --device /dev/gpiochip0 yourdockerhubuser/arm64v8-c-gpiod
## gpio-toggle 0 12
This example uses the Apalis iMX6 GPIO3 - GPIO2_IO6:
# docker run --rm -it --init --device /dev/gpiochip1 yourdockerhubuser/arm32v7-c-gpiod
## gpio-toggle 1 6
Run Read GPIO Using Interrupt Driven Events example using the previously built and deployed container. Choose your SoM from the tabs below:
This example uses the Apalis iMX8 GPIO3 - LSIO.GPIO0.IO12 as output and GPIO2 - LSIO.GPIO0.IO9 as input.
# docker run --rm -it --init --device /dev/gpiochip0 yourdockerhubuser/arm64v8-c-gpiod
## gpio-event 0 9 0 12
This example uses the Apalis iMX6 GPIO3 - GPIO2_IO6 as output and GPIO2 - GPIO2_IO5 as input.
# docker run --rm -it --init --device /dev/gpiochip1 yourdockerhubuser/arm32v7-c-gpiod
## gpio-event 1 5 1 6
The article .NET Core Development and Debugging on Torizon Using Visual Studio Code explains how to use libgpiod with .NET.
Our samples repository on GitHub provides an example: Python libgpiod example The following articles can help you with enough context for running and extending the sample: - Visual Studio Code Extension for Torizon - Python Development and Debugging on TorizonCore Using Visual Studio Code - Python development on TorizonCore
The Kernel Linux GPIO user space SysFS is deprecated and has been discontinued. It can still be enabled by CONFIG_GPIO_SYSFS but its use is discouraged and will be removed from mainline Linux after 2020. For GPIO access from user space the new char device API must be used.
The new user space API use the /dev/gpiochip devices through ioctl calls to manage GPIOs:
# ls /dev/gpiochip*
/dev/gpiochip0 /dev/gpiochip2 /dev/gpiochip4 /dev/gpiochip6
/dev/gpiochip1 /dev/gpiochip3 /dev/gpiochip5 /dev/gpiochip7
Each entry on the /dev/gpiochip corresponds to a GPIO bank that the operating system has access to.
This article complies to the Typographic Conventions for Torizon Documentation
Operating System in the Computer on Module:
To get the most out of this article and test things in practice, we recommend that you clone the torizon-samples repository to your computer:
$ cd ~
$ git clone https://github.com/toradex/torizon-samples.git
$ cd torizon-samples/gpio
Also, to build Container images for ARM architectures make sure to prepare your build environment according to the following article:
If you want to see things happening, hook up a LED (or a multimeter) and switch (and of course other components to interface with the TTL level from your SoM) to the GPIO pins:
For Colibri and Verdin, we leave it up to you to choose the pins.
Attention: The TTL level for Colibri and Apalis I/O is 3.3V and for Verdin is 1.8V. Do not apply 3.3V signals to Verdin I/O.
To verify the GPIO banks and lines check the datasheet of the module on the section I/O Pins -> Functions List. For example, let's assume we need to access MXM3 X1 pin 5 (Apalis GPIO3) from an Apalis iMX8:
From the datasheet we can see that Apalis MXM3 X1 Pin 5 has the GPIO function on ALT3 accessible at LSIO.GPIO0_IO12. This means we need to access GPIO bank 0 line 12.
Note: This bank and line nomenclature differ slightly depending on the processor family. Apalis iMX6 e.g. starts enumerating GPIO banks with 1, while GPIO banks in Linux always start at 0. That means that GPIO2_IO6 on Apalis iMX6 is GPIO bank 1 line 6 on Linux.
Warning: The highlighted function in the datasheet indicates the default function of the given pin. If the GPIO function is not indicated as default, there is a high chance that you will need to define the pins you will be using as GPIO in a custom Device Tree Overlay (DTO). Find further documentation and examples on how to do so here: Device Tree Overlays
libgpiod library encapsulates the ioctl calls and data structures behind a straightforward API.
Additionally, libgpiod project contains a set of command-line tools allowing access from shell scripts. These command-line tools can also be used to replace scripts which used the deprecated sysfs API directly.
For getting started with the libgpiod command-line tools let's exemplify some commands. We will use TorizonCore for testing with a pre-built container. We also provide optional instructions for you to re-build the container if you want.
Choose your SoM from the tabs below:
The Dockerfile below is built into the image torizonextras/arm64v8-gpiod:
Run the following command on the board terminal to download the image and mount the container for testing:
# docker run --rm -it --device /dev/gpiochip0 torizonextras/arm64v8-gpiod
The Dockerfile below is built into the image torizonextras/arm32v7-gpiod:
Run the following command on the board terminal to download the image and mount the container for testing:
# docker run --rm -it --device /dev/gpiochip0 torizonextras/arm32v7-gpiod
Note that in the docker run
command, the argument --device pass the char device from the GPIO bank that will be shared and accessed inside the container. You may specify that argument multiple times if access to different GPIO banks is required. Normally root user is required to access /dev/gpiochip devices. TorizonCore comes with udev rules which allow access for users part of the gpio group. Adding the torizon user to the group allows to also access GPIOs as a user from within the container. Use USER torizon
in your Dockerfile if you prefer running the container as non-root user, as exemplified in our sample Dockerfile.
Here we present how to use the command-line tools.
Search for the GPIO banks, /dev/gpiochiop0 ... /dev/gpiochipX, and how many GPIO lines they have:
## gpiodetect
gpiochip0 [5d080000.gpio] (32 lines)
Read and displays the information contained in the GPIO bank lines:
## gpioinfo
gpiochip0 - 32 lines:
line 0: unnamed unused input active-high
line 1: unnamed unused input active-high
line 2: unnamed unused input active-high
line 3: unnamed unused input active-high
line 4: unnamed unused input active-high
line 5: unnamed unused input active-high
line 6: unnamed unused input active-high
line 7: unnamed unused input active-high
line 8: unnamed "ov5640_mipi_reset" output active-high [used]
line 9: unnamed "ov5640_mipi_pwdn" output active-high [used]
line 10: unnamed unused input active-high
line 11: unnamed unused input active-high
line 12: unnamed unused input active-high
line 13: unnamed unused input active-high
line 14: unnamed unused input active-high
line 15: unnamed unused input active-high
line 16: unnamed unused input active-high
line 17: unnamed unused input active-high
line 18: unnamed unused input active-high
line 19: unnamed unused input active-high
line 20: unnamed unused input active-high
line 21: unnamed unused input active-high
line 22: unnamed unused input active-high
line 23: unnamed unused input active-high
line 24: unnamed unused input active-high
line 25: unnamed unused input active-high
line 26: unnamed unused input active-high
line 27: unnamed unused input active-high
line 28: unnamed unused input active-high
line 29: unnamed unused input active-high
line 30: unnamed unused input active-high
line 31: unnamed "usb3503 connect" output active-high [used]
This command is useful to check which rows are being used, with their respective use descriptions, for a GPIO bank.
Writes the output value of a certain line in a gpiochip passed by argument. The example set the GPIO bank 0 line 12 to output low:
## gpioset /dev/gpiochip0 12=0
You can also use only the GPIO bank index as a parameter:
## gpioset 0 12=0
Now the example to set the GPIO bank 0 line 12 to output high:
## gpioset 0 12=1
Reads the value of input from a certain line in a gpiochip passed by argument:
## gpioget 0 13
1
The return of this command can be 1 if the input is high and 0 if the input is low.
## gpioget 0 13
0
Wait for events on GPIO rows passed by argument:
## gpiomon 0 13
event: FALLING EDGE offset: 13 timestamp: [1570281706.661390750]
event: FALLING EDGE offset: 13 timestamp: [1570281706.661435750]
event: RISING EDGE offset: 13 timestamp: [1570281706.661604000]
event: RISING EDGE offset: 13 timestamp: [1570281706.916220125]
event: FALLING EDGE offset: 13 timestamp: [1570281706.918247625]
This command is useful for polling the lines to expect incoming input events.
The most important commands are gpioget
and gpioset
, though you could possibly use gpiomon
as well. Check out our example that writes and reads from GPIO pins. The sysfs commands are commented in the script:
Some examples are provided in this chapter, illustrating how to use the C API from libgpiod. Pre-built containers are not provided, therefore you are encouraged to build your own, in which case you will need the optional dependencies.
First, we will build and deploy the container. Then, we will explain and run the samples.
In this section, you will compile all the C examples and build a Container image to be easily deployed to the board.
Choose your SoM from the tabs below:
Note: For the examples below we will use the multi-stage Docker build. It is a best practice and you are encouraged to understand how it is implemented.
The sample Dockerfile used is:
Assuming that you have cloned the torizon-samples as described in the optional dependencies, you can modify and re-build the image by yourself in your development PC.
First, we will build the container image.
$ docker build -f Dockerfile.arm64 -t <yourDockerHubUsername>/arm64v8-c-gpiod .
Upload the image generated in the command above to your Docker Hub:
$ docker login
$ docker push <yourDockerHubUsername>/arm64v8-c-gpiod
After that, on the board terminal, run the following command to pull the image from Docker Hub:
# docker pull <yourDockerHubUsername>/arm64v8-c-gpiod
The sample Dockerfile used is:
Assuming that you have cloned the torizon-samples as described in the optional dependencies, you can modify and re-build the image by yourself in your development PC.
First, we build the container image.
$ docker build -f Dockerfile.armhf -t <yourDockerHubUsername>/arm32v7-c-gpiod .
Upload the image generated in the command above to your Docker Hub:
$ docker login
$ docker push <yourDockerHubUsername>/arm32v7-c-gpiod
After that, on the board terminal, run the following command to pull the image from Docker Hub:
# docker pull <yourDockerHubUsername>/arm32v7-c-gpiod
Now you are ready to understand and run the samples.
The example below uses the libgpiod API to access a GPIO bank and line that are the arguments to the program:
Here are some relevant highlights.
Include libgpiod library:
#include <gpiod.h>
Define GPIO chip and line structs:
struct gpiod_chip *output_chip; struct gpiod_line *output_line;
Configure a GPIO as output:
/* open the GPIO bank */ output_chip = gpiod_chip_open_by_number(bank); /* open the GPIO line */ output_line = gpiod_chip_get_line(output_chip, line); /* config as output and set a description */ gpiod_line_request_output(output_line, "gpio-test", GPIOD_LINE_ACTIVE_STATE_HIGH);
Toggle a GPIO:
/* Clear */ int line_value = 0; gpiod_line_set_value(output_line, line_value); /* Set */ line_value = 1; gpiod_line_set_value(output_line, line_value);
Run the example using the previously built and deployed container. Choose your SoM from the tabs below:
This example uses the Apalis iMX8 GPIO3 - LSIO.GPIO0.IO12:
# docker run --rm -it --init --device /dev/gpiochip0 yourdockerhubuser/arm64v8-c-gpiod
## gpio-toggle 0 12
This example uses the Apalis iMX6 GPIO3 - GPIO2_IO6:
# docker run --rm -it --init --device /dev/gpiochip1 yourdockerhubuser/arm32v7-c-gpiod
## gpio-toggle 1 6
This example uses the libgpiod API to register for an event (interrupt driven) on a rising edge. For this example make sure to add 4 arguments, the first two specifying the bank and line number of the input GPIO and the next two for the bank and line number of the output GPIO:
Here are some relevant highlights. What has been discussed in the previous section is omitted.
Request rising events notification:
ret = gpiod_line_request_rising_edge_events(input_line, "gpio-test");
Wait for an event to happen, read which event it was and validate that it's a rising event:
while (1) { gpiod_line_event_wait(input_line, NULL); if (gpiod_line_event_read(input_line, &event) != 0) continue; /* this should always be a rising event in our example */ if (event.event_type != GPIOD_LINE_EVENT_RISING_EDGE) continue; }
Run the example using the previously built and deployed container. Choose your SoM from the tabs below:
This example uses the Apalis iMX8 GPIO3 - LSIO.GPIO0.IO12 as output and GPIO2 - LSIO.GPIO0.IO9 as input.
# docker run --rm -it --init --device /dev/gpiochip0 yourdockerhubuser/arm64v8-c-gpiod
## gpio-event 0 9 0 12
This example uses the Apalis iMX6 GPIO3 - GPIO2_IO6 as output and GPIO2 - GPIO2_IO5 as input.
# docker run --rm -it --init --device /dev/gpiochip1 yourdockerhubuser/arm32v7-c-gpiod
## gpio-event 1 5 1 6