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!

(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.

Blink mit Multitasking

Verwenden Sie das BDB (book development board) zur Ausarbeitung des Beispiels.

Erstellen Sie unter FreeRTOS einen Task, der die LED_PUSH im Sekundentakt blinken lässt. Ein zweiter Task soll die LED_PULL ebenso im Sekundentakt blinken lassen.

Implementieren Sie nun in einem dritten Task eine Behandlung der beiden Taster. Beim Drücken des linken Tasters (SW2BOOT) soll das Blinked der LED_PULL verlangsamt, beim Drücken des rechten Tasters (SW3APP) beschleunigt werden.

Die Lösung soll iterativ verbessert/geändert werden (Verwenden Sie bedingte Compilierung (#ifdef), um zwischen den Lösungen per menuconfig zu wechseln):

  • Verwenden Sie im ersten Ansatz globale Variable zur Übergabe des Tastendrucks
  • Im zweiten Ansatz soll die globale Variable über einen Semaphor geschützt und synchronisiert werden
  • Schließlich soll das Ereignis über eine FreeRTOS Queue zugestellt werden

Vergleich von Sortieralgorithmen

Implementieren Sie die Sortierverfahren Selection Sort, Bubble Sort und Quicksort und führen Sie eine Geschwindigkeitsmessung durch. Verwenden Sie dafür mehrere Durchgänge in denen Sie Zufallsdaten erzeugen und diese jeweils mit den drei Verfahren sortieren.

Können Sie die in Sortierverfahren beschriebenen Aufwände bestätigen? Verwenden Sie die in Kapitel 3 beschriebene Instrumentierung zur Bestimmung der exakten Taktzyklenzahl.

Fiebermesser

Implementieren Sie einen Fiebermesser. Bis zu einer gemessenen Körpertemperatur von 37°C soll die LED des Entwicklungsboards grün, zwischen 37°C und 38°C wegen erhöhter Temperatur orange und darüber zur Anzeige von Fieber rot leuchten.

Während des Messvorgangs soll die LED blau leuchten. Die Temperatur soll so lange gemessen werden, bis der Messwert nicht mehr nennenswert steigt.

Implementierung

Als Sensor kann ein Sensor mit 1-wire-Bus, wie der DS18B20, der in verschiedenen Sensoren eingebaut ist. Im Beispiel wird eine günstige Edelstahlsonde verwendet.

Die Ausarbeitung fevercheck des Beispiels ist im Repository zu Vergleichszwecken abgelegt.

Bewegungsmelder

Mit einem Pyroelektrischen (PIR-) Sensor können Bewegungen warmer Objekte sehr stromsparend erkannt werden. Ein solcher Sensor, beispielsweise von Panasonic erhältlich bei Conrad, soll verwendet werden um die LED des Entwicklungsboards entsprechend zu dimmen. Bei erkannter Bewegung soll die LED fünf Sekunden lang hell sein, um anschließend wieder im gedimmten „Dämmermodus“ zu verweilen.

Die Ansteuerung des PIR-Sensors soll in einer Komponente pirsensor gekapselt sein. Eine PIR-Auslösung soll über einen dynamischen Callback in die Applikation gemeldet werden.

Implementierung

Die Ausarbeitung motiondetect des Beispiels ist im Repository zu Vergleichszwecken abgelegt. Der PIR-Sensor ist im Beispiel an GPIO 3 angeschlossen, der LED-Strip an GPIO 8. Die Auswahl kann in der Konfiguration geändert werden.

Laufschrift (Übungsbeispiel)

Entwickeln Sie auf einem Board mit 25×25 LEDs (wie dem in Bezugsquellen Entwicklungsboards beschriebenen ESP32-C3FH4-RGB) eine Laufschrift.

Der darzustellende Text wird als String mit speziellen Formatierungszeichen übergeben: \1 gefolgt von der Farbe, beispielsweise r setzt roten Text, gefolgt von b blauen Text. Die Anzeige des Strings "\1rWelcome \1gto \1bthe\1o>>ticker<<\1w!!! " ist in folgendem Video ersichtlich.

ticker bei der Anzeige

Implementierung

Die Ausarbeitung ticker des Beispiels ist im Repository zu Vergleichszwecken abgelegt.

Das Beispiel implementiert einen Patch für das rmt_led-Modul: Durch das Setzen der mem_block_symbols = 64 ist es nicht möglich, weitere RMT-Kanäle für andere Kommunikation parallel zu verwenden. Eine Änderung auf den Standardwert 48 ermöglicht dies. Zukünftige Versionen der led_strip-Bibliothek haben dieses Problem behoben.