====== 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''.
→ [[lyx_-_programmiersprache:guides|Guides]] · [[lyx_-_programmiersprache:units:hardware:gpio|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