GPIO mit Lyx
Die Lyx GPIO-Bibliothek bietet zwei unabhängige Zugriffsebenen: MMIO-Direktzugriff (kein Kernel-Context-Switch, Raspberry Pi 4 spezifisch) und Linux GPIO v2 ioctl (portabel, ab Kernel 5.10). Beide teilen sich dieselben High-Level-Wrapper aus gpio_pin.
→ Guides · std.hardware.gpio Referenz
Architektur der GPIO-Units
gpio_syscalls — mmap, munmap, ioctl, poll (raw syscalls)
gpio_barriers — GpioMemBarrier(), GpioInstBarrier() (ARM64)
rpi4 — BCM2711-Registerkonstanten (RPi4)
└─ gpio_mmio — MMIO-Direktzugriff (Variante A: RPi4, schnell)
gpio_ioctl — Linux GPIO v2 API (Variante B: portabel)
gpio_util — GpioDelayMicroseconds(), Timing
gpio_ext — SetAltMode() für UART/SPI/I²C auf RPi4
└─ gpio_pin — Typsichere Pin-Wrapper (InputPin / OutputPin)
| Variante | Unit | Vorteil | Einschränkung |
|---|---|---|---|
| MMIO | gpio_mmio | Kein Syscall nach Init, max. Geschwindigkeit | Nur Raspberry Pi 4 (BCM2711) |
| ioctl | gpio_ioctl | Portabel, jede Linux-Hardware | Kernel-Overhead pro Operation |
Variante A: MMIO (Raspberry Pi 4)
Direkt auf BCM2711-Register zugreifen — ideal für Software-PWM und Bit-Bang-Protokolle.
Initialisierung
import std.hardware.gpio_mmio;
import std.alloc;
fn main(): int64 {
var ctx: int64 := GpioCtxAlloc(); // 24-Byte-Kontext allokieren
var rc: int64 := GpioInit(ctx); // mmap auf /dev/gpiomem
if rc < 0 { GpioCtxFree(ctx); return -1; }
// Jetzt können Pins verwendet werden ...
GpioClose(ctx); // munmap + free
return 0;
}
Pin lesen und schreiben
import std.hardware.gpio_mmio;
// Pin 17 als Ausgang setzen und HIGH schalten:
GpioSetPinMode(ctx, 17, GPIO_PIN_OUTPUT);
GpioSetPullMode(ctx, 17, GPIO_PULL_NONE);
GpioWritePin(ctx, 17, GPIO_PIN_HIGH);
// Pin 27 als Eingang mit Pull-Up lesen:
GpioSetPinMode(ctx, 27, GPIO_PIN_INPUT);
GpioSetPullMode(ctx, 27, GPIO_PULL_UP);
var state: int64 := GpioReadPin(ctx, 27); // 0 oder 1
Wichtig — Memory Barriers (ARM64): Nach jedem Schreibzugriff auf ein GPIO-Register muss GpioMemBarrier() aufgerufen werden. Lese-Zugriffe (GpioReadPin) benötigen keine Barriere.
import std.hardware.gpio_barriers;
GpioWritePin(ctx, 17, GPIO_PIN_HIGH);
GpioMemBarrier(); // immer nach Schreibzugriff auf GPIO-Register
Software-PWM
import std.hardware.gpio_mmio;
// 1 kHz PWM, 50% Duty-Cycle, 1000 ms Gesamtdauer:
GpioSoftPWM(ctx, 18, 1000, 50, 1000);
// pin freq duty% duration_ms
Alternative Funktionen (UART, SPI, I²C)
import std.hardware.gpio_ext;
// Pin 14 auf ALT0 setzen (= TXD0 / UART auf RPi4):
GpioSetAltMode(ctx, 14, GPIO_PIN_ALT0);
| Alt-Mode | Konstante | Wert |
|---|---|---|
| ALT0 | GPIO_PIN_ALT0 | 4 |
| ALT1 | GPIO_PIN_ALT1 | 5 |
| ALT2 | GPIO_PIN_ALT2 | 6 |
| ALT3 | GPIO_PIN_ALT3 | 7 |
| ALT4 | GPIO_PIN_ALT4 | 3 |
| ALT5 | GPIO_PIN_ALT5 | 2 |
Variante B: Linux GPIO v2 ioctl (portabel)
Funktioniert auf jeder Linux-Hardware mit GPIO-Chip (Kernel 5.10+).
import std.hardware.gpio_ioctl;
import std.alloc;
fn main(): int64 {
// Chip-Informationen abfragen:
var info: int64 := GpioGetChipInfo("/dev/gpiochip0"c);
var numLines: int64 := GpioChipInfoLines(info);
GpioChipInfoFree(info);
// Mehrere Pins gleichzeitig anfordern (Multi-Line-Request):
var pins: int64 := alloc(8); // 1 Pin-Nummer
poke8(pins, 17); // Pin 17
var line_fd: int64 := GpioRequestLines(
"/dev/gpiochip0"c,
pins, 1, // 1 Pin
GPIO_V2_LINE_FLAG_OUTPUT, // Richtung
0 // initial-values
);
free(pins, 8);
// Schreiben: Maske + Wert
GpioSetLineValues(line_fd, 1, 1); // Bit 0 = Pin 17 = HIGH
GpioSetLineValues(line_fd, 1, 0); // Bit 0 = Pin 17 = LOW
GpioReleaseLine(line_fd);
return 0;
}
Edge-Erkennung (Event-basiert)
import std.hardware.gpio_ioctl;
import std.alloc;
var pins: int64 := alloc(8);
poke8(pins, 27);
var line_fd: int64 := GpioRequestLines(
"/dev/gpiochip0"c, pins, 1,
GPIO_V2_LINE_FLAG_INPUT | GPIO_V2_LINE_FLAG_EDGE_RISING | GPIO_V2_LINE_FLAG_EDGE_FALLING,
0
);
free(pins, 8);
// Blockierend warten (500 ms Timeout):
var rc: int64 := GpioWaitForEdge(line_fd, 500);
if rc > 0 {
// Flanke erkannt — Wert lesen
var bits_out: int64 := alloc(GPIO_LINE_VALUES_SIZE);
GpioGetLineValues(line_fd, 1, bits_out);
var val: int64 := peek64(bits_out + GPIO_LINE_VALUES_BITS) & 1;
free(bits_out, GPIO_LINE_VALUES_SIZE);
}
GpioReleaseLine(line_fd);
Typsichere Pin-Wrapper
gpio_pin bietet GpioInputPin und GpioOutputPin als typsichere Kontext-Objekte. Ein Input-Pin kann nicht versehentlich geschrieben werden — der Compiler gibt einen Fehler aus.
import std.hardware.gpio_pin;
import std.hardware.gpio_mmio;
import std.alloc;
// MMIO-Kontext initialisieren:
var ctx: int64 := GpioCtxAlloc();
GpioInit(ctx);
// Typsicherer Output-Pin auf Pin 17:
var out_pin: int64 := GpioOutputPinAlloc(ctx, 17);
GpioOutputPinInit(out_pin, GPIO_PULL_NONE);
GpioOutputPinWrite(out_pin, GPIO_PIN_HIGH);
// Typsicherer Input-Pin auf Pin 27:
var in_pin: int64 := GpioInputPinAlloc(ctx, 27);
GpioInputPinInit(in_pin, GPIO_PULL_UP);
var state: int64 := GpioInputPinRead(in_pin);
GpioInputPinFree(in_pin);
GpioOutputPinFree(out_pin);
GpioClose(ctx);
GpioInputPinWrite() und GpioOutputPinRead() existieren nicht — Compiler-Fehler verhindert Richtungsfehler.
Wichtige Konstanten
gpio_mmio / gpio_pin:
| Konstante | Wert | Bedeutung |
|---|---|---|
GPIO_PIN_INPUT | 0 | Eingang |
GPIO_PIN_OUTPUT | 1 | Ausgang |
GPIO_PIN_LOW | 0 | Low-Pegel |
GPIO_PIN_HIGH | 1 | High-Pegel |
GPIO_PULL_NONE | 0 | Kein Pull |
GPIO_PULL_DOWN | 1 | Pull-Down |
GPIO_PULL_UP | 2 | Pull-Up |
GPIO_CTX_SIZE | 24 | Kontext-Größe für alloc |
GPIO_PIN_CTX_SIZE | 16 | Pin-Kontext-Größe für alloc |
gpio_ioctl (Linux GPIO v2):
| Konstante | Bit | Bedeutung |
|---|---|---|
GPIO_V2_LINE_FLAG_INPUT | 2 | Eingang |
GPIO_V2_LINE_FLAG_OUTPUT | 3 | Ausgang |
GPIO_V2_LINE_FLAG_EDGE_RISING | 4 | Steigende Flanke |
GPIO_V2_LINE_FLAG_EDGE_FALLING | 5 | Fallende Flanke |
GPIO_V2_LINE_FLAG_BIAS_PULL_UP | 8 | Pull-Up |
GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN | 9 | Pull-Down |
Welche Variante wann?
| Szenario | Empfehlung |
|---|---|
| Raspberry Pi 4, maximale Geschwindigkeit (SoftPWM, Bit-Bang) | MMIO (gpio_mmio) |
| Portabler Code, andere Linux-Hardware | ioctl (gpio_ioctl) |
| Mehrere Pins gleichzeitig schalten (atomare Gruppe) | ioctl (GpioRequestLines mit Maske) |
| UART/SPI/I²C-Funktion aktivieren | MMIO + GpioSetAltMode (gpio_ext) |
| Typsichere Pin-Verwaltung | gpio_pin (über gpio_mmio) |
Letzte Aktualisierung: 2026-06-08
