The new GPIO Interface on the Rasberry PI: libgpiod

2021-05-02 hardware gpio

The GPIO Sysfs Interface is deprecated. The deprecated Sysfs would interact with GPIO using the /sys/class/gpio pseudo-filesytem. The Application Binary Interface - ABI - provides a character device based device driver and tools. The ABI is the new way to interact with GPIO on the Rasberry Pi. I really don’t like the name ABI, as it’s WAY too generic. Rather, I belive the proper name for this project is libgpiod.

  libgpiod - C library and tools for interacting with the linux GPIO
             character device (gpiod stands for GPIO device)

Advantages

Here are the main advantages I see for the new ABI:

  • Better SW Architecture
  • Resource Cleanup after program termination
  • A Shared Library libgpiod
  • Command Line Tools to interact with GPIO
  • Python Headers
  • Multiple GPIO Lines changed or read in single function call
  • Library supports callbacks for rising/falling/both edges of a GPIO line

Kernel Source

Here is the official source. It contains both the library and tools.

Deprecation of Sysfs

If you’re interacting with /sys/class/gpio no new features will be developed. Userspace consumers are now supposed to use the ABI to interact with GPIO.

Installation of the gpiod tools

At this point on Raspbian 10 Buster with a 5.10 Kernel both libgpiod and gpiod are not pre-packaged and we must install them. Fortunately, the install is very easy. To install the ABI the following is recommended.

$ sudo apt install gpiod

We can look more into what is installed:

$ apt show gpiod
Package: gpiod
Version: 1.2-3+rpi1
Priority: optional
Section: misc
Source: libgpiod
Maintainer: SZ Lin (林上智) <szlin@debian.org>
Installed-Size: 72.7 kB
Depends: libc6 (>= 2.16), libgpiod2 (>= 1.2)
Homepage: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
Download-Size: 13.9 kB
APT-Manual-Installed: yes
APT-Sources: http://raspbian.raspberrypi.org/raspbian buster/main armhf Packages
Description: Tools for interacting with Linux GPIO character device - binary
 libgpiod encapsulates the ioctl calls and data structures
 behind a straightforward API. This new character device
 interface guarantees all allocated resources are freed after
 closing the device file descriptor and adds several new
 features that are not present in the obsolete sysfs interface
 (like event polling, setting/reading multiple values at once or
 open-source and open-drain GPIOs).
 .
 This package contains the gpiod binary tools.

The library libgpiod2 has the following:

apt show libgpiod2
Package: libgpiod2
Version: 1.2-3+rpi1
Priority: optional
Section: libs
Source: libgpiod
Maintainer: SZ Lin (林上智) <szlin@debian.org>
Installed-Size: 103 kB
Depends: libc6 (>= 2.16), libgcc1 (>= 1:3.5), libstdc++6 (>= 5.2)
Conflicts: libgpiod1
Replaces: libgpiod1
Homepage: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
Download-Size: 29.0 kB
APT-Manual-Installed: yes
APT-Sources: http://raspbian.raspberrypi.org/raspbian buster/main armhf Packages
Description: C library for interacting with Linux GPIO device - shared libraries
 libgpiod encapsulates the ioctl calls and data structures
 behind a straightforward API. This new character device
 interface guarantees all allocated resources are freed after
 closing the device file descriptor and adds several new
 features that are not present in the obsolete sysfs interface
 (like event polling, setting/reading multiple values at once or
 open-source and open-drain GPIOs).
 .
 This package contains the required shared libraries.

Installation of the gpio Libraries

If we want to install the libraries for development we need to do the following.

$ sudo apt install libgpiod-dev

Here is the info on libgpiod-dev:

$ sudo apt info libgpiod-dev
Package: libgpiod-dev
Version: 1.2-3+rpi1
Priority: optional
Section: libdevel
Source: libgpiod
Maintainer: SZ Lin (林上智) <szlin@debian.org>
Installed-Size: 255 kB
Depends: libgpiod2 (= 1.2-3+rpi1)
Suggests: libgpiod-doc
Homepage: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
Download-Size: 46.3 kB
APT-Manual-Installed: yes
APT-Sources: http://raspbian.raspberrypi.org/raspbian buster/main armhf Packages
Description: C library for interacting with Linux GPIO device - static libraries and headers
 libgpiod encapsulates the ioctl calls and data structures
 behind a straightforward API. This new character device
 interface guarantees all allocated resources are freed after
 closing the device file descriptor and adds several new
 features that are not present in the obsolete sysfs interface
 (like event polling, setting/reading multiple values at once or
 open-source and open-drain GPIOs).
 .
 This package contains the required static libraries, headers, and C++ bindings.

The development package installs the C libraries and header files for us to use.

dpkg-query -L libgpiod-dev
/.
/usr
/usr/include
/usr/include/gpiod.h
/usr/include/gpiod.hpp
/usr/lib
/usr/lib/arm-linux-gnueabihf
/usr/lib/arm-linux-gnueabihf/libgpiod.a
/usr/lib/arm-linux-gnueabihf/libgpiodcxx.a
/usr/lib/arm-linux-gnueabihf/pkgconfig
/usr/lib/arm-linux-gnueabihf/pkgconfig/libgpiod.pc
/usr/lib/arm-linux-gnueabihf/pkgconfig/libgpiodcxx.pc
/usr/share
/usr/share/doc
/usr/share/doc/libgpiod-dev
/usr/share/doc/libgpiod-dev/README.gz
/usr/share/doc/libgpiod-dev/changelog.Debian.gz
/usr/share/doc/libgpiod-dev/copyright
/usr/lib/arm-linux-gnueabihf/libgpiod.so
/usr/lib/arm-linux-gnueabihf/libgpiodcxx.so

Namely, the /usr/include/gpiod.h C header file and the /usr/lib/arm-linux-gnueabihf/libgpiod.so Shared Library.

Nomenclature

With libgpiod we have the following nomenclature:

GPIO Chip - A chip that controlls multiple GPIO lines. The Raspberry Pi has /dev/gpiochip0. GPIO Line - Each GPIO Chip has multiple GPIO Lines. A line maps to physical GPIO pin.

Tools packaged in gpiod

We now get the following tools:

gpiodetect gpioinfo gpioget gpioset gpiomon gpiofind

The gpioinfo tool

$  gpioinfo --help
Usage: gpioinfo [OPTIONS] <gpiochip1> ...
Print information about all lines of the specified GPIO chip(s) (or all gpiochips if none are specified).

Options:
  -h, --help:		display this message and exit
  -v, --version:	display the version and exit

The gpiodetect tool

$ gpiodetect --help
Usage: gpiodetect [OPTIONS]
List all GPIO chips, print their labels and number of GPIO lines.

Options:
  -h, --help:		display this message and exit
  -v, --version:	display the version and exit

The gpiofind tool

$ gpiofind --help
Usage: gpiofind [OPTIONS] <name>
Find a GPIO line by name. The output of this command can be used as input for gpioget/set.

Options:
  -h, --help:		display this message and exit
  -v, --version:	display the version and exit

The gpiomon tool

$ gpiomon --help                                                                                                                                                                                                                                           1 ↵
Usage: gpiomon [OPTIONS] <chip name/number> <offset 1> <offset 2> ...
Wait for events on GPIO lines

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
  -n, --num-events=NUM:	exit after processing NUM events
  -s, --silent:		don't print event info
  -r, --rising-edge:	only process rising edge events
  -f, --falling-edge:	only process falling edge events
  -F, --format=FMT	specify custom output format

Format specifiers:
  %o:  GPIO line offset
  %e:  event type (0 - falling edge, 1 rising edge)
  %s:  seconds part of the event timestamp
  %n:  nanoseconds part of the event timestamp

The gpioset and gpioget tools

$ gpioset --help
Usage: gpioset [OPTIONS] <chip name/number> <offset1>=<value1> <offset2>=<value2> ...
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
$ gpioget --help
Usage: gpioget [OPTIONS] <chip name/number> <offset 1> <offset 2> ...
Read line value(s) from 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

Mapping GPIO to Physical Pins

Here is how the GPIO lines look in a Raspberry Pi:

$ gpioinfo
gpiochip0 - 54 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   "spi0 CS1"  output   active-low [used]
	line   8:      unnamed   "spi0 CS0"  output   active-low [used]
	line   9:      unnamed       unused   input  active-high
	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  output  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       unused  output  active-high
	line  32:      unnamed       unused  output  active-high
	line  33:      unnamed       unused   input  active-high
	line  34:      unnamed       unused   input  active-high
	line  35:      unnamed       "led1"   input  active-high [used]
	line  36:      unnamed       unused   input  active-high
	line  37:      unnamed       unused   input  active-high
	line  38:      unnamed       unused  output  active-high
	line  39:      unnamed       unused   input  active-high
	line  40:      unnamed       unused   input  active-high
	line  41:      unnamed       unused  output  active-high
	line  42:      unnamed       unused  output  active-high
	line  43:      unnamed       unused   input  active-high
	line  44:      unnamed       unused   input  active-high
	line  45:      unnamed       unused   input  active-high
	line  46:      unnamed       unused   input  active-high
	line  47:      unnamed       "led0"  output  active-high [used]
	line  48:      unnamed       unused   input  active-high
	line  49:      unnamed       unused   input  active-high
	line  50:      unnamed       unused   input  active-high
	line  51:      unnamed       unused   input  active-high
	line  52:      unnamed       unused   input  active-high
	line  53:      unnamed       unused   input  active-high

Take for example line 7 and line 8 which are labelled as spi0 CS1 and spi0 CS0. If we look on pinout.xyz we see the line corresponds to the GPIO number exactly. Check the ping numbering same for line 35 and line 48 which are wired to the header.

Examples using the gpiod tools

Hopefully, I’ll add the next two examples soon.

  1. Configure an output line and set it high and low. Example usage would be to blink an LED.
  2. Configure an input line. Example usage would be a push-button switch.
  3. Wait for an event on an input line. An example would be a external chip has data ready and we’d read from it.
comments powered by Disqus