Controlling GPIO from Linux User Space Print

 

This application note shows how to control STM32F7 GPIOs from the user level using the standard Linux GPIOLIB interface.


Changes to the Kernel Configuration

The generic GPIO interface is controlled by the CONFIG_GPIOLIB kernel option enabled by default in the rootfs project installed to each STM32F7 System-on-Module shipped by Emcraft. Most of the STM32 GPIO pins can be used in different multiplexed I/O roles (for instance, some GPIO pins can be also configured as an SPI interface, etc). Depending on the requirements of your application, you need to configure the pins that you want to use as GPIO for the GPIO role and other pins for an alternative I/O function.

In this application note, we configure the following two pins as GPIO:

  • PH2 - this pin is connected to the S2 User Push Button on the SOM-BSB-EXT baseboard and, as such, can be used as a GPIO Input.
  • PG9 - this pin is connected to the DS3 User LED on the SOM-BSB-EXT baseboard and, as such, can be used as a GPIO Output.

The pin multiplexing, as well as the GPIO specific configuration, is performed by the Linux kernel drivers using the information from the rootfs.dts.STM32F7 file. Let's edit this file and add the information about the above two GPIOs:

  • Delete the current inputs node. This implements support for wake-up from S2, and this is not the subject of this application note.
  • Create the pinctrl_outputs node with the information about specific (e.g. pull-up) settings of the used GPIOs.
  • Create the inputs and outputs nodes to initialize GPIOs with necessary (e.g. pull-up) settings (at the CONFIG_KEYBOARD_GPIO_POLLED, and CONFIG_LEDS_GPIO drivers probe routines).
  • The result should look like this:

/ {
...
pin-controller {
gpio {
pinctrl_inputs: ins {
st,pins {
S2.but = <&gpioh 2 IN PULL_UP
PUSH_PULL LOW_SPEED>;
};
};

pinctrl_outputs: outs {
st,pins {
DS3.led = <&gpiog 9 OUT NO_PULL
PUSH_PULL LOW_SPEED>;
};
};
};
};

inputs {
compatible = "gpio-keys-polled";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_inputs>;
};

outputs {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_outputs>;
};
...
}

After applying the above changes to the rootfs.dts.STM32F7 file, rebuild the rootfs project (Building Linux) and install it on the target (Installing Linux Images to Flash).

Ignore the following error message reported from the resultant rootfs.uImage during the boot:

gpio-keys-polled inputs: missing platform data
gpio-keys-polled: probe of inputs failed with error -22

This message is expected due to the following:

  • In this application note we do not want to use the "gpio-keys-polled" driver for controlling the GPIO, and so we do not fill the inputs node with the platform data about GPIOs;
  • However, we must provide the kernel with the pinctrl_inputs information. Therefore, we specify the inputs node in the rootfs.dts.STM32F7.


Testing GPIO

Each GPIO is assigned a unique integer GPIO number within the GPIO chip range of 0 to 175 by Linux. To calculate that number for a specific GPIO, use the following formula:

gpio = (bank * 16) + pin

Bank numbers start with 0 (corresponding to Bank A, etc), pin numbers start with 0 (corresponding to pin 0, etc).

For the User Push Button the specific pin is PH2, which corresponds to the following GPIO number:

(7 * 16) + 2 = 114

The first step is to add (export) the pin to the GPIO array and define it as an input. This is done as follows:

/ # echo 114 > /sys/class/gpio/export
/ # echo in > /sys/class/gpio/gpio114/direction

Now, all is ready to read the value of the User Push Button. First, leave the button unpressed on the board and read the signal. We enabled pull-up for this GPIO in rootfs.dts.STM32F7 (see the S2.but node), so when the User Push Button unpressed this GPIO reads as 1:

/ # cat /sys/class/gpio/gpio114/value
1

Push the button and make sure the GPIO value reads as 0:

/ # cat /sys/class/gpio/gpio114/value
0

Release the button and validate that the value has returned to 1:

/ # cat /sys/class/gpio/gpio114/value
1

For the User LED the specific pin is PG9, which corresponds to the following GPIO number:

(6 * 16) + 9 = 105

Export the GPIO and define it as an output:

/ # echo 105 > /sys/class/gpio/export
/ # echo out > /sys/class/gpio/gpio105/direction

Now run the following shell commands to turn the User LED on and off at a 1Hz frequency:

/ # while [ 1 ]; do echo 1 > /sys/class/gpio/gpio105/value; sleep 1; echo 0 > /sys/class/gpio/gpio105/value; sleep 1; done

Stop this test by pressing Ctrl-C, and run a composite test: control the User LED with the User Push Button (turn the LED on if the Button is unpressed, and turn the LED off if the Button is pressed):

/ # while [ 1 ]; do cat /sys/class/gpio/gpio114/value > /sys/class/gpio/gpio105/value; done


Alternative Ways to Access GPIO

In Linux, you may access GPIOs using different approaches, not only the ones described in this application note above. Here are some external links that might be usefull if you decide to try an alternative approach.

The following article describes accessing GPIOs from the kernel context:
https://lwn.net/Articles/532714/

To work with GPIOs from the user space, there are the following possibilities: