====== 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