10

Most of the libraries, in multiple languages, interact with the GPIO pins via /sys/class/gpio/export, /sys/class/gpio/import, /sys/class/gpio/gpio10/value, etc. However the linux kernel docs clearly state that is the legacy way of doing things.

What is the non legacy way of doing things?

If I understand correctly in kernel space I would use these functions or standard kernel drivers for common GPIO tasks.

What would I use for user space? Is there a Sysfs interface for the non legacy?

PS: I aware the kernel docs state that the legacy integer-based interface although considered deprecated is still usable for compatibility reasons. However I'm not interested in using that legacy code.

Simão Martins
  • 211
  • 1
  • 2
  • 6
  • 1
    Most libraries DO NOT interact with the GPIO pins via /sys/class/gpio/export they access the hardware directly, although they CAN use kernel services. Certainly WiringPi and AFAIK pigpiod directly access SoC registers. – Milliways Aug 19 '19 at 00:58
  • @Milliways: AIUI, WiringPi is now deprecated, and pigpio support for the 4B remains classified as "experimental' by its author. And so it seems there's a reasonably strong incentive to evaluate alternatives. I feel the incentives are even stronger for those needing libraries that work on hardware other than Raspberry Pi. – Seamus Sep 06 '20 at 21:04
  • @Seamus This post was written last August just after WiringPi was deprecated, but it still works and so does pigpiod. Neither has been updated for the Pi4, but both are fully functional on the Pi4, they just haven't been updated for the additional functionality on the Pi4. raspi-gpio provides access to Pi4 GPIO, and is included in the OS. – Milliways Sep 07 '20 at 01:38
  • @Milliways: I think my point may have been unclear to you. My comment was not to take issue with the historical accuracy of your comment. It was meant to update any readers to the current situation, and to point out that there may be advantages for using a library that works across multiple hardware platforms. – Seamus Sep 07 '20 at 04:20

2 Answers2

14

sysfs has been deprecated and has been replaced with libgpiod.

https://www.beyondlogic.org/an-introduction-to-chardev-gpio-and-libgpiod-on-the-raspberry-pi/

The interactions are with /dev/gpiochipx rather than /sys/class/gpio.

The only obvious improvement (to me) is that GPIO events now have a time-stamp.

joan
  • 71,024
  • 5
  • 73
  • 106
  • Re "improvement", what about cross-platform compatibility? – Seamus Sep 06 '20 at 21:05
  • @Seamus which platforms do you mean? I thought gpiochip was purely a Linux API. – joan Sep 06 '20 at 21:15
  • Apologies for the confusion. I had read a comment to the OP's question just before reading your answer, and I mistakenly assumed your statement referred to improvements relative to pigpio. I see now that your comparison is to sysfs. To be clear, I'm under the impression that pigpio is not generally portable to other hardware platforms. Am I wrong? – Seamus Sep 06 '20 at 21:24
  • @Seamus You are correct to say pigpio will not work on any device but the Raspberry Pi. It might be possible to port pigpio to non-raspberries but it would take significant effort and is not something I would support. – joan Sep 06 '20 at 22:18
  • Understood! :) Just one other thing - would cross-platform support for GPIO typically be set up with a generic library/API and a platform-specific driver? – Seamus Sep 06 '20 at 22:25
4

My understanding so far is that (as has been stated) the sysfs interface is deprecated. There are at least two relatively new C APIs in user space (apologies to WiringPi and PiGpio). One or both seem to have the label libgpiod

They can be installed on buster (but not jessie) with:

apt-get install gpiod libgpiod-dev libgpiod-doc

Not sure about stretch. Also not sure which API requires which installs.

1) The first C API relies on /usr/include/linux/gpio.h which holds data structures and defines used with system calls to interact with the gpios. This is written by Linus Walleij. An example of this API is shown below, and is derived from a talk by Linus Walleij indicated in the code comments. Programs using this API must have the #includes shown in the example below but don't need to be compiled with any libraries (AFAIK).

2) The second C API relies on /usr/include/gpiod.h which provides a simplified interface that abstracts setup and handles and allows contextless reads, writes, and other functions. This is maintained by Bartosz Golaszewski. An introduction to the API is given in some slides by Bartosz which can be found at:

https://ostconf.com/system/attachments/files/000/001/532/original/Linux_Piter_2018_-_New_GPIO_interface_for_linux_userspace.pdf?1541021776

Some good examples using this API can be found at:

https://framagit.org/cpb/example-programs-using-libgpiod/-/tree/master/

Note that programs using this API must:

#include <gpiod.h>

and be compiled with the -lgpiod library (for example):

gcc -o read-gpio -lgpiod read-gpio.c

I've successfully compiled and run some of the examples.

** There is a C++ API also provided by Bartosz Golaszewski that depends on /usr/include/gpiod.hpp. It is a C++ a wrapper based on the C API and depends on the C++11 standard.

Programs using this API must:

#include <gpiod.hpp>

An example of using this API is found in the same slides as the C API.

https://ostconf.com/system/attachments/files/000/001/532/original/Linux_Piter_2018_-_New_GPIO_interface_for_linux_userspace.pdf?1541021776

I have yet to get these examples to compile, but suspect there is a library inclusion I have yet to discover.


Below is an example gpio read program using the C API number 1 from above (the one authored by Linus Walleij). It repeatedly reads gpio 4 on /dev/gpiochip0 and prints it's value.

/****
* gpio-read.c -- example program for reading gpio values using the <linux/gpio.h> C API
* The API consists primarily of data structures used as parameters to system calls.
* Adapted from from a youtube video of Linus Walleij at the Embedded Linux Conference Europe
* GPIO for Engineers and Makers: starting at timestamp 44:11
* For simplicity, there is no error checking.
****/

//Need the gpio API and support for the system calls.
#include <linux/gpio.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>


int main(){


//Opening device and getting file descriptor.
int fd = open("/dev/gpiochip0",O_RDONLY);

//structure for holding chip information
//This structure is defined in /usr/include/linux/gpio.h
struct gpiochip_info cinfo;

//Getting the chip information via the ioctl system call
//GPIO_GET_CHIPINFO_IOCTL defined also in /usr/include/linux/gpio.h
int ret = ioctl(fd,GPIO_GET_CHIPINFO_IOCTL,&cinfo);

//print out the chip information
fprintf(stdout, "GPIO chip: %s, \"%s\", %u GPIO lines\n",
    cinfo.name, cinfo.label, cinfo.lines);

//structure for holding line information.
//structure defined in /usr/include/linux/gpio.h
struct gpioline_info linfo;

//get generic line information from system call
ret = ioctl(fd,GPIO_GET_LINEINFO_IOCTL, &linfo);

//Not sure what this line_offset is, but we specify the gpio number later.
fprintf(stdout,"line %2d: %s\n",linfo.line_offset,linfo.name);

//Reading lines
//Set up some handles for requests and data
struct gpiohandle_request req;
struct gpiohandle_data data;

//Although req and data can read multiple gpios at a time, we'll use just one
//This reads line offset 4, which corresponds to the BCM value in "gpio readall"
req.lineoffsets[0] = 4;
//have to indicate how many lines we are reading.
req.lines = 1;
//Make this an input request
req.flags = GPIOHANDLE_REQUEST_INPUT;

//Optionally give the line a name
strcpy(req.consumer_label, "First Switch");

//Get a line handle. Note that req.fd is provided a handle for the next ioctl. 
int lhfd = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);

//Loop with some delay that keeps checking the input and displaying the value
for(int ii = 0; ii < 1000; ++ii){

    ret = ioctl(req.fd,  GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);

    printf("line %d is %s\n",req.lineoffsets[0], data.values[0] ? "high" : "low");
    //wait 0.25 seconds
    usleep(250000);
}

return 0;
}

Compile with

gcc -o gpio-read gpio-read.c

Execute:

./gpio-read

This will show the value of the specific gpio offset every 0.25 seconds.

gorlux
  • 266
  • 1
  • 6
  • So, what's the API? Is it installed using apt-get install gpiod? Are function prototypes inside <linux/gpio.h>? Is there a library file to link against? – Dmitry Grigoryev Apr 26 '20 at 12:53
  • 1
    See my revised answer above. It discusses two C APIs. – gorlux May 20 '20 at 04:58
  • 1
    I like this answer, but it's not entirely clear to me. Your revised answer might be more clear if you showed what part of the answer was revised. One way to do this would be to use the "strike-through" tag; e.g. I have yet to get these examples to compile, but suspect there is a library inclusion I have yet to discover. Another way to do it is just delete the irrelevant text. – Seamus Sep 06 '20 at 21:17