Using libgpiod
The libgpiod library is a straigthforward C API that encapsulates the interaction with Linux’s GPIO.
To get started with the library, you can find several excellent resources online. GPIO Programming: Exploring the libgpiod Library can show you a good introduction. For the full documentation, you can check your system’s help or kernel.org’s gpiod.h source.
Installation
The library is available through the system’s repositories in any modern Linux distribution. In apt
-based systems, install it by running:
ubuntu@rpi:~$ sudo apt update
ubuntu@rpi:~$ sudo apt install libgpiod-dev libgpiod-doc
Example 1: Blink
The following example first defines all 12 input and output lines as follows:
#define NUM_OUTPUTS 12
const int output_line_ids[NUM_OUTPUTS] =
{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
#define NUM_INPUTS 12
const int input_line_ids[NUM_INPUTS] =
{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27};
It then sets the corresponding lines as outputs and inputs, accordingly. To do so, it uses libgpiod
’s gpiod_chip_get_line()
, gpiod_line_request_output_flags()
, and gpiod_line_request_input_flags()
.
Once everything is set up, the program turns the first output on and off repeatedly. If an LED is connected on the first output, you can expect to see it blink.
#define _GNU_SOURCE
#include <stdlib.h>
#include <gpiod.h>
#include <stdio.h>
#include <unistd.h>
#define Output_1 0
#define Output_2 1
#define Output_3 2
#define Output_4 3
#define Output_5 4
#define Output_6 5
#define Output_7 6
#define Output_8 7
#define Output_9 8
#define Output_10 9
#define Output_11 10
#define Output_12 11
#define Input_1 0
#define Input_2 1
#define Input_3 2
#define Input_4 3
#define Input_5 4
#define Input_6 5
#define Input_7 6
#define Input_8 7
#define Input_9 8
#define Input_10 9
#define Input_11 10
#define Input_12 11
#define NUM_OUTPUTS 12
const int output_line_ids[NUM_OUTPUTS] =
{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
#define NUM_INPUTS 12
const int input_line_ids[NUM_INPUTS] =
{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27};
int main(int argc, char **argv)
{
const char *chipname = "gpiochip0";
printf("gpiod_version: %s\n",gpiod_version_string());
// Open GPIO chip
struct gpiod_chip *chip = gpiod_chip_open_by_name(chipname);
if (!chip) {
perror("Open chip failed");
return 1;
}
// Set Outputs io1212
struct gpiod_line *output_lines[NUM_OUTPUTS];
for (int i=0; i<NUM_OUTPUTS; ++i) {
output_lines[i] = gpiod_chip_get_line(chip, output_line_ids[i]);
if (!output_lines[i]) {
perror("Get line failed");
return 1;
}
// Open Output lines for output
int ret = gpiod_line_request_output_flags(output_lines[i],
"io1212-1", // Consumer
GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE, //OPEN_SOURCE or OPEN_DRAIN,
0 // Default value
);
if (ret < 0) {
perror("Request line as output failed");
printf("Please check that SPI is not in use (sudo dtparam spi=off)\n");
return 1;
}
}
// Set Inputs io1212
struct gpiod_line *input_lines[NUM_INPUTS];
for (int i=0; i<NUM_INPUTS; ++i) {
input_lines[i] = gpiod_chip_get_line(chip, input_line_ids[i]);
if (!input_lines[i]) {
perror("Get line failed");
return 1;
}
// Open switch line for input
int ret = gpiod_line_request_input_flags(input_lines[i],
"io1212-1", // Consumer
0 //GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE
//The line has neither a pull-up nor a pull-down resistor
);
if (ret < 0) {
perror("Request line as input failed");
return 1;
}
}
// Blink Output_1 io1212
int count = 30;
while (count) {
int ret = gpiod_line_set_value(output_lines[Output_1], 1);
if (ret < 0) {
perror("Set line output failed");
return 1;
}
usleep(1000000);
ret = gpiod_line_set_value(output_lines[Output_1], 0);
if (ret < 0) {
perror("Set line output failed");
return 1;
}
usleep(1000000);
count--;
}
gpiod_chip_close(chip);
return 0;
}
After saving the previous code into a file named io1212-1.c
, you can compile and link it using:
gcc -o io1212-1 io1212-1.c -lgpiod
Example 2: Using inputs
The following code reads the value of the first input at a rate of 10 times per second, and sets the first output to the read value every time.
// Output_1 io1212 = Input_1 io1212
int count = 600;
while (count) {
int val = gpiod_line_get_value(input_lines[Input_1]);
if (val < 0) {
perror("Read line input failed");
return 1;
}
int ret = gpiod_line_set_value(output_lines[Output_1], val);
if (ret < 0) {
perror("Set line output failed");
return 1;
}
usleep(100000);
count--;
}
You can test it by replacing the “blink” logic in the previous example.