Skip to content
On this page

9. Userspace and Peripherals

Im folgenden Versuch soll möglichst einfach aus dem Userspace unter C über das Pseudofilesystem „sysfs“ auf digital Ein-/Ausgänge (GPIOs) zugegriffen werden. Die Variante sysfs ist für einfache Hardware das gängigste Verfahren ...

Alternativen für den Hardware-Zugriff unter Linux

Direkt aus dem Kernel

Also direkt aus einem selber erstellten Kernelmodule. Die Erstellungen eines Kernelmodulesist jedoch vergleichsweise aufwändig, erfordert viel Know-How und ist sicherheitskritisch, weshalb man Anwendungen generell im Userspace realisieren sollte.

Aus dem Userspace unter Beihilfe eines geeigneten vorhandenen Treibers

... für die betreffende Hardware. Linux unterstützt hierzu mehrere APIs um aus dem Userspace auf Peripherie-Treiber zuzugreifen:

  • Über das Pseudofilesystem Sysfs (unter /sys/class/…). Diese Variante ist für einfache Hardware wie GPIO, Temperatursensoren, LED-Ansteuerung, PWM, etc. üblich.
  • Via Device Interface also über einen Devicenode unter dem Ordner /dev/. Da diese Variante auch den ioctl() Systemcall ermöglicht, wird diese für eher komplexere Hardware sowie Hardware hinter einem Bussystem genutzt. (Ein Kernel-Treiber mit Device Interface werden Sie in einem späteren Versuch noch realisieren.)
  • Über ein Subsystem wie z.B. das Input-Subsystem für Human Interface Devices, HWMON für einfachere Sensoren oder das Industrial IO Subsystem für komplexere Sensoren und/oder performante/schnelle Peripherie ... (Diese Themen werden im Unterricht noch behandelt.)

mit mmap

Statt über einen Treiber können Bereiche des Physical Memory – sofern es der Kernel zulässt – auch direkt in den virtuellen Adressspace einer (Usermode-)Anwendung "gepaged" werden.

Da Peripherieregister ebenfalls im Physical Memory liegen, kann so aus einer Anwendung auch recht direkt auf Peripherieregister zugegriffen werden – vorausgesetzt der Kernel lässt dies zu und die Anwendung hat die erforderlichen Benutzerrechte, denn meist ist hierzu root-Recht nötig.

Dieser nahezu uneingeschränkte Zugriff auf das Physical Memory ist natürlich extrem sicherheitskritisch, weshalb diese Vorgehensweise allgemein nicht empfohlen und über die Kernel-Konfiguration meist auch unterbunden wird. Trotzdem wird diese Zugriffsart beim Raspberry Pi OS (ehemals Raspian) verwendet – sowohl vom Console Command gpio als auch über die Python Library Rpi.GPIO, denn Sicherheitaspekte hatten beim Raspberry Pi ursprünglich wenig Bedeutung.

Zugriff auf LEDs und GPIOs über Sysfs

TIP

Eigentlicher Zweck des Kernels ist ja „Hardwareabstraktion“ d.h. die Verwaltung von Hardwareressourcen wie Prozessor-, Speicher- und IO-Ressourcen sowie Abstraktion derselben auf eine hardware-unabhängige, sichere und funktionale Ebene, sodass Anwenderprogramme die Hardware möglichst einfach und unabhängig von der darunter liegenden Ansteuerung über Peripherieregistern verwenden können.

Unter Linux erfolgen deshalb und aus Sicherheitsgründen Hardwarezugriffe normalerweise nicht direkt aus dem Usermode (also direkt aus Anwendungen), sondern typischerweise indirekt über einen geeigneten Peripherie-Treiber im Linux-Kernel.

Einfache Hardware-Zugriffe wie digitale oder analoge Zustände auslesen oder setzen werden unter Linux bevorzugt über das Pseudofilesystem Sysfs realisiert, sofern für die betreffenden Peripherie ein Kerneltreiber mit Anbindung an das Sysfs vorhanden ist.

Kernelseitig ist das Pseudofilesystem Sysfs in das Linux Kernel Device Model eingebunden – einer kernelinternen dynamisch generierten Datenstruktur, bei welcher sich Kernelmodule resp. Peripherietreiber registrieren resp. „einhängen“ können.

Aus dieser Datenstruktur generiert der Kernel nebst dem sysfs Inhalt auch die unter /dev/ ersichtlichen Devicenodes, wobei /dev/ ja bekanntlich auch ein (automatisch beim Systemstart) eingebundenes Pseudofilesystem (devfs) ist.

Mittels mount erkennen Sie, dass das Pseudofilesystem sysfs wie üblich auf das Verzeichnis /sys gemountet wurde. In unserem Fall wird dieses Pseudodateisystem ja aufgrund eines Eintrags in der Datei /etc/fstab sowie einem sysinit Eintrags in /etc/inittab beim Start automatisch gemountet.

Führen Sie ls /sys/class sowohl auf dem Host als auch auf dem Zielsystem aus. Unter diesem Ordner werden alle im Kernel Device Model registrierten "Devices" (also Geräte resp. Peripherie) nach deren Device-Class sortiert aufgelistet.

Auf fast allen Linux-Systemen existiert z.B. die Device-Class /sys/class/leds worunter es Einträge für die auf dem System vorhandenen LEDs hat (vgl. ls /sys/class/leds'. Auf unserem Raspberry Pi z.B. einen Eintrag led0 für die grüne LED sowie led1 für die rote LED. Beide Einträge sind wiederum Order, worunter es wiederum weitere Einträge hat (überzeugen Sie sich davon!).

Über den Eintrag resp. die Pseudodatei trigger lässt sich einsehen und einstellen, welches Ereignis die betreffende LED ansteuert. Lesen Sie diesen Eintrag z.B. per cat /sys/class/leds/led0/trigger aus. Derjenige Eintrag welcher in eckigen Klammern ausgegeben wird, ist der momentan aktive – offensichtlich mmc0 weshalb jede Aktivität auf der SD-Karte die grüne LED triggert (resp. toggelt!).

Nebst vielen hardwarespezifischen Ereignissquellen gibt es auch Funktionen wie timer, oneshot und heartbeat: Aktivieren Sie den "timer" Mode per: echo timer >/sys/class/leds/led0/trigger wonach die LED regelmässig blinken sollte. Die Ein- und Auszeit (in Millisekunden) liesse sich danach über die Einträge delay_on und delay_off einsehen oder beeinflussen (überzeugen Sie sich davon!). Ähnlich funktionieren auch die Modi oneshot und heatbeat.

Soll hingegen die LED direkt aus dem Usermode angesteuert werden, sollte trigger auf none gesetzt werden, wonach über den Eintrag brightness die LED ein- und ausgeschaltet oder sofern es die Hardware und der GPIO-Treiber unterstützt auch gedimmt werden könnte:

Grüne LED einschalten per: echo 1 > /sys/class/leds/led0/brightness Grüne LED ausschalten per: echo 0 > /sys/class/leds/led0/brightness

Stellen Sie nun per echo mmc0 >/sys/class/leds/led0/trigger wieder auf Anzeige der SD-Aktivität, sodass beim Herunterfahren per halt erkennbar wird, wann auf der SD keine Aktivität mehr stattfindet.

Über obige Device Class leds lassen sich bloss LEDs ansteuern, welche über den Device Tree bereits statisch registriert sind. Diese statische Konfiguration des "Device Trees" erfolgt bekanntlich über den Device Tree Blob (in unserem Fall bcm2711-rpi-4-b.dtb) und/oder weiteren Device Tree Overlays (*.dtbo), welche vom Bootloader noch vor dem Starten des Kernels ins DRAM geladen werden!

Hingegen kann über die Device Class gpio zumindest bei unserer Kernel-Konfiguration jeder beliebige GPIO Port auch dynamisch (also zur Laufzeit) als Ein- oder Ausgang aktiviert werden.

Wenn Sie nach den GPIO Nummern der Raspi Pinleiste googlen oder diese per 'gpio readall' auf einem mit Raspian gebooteten Raspi auslesen, werden Sie leicht in die Irre geführt, denn das Raspberry Pi kennt drei verschiedene GPIO-Nummerierungen:

  • die beim Raspi als "Board" Nummerierung bezeichnete Nummerierierung der Stiftleistenpins,
  • die Wiring Pi Nummerierung, eine frei erfundene Nummerierung in Anlehnung an das Arduino,
  • die logischen GPIO Nummern des SoC Herstellers Broadcom (BCM),

Die GPIO Nummerierung im Linux-Kernel und damit auch die gpio-Nummern unter /sys/class/gpio beziehen sich letztere, also auf die logischen GPIO Nummern des SoC, also die Broadcom Nummerierung!

Bild: Broadcom GPIO Nummerierung auf welche sich auch der Linux-Kernel bezieht!

Bildquelle: https://www.raspberrypi.com/documentation/computers/os.html#gpio-and-the-40-pin-header

Raspi Kit LEDs

Im Boardkit hat es zwei SMD-LEDs jeweils mit Vorwiderstand bestückt entweder auf Stift- oder Buchsenleiste(n). Stecken oder Verbinden Sie die Anoade einer LED auf GPIO 12 (also Pin 20) sowie die Kathode auf dem daneben liegenden Ground (über zwei Jumperkabel).

TIP

der SMD-Vorwiderstand ist jeweils an der Kathode angeschlossen und diese wiederum mit einem grünen Punkt markiert. Sie können die korrekte Polarität auch zwischen einem Ground und +3.3V auf Pin 1 testen!

Aktivieren und schalten Sie nun wie folgt gpio12:

bash
echo '12' > /sys/class/gpio/export # aktiviert den betreffenden GPIO-Port
echo 'out' > /sys/class/gpio/gpio12/direction # Datenrichtung einstellen ('in' oder 'out')
echo '1' > /sys/class/gpio/gpio12/value # gpio Port aktiv (high) setzen
cat /sys/class/gpio/gpio12/value # Zustand des gpio Ports lesen
echo '12' >/sys/class/gpio/unexport # gpio-Port inaktiv (low) setzen

Anmerkung: Die einfachen Anführungszeichen verdeutlichen bloss den Übergabewert, sind aber nicht nötig, denn die angegebenen Argumente von echo enthalten ja keine Sonderzeichen welche die Shell ansonsten umsetzen würde!

Beachten Sie, dass der Ordner /sys/class/gpio/gpio12 erst dann erscheint, wenn 12 auf den Eintrag /sys/class/gpio/export geschrieben wird - und mit dem unexport auch wieder verschwindet!

Alle Einträge unter /sys werden vom Pseudofilesystem Sysfs dynamisch (d.h. erst beim Zugriff) vom Kernel aufgrund des momentanen Zustandes des Linux Kernel Device Model erzeugt! Erst mit dem Schreiben auf export wird also ein GPIO beim Kernel Device Model registriert.

Deaktivieren sie zuletzt den gpio12 durch schreiben von 12 auf /sys/class/gpio/unexport wonach Sie sich vom Erfolg überzeugen (/sys/class/gpio/gpio12 darf danach nicht mehr vorhanden sein).

LED aus einem C-Programm 'gpio-test' ansprechen

Kopieren Sie das Projektverzeichnis hello auf gpio-test per cp -r <quellordner> <zielordner> und korrigieren Sie dann im Makefile unter gpio-test/ die Makefile-Variable APP entsprechend.

Erstellen Sie die Datei gpio-test.c worin Sie mittels mehrfachem Aufruf der C-Funktion system() die Commands ausführen, um gpio12 zu aktivieren und auf Ausgabe zu setzen. Beachten Sie dass system() gemäss dessen man-Page als Funktionsparameter einen beliebigen C-String erwartet und diesen in einer Shell (mittels /bin/sh) ausführt.

Um die LED blinken zu lassen, schalten Sie diese in einer Iteration von z.B. 10x jeweils durch weitere system()-Commands ein und wieder aus, wobei Sie jeweils mittels Funktion usleep() eine Pause von 0.2 Sekunden einlegen.

Vor dem Beenden des Programms soll dann der gpio12 wieder "unexported" werden

Wenn das Übersetzen (mit make) soweit funktioniert, sollte sich das Programm über die make install Regel auch auf's Zielsystem kopieren und hoffentlich ausführen lassen...

Boardkonfiguration und "Device Tree“

Bei fast allen SoCs kann über einen internen Pin-Multiplexer verschiedene Funktionen auf die SoC-Pads aufgeschaltet werden. Der GPIO-Mode ist also meist nur eine von etlichen Alternativen. In der obigen Darstellung der Raspberry Pi Pinleiste ist bei einigen Pins nebst GPIO-Nummer auch die primäre alternative Funktion (ALT0) in Klammern angegeben.

Alternative Function Assignments

s.a. https://datasheets.raspberrypi.org/bcm2711/bcm2711-peripherals.pdf, Kap. 5.3. Alternative Function Assignments

Abgesehen von den aufgeführten IOs der Raspi Pinleiste hat der BCM2711 SoC viele weitere IOs für alle Board-Schnittstellen (HDMI, USB, SD-Karten-Interface, PCIe, …). Diese IOs sind natürlich nicht auf den GPIO-Mode konfiguriert sondern auf den betreffenden alternativen Mode.

Diese Board-Grundeinstellung erfolgt einerseits durch den Bootloader (zumindest soweit, dass der Bootloader Dateien von der SD laden kann) andererseits über den Device Tree Blob (in unserem Fall bcm2711-rpi-4-b.dtb), welcher der Bootloader zusammen mit dem Kernels ins DRAM lädt und nach Start des Kernels von diesem interpretiert resp. in das Kernel Device Model lädt. Das Device Tree Blob wird übrigens beim Compilieren des Kernels aus so genannten "Device Tree Sourcen" generiert.

Device Tree

Unter buildroot Ordner auf: output/build/linux-custom/arch/arm/boot/dts/{bcm2711-rpi-4-b.dts,bcm2711.dtsi,bcm2835-rpi.dtsi}

An die GPIOs der Raspberry Pis dürfen nur Signale im Bereich 0V .. 3.3V angeschlossen werden, da VCCIO des SoC auf 3.3V verbunden ist.

Je nach SoC resp. konfigurierter VCCIO könnte dies auch viel tiefer sein, z.B. bloss 1.8V. Der Spannungsregler für die verschiedenen Spannungen des SoCs (und damit auch VCCIO) werden meist softwaremässig eingestellt.

Vergewissern Sie sich also bei unbekannten Boards vorgängig im Schema, Datenblatt und in der Kernel-Konfiguration betreffend der GPIO-Nummerierung und betreffend der IO-Spannungen resp. Kenn- und Grenzwerte.

  • Schliessen Sie nun auch noch den Taster an GPIO 21 gegen den daneben liegenden GND-Anschluss (also Pins 39 und 40) an.
  • Aktivieren Sie dann gpio21 wonach direction defaultmässig auf 'in' stehen sollte ...
  • Wenn Sie danach value einlesen, werden Sie vermutlich unabhängig vom Tastenzustand immer 0 einlesen und auch ein angeschlossenes Voltmeter wird immer 0V anzeigen. Weshalb wohl?

Overlays

Über die gpio Sysfs Class können zwar beliebige GPIOs aktiviert und auch die Datenrichtung konfiguriert werden, aber leider keine weitergehenden Parameter wie die Treiberstärke der Ausgänge, die Aktivierung interner Pullup- oder Pulldown-Widerstände oder alternativen Pin-Functions.

Diese weitergehenden Konfigurationen werden bei Linux üblicherweise über den Device Tree Blob vorgenommen oder falls der Bootloader es vorsieht durch eine entsprechende Bootloader-Konfiguration.

Wie auf der ersten Seite dieses Versuches unter Kap. Alternativen für den Hardware-Zugriff unter Punkt 3. erwähnt, gibt es beim Raspberry Pi OS (resp. Raspian) noch die Möglichkeit direkt aus einer Anwendung auf Peripherieregister zuzugreifen. Dieses Vorgehen ist jedoch aus erwähnten Gründen unprofessionell weshalb Buildroot diesen Weg nicht verfolgt.

Der Raspberry Pi Bootloader (welcher ja auf der GPU ausgeführt wird!) lädt bekanntlich den primären "Device Tree Blob" und kann optional auch Device Tree Overlays zu laden. Mit genügend Kenntnisse der Hardwarestruktur, könnten wir also eigenhändig eine Device Tree Overlay Source erstellen, welche den Pullup-Widerstand entsprechend konfiguriert, diese mittels dem "Device Tree Compiler" übersetzen und via Bootloader-Konfiguraitonsdatei config.txt beim Booten zuladen lassen.

Es geht aber auch einfacher, denn in der Bootloader-Konfiguraitonsdatei (config.txt) lassen sich die Pullup- und Pulldown-Widerstände der GPIOs auch direkt (durch den GPU-Booloader) konfigurieren ...

Die Datei config.txt ist bekanntlich auf der Boot-Partition, welche Sie im letzten Versuch in der Datei /etc/fstab als noauto eingetragen haben. Mounten Sie diese also manuell per mount /boot.

Weiter ist auf https://www.raspberrypi.com/documentation/computers/config_txt.html unter Kapitel GPIO Control angegeben, wie GPIOs über die config.txt Datei konfiguriert werden können! Ermitteln Sie dort wie der Pullup Widerstand auf GPIO 21 enabled wird.

Und fügen Sie am Ende der Datei config.txt ein entsprechender Kommentar sowie diesen Eintrag an.

Überzeugen Sie sich nach ausführen von reboot vom Erfolg, indem Sie wiederum gpio21 aktivieren sowie mit und ohne gedrückten Taster den 'value' einlesen!

Taster aus C-Programm gpio-test einlesen

  1. Strukturieren Sie Ihr Programm, sodass die Initialisierung beider GPIOs in einer separaten C-Funktion z.B. namens init_gpio() stattfindet.
  2. Geben Sie in der Hauptprogrammschleife zur Kontrolle während dem Blinken den Zustand des Taster-GPIOs mittels system() Funktion aus – also direkt mittels system("cat /sys/....");
  3. Testen Sie das Programm – es sollte beim Betätigen des Tasters den Tastenzustand ausgeben!
  4. Beachten Sie, dass der Taster bei Betätigung auf Ground (0V resp. „low“) verbindet, also effektiv „aktiv-low“ ist (im offenen Tasterzustand zieht ja der interne Pullup-Widerstand im SoC den Pin auf „high“). Um diese Inversion im Kernel zu berücksichtigen, können Sie in der Intitalisierung zusätzlich eine 1 auf die Pseudodatei /sys/class/gpio/..../active_low schreiben…

Unschönheiten der bisherigen Lösung

Unser Programm startet für jeden einzelnen GPIO-Zugriff per system() einen neuen Shell-Prozess, in welchen die Pseudodatei /sys/class/gpio/..../value wiederum über einen cat Command geöffnet, ausgelesen und danach gleich wieder geschlossen wird. Insbesondere das Generieren von Prozessen wie auch das Öffnen/Schliessen der (Pseudo-)Datei generiert dabei relativ viel unnötige Prozessorlast.

In unserem Szenario wäre dies noch tragbar, da die CPUs des Systems ja noch kaum beschäftigt sind, andererseits auf die Pseudodatei value ja nur in zeitlich rel. langen Abständen zugegriffen wird.

Hingegen landet der Output von system("...") direkt auf dem Standard Output, also auf der Console. In einer „echten“ Anwendung möchte man aber den Pinzustand im eigenen Programm auswerten und entsprechend darauf reagieren können. Beide Probleme werden Sie im nächsten Versuch beheben, indem Sie die Pseudodatei 'value' programmatisch öffnen und einlesen und nicht indirekt über system() über eine Shell und den cat Command.

Per Sysfs einen Hardware PWM ansteuern

Das softwaremässige Ein-Ausschalten von GPIOs lässt sich nur bis ca. 100Hz einigermassen genau und ohne viel CPU-Aufwand realisieren. Für Frequenzen im Audio-Bereich und darüber wird eine Hardware-PWM-Einheit benötigt. Die meisten Mikrocontroller und SoCs beinhalten derartige Hardware-PWMs, die SoCs der Raspis z.B. deren zwei. Damit lassen sich pulsbereiten modulierte Rechtecksignale ohne CPU-Intervention erzeugen, z.B. zwecks dimmen von LEDs oder LCD-Backlights oder bei den Raspis defaultmässig zwecks halbwegs passabler Audio-Ausgabe, denn durch Verwendung zweier PWMs werden bei den Raspis zusätzlicher Stereo Audio-Codec eingespart.

Die zwei PWM-Kanäle der Raspis können aber über ein Device Tree Overlay auch auf verschiedene Pins der Pinleiste gemappt werden.

Overlays

Eine knappe Erklärung zu allen vorhandenen Device Tree Overlays finden Sie unter dem buildroot Ordner unter: ./rpi-firmware-*/boot/overlays/README (Oder auf der Raspian Distribution direkt auf: /boot/overlay/README )

Wie auf der Pinleiste (Bild von den Raspi Pins), kann der erste PWM-Kanal u.a. auf GPIO12 gemappt werden, auf welchem wir ja die LED bereits gesteckt haben.

Typischerweise werden unter Linux derartige PWMs über einen SoC-spezifischen PWM-Treiber angesteuert, sodass man sich nicht erst mühsam mit SoC-spezifische Registeradressen herumschlagen muss.

Bei den Raspis ist dies nach Laden des Kernel Modules pwm-bcm2835 unter sysfs möglich.

Ergänzen Sie also zwecks nach Mounten von /boot fogenden Eintrag in der Datei /boot/config.txt:

bash
dtoverlay=pwm,pin=12,func=4
# Achtung: es sind keine Leerschläge zulässig!

Womit gemäss obiger Angabe das Overlay pwm.dtbo (aus boot/overlays) geladen und aufgrund der Optionen pin=12,func=4 der erste PWM-Kanal auf GPIO12 umgemappt wird. Mit einem anderen Overlay lassen sich auch beide PWMs ummappen wie im obigen README einsehbar.

Nach einem 'reboot' können Sie dann das erwähnte Raspi PWM Kernelmodule manuell laden per:

bash
modprobe pwm-bcm2835

Ein automatisches ausführen dieses Commands beim Booten wäre unter Buidroot via /etc/inittab möglich.

Sobald dieses Kernelmodule erfolgreich geladen ist, wird unter /sys/class/pwm zusätzlich der Eintrag pwmchip0 sichbar, worunter sich dann der PWM Kanal 0 auf bekannte Weise via sysfs aktivieren lässt:

bash
echo 0 > /sys/class/pwm/pwmchip0/export

Die Angaben der PWM-Periodendauer und PWM-Pulsdauer erfolgt unter Linux immer in Nanosekunden, z.B. für eine PWM-Frequenz von 100Hz und ein Tastverhältnis von 20% gedimmt per:

bash
echo 10000000 > /sys/class/pwm/pwmchip0/pwm0/period
echo 2000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable

Damit sollte die an GPIO12 angeschlossene LED entsprechend gedimmt leuchten. Um statt dessen die LED z.B mit 5Hz blinken zu lassen, muss die Periodendauer entsprechend verlängert und der Duty-Cyle z.B. auf 50% dies Wertes gesetzt werden.

Anmerkung: das Aktivieren durch Schreiben einer 1 auf den Eintrag enable ist nur mit gültigen period und duty_cycle Werten möglich!

DebugFs

Sofern in der Kernelkonfiguration das Kernel-Debugging freigeschaltet ist (was bei unserer Config bereits der Fall ist) und zudem das Pseudofilesystem debugfs auf den Mountpoint /sys/kernel/debug gemountet ist, erhält man unter /sys/kernel/debug/ für diverse Peripherieblöcke Debug-Informationen.

Kernel Config

Kernel-Debugging ist freigeschaltet. Dies zeigt ein grep CONFIG_DEBUG_FS output/build/linux-custom/.config . Falls nicht liesse sich die Linux-Kernel Configuration bei Buildroot aus den aktivem buildroot Ordner ändern per make linux-menuconfig.

Theoretisch wären für diverse Subsysteme und Peripherien weitere Debug-Quellen aktivierbar wie eine Suche nachCONFIG_DEBUG in der .config zeigt. Bedenken Sie aber dass diese teils zusätzliche CPU-Zeit erfordern...

Ein ls /sys/kernel/debug zeigt jedoch noch einen leeren Ordner sodass wir annehmen können, dass entweder das Pseudofilesytem debugfs noch nicht auf diesen Mountpoint gemountet ist oder CONFIG_DEBUG_FS in der Kernel Config nicht aktiviert ist.

Versuchen Sie deshalb debugfs temporär (bis zum nächsten reboot) zu mounten per:

bash
mount -t debugfs debugfs /sys/kernel/debug

Sofern dabei kein Fehler auftritt, sollten sich nun unter /sys/kernel/debug/ viele Einträge zeigen. Per cat /sys/kernel/debug/gpio kann z.B. der Zustand aller aktivierten GPIOs – nicht nur jene welche via sysfs aktiviert wurden sondern auch jene GPIOs, welche Kernel-intern von anderen Treibern aktiviert und verwendet werden.

Oder z.B. per cat /sys/kernel/debug/pinctrl/fe200000.gpio-pinctrl-bcm2711/pinmux-pins der Zustand der Pinmux-Einheit oder in /sys/kernel/debug/clk/clk_summary die Konfiguration der Systemclocks ...

Ein cat /sys/kernel/debug/clk/clk_summary zeigt unter osc u.a. auch die PWM Clock-Konfiguration.

Demgemäss läuft der pwm Clock auf knapp 100MHz (woraus resultiert, dass die die maximale Auflösung nicht 1ns genau ist!) und dieser Clock wiederum von einen PLL welcher aif ca. 3GHz taktet abgeleitet wird, welcher seinerseits von einem (Quarz)Oszillator getaktet wird, welcher auf 54MHz läuft.

Über wiederum andere Einträge liessen sich auch die Zustände aktiver Dateisysteme, Busse und Peripherieeinheiten einsehen. Für systemnahe Entwicklungen ist also debugfs eine wahre Fundgrube ergänzend zu den Pseudodateisystemen proc und sysfs.

Aufgabe UDP

  • Schreiben Sie einen UDP Server in C, welcher via write() das LED auf einen PWM Wert setzt.
  • Schreiben Sie einen passenden Client in Python auf dem Hostsystem, welches via UDP die Werte übermittelt.