type | slideOptions | ||||
---|---|---|---|---|---|
slide |
|
Zielgruppe: Applikations-Entwickler (auch HW) die in Linux GPIOs bedienen wollen.
- State not tied to process
- Concurrent access to sysfs attributes -> keine Zugriffskontrolle, kein locking
- If process crashes, the GPIOs remain exported (zwingt zu echo unexport usw.)
- Cumbersome API -> echo export beispiel
- Single sequence of GPIO numbers representing a two-level hierarchy - necessary to calculate the number of the GPIO
GPIO Nummer ausrechnen:
GPIO-Nummer = ( GPIO-Bank-Nr * 16|32 ) + GPIO-Offset
z.b. GPIO #31 auf GPIO-Bank #4: 3*32+31=127
Achtung: GPIO-Bank und GPIO-Offset zählen ab 0 (HWer und Manual zählen meist ab 1)
echo 127 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio127/direction
echo 1 > /sys/class/gpio/gpio127/value
echo in > /sys/class/gpio/gpio127/direction
cat /sys/class/gpio/gpio127/value
echo 127 > /sys/class/gpio/unexport
- v1.x Seit Linux v4.8 (2016)
- v2 seit Linux v5.10
- One device file per gpiochip (Bank)
/dev/gpiochip0, /dev/gpiochip1, /dev/gpiochipX
…
- Similar to other kernel interfaces: open() + ioctl() + poll() + read() + close()
- Possible to request multiple lines at once (for reading/setting values)
- Possible to find GPIO lines and chips by name
- Open-source and open-drain flags, user/consumer strings, uevents
- Reliable polling
- Z.B. Schalter an gpio und schnell drücken -> Wettlaufsituation 😉 Wer ist schneller: Der Read-Code oder der GPIO-Impuls?
sysfs: Events can get lost! | gpiod: Events never get lost!
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <poll.h>
#define GPIO_PIN "17" // Change this to the GPIO pin you want to use
int main() {
int gpio_fd;
char gpio_path[256];
struct pollfd pfd;
// Export the GPIO pin
gpio_fd = open("/sys/class/gpio/export", O_WRONLY);
if (gpio_fd == -1) {
perror("Unable to export GPIO");
exit(1);
}
write(gpio_fd, GPIO_PIN, sizeof(GPIO_PIN));
close(gpio_fd);
// Set the direction of the GPIO pin to input
sprintf(gpio_path, "/sys/class/gpio/gpio%s/direction", GPIO_PIN);
gpio_fd = open(gpio_path, O_WRONLY);
if (gpio_fd == -1) {
perror("Unable to set direction");
exit(1);
}
write(gpio_fd, "in", 2);
close(gpio_fd);
// Open the value file for reading
sprintf(gpio_path, "/sys/class/gpio/gpio%s/value", GPIO_PIN);
gpio_fd = open(gpio_path, O_RDONLY);
if (gpio_fd == -1) {
perror("Unable to open value file");
exit(1);
}
pfd.fd = gpio_fd;
pfd.events = POLLPRI | POLLERR;
while (1) {
int ret = poll(&pfd, 1, -1); // Wait for events indefinitely
if (ret < 0) {
perror("Poll error");
exit(1);
}
if (pfd.revents & POLLPRI) {
char buf[1];
lseek(gpio_fd, 0, SEEK_SET); // Move to the beginning of the file
read(gpio_fd, buf, 1);
printf("GPIO value: %c\n", buf[0]);
}
}
// Unexport the GPIO pin when done
gpio_fd = open("/sys/class/gpio/unexport", O_WRONLY);
if (gpio_fd == -1) {
perror("Unable to unexport GPIO");
exit(1);
}
write(gpio_fd, GPIO_PIN, sizeof(GPIO_PIN));
close(gpio_fd);
close(gpio_fd);
return 0;
}
#include <stdio.h>
#include <gpiod.h>
#define GPIO_CHIPNAME "gpiochip0" // Modify this to match your GPIO chip
#define GPIO_LINE_OFFSET 17 // Modify this to match your GPIO pin number
int main() {
struct gpiod_chip *chip;
struct gpiod_line *line;
// Initialize the GPIO chip
chip = gpiod_chip_open_by_name(GPIO_CHIPNAME);
if (!chip) {
perror("Failed to open GPIO chip");
return 1;
}
// Get the GPIO line
line = gpiod_chip_get_line(chip, GPIO_LINE_OFFSET);
if (!line) {
perror("Failed to get GPIO line");
gpiod_chip_close(chip);
return 1;
}
// Request the line for input
if (gpiod_line_request_input(line, "example-gpio") < 0) {
perror("Failed to request GPIO line");
gpiod_chip_close(chip);
return 1;
}
while (1) {
int value = gpiod_line_get_value(line);
printf("GPIO value: %d\n", value);
}
// Release resources
gpiod_line_release(line);
gpiod_chip_close(chip);
return 0;
}
Userspace Library zur Interaktion mit der
- locking sysfs vs. gpiod