Ein-/Ausgänge steuern ohne piControl

Denn die Ein- und Ausgänge sind in die Industrial I/O (iio) und General Purpose I/O (gpio) Subsysteme im Linux-Kernel eingeklinkt und können daher auch direkt manipuliert werden. Das gelingt aus Deiner Lieblingsprogrammiersprache ebenso wie direkt auf der Kommandozeile.

Allerdings verzichtest Du bei einer Direktansteuerung auf die Möglichkeiten, die das Prozessabbild bietet:

  • Als Abstraktionsschicht gewährleistet das Prozessabbild, dass verschiedene Systeme, wie z. B. Steuerungssoftware, HMI-Schnittstellen, Cloud-Anbindungen oder Feldbus-Daemons, problemlos miteinander funktionieren.
  • Durch das Prozessabbild kannst Du Deine Software auch auf anderen Geräten aus der Revolution Pi Familie verwenden.

Aber auch eine Direktansteuerung hat bestimmte Vorteile:

  • Eine Direktansteuerung kann für schnelles Testen und Prototyping sinnvoll sein.
  • Du kannst damit Spezialanforderungen umsetzen, die piControl nicht abdeckt.
  • Du kannst damit eine vorhandene Software auf dem RevPi Compact einsetzen, die bereits die iio- und gpio-Schnittstellen des Kernels verwendet.

Die Wahl zwischen piControl und Direktansteuerung sollte wohlüberlegt sein. Mit diesen beiden Möglichkeiten hast Du auf jeden Fall für jeden Job das richtige Werkzeug zur Hand.

piControl deaktivieren

Damit Dir piControl bei der Direktansteuerung nicht ins Gehege kommt, solltest du es als erstes deaktivieren.

  • Gib dazu folgendes Kommando in die Kommandozeile ein: “sudo rmmod piControl”.
  • Um piControl wieder zu aktivieren, musst Du folgendes Kommando in die Kommandozeile eingeben: “sudo modprobe piControl”.

Nach einem Reboot wird piControl  automatisch wieder gestartet. Wenn Du das nicht möchtest, musst Du piControl dauerhaft deaktivieren:

  • Öffne  “/etc/modules” mit Nano.
  • Schreibe das Zeichen “#” vor die Zeile für piControl. Damit kommentierst Du piControl aus.

Analoge Ein-/Ausgänge steuern

Die beiden analogen Ausgänge Deines RevPi Compact werden von einem 8-Bit-DAC (Digital/Analog Converter) gesteuert.

Die acht analogen Eingänge werden mittels eines Multiplexers von einem 21-Bit-ADC (Analog/Digital Converter) gesteuert.

Der Direktzugriff erfolgt über das Verzeichnis /sys/bus/iio/devices. Dort findest Du drei nummerierte Unterverzeichnisse:

  • Eines für den DAC,
  • eines für den ADC mit Multiplexer und
  • eines für den ADC ohne Multiplexer. Dieses kannst du ignorieren.

Hinweis: die Nummerierung der Verzeichnisse kann sich mit jedem Bootvorgang ändern! Du musst daher zunächst anhand der Datei “name” in jedem Unterverzeichnis herausfinden, welches Unterverzeichnis zu welchem Converter gehört.

  • Den DAC erkennst Du an der Bezeichnung “dac082s085″.
  • Den ADC mit Multiplexer erkennst Du an der Bezeichnung “ain_muxed”.

Innerhalb der Verzeichnisse befinden sich Dateien mit der Endung “raw”. Über diese Dateien kannst Du den Rohwert des DAC schreiben bzw. den des ADC lesen.

Im Verzeichnis für den ADC mit Multiplexer gibt es insgesamt 16 Dateien. Die Dateien 0 bis 7 sind für die Spannungsmessung. Die Dateien 8 bis 15 sind für die RTD-Messung.

$ cd /sys/bus/iio/devices
$ cat iio:device0/name
dac082s085
$ echo 127 > iio:device0/out_voltage0_raw
$ cat iio:device2/name
ain_muxed
$ cat iio:device2/in_voltage0_raw
-1048601

Der DAC verwendet eine Auflösung von 8 Bit und eine Referenzspannung von 10 Volt, die Formel zur Umrechnung lautet also: Rohwert = (gewünschte Spannung in mV << 8) / 10000.

Der ADC verwendet eine Auflösung von 21 Bit, eine Referenzspannung von 12,5 Volt und ist um ein Offset von 6,25 Volt verschoben, ergo: gemessene Spannung in mV = ((Rohwert * 12500) >> 21) + 6250.

Für die RTD-Messung musst du die gemessene Spannung in eine Temperatur umrechnen. Bediene dich dazu gerne im piControl Quelltext.

Beim Auslesen des ADC musst Du eine Latenzzeit von ca. 85 Millisekunden fürs Umschalten des Multiplexers und Durchführen der Messung einkalkulieren.

Digitale Ein-/Ausgänge steuern

Um direkt auf die digitalen Ein- und Ausgänge zuzugreifen, hast Du zwei verschiedene Möglichkeiten:

  • Über “/sys/class/gpio”, wie bei den analogen Ein-/Ausgängen, oder
  • über  Character Devices “/dev/gpiochip_din” und “/dev/gpiochip_dout”.

Der Zugriff über die Character Devices erfordert die Verwendung von ioctl()-Aufrufen und ist dadurch etwas komplizierter. Die API befindet sich in <linux/gpio.h> und Beispielcode findest du im tools-Verzeichnis des Linux-Kernels. Es gibt eine Library namens libgpiod mit C, C++ und Python-Bindings, die einen komfortableren Zugriff als über die rohe Kernel-API gewährt. Wenn Du in einer dieser Sprachen entwickelst, ist das der empfehlenswerteste Zugriffsweg. Als Schnelleinstieg kannst Du Dir die Vortragsfolien vom Autor der Library ansehen. Beginnend mit dem Release “buster” ist die Library auch als Debian-Paket installierbar.

Der Zugriff über /sys/class/gpio ist einfacher und Du kannst ihn von der Kommandozeile aus ausführen. Dieser Zugriff wird von den Kernel-Entwicklern aber als veraltet angesehen und soll nach 2020 entfernt werden.

Dennoch wird er von weit verbreiteten Tools wie /usr/bin/gpio aus dem wiringpi Paket verwendet und soll daher auch hier gezeigt werden:

  • Öffne das Verzeichnis “/sys/class/gpio”.

Du findest hier mehrere Unterverzeichnisse.

Da sich die Nummerierung der Unterverzeichnisse mit jedem Bootvorgang ändert, musst Du zunächst ermitteln, welches Unterverzeichnis zu den digitalen Eingängen und welches zu den digitalen Ausgängen gehört.

  • Öffne dazu die Datei “label” in jedem Unterverzeichnis.
  • Die digitalen Eingänge erkennst Du an der Bezeichnung “max3191x”.
  • Die digitalen Ausgänge erkennst Du an der Bezeichnung “74hc595”.

Als nächstes musst Du den gewünschten Ein-/Ausgang exportieren.

  • Addiere zur Nummer des Unterverzeichnisses die Nummer des Ein-/Ausgangs.
  • Schreibe das Ergebnis nach /sys/class/gpio/export.

Beispiel: Du möchtest auf den digitalen Eingang 5 zugreifen und  das Unterverzeichnis für die digitalen Eingänge heißt “gpiochip496”.

  • Schreibe die Zahl 501 nach /sys/class/gpio/export.

Damit hast du das neue Unterverzeichnis /sys/class/gpio501 kreiert und kannst durch Schreiben oder Lesen der darin befindlichen Datei “value” den Ein-/Ausgang steuern.

$ cd /sys/class/gpio
$ cat gpiochip496/label
max31913
$ echo 501 > export
$ cat gpio501/value
0
$ cat gpiochip504/label 
74hc595
$ echo 504 > export
$ while : ; do echo 1 > gpio504/value ; done
^C

Der digitale Eingangsbaustein erlaubt durch eine CRC-Prüfsumme die Erkennung von elektromagnetischen Störungen. Außerdem kann er Überhitzung detektieren. In einem solchen Fehlerzustand erhältst du beim Auslesen einen “I/O error”. In /var/log/kern.log wird dann eine “CRC error”- oder “overtemperature”-Meldung protokolliert. 

Die digitalen Ausgänge sind mit einem Watchdog ausgestattet. Ein Watchdog ist eine Komponente, die in einem System die Funktion anderer Komponenten überwacht. In diesem Fall müssen die digitalen Ausgänge mindestens alle 9 Millisekunden neu geschrieben werden. Geschieht das nicht, setzt der Watchdog die digitalen Ausgänge auf “low”, um einen sicheren Zustand herzustellen! Denn das System könnte ja abgestürzt sein.

Der Watchdog kann aber auch ungewollt zuschlagen, wenn das System stark ausgelastet ist. Denn dann kommt Dein Programm nicht immer rechtzeitig dazu, die Ausgänge zu beschreiben. Der Watchdog wird zwar sofort wieder inaktiv, sobald die Ausgänge erneut beschrieben werden. Trotzdem kommt es kurzzeitig zu einem “glitch”, bei dem ein Ausgang eigentlich “high” sein müsste, aber durch den Watchdog kurzzeitig “low” wird. Solche “glitches” kannst Du verhindern, indem Du Deinem Programm eine Realtime-Priorität gibst, z.B. indem Du beim Starten des Programms den Befehl “chrt -f 48” voranstellst.

LEDs steuern

Im Verzeichnis /sys/class/leds findest Du folgende Unterverzeichnisse

  • a1_green”,
  • “a1_red”,
  • “a2_green”,
  • “a2_red”
  • “power_red”.

In jedem dieser Unterverzeichnisse liegt eine Datei “brightness”. Diese Datei bestimmt das Verhalten der jeweiligen LED.

Du kannst die LEDs auf der Vorderseite deines RevPi Compact direkt ansteuern, indem Du in diese Datei schreibst.

Der Wert “0”schaltet die LED aus.

Ein Wert, der  größer als Null ist, schaltet die LED ein.

$ cd /sys/class/leds
$ echo 1 > a1_green/brightness
$ echo 0 > a1_green/brightness

Du siehst, der Zugriff auf die Ein- und Ausgänge ist kinderleicht. Lass uns im Forum wissen, was du damit Spannendes gebaut hast.