====== std.hardware.gpio ====== Nativer GPIO-Stack für Linux/ARM64 (Raspberry Pi 4 / BCM2711): von ARM64-Memory-Barriers und rohen Syscall-Wrappern über zwei komplementäre Zugriffsmodi (MMIO-Direktzugriff ohne Kontextwechsel und Linux GPIO-v2 ioctl) bis zu typsicheren Pin-Wrappern, Edge-Detection und Software-PWM. Alle acht Units arbeiten ohne externe Bibliotheken — nur POSIX-Syscalls und direkte Registerzugriffe. **Zwei Zugriffsmodi:** * **Variante A — MMIO** (''gpio_mmio''): Kein Kernel-Kontextwechsel nach ''GpioInit''. Ideal für zeitkritische Anwendungen: Software-PWM, Bit-Bang-Protokolle (I²C, SPI), Frequenzen bis ~1 MHz. Erfordert ''/dev/gpiomem'' (ohne Root) oder ''/dev/mem'' (mit Root). * **Variante B — ioctl** (''gpio_ioctl''): Linux GPIO Character Device API v2 (Kernel ≥ 5.10). Unterstützt atomare Multi-Pin-Operationen, Edge-Detection-Events und Consumer-Labels. Zugriff über ''/dev/gpiochipX''. → [[lyx_-_programmiersprache:units:hardware|std.hardware]] · [[lyx_-_programmiersprache:units:hardware:bluetooth|std.hardware.bluetooth]] · [[lyx_-_programmiersprache:units:hardware:usb|std.hardware.usb]] ---- ===== Architektur ===== Übersicht der internen Schichten und Abhängigkeiten: ┌─────────────────────────────────────────────────────┐ │ Typsichere Pin-Wrapper │ │ gpio_pin (OutputPin / InputPin) │ ├─────────────────────────────────────────────────────┤ │ Erweiterungen │ │ gpio_ext (AltMode · Edge-Detection · SoftPWM) │ ├──────────────────────────┬──────────────────────────┤ │ Variante A: MMIO │ Variante B: ioctl │ │ gpio_mmio │ gpio_ioctl │ │ (kein Syscall im Loop) │ (Linux GPIO-v2 API) │ ├──────────────────────────┴──────────────────────────┤ │ Hilfsfunktionen │ │ gpio_util (StringCopy · DelayMicroseconds) │ ├─────────────────────────────────────────────────────┤ │ Plattform-Konstanten (nur Konstanten) │ │ rpi4 (BCM2711 Register-Offsets · Pin-Modi) │ ├─────────────────────────────────────────────────────┤ │ Grundschicht │ │ gpio_syscalls · gpio_barriers │ └─────────────────────────────────────────────────────┘ ---- ===== Units ===== ^ Unit ^ Beschreibung ^ | [[lyx_-_programmiersprache:units:hardware:gpio_barriers|std.hardware.gpio_barriers]] | ARM64-Memory-/Instruction-Barrier-Intrinsics: GpioMemBarrier (DMB SY), GpioInstBarrier (ISB SY) | | [[lyx_-_programmiersprache:units:hardware:gpio_syscalls|std.hardware.gpio_syscalls]] | Low-Level Syscall-Wrapper: GpioOpen, GpioClose, GpioIoctl, GpioPoll, GpioMmap, GpioMunmap | | [[lyx_-_programmiersprache:units:hardware:gpio_util|std.hardware.gpio_util]] | Hilfsfunktionen: GpioCopyStringToBuf, GpioDelayMicroseconds (CLOCK_MONOTONIC Busy-Wait) | | [[lyx_-_programmiersprache:units:hardware:rpi4|std.hardware.rpi4]] | BCM2711-Hardware-Konstanten: Register-Offsets (GPFSEL, GPSET, GPCLR, GPLEV, Pull), Pin-Modi | | [[lyx_-_programmiersprache:units:hardware:gpio_mmio|std.hardware.gpio_mmio]] | MMIO-Direktzugriff (Variante A): GpioInit, GpioSetPinMode, GpioWritePin, GpioReadPin, GpioSetPullMode | | [[lyx_-_programmiersprache:units:hardware:gpio_ioctl|std.hardware.gpio_ioctl]] | Linux GPIO-v2 ioctl (Variante B): GpioGetChipInfo, GpioRequestLines, GpioSetLineValues, GpioGetLineValues | | [[lyx_-_programmiersprache:units:hardware:gpio_pin|std.hardware.gpio_pin]] | Typsichere Pin-Wrapper: GpioOutputPin* (nur Write), GpioInputPin* (nur Read) | | [[lyx_-_programmiersprache:units:hardware:gpio_ext|std.hardware.gpio_ext]] | Erweiterungen: GpioSetAltMode (ALT0–ALT5), GpioWaitForEdge, GpioSoftPWM | ---- ===== std.hardware.gpio_barriers ===== ARM64 Memory- und Instruction-Barrier-Intrinsics. Pflichtbestandteil für korrekte MMIO-Zugriffe auf dem Cortex-A72 (BCM2711): Der Out-of-Order-Prozessor kann Schreibzugriffe umordnen — ohne Barrieren sieht der GPIO-Controller keine definierte Reihenfolge. **Faustregel:** Nach jedem Schreibzugriff auf ein GPIO-Register ''GpioMemBarrier()'' aufrufen. Lesezugriffe (GPLEV) benötigen keine Barriere. ==== Funktionen ==== ^ Signatur ^ Beschreibung ^ | ''GpioMemBarrier()'' | Full-System-Memory-Barrier — ARM64: ''DMB SY'' · x86-64: ''MFENCE''. Nach jedem GPIO-Register-Schreibzugriff. | | ''GpioInstBarrier()'' | Instruction-Synchronization-Barrier — ARM64: ''ISB SY'' · x86-64: ''LFENCE''. Nach MMU-/Cache-Konfigurationsänderungen; für normales GPIO nicht nötig. | ---- ===== std.hardware.gpio_syscalls ===== Unterste Schicht: direkte POSIX-Syscall-Wrapper für GPIO-Gerätedateien (''/dev/gpiomem'', ''/dev/gpiochipX''). Wird von ''gpio_mmio'' und ''gpio_ioctl'' importiert; selten direkt verwendet. ==== Dateiöffnungs-Flags ==== ^ Konstante ^ Wert ^ Beschreibung ^ | ''GPIO_O_RDONLY'' | 0 | Nur lesen | | ''GPIO_O_WRONLY'' | 1 | Nur schreiben | | ''GPIO_O_RDWR'' | 2 | Lesen und schreiben | | ''GPIO_O_SYNC'' | 4096 | Synchrones I/O (immer für MMIO setzen) | ==== mmap-Konstanten ==== ^ Konstante ^ Wert ^ Beschreibung ^ | ''GPIO_PROT_READ'' | 1 | Mapping lesbar | | ''GPIO_PROT_WRITE'' | 2 | Mapping schreibbar | | ''GPIO_PROT_RW'' | 3 | Lesen und schreiben | | ''GPIO_MAP_SHARED'' | 1 | Änderungen im Mapping sichtbar für alle Prozesse | | ''GPIO_MAP_FAILED'' | −1 | mmap-Fehler-Sentinel | ==== poll-Event-Flags ==== ^ Konstante ^ Wert ^ Beschreibung ^ | ''GPIO_POLLIN'' | 1 | Daten zum Lesen verfügbar | | ''GPIO_POLLOUT'' | 4 | Schreiben möglich | | ''GPIO_POLLERR'' | 8 | Fehler am Dateideskriptor | ==== Funktionen ==== ^ Signatur ^ Beschreibung ^ | ''GpioOpen(path: pchar, flags: int64): int64'' | Öffnet ''/dev/gpiomem'' oder ''/dev/gpiochipX''; gibt fd ≥ 0 oder < 0 zurück | | ''GpioClose(fd: int64): int64'' | Schließt fd | | ''GpioRead(fd: int64, buf: int64, count: int64): int64'' | Liest count Bytes in buf | | ''GpioIoctl(fd: int64, request: int64, arg: int64): int64'' | ioctl-Syscall; gibt 0 oder Fehlercode zurück | | ''GpioPoll(fds_ptr: int64, nfds: int64, timeout_ms: int64): int64'' | poll() über mehrere Dateideskriptoren | | ''GpioMmap(addr: int64, length: int64, prot: int64, flags: int64, fd: int64, offset: int64): int64'' | Legt mmap-Mapping an; gibt Startadresse oder ''GPIO_MAP_FAILED'' zurück | | ''GpioMunmap(addr: int64, length: int64): int64'' | Gibt Mapping frei | | ''GpioPollFdSet(ptr: int64, fd: int64, events: int64)'' | Befüllt pollfd-Eintrag (8 Bytes: int32 fd, int16 events, int16 revents) | | ''GpioPollFdRevents(ptr: int64): int64'' | Liest revents aus pollfd-Eintrag | ---- ===== std.hardware.gpio_util ===== Zwei plattformunabhängige Hilfsfunktionen, die von ''gpio_ioctl'' (String-Kopie für Consumer-Label) und ''gpio_ext'' (Busy-Wait für SoftPWM) benötigt werden. ==== Konstanten ==== ^ Konstante ^ Wert ^ Beschreibung ^ | ''GPIO_CLOCK_MONOTONIC'' | 1 | POSIX CLOCK_MONOTONIC für ''clock_gettime'' | | ''GPIO_TIMESPEC_SIZE'' | 16 | Größe von ''struct timespec'' (sec 8 Bytes + nsec 8 Bytes) | | ''GPIO_NS_PER_US'' | 1 000 | Nanosekunden pro Mikrosekunde | | ''GPIO_NS_PER_SEC'' | 1 000 000 000 | Nanosekunden pro Sekunde | ==== Funktionen ==== ^ Signatur ^ Beschreibung ^ | ''GpioCopyStringToBuf(src: pchar, dst: int64, max_len: int64): int64'' | Kopiert null-terminierten String nach dst; schreibt max. max_len-1 Bytes + NUL; gibt Anzahl geschriebener Bytes zurück | | ''GpioDelayMicroseconds(delay_us: int64)'' | Busy-Wait für mindestens delay_us Mikrosekunden via CLOCK_MONOTONIC; Genauigkeit ±1–2 µs | ---- ===== std.hardware.rpi4 ===== BCM2711-Hardware-Konstanten für den Raspberry Pi 4. Enthält ausschließlich ''con''-Definitionen — keine Funktionen. Wird von ''gpio_mmio'' importiert. ==== Plattform-Adressen ==== ^ Konstante ^ Wert ^ Beschreibung ^ | ''RPI4_PERIPHERAL_BASE'' | 0xFE000000 | Peripheral-Basis-Adresse (BCM2711) | | ''RPI4_GPIO_BASE'' | 0xFE200000 | GPIO-Basis (PERIPHERAL_BASE + 0x200000) | | ''RPI4_GPIO_MAP_SIZE'' | 4096 | Mapping-Größe (eine Seite für alle GPIO-Register) | | ''RPI4_MAX_PIN'' | 53 | Maximale Pin-Nummer auf BCM2711 | | ''RPI4_MAP_FAILED'' | −1 | mmap-Fehler-Sentinel | | ''RPI4_HAS_NEW_PULL_REGS'' | 1 | Standard: neue Pull-Register (BCM2711 Rev ≥ 1.2) | ==== Function-Select-Register (GPFSEL) ==== 3 Bits pro Pin, 10 Pins pro 32-Bit-Register: ^ Konstante ^ Offset ^ Beschreibung ^ | ''RPI4_GPFSEL0'' | 0x00 | Pins 0–9 | | ''RPI4_GPFSEL1'' | 0x04 | Pins 10–19 | | ''RPI4_GPFSEL2'' | 0x08 | Pins 20–29 | | ''RPI4_GPFSEL3'' | 0x0C | Pins 30–39 | | ''RPI4_GPFSEL4'' | 0x10 | Pins 40–49 | | ''RPI4_GPFSEL5'' | 0x14 | Pins 50–53 | ==== Set / Clear / Level-Register ==== ^ Konstante ^ Offset ^ Beschreibung ^ | ''RPI4_GPSET0'' | 0x1C | Pins 0–31 setzen (Write-1-to-set) | | ''RPI4_GPSET1'' | 0x20 | Pins 32–53 setzen | | ''RPI4_GPCLR0'' | 0x28 | Pins 0–31 löschen (Write-1-to-clear) | | ''RPI4_GPCLR1'' | 0x2C | Pins 32–53 löschen | | ''RPI4_GPLEV0'' | 0x34 | Pins 0–31 lesen (Read-Only) | | ''RPI4_GPLEV1'' | 0x38 | Pins 32–53 lesen | ==== Pull-Widerstands-Register ==== ^ Konstante ^ Offset ^ Beschreibung ^ | ''RPI4_GPPUD'' | 0x94 | Pull-Control Legacy (0=None, 1=Down, 2=Up) | | ''RPI4_GPPUDCLK0'' | 0x98 | Pull-Clock Pins 0–31 (Legacy) | | ''RPI4_GPPUDCLK1'' | 0x9C | Pull-Clock Pins 32–53 (Legacy) | | ''RPI4_PUP_PDN_REG0'' | 0xE4 | Pull-Register Pins 0–15 (Neu, 2 Bits/Pin) | | ''RPI4_PUP_PDN_REG1'' | 0xE8 | Pull-Register Pins 16–31 | | ''RPI4_PUP_PDN_REG2'' | 0xEC | Pull-Register Pins 32–47 | | ''RPI4_PUP_PDN_REG3'' | 0xF0 | Pull-Register Pins 48–53 | ==== Pin-Modus-Codes (GPFSEL 3-Bit-Kodierung) ==== ^ Konstante ^ Wert ^ Beschreibung ^ | ''RPI4_MODE_INPUT'' | 0 (000) | Eingang | | ''RPI4_MODE_OUTPUT'' | 1 (001) | Ausgang | | ''RPI4_MODE_ALT0'' | 4 (100) | Alt-Funktion 0 | | ''RPI4_MODE_ALT1'' | 5 (101) | Alt-Funktion 1 | | ''RPI4_MODE_ALT2'' | 6 (110) | Alt-Funktion 2 | | ''RPI4_MODE_ALT3'' | 7 (111) | Alt-Funktion 3 | | ''RPI4_MODE_ALT4'' | 3 (011) | Alt-Funktion 4 | | ''RPI4_MODE_ALT5'' | 2 (010) | Alt-Funktion 5 | ---- ===== std.hardware.gpio_mmio ===== MMIO-Direktzugriff auf BCM2711-GPIO-Register (Variante A). Öffnet ''/dev/gpiomem'' und legt ein mmap-Mapping über die Register an. Nach dem einmaligen ''GpioInit''-Aufruf sind alle weiteren Pin-Operationen reine Speicherzugriffe ohne Syscall — ideal für zeitkritische Bit-Bang-Protokolle und Software-PWM. ==== Kontext-Konstanten und Pin-Flags ==== ^ Konstante ^ Wert ^ Beschreibung ^ | ''GPIO_CTX_SIZE'' | 24 | Größe des heap-allozierten GPIO-Kontexts in Bytes | | ''GPIO_PIN_INPUT'' | 0 | Pin-Modus: Eingang | | ''GPIO_PIN_OUTPUT'' | 1 | Pin-Modus: Ausgang | | ''GPIO_PIN_LOW'' | 0 | Pegel: LOW | | ''GPIO_PIN_HIGH'' | 1 | Pegel: HIGH | | ''GPIO_PULL_NONE'' | 0 | Kein Pull-Widerstand | | ''GPIO_PULL_DOWN'' | 1 | Pull-Down-Widerstand | | ''GPIO_PULL_UP'' | 2 | Pull-Up-Widerstand | ==== Kontext-Verwaltung ==== ^ Signatur ^ Beschreibung ^ | ''GpioCtxAlloc(): int64'' | Alloziert GPIO-Kontext (24 Bytes); gibt Zeiger zurück | | ''GpioCtxFree(ctx: int64)'' | Gibt Kontext frei (nur den Kontext-Puffer, nicht das Mapping) | | ''GpioGetMem(ctx: int64): int64'' | Gibt Basisadresse des mmap-Mappings zurück | | ''GpioIsMapped(ctx: int64): int64'' | 1 wenn Mapping aktiv, 0 wenn nicht initialisiert | | ''GpioHasNewPull(ctx: int64): int64'' | 1 wenn neue BCM2711-Pull-Register aktiv | ==== Initialisierung und Freigabe ==== ^ Signatur ^ Beschreibung ^ | ''GpioInit(ctx: int64): int64'' | Öffnet ''/dev/gpiomem'' (kein Root) oder ''/dev/mem'' (Root); legt Mapping an; ''GpioMemBarrier()'' danach; gibt 1 bei Erfolg zurück | | ''GpioClose(ctx: int64)'' | ''GpioMemBarrier()'' + ''munmap''; setzt ''is_mapped = 0''; No-op wenn nicht initialisiert | ==== Pin-Operationen ==== ^ Signatur ^ Beschreibung ^ | ''GpioSetPinMode(ctx: int64, pin: int64, mode: int64): int64'' | Konfiguriert Pin via GPFSEL-Register (RMW + ''GpioMemBarrier()''); gibt 1 bei Erfolg zurück | | ''GpioWritePin(ctx: int64, pin: int64, state: int64): int64'' | Setzt (GPSET) oder löscht (GPCLR) Pin atomar ohne RMW; ''GpioMemBarrier()'' danach | | ''GpioReadPin(ctx: int64, pin: int64): int64'' | Liest Pegel aus GPLEV-Register; gibt 0/1 zurück, -1 bei Fehler | | ''GpioSetPullMode(ctx: int64, pin: int64, mode: int64): int64'' | Konfiguriert Pull-Widerstand; unterstützt neues BCM2711-Format und Legacy-3-Schritt-Protokoll | import std.hardware.gpio_mmio; import std.alloc; import std.io; fn BlinkLed(pin: int64, times: int64): void { var ctx := GpioCtxAlloc(); GpioInit(ctx); GpioSetPinMode(ctx, pin, GPIO_PIN_OUTPUT); var i: int64 := 0; while (i < times) { GpioWritePin(ctx, pin, GPIO_PIN_HIGH); GpioDelayMicroseconds(500000); // 500 ms GpioWritePin(ctx, pin, GPIO_PIN_LOW); GpioDelayMicroseconds(500000); i := i + 1; } GpioClose(ctx); GpioCtxFree(ctx); } ---- ===== std.hardware.gpio_ioctl ===== Linux GPIO-v2 ioctl-Interface (Variante B, Kernel ≥ 5.10). Öffnet ''/dev/gpiochipX'' und verwendet die standardisierte ''gpio_v2_*''-Kernel-API. Unterstützt atomare Multi-Pin-Operationen (bis 64 Pins gleichzeitig), Consumer-Labels und Edge-Detection über Line-Fds. ==== ioctl-Codes ==== ^ Konstante ^ Wert ^ Beschreibung ^ | ''GPIO_GET_CHIPINFO_IOCTL'' | 0x8044B401 | Chip-Info lesen (_IOR, 68 Bytes) | | ''GPIO_V2_GET_LINE_IOCTL'' | 0xC250B407 | Lines anfordern (_IOWR, 592 Bytes) | | ''GPIO_V2_LINE_GET_VALUES_IOCTL'' | 0xC010B40E | Line-Werte lesen (_IOWR, 16 Bytes) | | ''GPIO_V2_LINE_SET_VALUES_IOCTL'' | 0xC010B40F | Line-Werte setzen (_IOWR, 16 Bytes) | ==== Line-Flags (gpio_v2_line_flag) ==== ^ Konstante ^ Bit ^ Beschreibung ^ | ''GPIO_V2_LINE_FLAG_USED'' | 0 | Pin bereits belegt | | ''GPIO_V2_LINE_FLAG_ACTIVE_LOW'' | 1 | Aktiv-Low-Logik | | ''GPIO_V2_LINE_FLAG_INPUT'' | 2 | Eingang | | ''GPIO_V2_LINE_FLAG_OUTPUT'' | 3 | Ausgang | | ''GPIO_V2_LINE_FLAG_EDGE_RISING'' | 4 | Steigende Flanke auslöst Ereignis | | ''GPIO_V2_LINE_FLAG_EDGE_FALLING'' | 5 | Fallende Flanke löst Ereignis aus | | ''GPIO_V2_LINE_FLAG_OPEN_DRAIN'' | 6 | Open-Drain-Ausgang | | ''GPIO_V2_LINE_FLAG_OPEN_SOURCE'' | 7 | Open-Source-Ausgang | | ''GPIO_V2_LINE_FLAG_BIAS_PULL_UP'' | 8 | Pull-Up aktivieren | | ''GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN'' | 9 | Pull-Down aktivieren | | ''GPIO_V2_LINE_FLAG_BIAS_DISABLED'' | 10 | Pull-Widerstand deaktivieren | ==== Struct-Größen ==== ^ Konstante ^ Wert ^ Beschreibung ^ | ''GPIO_CHIP_INFO_SIZE'' | 68 | gpiochip_info: name[32] + label[32] + lines(u32) | | ''GPIO_LINE_VALUES_SIZE'' | 16 | gpio_v2_line_values: bits(u64) + mask(u64) | | ''GPIO_LINE_REQUEST_SIZE'' | 592 | gpio_v2_line_request (vollständige Struktur) | | ''GPIO_V2_LINES_MAX'' | 64 | Maximale Lines pro Request | ==== Funktionen ==== ^ Signatur ^ Beschreibung ^ | ''GpioGetChipInfo(chip_path: pchar): int64'' | Öffnet ''/dev/gpiochipX'' und liest ''gpiochip_info''; gibt heap-allozierten Puffer zurück (0 = Fehler) | | ''GpioChipInfoFree(info: int64)'' | Gibt den von ''GpioGetChipInfo'' allozierten Puffer frei | | ''GpioChipInfoLines(info: int64): int64'' | Gibt die Anzahl verfügbarer Lines zurück | | ''GpioRequestLines(chip_path: pchar, pins_ptr: int64, num_lines: int64, flags: int64, consumer: pchar): int64'' | Fordert Pins an; gibt Line-Fd zurück (−1 = Fehler) | | ''GpioSetLineValues(line_fd: int64, mask: int64, bits: int64): int64'' | Setzt Ausgangspegel; mask = Bitmap der zu ändernden Lines; bits = Zielwerte; gibt 1 bei Erfolg zurück | | ''GpioGetLineValues(line_fd: int64, mask: int64, bits_out: int64): int64'' | Liest Pegel; schreibt Ergebnis nach bits_out (min. 8 Bytes); gibt 1 bei Erfolg zurück | | ''GpioReleaseLine(line_fd: int64)'' | Schließt Line-Fd (gibt Pins frei) | import std.hardware.gpio_ioctl; import std.alloc; import std.io; fn IoctlBlinkLed(pin: int64): void { // Chip-Info abfragen var info := GpioGetChipInfo("/dev/gpiochip0"); PrintLn("Lines: " + IntToStr(GpioChipInfoLines(info))); GpioChipInfoFree(info); // Pin als Ausgang anfordern var pins: int64 := alloc(4); poke32(pins, pin); // Pin-Nummer als int32 eintragen var lineFd := GpioRequestLines("/dev/gpiochip0", pins, 1, GPIO_V2_LINE_FLAG_OUTPUT, "blink"); free(pins, 4); // 5× blinken var i: int64 := 0; while (i < 5) { GpioSetLineValues(lineFd, 1, 1); // mask=1 (Line 0), bits=1 (HIGH) GpioDelayMicroseconds(500000); GpioSetLineValues(lineFd, 1, 0); // bits=0 (LOW) GpioDelayMicroseconds(500000); i := i + 1; } GpioReleaseLine(lineFd); } ---- ===== std.hardware.gpio_pin ===== Typsichere Pin-Wrapper (Variante für MMIO). Implementiert ein Konventions-basiertes Typsystem: ''GpioOutputPin*''-Funktionen existieren nur für Schreibzugriffe, ''GpioInputPin*''-Funktionen nur für Lesezugriffe. Ein Aufruf der jeweils falschen Seite (z. B. ''GpioOutputPinRead'') schlägt mit "unknown function" beim Compilieren fehl. ==== Konstanten ==== ^ Konstante ^ Wert ^ Beschreibung ^ | ''GPIO_PIN_CTX_SIZE'' | 16 | Größe des Pin-Kontexts: gpio_ctx(8) + pin_nr(8) | ==== OutputPin-Funktionen (nur Write) ==== ^ Signatur ^ Beschreibung ^ | ''GpioOutputPinAlloc(gpio_ctx: int64, pin_nr: int64): int64'' | Alloziert OutputPin-Kontext; verknüpft mit MMIO-Kontext und Pin-Nummer | | ''GpioOutputPinInit(pin_ctx: int64, pull: int64): int64'' | Setzt Pin-Modus auf OUTPUT + optionaler Pull; gibt 1 bei Erfolg zurück | | ''GpioOutputPinWrite(pin_ctx: int64, state: int64): int64'' | Setzt Pegel (''GPIO_PIN_HIGH'' / ''GPIO_PIN_LOW''); gibt 1 bei Erfolg zurück | | ''GpioOutputPinFree(pin_ctx: int64)'' | Gibt Pin-Kontext frei | ==== InputPin-Funktionen (nur Read) ==== ^ Signatur ^ Beschreibung ^ | ''GpioInputPinAlloc(gpio_ctx: int64, pin_nr: int64): int64'' | Alloziert InputPin-Kontext | | ''GpioInputPinInit(pin_ctx: int64, pull: int64): int64'' | Setzt Pin-Modus auf INPUT + optionaler Pull (typisch ''GPIO_PULL_UP'' für Taster) | | ''GpioInputPinRead(pin_ctx: int64): int64'' | Liest Pegel; gibt 0 (LOW), 1 (HIGH) oder −1 (Fehler) zurück | | ''GpioInputPinFree(pin_ctx: int64)'' | Gibt Pin-Kontext frei | import std.hardware.gpio_mmio; import std.hardware.gpio_pin; import std.alloc; import std.io; fn ButtonControlsLed(ledPin: int64, btnPin: int64): void { var ctx := GpioCtxAlloc(); GpioInit(ctx); var led := GpioOutputPinAlloc(ctx, ledPin); GpioOutputPinInit(led, GPIO_PULL_NONE); var btn := GpioInputPinAlloc(ctx, btnPin); GpioInputPinInit(btn, GPIO_PULL_UP); // Taster gegen GND mit Pullup var i: int64 := 0; while (i < 1000) { var pressed := GpioInputPinRead(btn); // Taster mit Pullup: gedrückt = LOW (0), losgelassen = HIGH (1) GpioOutputPinWrite(led, 1 - pressed); GpioDelayMicroseconds(5000); // 5 ms Entprellzeit i := i + 1; } GpioOutputPinFree(led); GpioInputPinFree(btn); GpioClose(ctx); GpioCtxFree(ctx); } ---- ===== std.hardware.gpio_ext ===== Erweiterungen für Alternativfunktionen, Edge-Detection und Software-PWM. Baut auf ''gpio_mmio'' und ''gpio_ioctl'' auf. ==== Alt-Modus-Konstanten ==== Die Bit-Codes sind nicht linear (BCM2711 GPFSEL 3-Bit): ^ Konstante ^ Wert ^ Beschreibung ^ | ''GPIO_PIN_ALT0'' | 4 (100) | Alternativfunktion 0 (z. B. SPI0, I2C auf bestimmten Pins) | | ''GPIO_PIN_ALT1'' | 5 (101) | Alternativfunktion 1 | | ''GPIO_PIN_ALT2'' | 6 (110) | Alternativfunktion 2 | | ''GPIO_PIN_ALT3'' | 7 (111) | Alternativfunktion 3 | | ''GPIO_PIN_ALT4'' | 3 (011) | Alternativfunktion 4 | | ''GPIO_PIN_ALT5'' | 2 (010) | Alternativfunktion 5 | ==== Funktionen ==== ^ Signatur ^ Beschreibung ^ | ''GpioSetAltMode(ctx: int64, pin: int64, mode: int64): int64'' | Setzt Pin auf Alt-Funktion (GPIO_PIN_ALT0–ALT5); delegiert an GpioSetPinMode; gibt 1 bei Erfolg zurück | | ''GpioWaitForEdge(line_fd: int64, timeout_ms: int64): int64'' | Blockiert via ''sys_poll'' auf Line-Fd bis zur nächsten Flanke; timeout_ms: 0=sofort, −1=unbegrenzt; gibt 1=Ereignis, 0=Timeout, −1=Fehler zurück | | ''GpioSoftPWM(ctx: int64, pin: int64, frequency: int64, dutyCycle: int64, duration_ms: int64)'' | Software-PWM per Busy-Wait; blockiert CPU vollständig für duration_ms; dutyCycle: 0–100; frequency: ≤ ~1 MHz | ==== SoftPWM-Randfälle ==== ^ Eingabe ^ Verhalten ^ | ''frequency ≤ 0'' | Sofortige Rückkehr (Guard) | | ''dutyCycle = 0'' | Pin bleibt LOW für die gesamte Dauer | | ''dutyCycle ≥ 100'' | Pin bleibt HIGH für die gesamte Dauer | | ''frequency > 1 000 000'' | period_us wird auf 1 µs geklemmt (kein Überlauf) | import std.hardware.gpio_mmio; import std.hardware.gpio_ext; import std.hardware.gpio_ioctl; import std.alloc; fn FadeLed(pin: int64): void { var ctx := GpioCtxAlloc(); GpioInit(ctx); GpioSetPinMode(ctx, pin, GPIO_PIN_OUTPUT); // Fade-In: 0 % → 100 % Helligkeit var duty: int64 := 0; while (duty <= 100) { GpioSoftPWM(ctx, pin, 1000, duty, 20); // 1 kHz, 20 ms pro Schritt duty := duty + 5; } GpioClose(ctx); GpioCtxFree(ctx); } fn WaitForButton(lineFd: int64): void { // Wartet auf fallende Flanke (Tasterdruck) — max. 10 Sekunden var r := GpioWaitForEdge(lineFd, 10000); if (r == 1) { Print("Taster gedrückt!\n"); } if (r == 0) { Print("Timeout.\n"); } } ---- ===== Variante A vs. Variante B ===== Entscheidungshilfe für die Wahl des Zugriffsmodus: ^ Kriterium ^ MMIO (gpio_mmio) ^ ioctl (gpio_ioctl) ^ | Syscalls im Betrieb | Keine (nach GpioInit) | Pro Set/Get ein ioctl | | Zeitkritisch (< 10 µs) | Ja | Nein | | Software-PWM / Bit-Bang | Ideal | Ungeeignet | | Multi-Pin atomar | Nein (sequenziell) | Ja (bis 64 Pins) | | Edge-Detection | Über gpio_ext + ioctl | Nativ (EDGE-Flags) | | Root erforderlich | Nein (/dev/gpiomem) | Nein (/dev/gpiochip0) | | Portabilität | RPi4/BCM2711 | Alle Linux-GPIO-Treiber | ---- ===== Verwandte Units ===== * ''[[lyx_-_programmiersprache:units:hardware:usb|std.hardware.usb]]'' — USB-Stack (HID, CDC, Bulk, Gadget) * ''[[lyx_-_programmiersprache:units:hardware:bluetooth|std.hardware.bluetooth]]'' — Bluetooth-Stack (BLE/Classic) * ''[[lyx_-_programmiersprache:units:thread|std.thread]]'' — Threads für parallele Pin-Überwachung * ''[[lyx_-_programmiersprache:units:signals|std.signals]]'' — Signalbehandlung für sauberes Shutdown (GpioClose) * ''[[lyx_-_programmiersprache:units:time|std.time]]'' — Zeitstempel und Timer-Funktionen Letzte Aktualisierung: 2026-06-07