An Introduction to chardev GPIO and Libgpiod on the Raspberry PI

Linux 4.8 introduced a new GPIO user space subsystem for accessing GPIO. This tutorial provides an introduction to the new Character Device GPIO and explores how to control GPIO from the command line.

sysfs GPIO

User-mode GPIO (General Purpose Input/Output) has historically been performed via the legacy “integer-based”sysfs pseudo file system.  For example, to set GPIO25, one would:

# echo out > /sys/class/gpio/gpio25/direction
# echo 1 > /sys/class/gpio/gpio25/value

GPIO access via this legacy sysfs interface has been deprecated since version 4.8 of the Linux kernel.

chardev GPIO

The new way of doing GPIO is via the “descriptor-based” character device ABI (Application Binary Interface). The interface is exposed at /dev/gpiochipN or /sys/bus/gpiochipN where N is the chip number.

Outside of ensuring all allocated resources are cleaned up on closing, the main feature of this new interface is a discovery mechanism, mitigating the need to use magic numbers to address IO. Other new features include open-drain I/O support and the ability to read and set multiple I/O lines at once. Going forward, new features will only be supported in the chardev GPIO.

Unfortunately the new interface prevents manipulating GPIO with standard command line tools (i.e. echo).  Dedicated user-mode tools are now required.

The Linux kernel is distributed with three basic user-mode tools written primarily for testing the interface. The source can be found in linux/tools/gpio/

The three tools are:

  • lsgpio – example on how to list the GPIO lines on a system.
  • gpio-event-mon – monitor GPIO line events from userspace.
  • gpio-hammer – example swiss army knife to shake GPIO lines on a system.

To cross-compile, simply use:

# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-

lsgpio is the most useful of these debug tools, however none of these tools will allow the user to configure, set and clear GPIO lines.

Libgpiod

Libgpiod (Library General Purpose Input/Output device)  provides both API calls for use in your own programs and the following six user-mode applications to manipulate GPIO lines:

  • gpiodetect – list all gpiochips present on the system, their names, labels and number of GPIO lines
  • gpioinfo – list all lines of specified gpiochips, their names, consumers, direction, active state and additional flags
  • gpioget – read values of specified GPIO lines
  • gpioset – set values of specified GPIO lines, potentially keep the lines exported and wait until timeout, user input or signal
  • gpiofind – find the gpiochip name and line offset given the line name
  • gpiomon – wait for events on GPIO lines, specify which events to watch, how many events to process before exiting or if the events should be reported to the console

To cross-compile Libgpiod for the Raspberry PI on your Ubuntu 18.04 host, first install the following prerequisites:

sudo apt-get install autoconf autoconf-archive libtool libkmod-dev pkg-config

Then download, cross-compile and install.

wget https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/snapshot/libgpiod-1.1.1.tar.gz 
tar -xzf libgpiod-1.1.1.tar.gz 
cd libgpiod-1.1.1/ 
./autogen.sh --enable-tools=yes --host=arm-linux-gnueabi --prefix=/home/<home dir>/export/rootfs ac_cv_func_malloc_0_nonnull=yes 
make 
make install

Setting ac_cv_func_malloc_0_nonnull=yes will prevent an undefined reference to `rpl_malloc’ error at linking.

Usage

Below is example usage on a Raspberry PI Model B+ V1.2.

To detect/list GPIO character devices:

# gpiodetect
gpiochip0 [pinctrl-bcm2835] (54 lines)

To list the I/O lines available on this device:

# gpioinfo pinctrl-bcm2835
gpiochip0 - 54 lines:
        line   0:       "SDA0"       unused   input  active-high
        line   1:       "SCL0"       unused   input  active-high
        line   2:       "SDA1"       unused   input  active-high
        line   3:       "SCL1"       unused   input  active-high
        line   4:  "GPIO_GCLK"       unused   input  active-high
        line   5:  "CAM_GPIO1"       unused   input  active-high
        line   6:    "LAN_RUN"       unused   input  active-high
        line   7:  "SPI_CE1_N"       unused   input  active-high
        line   8:  "SPI_CE0_N"       unused   input  active-high
        line   9:   "SPI_MISO"       unused   input  active-high
        line  10:   "SPI_MOSI"       unused   input  active-high
        line  11:   "SPI_SCLK"       unused   input  active-high
        line  12:         "NC"       unused   input  active-high
        line  13:         "NC"       unused   input  active-high
        line  14:       "TXD0"       unused   input  active-high
        line  15:       "RXD0"       unused   input  active-high
        line  16: "STATUS_LED_N" "ACT" output active-low [used]
        line  17:     "GPIO17"       unused   input  active-high
        line  18:     "GPIO18"       unused   input  active-high
        line  19:         "NC"       unused   input  active-high
        line  20:         "NC"       unused   input  active-high
        line  21:     "GPIO21"       unused   input  active-high
        line  22:     "GPIO22"       unused   input  active-high
        line  23:     "GPIO23"       unused   input  active-high
        line  24:     "GPIO24"       unused   input  active-high
        line  25:     "GPIO25"       unused  output  active-high
        line  26:         "NC"       unused   input  active-high
        line  27:  "CAM_GPIO0"       unused   input  active-high
        line  28:    "CONFIG0"       unused   input  active-high
        line  29:    "CONFIG1"       unused   input  active-high
        line  30:    "CONFIG2"       unused   input  active-high
        line  31:    "CONFIG3"       unused   input  active-high
        line  32:         "NC"       unused   input  active-high
        line  33:         "NC"       unused   input  active-high
        line  34:         "NC"       unused   input  active-high
        line  35:         "NC"       unused   input  active-high
        line  36:         "NC"       unused   input  active-high
        line  37:         "NC"       unused   input  active-high
        line  38:         "NC"       unused   input  active-high
        line  39:         "NC"       unused   input  active-high
        line  40:   "PWM0_OUT"       unused   input  active-high
        line  41:         "NC"       unused   input  active-high
        line  42:         "NC"       unused   input  active-high
        line  43:         "NC"       unused   input  active-high
        line  44:         "NC"       unused   input  active-high
        line  45:   "PWM1_OUT"       unused   input  active-high
        line  46: "HDMI_HPD_P"       unused   input  active-high
        line  47: "SD_CARD_DET"      unused   input  active-high
        line  48:   "SD_CLK_R"       unused   input  active-high
        line  49:   "SD_CMD_R"       unused   input  active-high
        line  50: "SD_DATA0_R"       unused   input  active-high
        line  51: "SD_DATA1_R"       unused   input  active-high
        line  52: "SD_DATA2_R"       unused   input  active-high
        line  53: "SD_DATA3_R"       unused   input  active-high

Display help for the gpioset command:

# gpioset --help
Usage: gpioset [OPTIONS]  = = ...
Set GPIO line values of a GPIO chip
Options:
  -h, --help:           display this message and exit
  -v, --version:        display the version and exit
  -l, --active-low:     set the line active state to low
  -m, --mode=[exit|wait|time|signal] (defaults to 'exit'):
                tell the program what to do after setting values
  -s, --sec=SEC:        specify the number of seconds to wait (only valid for --mode=time)
  -u, --usec=USEC:      specify the number of microseconds to wait (only valid for --mode=time)
  -b, --background:     after setting values: detach from the controlling terminal

Modes:
  exit:         set values and exit immediately
  wait:         set values and wait for user to press ENTER
  time:         set values and sleep for a specified amount of time
  signal:       set values and wait for SIGINT or SIGTERM

To toggle GPIO25 high for 1 second:

# gpioset --mode=time --sec=1 pinctrl-bcm2835 25=1

Be the first to comment

Leave a Reply

Your email address will not be published.


*