Die Laufzeitumgebung CircuitPython läuft auf so gut wie allen Kleinstrechnern und auch Mikrocontrollern, womit sie sich perfekt zum plattformübergreifenden Programmieren eignet.
Klassischerweise laufen auf Mikrocontrollern (Micro Controller Unit, MCU) wegen der extrem knappen Ressourcen, bei denen es oft auf jedes Byte ankommt, entweder Assembler- oder C/C++-Programme. Über die Jahre statteten die Hersteller ihre Produkte aber immer besser aus, und inzwischen gibt es für wenig Geld leistungsfähige Exemplare mit ausreichend Reserven auch für interpretierte Sprachen.
Hinzu kommt, dass in vielen Bereichen die typischen Anwendungen eine MCU sowieso nicht ausreizen, etwa bei der Ausbildung oder in Heimprojekten. Hier liegt es nahe, eine leichter erlernbare Skriptsprache statt C/C++ zu nutzen. So gibt es inzwischen Prozessorfamilien mit guter Python-, Lua- oder Javascript-Unterstützung (Abbildung 1).

Abbildung 1: Diverse MCUs mit Unterstützung für Skriptsprachen. Von links nach rechts: Trinket-M0, ESP32 und Espruino Pico.
Aber auch auf kleinen SBCs wie dem Pi Zero stehen genügend Haupt- und Massenspeicherplatz zur Verfügung, um darauf problemlos Skriptsprachen zu verwenden. Gerade Python glänzt hier durch unzählige fertige Module für jeden nur erdenklichen Einsatzzweck.
Wie viele andere Distributionen steckt auch Raspbian aktuell in der finalen Übergangsphase von Python 2 auf Python 3. Ersteres pflegen die Entwickler in Kürze nicht mehr, weil die parallele Unterstützung von zwei Python-Varianten zu viel Zeit erfordert. Da stellt sich die Frage, wofür ein weiterer Python-Dialekt überhaupt nötig oder sinnvoll erscheint.
Auf dem RasPi und anderen SBCs verwendet CircuitPython keinen eigenen Interpreter, sondern setzt Python 3 voraus. CircuitPython ist nämlich nicht nur ein Interpreter (auf MCUs), sondern auch eine Hardware-Abstraktionsschicht in Form einer Sammlung von Systembibliotheken. Zwar gibt es für den RasPi bereits diverse Bibliotheken, die die Hardware abstrahieren, aber diese wurden so Pi-zentrisch gestaltet, dass die entsprechenden Programme ohne Anpassungen nur auf dem RasPi laufen. CircuitPython dagegen verspricht Kompatibilität über Hardware-Grenzen hinweg.
Programmiermodelle
Das Programmiermodell jedes noch so minimalen Kleinstcomputers unterscheidet sich prinzipiell von dem eines Mikrocontrollers. Auf dem Computer läuft ein Betriebssystem, das (vereinfacht gesagt) die Hardware, Programme und Nutzer verwaltet.
Das Betriebssystem teilt die verfügbaren CPU(s) der Reihe nach allen gestarteten Programmen zu. Auf diese Weise laufen mehrere Programme quasi parallel, selbst wenn nur ein einzelner Prozessor bereitsteht. Allerdings kann sich nur auf Echtzeitbetriebssystemen ein Programm darauf verlassen, dass es zuverlässig innerhalb eines definierten Zeitraums Rechenzeit bekommt. Auf herkömmlichen Betriebssystemen muss es schlicht warten, bis es an der Reihe ist.
Bei einer MCU dagegen gibt es kein Betriebssystem: Das einzige Anwendungsprogramm kontrolliert auch alle Ressourcen. Damit lassen sich auch zeitkritische Anwendungen, die etwa innerhalb von Mikrosekunden großen Zeitfenstern Bits auf die Leitung schicken sollen, problemlos realisieren. Typische Anwendungsprogramme bestehen hier aus drei Teilen: Der erste initialisiert die Hardware der MCU, danach folgt eine Endlosschleife. Der dritte Teil kümmert sich um Interrupts, also Unterbrechungen des normalen Ablaufs, etwa durch eintreffende Daten.
Von der zuverlässigen Zuteilung von Rechenzeit und weiteren Ressourcen abgesehen gibt es dieses Programmiermodell auch bei vielen Programmen unter Raspbian. Das Auslesen von Sensoren und Wegschreiben der Daten erfolgt in regelmäßigen Intervallen. Deswegen ist es auch möglich, für Probleme dieser Art CircuitPython mit seinem einfacheren Programmiermodell einzusetzen.
Blinka
Wer seinen RasPi für CircuitPython fit machen möchte, braucht die nach dem Maskottchen von CircuitPython benannte Bibliothek Blinka. Deren Installation inklusive aller Abhängigkeiten erledigt das Skript aus Listing 1. Unter Raspbian gibt es für Python-Standardpakete auch viele Packages im normalen Repository. Das Skript nutzt jedoch den plattformübergreifenden Python-Package-Installer Pip3. Das Tool lädt die Pakete herunter, baut sie bei Bedarf aus den Quellen und legt sie im Verzeichnis /usr/lib/python3.6/dist-packages/ ab.
Listing 1
#!/bin/bash apt-get update apt-get -y install python3-pip pip3 install RPI.GPIO adafruit-blinka # SPI und I2C aktivieren (nach Bedarf) echo "dtparam=spi=on" >> /boot/config.txt echo "dtparam=i2c_arm=on" >> /boot/config.txt echo "i2c-dev" >> /etc/modules # Anwendungsbibliotheken installieren pip3 install adafruit-circuitpython-bme280
Das Skript aktiviert auch gleich die I2C- und SPI-Schnittstelle, denn das Auslesen von Sensoren ist eine der maßgeschneiderten Anwendungen für CircuitPython. Nach einem Reboot stehen die Interfaces dann für Anwendungen bereit. Haben Sie sie bereits zuvor via Raspi-config auf dem System aktiviert, dann kommentieren Sie die Zeilen 8 bis 10 in Listing 1 aus. Am Installationsskript selbst sieht man, dass Blinka intern RPI.GPIO verwendet – das gilt aber nur für den RasPi.
Neben der Blinka-Schicht benötigen Sie je nach Anwendung noch diverse Bibliotheken. Unser Beispielprogramm soll in einer Endlosschleife den Temperatur-, Feuchtigkeits- und Drucksensor BME280 [1] auslesen und die Ergebnisse auf einem altmodischen Display mit zwei Zeilen zu je 16 Zeichen ausgeben. Dafür installiert die Zeile 13 noch eine weitere CircuitPython-Bibliothek von Adafruit für den Sensor.






