Controlling GPIO from Linux User Space Print

 

This application note shows how to control the i.MX RT1050 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. Most of the i.MX RT1050 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.

The device driver for i.MX family GPIO controller is enabled in the kernel config. The gpio-leds and gpio-keys drivers will be enabled and configured in the DTS file, in order to support the USER_LED and USER_BUTTON of the IMXRT1050-EVK board.

Verify that the USER LED and USER BUTTON interfaces are functional via the standard gpio-leds and gpio-keys interfaces.

Due to the pin conflict with the Ethernet PHY reset GPIO, the USER LED node is disabled by default in the i.MXRT1050 device tree. To test the USER LED>, enable the corresponding node and disable the fec node in the DTS file, then rebuild and reinstall the project:

diff --git a/rootfs/rootfs.dts.IMXRT105X_NXPEVK b/rootfs/rootfs.dts. IMXRT105X_NXPEVK index 5e985d80..cf16c2e5 100644 --- a/rootfs/rootfs.dts.IMXRT105X_NXPEVK +++ b/rootfs/rootfs.dts.IMXRT105X_NXPEVK @@ -62,11 +62,11 @@ leds { compatible = "gpio-leds"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_leds>; /* disbale user-led by deafult due to * pinctrl conflict with the FEC device */ - status = "disbaled"; + status = "okay"; user-led { label = "user-led"; gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; default-state = "off"; @@ -91,11 +91,11 @@ }; &fec { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec>; - status = "okay"; + status = "disabled"; assigned-clocks = <&clks IMXRT1050_CLK_ENET_REF>, <&clks IMXRT1050_CLK_PLL6_BYPASS>; assigned-clock-rates = <50000000>; assigned-clock-parents = <0>, <&clks IMXRT1050_CLK_PLL6>;

  1. Use the following command to turn on the USER LED:
  2. # echo 0 > /sys/class/leds/user-led/brightness

  3. Use the following command to turn off the USER LED:
  4. # echo 1 > /sys/class/leds/user-led/brightness

  5. From the Linux shell, start the evtest utility. Then press the USER BUTTON and make sure the evtest has reported the events correctly:
  6. / # evtest /dev/input/event1
    Event: time 5119.210038, type EV_KEY, code KEY_A, value 1
    Event: time 5119.210038, type EV_SYN, code SYN_REPORT, value 0
    Event: time 5119.370034, type EV_KEY, code KEY_A, value 0
    Event: time 5119.370034, type EV_SYN, code SYN_REPORT, value 0

In order to test raw GPIO functions, disable definition of the USER BUTTON in the kernel DTS file, then rebuild and reinstall the project:

diff --git a/rootfs/rootfs.dts.IMXRT105X_NXPEVK b/rootfs/rootfs.dts. IMXRT105X_NXPEVK index 1dc04ea1..7b9e2eb4 100644 --- a/rootfs/rootfs.dts.IMXRT105X_NXPEVK +++ b/rootfs/rootfs.dts.IMXRT105X_NXPEVK @@ -52,11 +52,13 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_keys>; +#if 0 user-button { label = "user-button"; gpios = <&gpio5 0 GPIO_ACTIVE_LOW>; linux,code = <KEY_A>; }; +#endif }; leds {

Each GPIO is assigned a unique integer GPIO number within the GPIO chip range of 0 to 160 by Linux. The i.MX RT1050 supports 4 GPIO blocks of 32 pieces GPIO1, GPIO2, GPIO3, GPIO4. The GPIO5, on which there are nominally 32 signals, but only 3 are actually available: GPIO5_IO00, GPIO5_IO01 and GPIO5_IO02 - the rest are not output anywhere.
To calculate that number for a specific GPIO, use the following formula: 
gpio_idX(GPIOX_IOY) = (X - 1) * 32 + Y
where an X value is a GPIO number and Y is a GPIO pin number.
For example: gpio number for GPIO5.0 will be (5 – 1) * 32 + 0 = 128.
  1. Export GPIO5_00 and configure it as an input:
  2. / # echo 128 > /sys/class/gpio/export
    / # echo in > /sys/class/gpio/gpio128/direction

  3. Make sure the value of GPIO5_00 is 1 when the USER BUTTON is untouched (due to the internal PULL-UP being enabled):
  4. / # cat /sys/class/gpio/gpio128/value
    1
    / #

  5. Press and hold the USER BUTTON and make sure the GPIO5_00 value has changed to 0:
  6. / # cat /sys/class/gpio/gpio128/value
    0

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 useful 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:

  1. Using the GPIOLIB interface (described in this application note):
    https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
  2. Using the drivers of the Linux LED/Input subsystems:
    https://www.kernel.org/doc/Documentation/leds/leds-class.txt
    https://www.kernel.org/doc/Documentation/input/input.txt
    These drivers allow to use different GPIO-related mechanisms already implemented in Linux. For example, you may simply force a LED connected to GPIO output to blink with the specified frequency, or simply force input subsystem to generate a some-button-pressed event on changing GPIO input.