Alea jacta est

Wie Cäsar bereits wusste, werden wichtige Entscheidungen per Würfel gefällt. Aus diesem Grund soll ein Würfel mit dem ESP-Board zum Buch implementiert werden.

Grundsätzlich stehen zwei Taster und eine LED-Matrix für die Benutzerschnittstelle zur Verfügung. Ein Druck auf den linken Taster soll den Würfel starten, worauf die LED-Matrix “rauschen” und nach einer Sekunde eine zufällige Zahl darstellen soll. Das Rauschen können verschiedene Zahlen sein, die immer langsamer werden bis eine Zahl stehenbleibt oder zufälliges Rauschen, das in eine Zahl “morpht” – oder sonst was cooooles. Puristen werden die Seiten des Würfels modellieren und implementieren, dass nur benachbarte Seiten erscheinen (die 1 liegt ja gegenüber der 6 und kann so nicht unmittelbar folgen) 🙂

Für den Cheat-Mode drückt man kurz den rechten Taster. Dann startet man normal mit linkem Taster und erhält eine 6.

Als Quelle für den Zufall soll das RNG-Peripheriemodul des ESP32-C3 verwendet werden. Auf die Tastendrucke soll per Interrupt reagiert werden.

DEW – Digital Egg Watch :-)

Implementiere eine digitale Eieruhr. Beim Einschalten soll die Uhr zur Eingabe der Kochzeit auffordern. Stellen Sie dann mit den Tastern eine Zeit zwischen 1 und 15 Minuten (beides inklusive) ein.

Nach dem Start der Uhr soll flächug rot angezeigt werden, dass das Kochen begonnen hat. Die Farbe soll in der Zielzeit langsam grün werden. Bei Erreichen der Zielzeit soll die Uhr grün blinken.

Um das System für die Kochenden einfacher zu machen, sollen die verbleibenden Minuten in einer LED-Zeile binär, die verbleibenden Sekunden in einer LED-Zeile binär angezeigt werden. Ja, das macht es dann wirklich gut bedienbar! 🙂

Für das User Interface stehen zwei Taster und die 25 LEDs zur Verfügung.

Nun denn, auf die Plätzchen, fertig, backt!

Espressif IDE <-> Visual Studio Code Plugin

Espressif stellt mit dem IDF die Espressif IDE zur Verfügung. Hierbei handelt es sich um eine Eclipse IDE mit vorinstalliertem Espressif Plugin. Dieses kann in einer (frei verfügbaren) Eclipse Installation auch per Market Place nachinstalliert werden.

Im ebenso freien Editor Visual Studio Code (VS Code) von Microsoft lässt sich ebenso ein Espressif Plugin (hier Extension genannt) installieren.

Im Buch habe ich in der Einleitung die Espressif IDE aufgrund der damaligen reiferen Version des Plugins. Die Beispiele habe ich aber auch alle in VS Code getestet. Derzeit verwende ich (wegen des Indexer-Problems) für meine Projekte eher VS Code.

Vor-/Nachteile Eclipse

  • (+) Vollwertige IDE, die auch von vielen anderen Herstellern verwendet wird (z.B. Texas Instruments).
  • (+) Debugger funktioniert hervorragend
  • (-) Der Indexer funktioniert nicht zuverlässig: es kann vorkommen, dass funktionsfähiger Code im Editor als fehlerhaft markiert wird. Ein Rebuild des Indexers behebt das Problem leider nicht zuverlässig.

Vor-/Nachteile VS Code

  • (+) Zunehmend verbreitet und beliebt, vor allem mit dunkler Skin
  • (+) Virtualisierung/Containerisierung des ESP-IDF möglich (aber noch etwas umständlich)
  • (-) Debugger arbeitet nicht zuverlässig
  • (-) Mehr Handarbeit bei den Projekteinstellungen (settings.json usw.)

Weitere Vor-/Nachteile nehme ich gerne in die Liste auf! 🙂

Anmerkung

Zum unzuverlässigen Debuggen unter VS Code gibt es seit V1.8.0 (Juli 24) eine gute Nachricht: Man kann den Eclipse CDT Debug Adapter verwenden, indem man in launch.json eine Konfiguration aufnimmt (siehe https://github.com/espressif/vscode-esp-idf-extension/pull/1131):

{     
"type": "gdbtarget",     
"request": "attach",     
"name": "Eclipse CDT Remote"   
},

Die gesamte launch.json ist damit:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "gdbtarget",
      "request": "attach",
      "name": "Eclipse CDT Remote"
    },
    {
      "type": "espidf",
      "name": "Launch",
      "request": "launch"
    }
  ]
}

Wenn der ESP32-C3 nicht mehr erreichbar ist

Es kann vorkommen, dass der ESP32-C3 aufgrund von Programm(ier)fehlern nicht mehr erreichbar ist. Der Fall äußert sich dadurch, dass im Gerätemanager die COM-Schnittstelle für den ESP nicht mehr aufgeführt wird:

Auch der Debug-Port ist nicht mehr verfügbar:

In diesem Fall drückt man gleichzeitig den Boot-Taster und den Reset-Taster des Boards (ESP Development Board oder Board zum Buch) und lässt erst den Reset-Taster los und später den Boot-Taster. Damit wird der Bootloader des ESP aktiv. Dann sollten die fehlenden Einträge wieder vorhanden sein:

und

Vor einem neuerlichen Reset (nur Reset-Taster drücken) sollte nun über USB eine funktionsfähige Programmversion aufgespielt werden (z.B. blink).

Nach dem Update kann ein Reset durchgeführt werden, und das Board verhält sich wieder „normal“.

Workshop: First Steps on ESP32-C3

In den rund zweieinhalb Stunden werden wir erst ein bisschen über die Grundlagen sprechen. Fragen wie „Was ist ein embedded System?“, „Aus welchen Komponenten besteht ein embedded System?“, „Wie programmiert man ein embedded System und was ist eine Firmware?“ werden diskutiert.

In praktischen Übungen werden wir erst die LEDs in Betrieb nehmen, dann die Taster. Im Anschluss programmieren wir ein kleines Spielchen. Die dafür notwendigen Entwicklungsboards werden für die Dauer des Workshops zur Verfügung gestellt.

Als Programmiersprache kommt C zum Einsatz.

Dauer

2 1/2 Stunden

Ziel

Kennenlernen der modernen ESP32-C Controller mit RISC-V Prozessor und erste Schritte zur eigenen Firmware

Voraussetzungen

Begleitmaterial

How-To: ESP-IDF in Docker (Windows) – Complete Guide

Espressif stellt Docker Container für die Entwicklung zur Verfügung. Die Entwicklung erfolgt unter der Verwendung von Visual Studio Code Dev Containers. Um neben dem Builden auch das Flashen und Debuggen zu ermöglichen muss zusätzliche Software installiert werden. Die folgende Anleitung basiert auf dem bestehenden Espressif-Tutorial. (letzter Zugriff: 08.01.2024)

Benötigte Software

Folgende Software muss installiert werden:

  1. Visual Studio Code (Espressif IDF)
  2. Docker Desktop (WSL 2)
  3. usbipd

Visual Studio Code

Die Erweiterung Espressif IDF kann über den Marketplace in VS Code installiert werden. Eine detailierte Anleitung wird von Espressif zur Verfügung gestellt.

Docker Desktop (WSL 2)

Das Windows Subsystem for Linux (WSL) wird für Docker bzw. von Containern für den Zugriff auf lokale USB-Geräte benötigt. Microsoft bietet eine Installationsanleitung für WSL an. Für die Erstellung dieser Anleitung wurde Ubuntu 22.04 verwendet.

Siehe Docker Desktop WSL 2 backend on Windows für die Installation von Docker Desktop mit WSL. Nach einer erfolgreichen Installation von Docker/WSL2 können mit folgendem Befehl die installierten WSL Distributionen angezeigt werden:

wsl -l -v

In den Einstellungen von Docker Desktop muss die WSL Integration für die entsprechende Distribution aktiviert werden:

usbipd

Das Tool usbipd wird verwendet um lokale USB-Geräte in WSL zur Verfügung zu stellen. (Download)

Nach der Installation steht usbipd als CLI-Tool zur Verfügung. Folgende Schritte erklären die Anbindung eines Debug Adapter an WSL.

  1. USB-Gerät identifizieren:
    usbipd list

  2. USB-Gerät teilen: (Dieser Befehl benötigt Administratorrechte)
    usbipd bind -b <Device-BusID>

  3. USB-Gerät mit WSL verbinden:
    usbipd attach --wsl --busid=<Device-BusID>

  4. USB-Gerät mit WSL automatisch verbinden: (Das Gerät wird beim An- und Abstecken automatisch mit WSL verbunden)
    usbipd attach --wsl --busid=<Device-BusID> -a

Nachdem der Debug Adapter „attached“ wurde, kann in WSL mit folgendem Befehl geprüft werden ob das Gerät erkannt wurde:
dmesg | tail

Konfiguration und Entwicklung in VS Code

Damit nicht pro Projekt ein separater Container erstellt wird, können mehrere Projekte unter einem übergeordneten Ordner zusammen verwaltet werden. In folgendem Beispiel ist dies der Ordner WS_C_esp_vscode mit dem Projekt blink.

Der Ordner .devcontainer kann in VS Code von der Espressif Erweiterung generiert werden:

Im Ordner .devcontainer befindet sich zwei Dateien:

  • devcontainer.json
  • Dockerfile

Update: Version 1.7.0 der VS Code ESP IDF Erweiterung behebt die folgenden Fehler.
Wenn die aktuelle Version der Erweiterung verwendet wird geht es unter Starten des Container weiter.

In devcontainer.json wird das zu verwendende Projekt und der Python-Pfad des Docker Containers konfiguriert. Das Dockerfile definiert die Installation des Containers. Zum Zeitpunkt des erstellen dieser Anleitung (IDF Version 5.1.2) müssen diese Dateien angepasst werden. Die angepassten Dateien mit Kommentaren stehen hier zum Download zur Verfügung:

Werden die Anpassungen nicht durchgeführt, dann werden folgenden Fehler im Container auftreten, da die Python-Installation nicht gefunden wird bzw. der Benutzer nicht über Zugriffsrechte auf das USB-Gerät verfügt:

/opt/esp/python_env/idf5.1_py3.8_env/bin/python: No such file or directory

Error: libusb_open() failed with LIBUSB_ERROR_ACCESS

Starten des Container

Der Container wird über die Kommando-Palette gestartet:

Das initiale Starten des Container dauert länger, da das Container-Image heruntergeladen werden muss. Der Fortschritt des Startprozess kann per Klick auf „show log“ angezeigt werden:

Nachfolgende Starts werden schneller durchgeführt. Da die Espressif Erweiterung die Microsoft C++ Erweiterung benötigt muss der Container nach dem ersten Start geschlossen und erneut geöffnet werden.

Installation Python Packages

Zum Zeitpunkt der Erstellung dieser Anleitung (IDF V5.1.2) werden die benötigten Python Packages für das Debuggen nicht direkt beim Setup des Containers installiert. Dies muss manuell im Container erfolgen:

Wenn die Python Packages nicht installiert werden kommt es beim Debuggen zu folgendem Fehler:
ModuleNotFoundError: No module named 'esp_debug_backend'

Builden, Flashen und Debuggen

Der USB-Port und das zu verwendende Gerät kann direkt in der Espressif Erweiterung eingestellt werden:

Nun kann, unter Verwendung der Espressif Erweiterung, ein Build ausgeführt werden. Auch das Flashen per JTAG sowie das Debugging ist nun direkt im Container möglich.

Autovervollständigung, highlighting und Code-Navigierung

Unter Umständen kommt es zu Problemen mit der Autovervollständigung oder mit der Navigierung im Code. Es gibt es zwei Möglichkeiten um dieses Problem zu beheben:

  1. Anpassen der Datei c_cpp_properties.json im Ordner .vscode
    Hierbei wird die Datei um folgende Zeile ergänzt:
    "compileCommands": "${workspaceFolder}/build/compile_commands.json"
    Achtung: Die Datei compile_commands.json existiert erst nach einem erfolgreichen Build
  2. Anpassen der Datei settings.json im Ordner .vscode
    Hierbei wird die Datei um folgende Zeile ergänzt:
    "C_Cpp.intelliSenseEngine": "Tag Parser"

(2) RISC-V Simulator

Erweitern Sie den RISC-V Disassembler um eine Befehlsabarbeitung. Implementieren Sie dazu die Registerbank, den Befehlsspeicher und den Datenspeicher als eigene Klassen (sofern Sie eine objektorientierte Sprache einsetzen).

Arbeiten Sie Befehl für Befehl ab, so wie die Befehle im RISC-V Instruction Set Manual (Volume 1) definiert sind. Geben Sie am Ende der Abarbeitung die Inhalte der Register auf dem Bildschirm aus.

Eine Implementierung der Peripherie ist nicht notwendig. Aus diesem Grund werden Funktionen wie printf() nicht funktionieren.

(1) RISC-V Disassembler

Entwickeln Sie ein PC-Programm (Beispielsweise in C, C++ oder Java), das ein RISC-V Compilat disassembliert. Es soll Anweisung für Anweisung auf dem Bildschirm ausgeben.

Implementieren Sie alle Befehle des RV32I – und des RV32M Befehlssatzes. Achten Sie dabei besonders auf die korrekte Behandlung der Immediate-Values (die ja „scrambled“, also durcheinander codiert sind).

Um Testdaten (Compilate) zu generieren, gehen Sie dabei wie folgt vor:

C in RISC-V übersetzen und Hex-File generieren

Um ein C-Programm bzw. einzelne C-Funktionen in RISC-V-Code zu übersetzen, kann das Programm per

riscv32-esp-elf-c++.exe -c -march=rv32im -mabi=ilp32 .\square.c

compiliert werden (im Beispiel square.c). Die Parameter rv32im und ilp32 definieren die Zielarchitektur: RV32I + Multiply. In diesem Fall keine Compressed-Befehle, die der ESP32-C3 aber unterstützt.Das entstandene .o-File kann dann per

riscv32-esp-elf-objcopy.exe -O ihex .\square.o .\square.hex

in ein Intel-Hex-File übersetzt werden. Der generierte Inhalt sieht dann so aus:

Diese Daten können dann händisch oder per Tool in den Simulator übernommen werden.

HexFile2CArrayConverter

Mit diesem Tool kann ein generiertes Hex-File in ein C Array konvertiert werden, um dieses anschließend im Programm weiterzuverwenden.

Ein typischer generierter Output ist:

// -------------- code begin, generated Wed Nov 08 11:00:31 CET 2023
static const uint8_t squarefct_0[] = {   

0x13, 0x01, 0x01, 0xFE, 0x23, 0x2E, 0x81, 0x00, 0x13, 0x04, 0x01, 0x02, 0x23, 0x26, 0xA4, 0xFE,    

0x83, 0x27, 0xC4, 0xFE, 0xB3, 0x87, 0xF7, 0x02, 0x13, 0x85, 0x07, 0x00, 0x03, 0x24, 0xC1, 0x01,

0x13, 0x01, 0x01, 0x02, 0x67, 0x80, 0x00, 0x00};


static const uint8_t* squarefcts[] = { squarefct_0};
static const uint32_t squarefct_startaddresses[] = { 0x00000000};
static const uint32_t squarefct_arraysizes[] = { 39};
#define SQUAREFCTCOUNT 1
// -------------- code end

Aufruf des Tools:

java -jar HexFile2CArrayConverter.jar

Synopsis: HexToCConverter <file.hex> <arrayname> [-w/-b]
  converts the given HEX file; the result will be printed in the terminal
    and also copied into the Clipboard.
  the name of the created array must be provided in <arrayname>. A C style name
    shall be used.
  use -w to generate arrays of words (uint32_t), -b arrays of bytes (uint8_t)

React-O-Mat

Entwickeln Sie auf dem Book Development Board oder einem anderen Board mit zwei Tastern ein Programm, das die grüne LED aufleuchten lässt. Schalten Sie nach einer zufälligen Zeit die LED dunkel.

Nun sind zwei Spieler gefordert, einer den linken und einer den rechten Knopf zu drücken. Die Spielerin, die zuerst gedrückt hat, hat gewonnen. Auf der LED-Matrix soll ein blauer Pfeil zur siegenden Spielerin zeigen.

Sollte ein Spieler zu früh drücken, hat dieser verloren. Dies soll auf der LED-Matrix mit einem roten Pfeil auf den jeweiligen Spieler angezeigt werden.

Durch einen Reset kann das Spiel nun neu gestartet werden.

Verwenden Sie zum Erkennen der Knopfdrücke Interrupts.