IoT für Webentwickler: Die ersten Schritte mit PlatformIO

Von Null auf Firmware mit PlatformIO
Keine Kommentare

PlatformIO ist ein Open Source Ecosystem für die IoT-Entwicklung und hat zum Ziel, die Entwicklung für verschiedene Embedded-Boards und Entwicklungsplattformen zu erleichtern. Im ersten Teil dieses Artikels haben wir bereits einen Blick darauf geworfen. Dieses Mal wollen wir das Thema vertiefen und betrachten die ersten Schritte, um von Null auf laufende Firmware zu kommen.

Im ersten Teil meiner Artikelserie ist es schon zwischen den Zeilen erkennbar geworden: Software- bzw. Firmware-Entwicklung für Embedded Devices – in unserem Fall also Constrained Devices mit wenig Leistung – kann sehr vielschichtig sein. Vor allem im Bereich C/C++ sieht man sich als Entwickler mit Herausforderungen am unteren Teil des Entwicklungsstacks konfrontiert: Cross-Compiler und Linker, Bibliotheken, Include-Pfade sowie Build-/Flash-Werkzeuge wollen ausgewählt und installiert werden, und zwar vielfach abhängig von der unterliegenden Hardware. Eine Cross-Toolchain für einen Arduino mit Atmel-AVR-Prozessor sieht anders aus als eine für einen ARM Cortex M. Da ist es gut, wenn man ein Werkzeug hat, das sich um diese Zusammenstellung der Werkzeuge kümmert.

PlatformIO nimmt dem Entwickler genau diese Arbeit ab: Es kennt aktuell 24 Entwicklungsplattformen für Embedded (z. B. Atmel AVR, Espressif 8266 …), 15 Embedded-Frameworks (z. B. Arduino, ARM mbed …), über 470 Boards (Arduino Uno, NodeMcu ESP8266 …) und Tausende von Bibliotheken und Beispiele. Da sollte für den einfachen Einstieg etwas dabei sein.

Integriert in die Entwicklungsumgebung

PlatformIO lässt sich in verschiedenen Flavours installieren und betreiben. Zum einen hat man mit PlatformIO Core die Möglichkeit, alles auf der Kommandozeile zu machen. Das ist für Entwickler hilfreich, die sich auf Ebene der Shell wohlfühlen, aber auch für die Nutzung mit Cloud-IDEs sehr sinnvoll, aber dazu mehr in einem späteren Teil dieser Serie.

PlatformIO bringt Integrationen für verschiedene IDEs mit. Für den weiteren Teil der Serie wird Visual Studio Code von Microsoft verwendet. In der Entwicklergemeinde ist es aufgrund seiner offenen Architektur bzgl. Erweiterungen sehr beliebt. Ein Klick auf das Icon für Erweiterungen in der linken Menüzeile und die Eingabe von platformio in das Suchfeld führen mit dem ersten Treffer zur offiziellen VSCode-Erweiterung von PlatformIO. Nach einem Klick auf INSTALLIEREN ist die Erweiterung verfügbar.

Der Kern von PlatformIO basiert auf Python 2.7, das unter MacOS und Linux zum Standardrepertoire gehört. Windows-Nutzer müssen ggf. Python nachinstallieren, was aber durch den PlatformIO-Installer automatisiert erfolgt und auf der PlatformIO-Website gut dokumentiert ist. Weiterhin kann die Installation von C-Compilern wie clang unter MacOS notwendig sein.

Nach dem Start von VSCode wird man mit dem Homescreen von PlatformIO begrüßt, zumindest solang man den Checkmark SHOW AT STARTUP ausgewählt hat (Abb. 1).

Abb. 1: Alle Funktionen im PlatformIO Homescreen

Der Homescreen vereint alle Funktionalitäten, die das PlatformIO Backend anbietet: Verwalten der eigenen Accountdaten (optional), Suche nach Boards, Bibliotheken, Plattformen, Suche nach angeschlossenen Devices und Verwaltung von Projekten.

Boards und Frameworks

Für die folgenden Beispiele der Serie verwende ich das Board NodeMcu 1.0 mit einem ESP8266-Prozessor. Beim ESP8266 handelt es sich um ein sehr günstiges WiFi SoC (System on a Chip) der chinesischen Firma Espressif Systems, für den neben dem Espressif-eigenen Embedded-Framework auch ein Port des Arduino-Frameworks verfügbar ist, d. h. ein Großteil der von Arduino bekannten Sketches funktioniert auch mit diesem Board. Und dank der integrierten WiFi-Konnektivität sind IoT-Lösungen mit MQTT-, CoAP- oder HTTP-Kommunikation möglich.

Ob das eigene Board von PlatformIO unterstützt wird, wofür die Wahrscheinlichkeit mit aktuell über 470 unterstützten Boards schon hoch ist, kann man im Board-Explorer sehen (Abb. 2): Per Klick auf das BOARDS-Icon in PlatformIO HOME.

Abb. 2: Suchen und Finden des eigenen Boards

Nach Eingabe des Board-Namens findet man schnell das eigene Board. Die Tabelle zeigt die unterstützten Plattformen, Frameworks und technische Daten zum Board. Jedes Board besitzt eine Board-ID, die nach dem Aufklappen des Eintrags mit dem +-Icon sichtbar ist. Diese Board-ID wird für die Projektanlage relevant und kann in die Zwischenablage kopiert werden.

Eine ähnliche Suche nach Embedded-Plattformen ist mit einem Klick auf PLATFORMS ebenfalls vorhanden. Durch die Querverlinkung zwischen Boards, Plattformen und Frameworks kann man so überprüfen, welche Implementierungsmöglichkeiten man hat. Links führen zur Herstellerdokumentation oder zu Quellcode-Repositories.

Das erste Beispielprojekt

Im Normalfall legt man ein neues Projekt über den PlatformIO Project Wizard an. Nach einem Klick auf NEW PROJECT im Homescreen öffnet sich der Wizard und fragt die minimal notwendigen Rahmenbedingungen für die Anlage eines Projekts ab: Für welches Board soll das Projekt sein und mit welchem Embedded-Framework soll es arbeiten? Die Wahl des Boards bestimmt die zu installierende Compiler-Toolchain. Im Beispiel des ESP8266 ist das die Toolchain für die Xtensa-Prozessoren (der ESP8266 ist ein Tensilica Xtensa) mit dem sogenannten Esptool zum Flashen. Die Wahl des Embedded-Frameworks bestimmt, von wo der Frameworkcode heruntergeladen werden soll – in unserem Fall vom GitHub-Repository der Espressif-Systems. PlatformIO wird Toolchain und Frameworks automatisch in einem lokalen Home-Verzeichnis des Nutzers installieren und sowohl in der IDE als auch der Kommandozeile zur Verfügung stellen – eine gewaltige Vereinfachung und Beschleunigung, insbesondere beim Wechsel von Boards oder Plattformen.

Um möglichst schnell mit funktionsfähigem Code zu starten, wählen wir mit einem Klick auf PROJECT EXAMPLES ein Beispiel aus. PlatformIO bringt Beispiele für verschiedene Plattformen mit, der Bereich Arduino ist reichlich gefüllt (Abb. 3).

Abb. 3: Auswahl einer Beispielvorlage

Die Beispiele sind nach Plattformen sortiert. Als einfaches Starter-Projekt wählen wir in der Kategorie ESPRESSIF8266 das Beispiel „arduino-blink“ aus. Ein Klick auf IMPORT legt das Projekt an und öffnet es im VSCode-Explorer.

Für PlatformIO ist ein Projekt in einem Verzeichnis lokalisiert, in dem sich alle Sources, abhängigen Bibliotheken, Einstellungen zum gewählten Framework/Board (Environment) und der kompilierte Binärcode befinden. Passenderweise ist auch eine .gitignore-Datei enthalten, die Verzeichnisse mit Binärdateien oder lokalen IDE-Einstellungen ausklammert.

Der Quellcodesketch findet sich in src/main.cpp. Das Arduino-Framework ist in C++ realisiert und liefert für viele Funktionalitäten Klassen in einem Abstraktionsgrad, die den Einstieg erleichtern. Auch, wer noch nicht bzw. nicht viel in C/C++ programmiert hat, sollte hier gut klarkommen. Und, ja, hinter jedes C-Statement gehört ein Semikolon. Listing 1 zeigt das generierte Beispiel.

#include "Arduino.h"
void setup() {
  // initialize LED digital pin as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
  // turn the LED on (HIGH is the voltage level)
  digitalWrite(LED_BUILTIN, HIGH);
  // wait for a second
  delay(1000);
  // turn the LED off by making the voltage LOW
  digitalWrite(LED_BUILTIN, LOW);
   // wait for a second
  delay(1000);
}

Der Sketch unterteilt sich in zwei Abschnitte: Die setup()-Funktion wird einmal beim Initialisieren des Boards aufgerufen. Sie enthält dementsprechend Code, der einmal bestimmte Board-Vorbereitungen trifft. Im Beispiel wird über pinMode der I/O-Port für die auf dem Board fest verbaute LED (LED_BUILTIN) auf OUTPUT gesetzt – um die LED schalten zu können.

Die loop()-Methode hingehen wird vom Arduino-Framework laufend aufgerufen – das Framework erwartet, dass die Funktion nicht längerfristig blockiert, sondern zurückkehrt, um dann wieder aufgerufen zu werden. Im Beispiel wird mit digitalWrite die LED auf HIGH bzw. LOW gesetzt, um sie ein- und auszuschalten. Tipp: die fest verbaute LED auf dem NodeMcu ist invertiert verschaltet, HIGH schaltet sie aus, LOW ein. Dazwischen wird mit delay gewartet.

API Summit 2018

From Bad to Good – OpenID Connect/OAuth

mit Daniel Wagner (VERBUND) und Anton Kalcik (business.software.engineering)

An dieser Stelle erweitern wir den Sketch um eine Programmausgabe auf der seriellen Schnittstelle, quasi ein simplifiziertes Embeded-Logging. Die dazu passende C++-Klasse im Arduino-Framework heißt Serial und ist fest vordefiniert. Sie bietet mehrere Funktionen zur Ausgabe aus dem ersten seriellen Port, der bei den meisten Arduino-kompatiblen Boards mit dem USB-Kabel verdrahtet ist.

Listing 2 zeigt die Erweiterungen: In der setup()-Funktion wird der serielle Port mit 9 600 Bits/s initialisiert (Serial.begin), in der loop()-Funktion schicken wir jedes Mal beim Aufruf der Funktion einen Punkt.

 
void setup() {
  // initizalize Serial with 9600 bps
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // send something..
  Serial.print(".");
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
(…)

Compile, Flash, Monitor

Im nächsten Schritt geht es darum, den Code auf dem Board zum Leben zu erwecken. Die PlatformIO Extension blendet links unten in die VSCode Icon-Leiste mehrere Aktionsbuttons ein (Abb. 4). Die Namen der Funktionen lassen sich durch Hovern anzeigen, von links nach rechts: Probleme beim Kompilieren, PlatformIO Home, Build (Kompilieren/Linken, ohne zu Flashen), Upload (Build mit Flashen), Upload to Remote Device (Flashen über ein Netzwerk), Clean (entspricht einem make clean), Test, Run Task, Serial Monitor und Terminal.

Abb. 4: Aktionsbuttons in der Kommandoleiste

Mit Klick auf den Pfeil (Upload) wird das aktuelle Projekt kompiliert, zu einem Firmware-Binary gelinkt und auf das per USB angeschlossene Device hochgeladen, also dort in den Flash-Speicher geschrieben. PlatformIO erkennt die angeschlossenen Boards anhand ihrer Signatur. Sie lassen sich im Homescreen auch jederzeit mit Klick auf „Devices“ anzeigen. Unter Linux und MacOS werden die Ports mit einer Datei in /dev identifiert (z. B. /dev/cu.SLAB-USBtoUART oder /dev/ttyUSB0), unter Windows werden sie als die bekannten COM:xx-Ports verwaltet. Solange nur ein Board angeschlossen ist, braucht es keine weitere Abfrage, PlatformIO verwendet beim Uploadkommando einfach dieses eine Board.

Abbildung 5 zeigt im oberen Textfenster die Datei platformio.ini. Sie enthält die Definition der Umgebungen, der Kombinationen aus Board und Framework, zusammen mit spezifischen Einstellungen. Das Beispiel enthält mehrere Environments, für unser Beispiel entfernen wir alles außer dem Abschnitt [env:nodemcuv2]. Ein Tipp für den ESP8266 lautet an dieser Stelle, die Zeile upload_speed = 921600 ans Ende einzufügen. Damit wird der Flash-Vorgang substantiell beschleunigt.

Abb. 5: Compile und Upload

Nach Klick auf den Uploadbutton in der Iconleiste öffnet sich ein Terminalfenster und zeigt den Compile-, Link- und Uploadvorgang. Nach erfolgreichem Flashen fängt das Board gemäß Sketch an zu blinken. Wie kommen wir nun aber an unsere Debug-Ausgabe? Ein Klick auf das Stecker-Icon (SERIAL PORT MONITOR) öffnet sich ein weiteres Terminalfenster mit einer Instanz von miniterm, die sich mit dem USB-Port und den Grundeinstellungen 9600bit/s 8N1 öffnet. Man sieht, wie im Sketch programmiert, im 2-Sekunden-Takt einen Punkt auf der Ausgabe.

Das Buildsystem

PlatformIO liefert hier für seinen Nutzer eine sehr gute Abstraktion auf das darunterliegende Buildsystem. Als Entwickler muss man sich nicht mit Makefiles, Linkereinstellungen und anderem auseinandersetzen, da PlatformIO durch den Einsatz von SCons viele Buildschritte abdeckt. In einem der folgenden Artikelteile sollen die Teile unter der Haube näher beleuchtet werden.

Um von der IDE aus an die verschiedenen Funktionen des Buildsystems zu gelangen, reicht ein Klick auf das RUN-TASKS-Icon (Abb. 6). Es öffnet eine Liste von Tasks, die im Prinzip den Targets des Buildsystems entsprechen wie z. B. Clean um Buildartefakte zu löschen. Freunde der Kommandozeile können in der Iconleiste ein Terminal öffnen und mit dem Befehl pio run –target clean dasselbe erreichen.

Abb. 6: Compile und Upload

Fazit

Das hier Gezeigte reicht aus, um die ersten Schritte mit dem eigenen Embedded-Board abseits von herstellerspezifischen Entwicklungsumgebungen zu machen. PlatformIO bietet Zugriff auf zahlreiche Entwicklungsframeworks und Boards und hat mit SCons ein sehr mächtiges Buildsystem mit vielen Funktionen, auf die wir hier im weiteren Verlauf der Artikelserie eingehen möchten. Dazu zählen vor allem die für moderne, agile Entwicklung notwendige Arbeit in (verteilten) Teams, Integration in Code Repositories, Continuous-Integration- und -Delivery-Umgebungen sowie die Möglichkeit, Code automatisiert zu testen.

Entwickler Magazin

Entwickler Magazin abonnierenDieser Artikel ist im Entwickler Magazin erschienen.

Natürlich können Sie das Entwickler Magazin über den entwickler.kiosk auch digital im Browser oder auf Ihren Android- und iOS-Devices lesen. In unserem Shop ist das Entwickler Magazin ferner im Abonnement oder als Einzelheft erhältlich.

Unsere Redaktion empfiehlt:

Relevante Beiträge

X
- Gib Deinen Standort ein -
- or -