• Keine Ergebnisse gefunden

GPIO-Zugriff über das Sys-Filesystem

5.3 Hardwarezugriffe

5.3.2 GPIO-Zugriff über das Sys-Filesystem

pageaddr = mmap( NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, dd, 0 );

printf("pageaddr mmap: %p\n", pageaddr );

if (pageaddr) {

ptr = (int *)pageaddr;

printf("*pageaddr: %d\n", *ptr );

*ptr = 55; /* access to the mapped area */

}

munmap( pageaddr, 4096 );

return 0;

}

Um einen eingeblendeten Speicherbereich wieder freizugeben, ruft die Applikation int munmap(void *addr, size_t length) auf.

5.3.2 GPIO-Zugriff über das Sys-Filesystem

Einige Gerätetreiber ermöglichen den Zugriff auf die Hardware über das Sys-Filesystem. Das Sys-Filesystem (sysfs) ist eine virtuelle Verzeich-nis- und Dateistruktur. Virtuell bedeutet, dass Verzeichnisse und vor al-lem der Inhalt von Dateien nicht auf einer Festplatte (beziehungsweise allgemein gesprochen auf einem Hintergrundspeicher) liegen, sondern vom Betriebssystemkern dynamisch erst beim Zugriff erzeugt werden.

Insbesondere das GPIO-Subsystem des Linux-Kernels unterstützt standardmäßig das Sys-Filesystem. Daher wird dieses im Folgenden he-rangezogen, um Interfaces und Zugriffe vorzustellen.

GPIOs (General Purpose Input Output) sind Ein-/Ausgabeleitungen an denen Hardwarekomponenten, die im einfachsten Fall über Pins mit Schalter, Taster und Leuchtdioden verbunden werden. Diese GPIO-Pins sind häufig flexibel konfigurierbar: Als Ausgabeleitung eingesetzt, liegt programmgesteuert Spannung, typischerweise 3,3 V, oder 5 V, oder eben keine Spannung, also 0 V, an. Als Eingabe konfiguriert, über-nimmt der Prozessor nach Aufforderung, falls Spannung anliegt, eine

»1«, ansonsten eine »0«.

Auch der Raspberry Pi hat derartige GPIOs. Die 26-polige Stecker-leiste des preiswerten Kleincomputers stellt dazu insgesamt 17 von 54 Ein-/Ausgabeleitungen, die sogenannten GPIOs (General Purpose Input Output), zur Verfügung (siehe Abb. 5-2).

GPIO2

Falls Sie eine gelbe, grüne oder rote LED, einen Widerstand (um die 300 ) und Kabel parat haben, können Sie den Zugriff auf GPIOs leicht testen. Dazu bauen Sie wie in Abbildung 5-3 dargestellt eine Schaltung aus der LED und dem Widerstand auf.

Abb. 5-2

5.3 Hardwarezugriffe 163

Beide werden in Reihe geschaltet und mit der Steckerleiste auf dem Raspberry Pi verbunden. Die Seite der Reihenschaltung, an der die Ka-thode der LED (die Seite mit dem kürzeren Beinchen beziehungsweise mit der abgeflachten Unterkante) liegt, wird mit GND (Pin 6) verbun-den; die andere Seite mit GPIO4 (Pin 7). Hilfreich für den Aufbau ist ein Breadboard, in das die Bauteile gesteckt werden können. Bei einem Breadboard sind die Löcher vertikal miteinander jeweils einmal ober-halb und einmal unterober-halb verbunden. Hintergrundinformationen zu den Bauteilen und der Schaltung finden Sie übrigens in [Grant2012].

Über das Sys-Filesystem erfolgt anschließend der Test der Schaltung.

Um auf eine GPIO-Leitung zugreifen zu können, muss diese im ersten Schritt reserviert und im zweiten Schritt konfiguriert werden. Danach erst können die eigentlichen Zugriffe — entweder ausgeben oder einle-sen — durchgeführt werden. Sollte die GPIO-Leitung nicht mehr benö-tigt werden, wird sie wieder freigegeben (siehe Abb. 6-2).

Die GPIO-Konfiguration findet sich im Verzeichnisbaum unter /sys/

class/gpio/. Um jetzt eine Leitung, beispielsweise die Leitung GPIO4, benutzen zu können, muss sie reserviert werden. Zur Reservierung wird die Nummer der GPIO-Leitung (aus Sicht der CPU, also nicht die Num-mer des Pins an der Doppelstiftleiste) per echo in die Datei /sys/class/

gpio/export geschrieben. Dazu sind allerdings Root-Rechte notwendig.

Daraufhin legt der Kernel ein neues Verzeichnis für GPIO4 (gpio4/) an.

Beispiel 5-11 zeigt die dazu notwendigen Befehle.

# cd /sys/class/gpio/

# ls

export gpiochip0 unexport

# echo "4" >export

# ls

export gpio4 gpiochip0 unexport

# cd gpio4

# ls

active_low direction edge power subsystem uevent value

In dem neuen Verzeichnis gpio4/ gibt es eine Reihe von Dateien, unter anderem auch direction, über die mit den Schlüsselwörtern »out« und

»in« konfiguriert wird, ob es sich um eine Ausgabe- oder eine Eingabe-leitung handelt. Mit einem echo "1" >/sys/class/gpio/gpio4/value wird schließlich die Spannung auf 3,3 V gesetzt. Damit leuchtet die LED. Ei-ne »0« in die gleiche Datei geschrieben, stellt eiEi-ne Spannung von 0 V ein und schaltet die LED wieder aus. In Beispiel 5-12 finden Sie ein Skript, das aus der LED ein Blinklicht macht. Dazu wird in einer Schleife die LED eingeschaltet, eine Sekunde geschlafen, ausgeschaltet und noch-mals eine Sekunde geschlafen. Der Befehl trap dient übrigens dazu, beim

Beispiel 5-11 Kommandos auf dem Raspberry Pi zur Reservierung von GPIO4

Abbrechen des Skripts beispielsweise per [Strg][c] den Pin wieder freizu-geben.

#!/bin/bash

trap "echo \"4\" >/sys/class/gpio/unexport" EXIT echo "4" >/sys/class/gpio/export

echo "out" >/sys/class/gpio/gpio4/direction while true

do

echo "1" >/sys/class/gpio/gpio4/value sleep 1

echo "0" >/sys/class/gpio/gpio4/value sleep 1

done

Beispiel 5-12 Skriptgesteuerter Zugriff auf GPIOs

5.3 Hardwarezugriffe 165

6 Gerätetreiber selbst gemacht

Im Bereich eingebetteter Systeme ist es üblich, Sensoren und Aktoren mit dem eigentlichen Rechnerboard, beispielsweise dem Raspberry Pi, über GPIOs, I2C, SPI oder USB zu verbinden. Der Zugriff auf diese Hardware kann zwar wie beschrieben aus dem Userland erfolgen, was aber zwei Nachteile mit sich bringt. Erstens ist der Zugriff sehr langsam und zweitens beeinträchtigt die Lösung die Betriebssicherheit (Safety).

Schließlich ist eine der Aufgaben und Philosophien eines Betriebssys-tems, Hardwarezugriffe nur im Kernel zuzulassen. In den meisten Fällen ist es also sinnvoll, einen Gerätetreiber als Erweiterung des Linux-Kern-els zu schreiben.

Ein Grund, warum häufig die Userland-Lösung einem Gerätetreiber vorgezogen wird, besteht in fehlendem Know-how bezüglich Kernelpro-grammierung und dem dafür erwarteten Aufwand. Dabei sind einfache Treiber, die zunächst keine besonderen Funktionalitäten aufweisen, leicht zu erstellen. Allerdings zeigt die Erfahrung, dass die Hardwarezu-griffe immer komplexer werden und damit auch der Code des Geräte-treibers. Für eine professionelle Entwicklung eines zuverlässigen und si-cheren Systems geht aber letztlich kein Weg an einem Gerätetreiber vor-bei. Im Folgenden finden Sie eine Einführung in die Gerätetreiberpro-grammierung, mehr Details und Hintergrundinfos finden Sie in [Qu-Ku2011b].

167

6.1 Einführung in die Treiberprogrammierung

Um einen einfachen Gerätetreiber zu schreiben, der ein virtuelles Gerät be-dient, sind die folgenden Schritte notwendig:

1. Sicherstellen, dass der passende Kernelquellcode installiert und konfigu-riert ist.

2. Verzeichnis für den Treiberquellcode anlegen (hier ~/embedded/driver/

hello/).

3. In das Verzeichnis wechseln und den Quellcode erstellen. Hierzu gehö-ren insbesondere die wesentlichen Treiberfunktionen wie mod_init(), mod_exit(), driver_read() und driver_write(). Außerdem ist die Da-tenstruktur struct file_operations wichtig, die die Adressen der Trei-berfunktionen aufnimmt.

4. Im Quellcodeverzeichnis des Gerätetreibers ein Makefile erstellen.

5. Den Treiber durch Aufruf von make generieren.

Soll der Treiber auf dem Entwicklungsrechner für das Target (Rasp-berry Pi) generiert werden, ist Make mit gesetzten Umgebungsvariablen KDIR, CROSS_COMPILE und ARCH zu starten.

6. Falls es sich um eine Cross-Entwicklung handelt, wird der generierte Treiber auf das Target übertragen (beispielsweise per ssh).

7. Der Treiber wird per insmod in den Kernel geladen. Das per Buildroot ge-nerierte System sollte die Programme insmod, rmmod, lsmod und modprobe generiert haben. Ansonsten sind diese in der Busybox-Konfiguration un-ter [Linux Module Utilities] auszuwählen und das System neu zu generie-ren.

8. Auf dem Target kann es notwendig sein, per mknod eine Gerätedatei an-zulegen.

9. Der Treiber kann getestet werden. Vielfach ist das per cat und echo mög-lich.

Ein Gerätetreiber ist ein Satz von Funktionen, der den Zugriff auf die Hardware steuert. Die Hardware muss dabei nicht immer physisch exis-tent sein, ein Treiber kann dem Anwender durchaus auch eine virtuelle Hardware bereitstellen. Gerätetreiber sind für den eigentlichen Zugriff auf Hardware notwendig.

Um einen Gerätetreiber schreiben zu können, werden vorkonfigu-rierte beziehungsweise kompilierte Kernelquellen benötigt. Dieser Vor-gang ist in Abschnitt 3.3.1 beschrieben.