Inhaltsverzeichnis

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