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