Flexibele ontwikkelomgeving voor Arduino, Espressif en veel meer

PlatformIO is een populaire open source ontwikkelomgeving voor embedded apparaten. In één omgeving maak je toepassingen voor het Arduino platform, voor de ESP8266 en ESP32, voor ARM-microcontrollers en nog veel meer. In deze workshop gaan we ermee aan de slag.

Koen Vervloesem

Als je embedded software wil ontwikkelen, dan merk je al snel dat elke hardwareproducent zijn eigen ontwikkeltools naar voren schuift. Voor Arduino is dat de Arduino IDE, Nordic Semiconductor levert een eigen versie van SEGGER Embedded Studio en STMicroelectronics zweert bij STM32CubeIDE.

Elk van deze tools heeft natuurlijk zijn voordelen, maar als je vaak met verschillende hardware werkt, dan is het complex om je met meerdere ontwikkelomgevingen vertrouwd te maken. PlatformIO (https://platformio.org) biedt een oplossing: het is een cross-platform, cross-architecture, multi-framework ontwikkelomgeving voor embedded software. Je kunt daardoor in één universele omgeving al je ontwikkelprojecten voor diverse hardware uitvoeren.

Platforms en frameworks

PlatformIO ondersteunt meer dan 800 ontwikkelbordjes en microcontrollers, waaronder de Atmel AVR-serie en Arduino bordjes, de Espressif ESP32 en ESP8266, de Microchip PIC32, de Nordic nRF5-chips, de RaspberryPi Pico en andere RP2040-gebaseerde bordjes, de STM32-familie van STMicroelectronics en de Teensy bordjes. De ondersteuning voor al deze hardware is verzameld in 35 ontwikkelplatforms.

Daarnaast ondersteunt PlatformIO ook 25 frameworks, zoals Arduino, het Espressif IoT Development Framework (IDF), FreeRTOS, Mbed, STM32Cube en Zephyr. Op die manier kun je bijvoorbeeld Arduino- of Zephyr code gewoon overnemen in PlatformIO, op verschillende directoryindelingen en configuratiebestanden na.

Visual Studio Code

PlatformIO voorziet in integraties met allerlei editors en ontwikkelomgevingen, zoals Visual Studio Code, CLion, Atom, Eclipse, Siblime Text, maar ook Emacs en Vim. De makers raden zelf Visual Studio Code (https://code.visualstudio.com) aan, de open source cross-platform ontwikkelomgeving van Microsoft. Wil je de telemetrie van Microsoft vermijden? Gebruik dan VSCodium (https://vscodium.com), dat voor de rest functioneel identiek is. Om de Visual Studio Marketplace in VSCodium te kunnen gebruiken (om PlatformIO te installeren), moet je dan wel de instructies op https://github.com/VSCodium/vscodium/blob/master/DOCS.md#howto-vscode-marketplace volgen. Mogelijk overtreed je daarmee de gebruiksvoorwaarden van de Visual Studio Marketplace.

Download en installeer Microsoft Visual Studio Code. Open het programma en open in de linkerzijbalk ‘Extensions’ (het icoontje met de vier blokjes). Zoek daar dan op ‘platformio’ en klik op ‘PlatformIO IDE’. Klik daar op ‘Install’ om de uitbreiding te installeren. Vervolgens verschijnt er links een icoontje van een alien, daarmee open je PlatformIO. Klik onder ‘PIO Home’ op ‘Open’.

Installeer PlatformIO als extensie in Microsoft Visual Studio Code.

PlatformIO Home

Je hebt nu het home-scherm van PlatformIO geopend, waarin je nieuwe projecten kunt aanmaken, je bestaande projecten kunt openen en voorbeeldprojecten kunt bekijken. Onder het icoontje ‘Home’ heb je nog andere icoontjes. Zo heb je bij ‘Projects’ toegang tot al je projecten, kun je een bestaand project van elders toevoegen of een nieuw project creëren.

Bij ‘Libraries’ kun je alle beschikbare bibliotheken doorzoeken en de instructies bekijken om ze aan je projecten toe te voegen. In het tabblad ‘Updates’ van dit scherm krijg je onmiddellijk te zien welke bibliotheken in je projecten niet meer up-to-date zijn. In ‘Boards’ zoek je eenvoudig of een specifiek ontwikkelbordje ondersteund is en klik je door naar de documentatie daarvan op de website van PlatformIO.

Bij ‘Platforms’ vind je in het eerste tabblad welke platforms je al geïnstalleerd hebt. De volgende tabbladen geven je toegang tot embedded platforms (zoals Atmel AVR, Espressif 32 en Nordic nRF52) en desktopplatforms (zoals Linux ARM, Linux x86_64 en Windows x86). In het tabblad ‘Frameworks’ doorzoek je dan weer frameworks, zoals Arduino, ESP-IDF, FreeRTOS en Zephyr.

Nieuw project

Laten we als voorbeeld een nieuw project aanmaken om de LED op een Seeeduino XIAO-bordje (met SAMD21-microcontroller) te laten knipperen. Heb je een ander bordje? Dan verloopt dit vrijwel hetzelfde. Klik in het home-scherm van PlatformIO op ‘New Project’, geef je project een naam en selecteer een van de ondersteunde bordjes. Kies bij het framework voor Arduino. Klik tot slot onderaan rechts op ‘Finish’ om het project aan te maken.

De initialisatie van het project duurt nu even, omdat PlatformIO de benodigde toolchains, frameworks en software development kits downloadt en installeert. Je krijgt ondertussen wat uitleg over de directorystructuur van een PlatformIO project en de opbouw van het projectconfiguratiebestand.

De projectwizard maakt een nieuw project voor je aan voor het gekozen bordje en framework.

Projectstructuur

Nadat de projectwizard klaar is, vind je in de ‘Explorer’ (het icoontje links bovenaan) de aangemaakte directory. Elk PlatformIO project heeft een vaste directorystructuur, met de configuratie van het project in het bestand platformio.ini. De projectwizard heeft aan de hand van de selectie die je bij het aanmaken van het nieuwe project maakte dat bestand de volgende inhoud gegeven:

[env:seeed_xiao]
platform = atmelsam
board = seeed_xiao
framework = arduino

De sectie env:seeed_xiao is een omgeving met op de regels erna variabelen die bepalen welk platform, bordje en framework PlatformIO gebruikt. In dit geval gebruiken we het Arduino framework op het Seeeduino XIAO-bordje van het Atmel SAM-platform.

Van de directory’s die de projectwizard heeft aangemaakt, is alleen src verplicht. Hierin komt je broncode, standaard een bestand main.cpp. Omdat je hebt aangegeven dat je het Arduino platform gebruikt, heeft de projectwizard in dit bestand al een include voor Arduino.h geplaatst en lege functies setup() en loop().

Arduino code

Vul dit bestand main.cpp nu aan tot de volgende code:

#include <Arduino.h>

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

Merk op: dit is exact dezelfde Arduino code als je in de Arduino IDE zou invoeren, op de eerste regel na. De Arduino IDE doet immers automatisch een include van het headerbestand Arduino.h, terwijl je dat in PlatformIO nog zelf moet doen.

Er is nog een ander verschil, maar dan in de directorystructuur. De Arduino IDE verwacht dat de naam van het bestand met je code de extensie .ino heeft en dat dit bestand zich in een directory bevindt met dezelfde naam, maar dan zonder .ino. Met andere woorden, ons voorbeeld zou je dan in Blink/Blink.ino plaatsen. PlatformIO daarentegen beschouwt de code als wat ze echt is, namelijk C++, en verwacht dan ook een bestand main.cpp, en dat in de directory src.

Als je Arduino code online vindt en je die in PlatformIO wil bouwen, moet je dus enkele wijzigingen doorvoeren: voeg een regel #include <Arduino.h> aan het begin van de code toe en geef het codebestand een nieuwe naam en plaats deze in een directory src.

Project bouwen

Bouw nu je project met de toetsencombinatie ‘Ctrl+Alt+b’, met ‘Build’ in de Project Tasks van het PlatformIO icoontje links, of met een klik op het vinkje in de toolbar onderaan. Op het einde krijg je in de terminal SUCCESS in het groen te zien.

Sluit nu je bordje via USB aan op je computer. Je uploadt de firmware met de toetsencombinatie ‘Ctrl+Alt+u’, met ‘Upload’ in de Project Tasks, of met een klik op het pijltje naar rechts in de toolbar onderaan. Als alles goed gaat, krijg je onderaan weer in het groen SUCCESS te zien en knippert de ingebouwde LED van je bordje (oranje bij de Seeeduino XIAO).

Upload je gecompileerde code naar het ontwikkelbordje.

Andere bordjes toevoegen

Je code draait nu op een Seeeduino XIAO-bordje. Maar wat als je ondersteuning voor andere bordjes wil toevoegen? Zolang die bordjes ook een Arduino core hebben en de variabele LED_BUILTIN hierin is gedefinieerd, hoef je hiervoor niets aan de code te veranderen. Je voegt gewoon een omgeving toe aan het bestand platformio.ini.

Wil je je code bijvoorbeeld op de Arduino Nano RP2040 Connect uitvoeren? Voeg dan de volgende omgeving toe:

[env:nanorp2040connect]
platform = raspberrypi
board = nanorp2040connect
framework = arduino
upload_protocol = picotool
upload_port = /dev/ttyACM0

Als je nu het project weer bouwt, bouwt PlatformIO dit voor beide omgevingen. Daarvoor downloadt het overigens eerst nog de benodigde ondersteuning voor de Arduino Nano RP2040 Connect, wat de eerste keer even duurt. Op het einde krijg je in de terminal twee keer SUCCESS te zien in het groen.

Om je code te uploaden, sluit je eerst je Arduino Nano RP2040 Connect aan. Dan klik je het best op het PlatformIO icoontje links. Je ziet nu bovenaan bij ‘Project Tasks’ de twee omgevingen die je hebt aangemaakt. Klik op de omgeving ‘nanorp2040connect’ en dan op ‘Upload’.

Meerdere omgevingen

Hetzelfde doe je om je code ook voor andere bordjes te bouwen en te uploaden. Je zoekt op https://docs.platformio.org/en/stable/boards/index.html naar de instructies voor je bordje en welke omgeving je daarvoor moet aanmaken in platformio.ini. Zo ziet de omgeving voor de Raspberry Pi Pico er hetzelfde uit als voor de Arduino Nano RP2040 Connect, maar dan met board = pico. Vergeet niet om elke omgeving een unieke naam te geven (het gedeelte na env).

Als je met meerdere omgevingen werkt, kun je dit nog stroomlijnen in het projectconfiguratiebestand. Een eerste taak die je kunt uitvoeren is de gemeenschappelijke configuratieopties in een afzonderlijke sectie zetten. In ons geval is dat het gebruik van het Arduino framework:

[env]
framework = arduino

Deze regel kun je dan uit elk van de omgevingen verwijderen. PlatformIO past immers alle opties in deze sectie toe op elke omgeving.

Je kunt ook een standaardomgeving aanmaken. Momenteel bouwt PlatformIO je code voor alle omgevingen als je op het vinkje in de toolbar onderaan klikt. Maar als je veel omgevingen toevoegt, duurt het dan telkens lang om je code te bouwen. Dat los je op met een standaardomgeving:

[platformio]
default_envs = pico

Vanaf nu bouwt PlatformIO je code alleen voor de Raspberry Pi Pico, wanneer je op het vinkje in de toolbar onderaan klikt. Het bouwen en uploaden voor je standaardomgeving kun je ook doen via de projecttaak ‘Default’ achter het PlatformIO icoontje links.

In platformio.ini definieer je eenvoudig meerdere omgevingen.

Externe bibliotheken

PlatformIO laat je ook toe om eenvoudig externe softwarebibliotheken in je code te gebruiken. Probeer dit eens uit met een voorbeeld voor de Arduino Nano RP2040 Connect. Open PIO Home en klik daar rechts op ‘Project Examples’. Selecteer het voorbeeld arduino-external-libs bij Raspberry Pi RP2040 en klik op ‘Import’ om het voorbeeld te importeren in je projecten.

Open het project en bekijk de inhoud van het projectconfiguratiebestand:

[env]
platform = raspberrypi
framework = arduino
lib_deps =
    SPI
    adafruit/Adafruit 9DOF
    arduino-libraries/Ethernet

[env:pico]
board = pico

[env:nanorp2040connect]
board = nanorp2040connect

De gebruikte bibliotheken staan hier elk op een regel vermeld bij lib_deps. De namen van die bibliotheken vind je op https://registry.platformio.org/search?t=library, waar ook voor elke bibliotheek instructies staan om deze in PlatformIO te gebruiken.

Bouw de code nu voor de omgeving nanorp2040connect en upload ze naar je Arduino Nano RP2040 Connect. Klik daarvoor op ‘Upload and Monitor’, zodat PlatformIO na het uploaden onmiddellijk de uitvoer van je programma begint te monitoren via de seriële verbinding.

Op de opdrachtregel

De belangrijkste taken in PlatformIO kun je ook op de opdrachtregel uitvoeren. Dat kan in de terminal die in Visual Studio Code geïntegreerd is. Zo bouw je op de volgende manier de standaardomgeving (of alle gedefinieerde omgevingen als er geen standaardomgeving is):

pio run

En zo bouw je een specifieke omgeving:

pio run -e seeed_xiao

Uploaden van de firmware voor de standaardomgeving doe je zo:

pio run -t upload

Ook dat kun je weer voor een specifieke omgeving doen door de optie -e en de naam van de omgeving toe te voegen.

Je kunt ook een platform installeren:

pio platform install atmelavr

Als je een bibliotheek zoekt, kan dat ook met pio:

pio lib search 9dof

Net zoals de installatie:

pio lib install "Adafruit 9DOF"

Overigens voegt PlatformIO dan de huidige versie toe aan de bibliotheken in elke omgeving van het bestand platformio.ini van je huidige project, door de volgende regel toe te voegen:

lib_deps = adafruit/Adafruit 9DOF@^1.1.4

Je kunt ook de ondersteunde bordjes van een platform opvragen:

pio boards atmelavr

Verder kun je statische code analyse met cppcheck (https://cppcheck.sourceforge.io/) uitvoeren:

pio check

Je kunt de aangesloten apparaten opvragen:

pio device list

En de seriële uitvoer van een apparaat monitoren:

pio device monitor

Elk van die opdrachten accepteert nog extra opties. Voeg de optie -h achter de opdracht toe om een overzicht daarvan te krijgen.

Zonder Visual Studio Code

Overigens kun je ook volledig op de opdrachtregel met PlatformIO werken, zonder daarvoor een grafische interface zoals Visual Studio Code te gebruiken. Installeer daarvoor PlatformIO als Python module met pip:

pip3 install platformio

Daarna kun je de pio-opdrachten, zoals hierboven uitgelegd, in je terminal gebruiken. Een project initialiseren in de huidige directory doe je zo:

pio project init

PlatformIO maakt dan de standaard directorystructuur aan.

En verder

PlatformIO komt ook met een hoop voorbeeldcode, die je vindt op https://github.com/platformio/platformio-examples. Voor elk platform dat je in PlatformIO hebt geïnstalleerd, zijn de voorbeeldprojecten eenvoudig beschikbaar in PIO Home. Als je voor het eerst met een platform in PlatformIO werkt, is het een goed idee om eerst een van de voorbeeldprojecten te bouwen en te uploaden om te verifiëren of alles goed werkt.

Verder heeft PlatformIO nog allerlei geavanceerde mogelijkheden waarop we in deze workshop niet zijn ingegaan. Zo kun je debugging en unit tests in je projecten integreren. Meer informatie daarover vind je in de documentatie. Heb je vragen, dan kun je altijd terecht op het forum (https://community.platformio.org/).