Build libgpiod the "New GPIO Interface for User Space"

Recommended Posts

Well, it's time to say goodbye to sysfs and hello to libgpiod! @zador.blood.stained pointed me in the right direction, but you need to do one little hack I'll explain below involving compiler_types.h. I tested this on a NanoPi Duo, but it should work on any mainline Armbian release (and other distros as well) as long as the kernel is >= 4.8. Try ls /dev/gpiochip* and see if anything is listed. If so, then proceed.


I'm continuing work on my Github site https://github.com/sgjava/libgpiod-extra, so please report any issues there. There is an Armbian install script that automates the steps below :) I generated the Python wrapper, but there's a lot of functions to test, so I'm not sure of the quality. I'm working on some simple Python tests.

  • sudo armbian-config, Software, Headers
  • sudo apt-get install libtool pkg-config
  • git clone https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
  • cd libgpiod
  • mkdir -p include/linux
  • cp /usr/src/linux-headers-$(uname -r)/include/linux/compiler_types.h include/linux/.
  • ./autogen.sh --enable-tools=yes --prefix=/usr/local CFLAGS="-I/usr/src/linux-headers-$(uname -r)/include/uapi -Iinclude"
  • make
  • sudo make install
  • sudo ldconfig

Let's try some commands:


sudo gpiodetect


gpiochip0 [1c20800.pinctrl] (224 lines)
gpiochip1 [1f02c00.pinctrl] (32 lines)


sudo gpioinfo | grep "\[used\]"


    line  10:      unnamed "nanopi:blue:status" output active-high [used]
    line 166:      unnamed         "cd"   input  active-high [used]
    line 202:      unnamed  "interrupt"   input  active-high [used]
    line 205:      unnamed      "reset"  output   active-low [used]
    line   6:      unnamed          "?"  output  active-high [used]
    line   7:      unnamed   "vcc-wifi"  output  active-high [used]
    line  10:      unnamed "nanopi:green:pwr" output active-high [used]


Notice how it found the Duo's built in LEDs :)


Now let's test the Duo's built in button (press and release 3 times):


sudo gpiomon --num-events=3 --rising-edge gpiochip1 3


event:  RISING EDGE offset: 3 timestamp: [1516774143.944174870]
event:  RISING EDGE offset: 3 timestamp: [1516774145.123474395]
event:  RISING EDGE offset: 3 timestamp: [1516774145.987531088]


Wire up LED (the normal way) and use Duo's IOG11 then to turn on and off:


sudo gpioset gpiochip0 203=0

sudo gpioset gpiochip0 203=1


Python code

import time
from libgpiod.libgpiod import *

chip = gpiod_chip_open("/dev/gpiochip0")
line = gpiod_chip_get_line(chip, 203)
# The will set line for output and set initial value (LED on)
if gpiod_line_request_output(line, "test", 0) == 0:
    # LED off
    gpiod_line_set_value(line, 1)

More reading at https://www.cnx-software.com/2017/11/03/learn-more-about-linuxs-new-gpio-user-space-subsystem-libgpiod and https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/README. Maybe @Larry Bank will work on ArmbianIO II :) It looks like in the old Github site there was a milestone to create Python and C++ wrappers https://github.com/brgl/libgpiod/milestone/3. Once I learn more about libgpiod I may just generate them like I did for ArmbianIO.

Share this post

Link to post
Share on other sites

Hi, thank you for this work!


is it suitable for orange pi one?

as I can see your lib for piton, but can you share c++ example with interrupts and call back function?

Share this post

Link to post
Share on other sites

If it runs on mainline and you see something listed using ls /dev/gpiochip* then there's a good chance it will work, so you'll have to test it yourself. libgpiod is written in C, but the author said he's working on C++ 11 bindings. Right now I have one C example and a few Python ones in my project https://github.com/sgjava/libgpiod-extra. For now you'll need to do blocking callbacks (built in) or just stick a wait for edge in a thread. gpiod queues events, so you will not miss any like sysfs. I'll have a Python threaded callback example soon.

Share this post

Link to post
Share on other sites

OK, I whipped up a simple Python program using a thread to wait for an edge event while the main program is doing something else. https://github.com/sgjava/libgpiod-extra/blob/master/python/buttonthread.py


You can pass --chip with GPIO chip number and --line for the line (pin) where your built in button is located. Really no need for IRQs since the events are queued and the thread is waiting on the edge to happen. You can use the thread to do a callback using OOP and an Observer pattern. This is more elegant than having C callback to Python, Java, etc.

Share this post

Link to post
Share on other sites

I got libgpiood working at orange pi one.


My question is about internal resistors, when line direction is INPUT

what about pull_up and pull_down commands ((( ?




Share this post

Link to post
Share on other sites

Did you look at the C header?


 * @brief Miscellaneous GPIO request flags.
enum {
	/**< The line is an open-drain port. */
	/**< The line is an open-source port. */
	/**< The active state of the line is low (high is the default). */

Common GPIO Properties

These properties are met through all the other documents of the GPIO interface
and it is useful to understand them, especially if you need to define GPIO

Active-High and Active-Low
It is natural to assume that a GPIO is "active" when its output signal is 1
("high"), and inactive when it is 0 ("low"). However in practice the signal of a
GPIO may be inverted before is reaches its destination, or a device could decide
to have different conventions about what "active" means. Such decisions should
be transparent to device drivers, therefore it is possible to define a GPIO as
being either active-high ("1" means "active", the default) or active-low ("0"
means "active") so that drivers only need to worry about the logical signal and
not about what happens at the line level.

Open Drain and Open Source
Sometimes shared signals need to use "open drain" (where only the low signal
level is actually driven), or "open source" (where only the high signal level is
driven) signaling. That term applies to CMOS transistors; "open collector" is
used for TTL. A pullup or pulldown resistor causes the high or low signal level.
This is sometimes called a "wire-AND"; or more practically, from the negative
logic (low=true) perspective this is a "wire-OR".

One common example of an open drain signal is a shared active-low IRQ line.
Also, bidirectional data bus signals sometimes use open drain signals.

Some GPIO controllers directly support open drain and open source outputs; many
don't. When you need open drain signaling but your hardware doesn't directly
support it, there's a common idiom you can use to emulate it with any GPIO pin
that can be used as either an input or an output:

 LOW:	gpiod_direction_output(gpio, 0) ... this drives the signal and overrides
	the pullup.

 HIGH:	gpiod_direction_input(gpio) ... this turns off the output, so the pullup
	(or some other device) controls the signal.

The same logic can be applied to emulate open source signaling, by driving the
high signal and configuring the GPIO as input for low. This open drain/open
source emulation can be handled transparently by the GPIO framework.

If you are "driving" the signal high but gpiod_get_value(gpio) reports a low
value (after the appropriate rise time passes), you know some other component is
driving the shared signal low. That's not necessarily an error. As one common
example, that's how I2C clocks are stretched:  a slave that needs a slower clock
delays the rising edge of SCK, and the I2C master adjusts its signaling rate


Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now