Über Pulsweitenmodulation lassen sich mit Single-Board-Computern Blinklichter, gedimmte LEDs und variable Motordrehzahlen unkompliziert realisieren – vorausgesetzt, der Kernel ist richtig konfiguriert.
Der Raspberry Pi gehört neben dem Arduino und dem ESP32 zu den Lieblingsobjekten jedes Elektronik-Makers. Kein Wunder, lässt sich doch bei dem preiswerten Linux-Rechner über die Steckerleiste mit wenig Aufwand Hardware ankoppeln und vor allem mit ein paar Zeilen Python ansprechen. Mal eben eine LED anschalten oder einen Sensor ankoppeln? Kein Problem.
An den Pins der Steckerleiste lässt sich per Software durch das Schreiben einer 1 beziehungsweise 0 eine Spannung von 3,3 respektive 0 Volt anlegen. Zwar liefern die Ausgänge nur begrenzt Strom, aber mit etwas zwischengeschalteter Hardware (H-Brücke) lassen sich auch Motoren betreiben. Schreibt die Software eine 1 auf den zum Ausgang gehörenden GPIO-Pin, liegen 3,3 Volt an, und der Motor dreht sich. Seine Drehzahl richtet sich nach der angelegten Spannung und der Bauform. Sobald man eine 0 auf den Pin schreibt, sinkt die Spannung auf 0 Volt; der Motor steht. Motor an, Motor aus – da muss doch mehr gehen?
Betreibt man den Motor gepulst, indem man ihn an- und, bevor er auf volle Drehzahl kommt, wieder abschaltet und dieses Spiel in schneller Folge wiederholt, dreht sich der Motor aufgrund der Trägheit insgesamt langsamer. Die Drehzahl hängt von der Häufigkeit der Schaltvorgänge ab sowie vom Verhältnis der Zeitspannen, in denen man den Motor mit Strom versorgt und abschaltet.
Diese Art, einen Ausgang gepulst zu betreiben, nennt sich konsequenterweise Pulsweitenmodulation (Pulse Width Modulation) oder kurz PWM (Abbildung 1). Verschaltet man anstelle des Motors eine LED am Ausgang und betreibt ihn pulsweitenmoduliert mit einem Tastgrad von 50 Prozent, leuchtet die LED (etwa) nur noch halb so hell. Eine sehr niedrige Frequenz mit einer langen Periodendauer erzeugt dagegen ein klassisches Blinklicht.
Per Software erzeugt man ein pulsweitenmoduliertes Signal einfach mithilfe einer Schleife, in der der Ausgang den Zustand ständig wechselt und zwischendurch etwas pausiert (siehe Kasten “Softwaregesteuerte PWM”). Die damit erzielbare Genauigkeit lässt allerdings zu wünschen übrig, der Code muss parallel zur eigentlichen Applikation arbeiten und verbraucht zudem noch Rechenzeit.
Softwaregesteuerte PWM
Der Raspberry Pi bringt zwei in Hardware realisierte PWM-Kanäle mit, die sich auf zwei der vier GPIO-Pins 12, 13, 18 und 19 konfigurieren lassen. Setzt man die PWM per Software um, kann man auch andere Pins nutzen. Das Struktogramm in Abbildung 2 zeigt das prinzipielle Vorgehen: In einer Schleife erzeugt der Code den Impuls durch Ausgabe einer 1 auf den gewünschten GPIO-Pin, danach schläft er für die Impulsdauer (Pulsweite). Anschließend schaltet er durch Ausgabe einer 0 die Spannung am Ausgang auf 0 Volt und pausiert dann noch einmal bis zum Ende der Periodendauer.
Sieht man die PWM als Teil eines Ganzen, beispielsweise als Komponente einer Regelung, wird klar, dass dieser Part parallel zum Berechnen der Regelparameter laufen muss. Das Anpassen von Pulsweite oder Frequenz erfordert zudem eine Interprozesskommunikation, im einfachsten Fall über globale Variablen. Das macht die zunächst theoretisch einfache Realisierung in der Praxis erheblich komplizierter als eine Lösung via Hardware.
Hinzu kommt ein weiterer wesentlicher Nachteil: Während bei einer per Hardware gesteuerten PWM die Genauigkeit im unteren Mikrosekundenbereich liegt, muss man auf Softwareebene mit Abweichungen einzelner Perioden im Millisekundenbereich rechnen. Selbst das klappt nur mithilfe tiefer Griffe in die Trickkiste der Echtzeitprogrammierung. Obendrein frisst die softwareseitige PWM der CPU Rechenzeit weg. Bei kurzen Periodendauern (sprich: hohen Frequenzen) macht sich das signifikant bemerkbar und darf keinesfalls vernachlässigt werden.
Kollision mit Audio
Eine so simple Aufgabe wie das Erzeugen eines gepulsten Signals lässt sich viel besser durch Hardware realisieren, weswegen moderne Controller entsprechende Funktionsblöcke gleich mitbringen. Der Raspberry Pi verfügt über zwei PWM-Kanäle, die sich dank Linux und eines PWM-Subsystems im Kernel einfach über das Sys-Filesystem ansteuern lassen.
Allerdings gelingt standardmäßig der Zugriff auf diese Hardware-PWM nicht: Der auf dem Raspberry Pi verbaute Broadcom-Controller bietet zwar eine unglaubliche Funktionsvielfalt, doch kann der Anwender diese Möglichkeiten nicht unbedingt alle zeitgleich nutzen. Die angesprochene Hardware-PWM beispielsweise kollidiert mit der internen Audioverarbeitung, die in der Standardkonfiguration den Vorzug genießt.
Hilfe vom Bootloader
Um die Hardware-PWM zu nutzen, steht folglich am Anfang das Aktivieren und Konfigurieren durch den Bootloader. Dazu erweitert man auf einem aktuellen Raspbian die in der Boot-Partition befindliche Datei config.txt um die Zeile dtoverlay=pwm. Kommt ein Kernel mit einer Version kleiner als 4.9 zum Einsatz, lautet die Zeile stattdessen dtoverlay=pwm-with-clk. Weitere Einzelheiten nennt der Kasten “Boot-Konfiguration für PWM”.
Boot-Konfiguration für PWM
Raspberry Pi A und B, RasPi 2 und 3, Pi Zero, Raspberry Pi 4, Compute- und Industrie-Module – die Hardware der einzelnen Raspberry-Pi-Modelle unterscheidet sich teils recht grundlegend. Um die Hardware trotz aller Unterschiede weitestgehend mit nur einem Kernel zu bedienen, lagerten die Linux-Entwickler schon vor Jahren die eigentliche Hardwarebeschreibung (Adressen, Interrupts, DMA-Kanäle) in sogenannte Devicetrees aus und trennten sie so vom Kernel-Code. Beim Booten legt der Bootloader den für den jeweiligen Kernel relevanten Devicetree in den Hauptspeicher und übergibt dem Kernel beim Starten dessen Adresse. Devicetrees liegen mittlerweile modular in Form sogenannter Overlays vor, der Bootloader zeichnet für das Laden der benötigten Overlays verantwortlich.
Auf dem Raspberry Pi finden sich in der Datei /boot/overlays/README die Beschreibung der Overlays und deren Konfigurationsparameter. Demnach konfiguriert das Overlay pwm einen einzelnen PWM-Kanal, während pwm-2chan die Konfiguration von zwei Kanälen abhandelt. Dabei kann der Anwender die einzelnen Kanäle auf unterschiedliche GPIOs legen (Abbildung 3): PWM0 lässt sich im Wesentlichen auf GPIO 12 (auf der Steckerleiste Pin 32) oder GPIO 18 (Pin 12) ausgeben, PWM1 auf GPIO 13 (Pin 33) oder GPIO 19 (Pin 35). Wer Audio und PWM zusammen einsetzen will, stößt dabei auf Probleme: Pin 18 wird vom I2S-Audio-Interface verwendet, der analoge Audioausgang benötigt beide PWM-Kanäle.
Um die Pulsweitenmodulation zu konfigurieren, stehen die Overlay-Parameter pin, func, pin2 und func2 zur Verfügung. Die Tabelle “Konfigurationszeile zum Aktivieren von PWM” zeigt die Konfigurationszeile, die man der Datei /boot/config.txt anhängen muss, um die jeweiligen PWMs freizugeben und mit den gewünschten GPIO-Pins zu verknüpfen.

Abbildung 3: Via Hardware generierte PWM-Signale lassen sich beim Raspberry Pi an zwei von vier Pins ableiten.
|
PWM 0 |
PWM 0 |
PWM 1 |
PWM 1 |
|
|---|---|---|---|---|
|
GPIO 12 |
GPIO 18 |
GPIO 13 |
GPIO 19 |
Konfiguration |
|
X |
|
|
|
|
|
|
X |
|
|
|
|
|
|
X |
|
|
|
|
|
|
X |
|
|
X |
|
X |
|
|
|
X |
|
|
X |
|
|
|
X |
X |
|
|
|
|
X |
|
X |
|
Bootet man mit dieser Konfiguration, lädt der Raspberry Pi automatisch den Treiber pwm_bcm2835 und füttert ihn mit den notwendigen Hardwareadressen. Im Verzeichnis /sys/class/pwm/ gibt es jetzt ein neues Unterverzeichnis pwmchip0/ und darin unter anderem die virtuellen Dateien export, npwm und unexport.
Die Datei npwm gibt die Anzahl der PWM-Kanäle zurück. Im Fall des Raspberry Pi sind das zwei, von denen sich jedoch, abhängig von der beim Booten aktivierten Hardware-Konfiguration, eventuell nur einer nutzen lässt.








