I’m looking into using libgpiod to control the GPIO on the Beaglebone AI in user space. I’m starting small and trying to use the included command line tools gpioget and gpioset, but not having any success.
The Beaglebone AI System Manual lists what looks like the gpio chip and line under pinmux mode 14. P8.19 looks to be gpiochip4 line 10. Am I reading that right?
I have P8.19 configured in a device tree overlay to be an INPUT_PULLUP, pinmuxed to mode 14. I have a button wired up to P8.19, which shorts it to GND. I have verified that the button works using sysfs P8.19 GPIO number is 106, also listed in the same table from the system manual):
echo 106 > /sys/class/gpio/export
The last command outputs 1 when the button is not depressed, 0 when it is, as expected. I’m unable to use gpioget to see the same results:
gpioget gpiochip4 10
When I run that, I always get back 0. Any thoughts?
You can use gpioinfo to dump the whole pin list..
But, 106 = 3*32 +10 - which should be gpiochip3 10, as long as the
gpio's are linear..
You can also run:
Which is nicely documented, only using the legacy method..
That was it! gpioget gpiochip3 10 worked.
It would be interesting to know if libgpiod proves fast enough for
your application. It has C++ and Python bindings that allow you to
set and get multiple lines on a gpiochip with a single ioctl().
I am in communication with Bartosz, who made the libgpiod userspace
library and utilities, and Linus Walleij who created the gpiod
interface (which includes the gpiochip character devices). They both
seem open minded to improving interfaces to address real-world use
Personally. I think trying to toggle a GPIO as fast as possible in Linux is the wrong way to go about it. According to what I’ve read(and I have no personal desire to test it). An empty ioctl() has 63ns latency. Add that on top of gpiod’s time. Then it starts to add up. Not to mention: how proficient a given developer is when writing performant code.
So, for doing anything blazing fast, we’re back full circle. However, I think it would be better to use/buy hardware specialized for the task at hand. With that said, there is nothing wrong with experimenting. Until you let the blue smoke out. . .
I don’t intend to toggle a GPIO as fast as possible (except to test), but from a performance standpoint that demonstration seemed to indicate that there are issues with sysfs. Hopefully, libgpiod will prove to be better!
Bartosz explains the differences and improvements that new gpiod
interface provides in this talk:
Essentially, if you need read or set multiple lines, it is faster.
Also, it has an improved way to read events as well.
Slides if you prefer over video:
I’m starting to play with gpiod on a Beaglebone Black. One of the advantages of gpiod is you can toggle multiple pins on the same chip all at once.
So I try:
while true; do
gpioset 1 18=0 19=0
gpioset 1 18=1 19=1
This is toggling pins P9_14 and P9_16. I expect to see the two pins toggle on at the same time, but what I get is
a 4 microsecond delay from P9_14 switching and P9_16 switching.
Should there be such a long delay? I’d expect the two to switch at the same time (which is what happens when toggle pins via the PRU).
I do the same experiment with python and I see a 70 us delay.
software takes time to execute.
Yes, but the hardware on the am335x can toggle multiple pins on the same chip in the same clock cycle. Seems like the software should be able to support it.
Interesting… I wrote a c version and the pins are toggle at the exact same time. Now, how to get gpioset to work correctly.
It’s unlikely to be exactly the same time, it’s just within some undefined margin for error. Compiled C code can get the two pins set within a small number of 1 GHz clocks. With a fast enough scope, you’’ll probably find at least a few ns difference, if this isn’t obscured by parasitic capacitance in the traces and wiring. Sure, this is a 3 orders of magnitude less than gpiod, but there are folks out there working in femtoseconds for whom a nanosecond would be far too long. Time is a very stretchy thing.
On my 100MHz 'scope they look the same. I think it’s one instruction toggling the pair. They are toggling at some 268KHz.
Alright then. Something in the chip is indeed flipping them on the same clock edge.
You could always look at the source code for libgpiod.
libgpiod - C library and tools for interacting with the linux GPIO
character device (gpiod stands for GPIO device)
Since linux 4.8 the GPIO sysfs interface is deprecated. User space should
use the character device instead. This library encapsulates the ioctl calls
and data structures behind a straightforward API.
However, to save some time -- from what I can tell, while the library
consolidates multiple pins (lines) per controller chip, it then passes that
on to a kernel call. I've not located the source (kernel) for that level.
If it is somewhat generalized, it may be coded to handle hardware that can
only get/set one line at a time -- even if the actual hardware allows
I’ve been looking through gpioset.c, but it’s rather involved so I haven’t figured it out yet.
Could the python libgpiod be rewritten to use just on call to set the pins so there isn’t a delay?
It doesn't seem to use the same/direct calls... I've tracked it down to
the function at line 661
and macro definition at line 778
which seems to define a loop operation.
Interesting… Why go through all the trouble to set bits on a chip by chip basis, and then end up setting them in a loop?
Here are the toggling standings.
c via sysfs: 3kHz
python via sysfs: 6KHz
c via gpiod: 300KHz
Now to get python via gpiod to work.
For the most part, the Python library is just a wrapper of the C
The Python gpiod_LineBulk_set_values invokes gpiod_line_set_value_bulk
which, at line 848 of
operates using a loop.
How is the toggling rate slower in C than in Python when using sysfs? That seems strange to me.