Im ersten Artikelteil haben wir gezeigt, wie man auf einem Linux-PC ein convolutionales neuronales Netzwerk (CNN) zur Erkennung gesprochener Schlüsselwörter trainiert. Das Ergebnis waren mehrere Dateien, die das CNN und seine Funktionen enthielten. In diesem Artikel beginnen wir mit der Entwicklung auf dem Maxim Micro SDK und implementieren den Code zur Steuerung unserer Kaffeemaschinen-Demo. Wir zeigen nicht nur, wie der Code erstellt wurde und funktioniert, sondern auch, wie Sie die IDE einrichten und zeigen einige Tricks und Tipps für Ihre eigenen Projekte.
 
Das Micro-SDK von Maxim basiert auf der bekannten und weit verbreiteten Eclipse-IDE. Diese IDE wird von vielen Anbietern verwendet und kann aufgrund ihrer Anpassungsfähigkeit mit Add-Ons ausgestattet und stark individualisiert werden. Maxim verwendet eine weitgehend unveränderte Eclipse-IDE mit nur wenigen Ergänzungen, mit denen Sie Ihr MCU-Projekt etwas komfortabler einrichten können. Dies ermöglicht nicht nur eine einfache Wartung, der Anwender kann die IDE bei Bedarf eigenen Wünschen anzupassen.

Im Moment läuft das Maxim-Micro-SDK nur unter Windows, daher werden wir uns für dieses Projekt an Windows 10 halten. Auch der Standardpfad für die SDK-Installation (Bild 1) wird nicht angetastet, da Leer- oder andere Sonderzeichen in Windows-Pfaden Probleme verursachen können.

 
Bild 1. Der Standardpfad.

Nach dem Herunterladen des Installationsprogramms von der Maxim-Website starten Sie den Setup. Ein Assistent wird angezeigt. Bei den Installationsoptionen (Bild 2) müssen Sie nur den MAX78000 als unterstütztes MCU-Device auswählen. Dadurch wird die Installation leicht und es werden nur wenige nicht benötigte Dateien auf der Festplatte abgelegt. Die Installation kann eine Weile dauern und erfordert eine aktive Internetverbindung, um zusätzliche Abhängigkeiten herunterzuladen.

Bild 2. Wählen Sie nur den MAX78000 als MCU aus.

Nach Abschluss der Installation kann das Maxim Micro-SDK gestartet werden. Navigieren Sie einfach in Ihrem Startmenü zu Maxim Integrated SDK und wählen Sie Eclipse MaximSDK (Bild 3).

Bild 3. Eintrag im Startmenü.

Die Eclipse-IDE startet wie in Bild 4 dargestellt.

Bild 4. Eclipse beim ersten Start.

Baustelle

Der MAX78000 ist ein neuer Maxim-Mikrocontroller. Während der Controller produziert und ausgeliefert wird, arbeitet das Unternehmen schon weiter an der Verbesserung und Aktualisierung der Dokumentation. Auf der GitHub-Seite des MAX78000 erhalten Sie nicht nur die neusten Dokumente und die aktuelle Software, Sie können dort Probleme melden, auf die Sie stoßen. Dies gilt nicht nur für den Code im SDK, sondern auch für das MAX78000-Benutzerhandbuch, in dem noch nicht alle Kapitel fertiggestellt sind, so zum Beispiel der RISC-V-Abschnitt. Und Sie können davon ausgehen, dass in Zukunft weitere Abschnitte hinzukommen werden, um diesen Aspekt des Chips etwas detaillierter zu beschreiben. Da sie sich ständig verbessern, können Sie die Dokumente und das SDK eher als Rolling Release auf dem Weg zur Version 1.0 betrachten. Wenn Ihnen noch Informationen fehlen, sollten Sie Maxim um Hilfe bitten oder etwas tiefer in den Code eintauchen.

Ein neues Projekt, Makefiles und einige Tricks

Mit einem neuen HelloWorld-Projekt wollen wir die Grundlagen sowie einige versteckte Aspekte des Maxim-SDK zeigen. Zugegeben, Makefiles sind nicht jedermanns Sache, und je nachdem, mit welchen Tools Sie bisher gearbeitet haben, automatisieren diese die Codegenerierung, überprüfen automatisch Abhängigkeiten und generieren ein Makefile. Oder aber diese Tools verwenden andere Systeme wie CMake oder SCons, um ausführbare Dateien zu erzeugen. Da wir uns aber mit Makefile-basierten Projekten beschäftigen wollen, geben wir einige Hinweise, um den Projektstart noch komfortabler zu gestalten.
Um ein neues Projekt zu starten, öffnen Sie das Ecplise-MaximSDK, so dass Ihnen die Willkommensseite angezeigt wird (Bild 5).

Bild 5. Eclipse zeigt den Maxim-Projektassistenten.

Für ein neues Projekt verwenden wir den mitgelieferten Assistenten in Bild 6.

Bild 6. Wizard-Einstellungen für den Projektnamen.

Geben Sie dem Projekt einen Namen und nehmen Sie im folgenden Dialog die gleichen Einstellungen wie in Bild 7 vor.

Bild 7. Projekteinstellungen.

Damit wird das Beispielprojekt HelloWorld in unseren Arbeitsbereich kopiert. Falls Sie die Liste durchsehen und Projekte und Beispiele für den AI-Accelerator vermissen, keine Sorge, wir kommen später darauf zurück. Doch jetzt wollen wir den Chip und seine Entwicklungsumgebung erst ein wenig besser kennenlernen.
Wenn alles nach Plan läuft, sehen Sie ein neues Projekt (Bild 8).

 
Bild 8. HelloWorld-Projekt.

Wenn Sie sich den Code dieses einfachen HelloWorld-Projekts ansehen, werden Sie zunächst feststellen, dass viele Includes und Funktionen nicht aufgelöst werden können. Dies ist derzeit eine Einschränkung im SDK, wenn Sie mit Hilfe von Eclipse durch den Code navigieren möchten. Maxim rät, einen Blick auf troubleshooting unresolved symbols zu werfen, um das Problem zu lösen. Wenn Sie mit dem kleinen Hammersymbol (Bild 9) links oben den Code kompilieren, erhalten Sie eine ausführbare Datei, die auf den MAX78000 geflasht werden kann.

Bild 9. Verwenden Sie den Hammer zum Kompilieren.

In den unteren Fenstern sehen Sie einige Zeilen der Ausgabe auf einer Konsole, die fehlerfrei laufen sollte. Ihre erste ausführbare HelloWorld-Datei ist fertig und alles wird durch Makefiles gesteuert. Schauen wir uns als nächstes das Projekt an!

C und das Makefile

Das Makefile mit dem Namen makefile befindet sich im Stammverzeichnis Ihres Projekts. Derzeit sehen Sie eine Datei mit dem Namen main.c, in der C-Code für den Cortex-M4 MCU-Kern erstellt wird. Wenn wir mit einfachem C-Code arbeiten, ist das ja in Ordnung, aber was ist, wenn Sie C++ verwenden wollen? Sie müssen nur die Datei von main.cpp umbenennen, um zu erreichen, dass der Code als C++-Code behandelt wird. Wenn Sie nun den Compile-Button drücken, werden Sie feststellen, dass die HelloWelt-Executable nicht von Grund auf neu oder überhaupt nicht gebildet wird. Auch ist im Makefile als Vorgabe definiert, dass Sie als Evaluation Board das MAX78000EVKIT verwenden. Da wir ein MAX78000FTHR_RevA verwenden werden, müssen wir im Makefile die Zeile BOARD=EvKit_V1 auskommentieren und bei der Zeile BOARD=FTHR_RevA die Auskommentierung aufheben.

Da Eclipse und die in den Makefiles verwendeten Tools den kompilierten Code im Build-Ordner noch sehen, wird keine erneute Kompilierung gestartet, da sie nicht erforderlich zu sein scheint. Das können wir aber mit ein paar Mausklicks manuell bereinigen, wie in Bild 10 zu sehen.

Bild 10. Menüeintrag zum Bereinigen eines Projekts.

Wählen Sie Clean..., so dass ein Assistent-Fenster erscheint. Da wir nur ein Projekt haben, wählen Sie wie in Bild 11 All. Dadurch wird das Projekt bereinigt, so dass Sie später einen definierten Build durchführen können

Bild 11. Assistent zum Bereinigen von Projekten.

Wenn wir nun unsere umbenannte main.cpp kompilieren, löst der Linker Fehlermeldungen aus, da einige Funktionen und Symbole nicht aufgelöst werden können. Der Grund dafür ist die Art und Weise, wie der C- und der C++-Compiler den Code erzeugen. Da wir unsere main.c in main.cpp umbenannt haben, wird nun der g++-Compiler aufgerufen. Auch wenn es ein C++-Compiler ist, versteht er doch C-Code und -Syntax. Teile des SDKs gehen immer noch von einfachem C aus und werden doch vom gcc-Compiler kompiliert. Der Linker muss nun kompilierten C++- und C-Code zu einer ausführbaren Datei mischen.

Um C++-Code zu erhalten, der mit C-Code gelinkt werden kann, müssen wir an einigen Stellen extern „C“ angeben, damit der Compiler eine ausführbare Datei formen kann. Dies kann wie in Bild 12 gezeigt geschehen.

Bild 12. Das C++-Projekt kann eine externe Deklaration von „C“ erfordern..

Dies sollte, wenn möglich, in der Regel innerhalb der eingebundenen Header-Dateien geschehen. Der Wunsch auf GitHub nach einer entsprechend aktualisierten SDK wird von Maxim bearbeitet. Wenn auch Sie etwas finden, was verbessert werden könnte, seien Sie mutig und tragen das in den Issue Tracker von GitHub ein! Ihr Wunsch wird möglicherweise zu hilfreichen Änderungen oder Verbesserungen führen, die nicht  nur Ihnen nutzen, sondern von der die gesamte Community profitiert.

Ändern von Ordnern und dem Makefile

Wenn wir nun Code zum Projekt hinzufügen, werden Sie bald feststellen, dass dieser nicht kompiliert wird. Der Grund liegt im Makefile. Wie in Bild 13 zu sehen, muss jede Datei in der SCRS-Zeile 76 hinzugefügt werden.

 
Bild 13. Das Makefile.

Da dies zu Anfang etwas kompliziert werden kann, kann man das wie in Bild 14 dargestellt automatisieren und alle Codedateien in Ihrem Projektordner einbeziehen.

Bild 14. Modifiziertes Makefile.

So müssen Sie nicht jede einzelne Quelldatei von Hand in Ihr Makefile einbinden. Beachten Sie auch, dass die Ordnerstruktur geändert wird. Alle Quelldateien, einschließlich der main-Dateien, befinden sich nun in ./src/, wo Sie weitere Ordner und Dateien hinzufügen können. Außerdem können Sie sehen, dass dem Projekt ein Ordner MAX78000_FTHR hinzugefügt wurde. Dies sind symbolische Links zu den Board-Support-Dateien, Start-up-Dateien und Linker-Scripts innerhalb des SDKs. Außerdem finden Sie dort einigen Code für Onboard-Peripherie, sofern vorhanden.

Lost Places

Diese symbolischen Links wurden hinzugefügt, um Ihnen einige Details für den Board-Startup-Code zu zeigen. Hier können Sie den Code an Ihre eigenen Bedürfnisse anpassen. Das Thema ist allerdings recht kompliziert, so dass wir es hier nur anreißen wollen. Wie in Bild 15 gezeigt, sind startup_max78000.S und system_max78000.c für den Code verantwortlich, der vom System direkt nach dem Reset ausgeführt wird.

Bild 15. Startup-Dateien.

In startup_max78000.S wird der Cortex-M4-Kern auf die Ausführung von Code vorbereitet. Es werden die beiden Funktionen SystemInit und main aufgerufen. Es sollte klar sein, wo die main-Funktion zu finden ist, aber SystemInit wird innerhalb von system_max78000.c versteckt. Bild 16 zeigt, dass die Funktion als _weak void SystemInit(void) deklariert wird. Der _weak-Key bedeutet: Wenn der Linker eine zweite void SystemInit(void)-Funktion ohne den _weak-Schlüssel findet, wird diese ausgewählt und gelinkt.

Bild 16. Funktion Weak StartupInit().

Nicht nur SystemInit, sondern auch die beiden von ihr aufgerufenen Funktionen SystemCoreClockUpdate und Board_Init sind als _weak deklariert. Board_Init ist auch in der Datei board.c vorhanden, wie Sie in Bild 17 sehen können. An dieser Stelle werden alle grundlegenden Komponenten initialisiert, bevor main() aufgerufen wird, nämlich die GPIOs, UART 0 als serielle Konsole, der Spannungsregler und die LEDs. UART 0, der mit dem Onboard-Debugger verbunden ist, wird als Standard-Ein- und Ausgabegerät für alle Funktionen verwendet, die mit printf zu tun haben. Das Ändern dieser Dateien ist eigentlich fortgeschrittenen Anwender vorbehalten. Wenn dies Ihr erstes Projekt ist, sollten Sie Änderungen nur mit großer Vorsicht vornehmen.

Bild 17. Datei Board.c mit Board_Init().

C oder C++ wählen und Code an den MAX78000 senden

Zu Beginn wählen Sie zwischen C und C++ für Ihr Projekt aus. Wenn Sie sich für C++ entscheiden, löschen Sie die main.c unseres Beispielprojekts, bei C löschen Sie main.cpp. Nachdem unser HelloWord fertig kompiliert ist, müssen wir es auf den MAX78000 hochladen. Wir verwenden den Onboard-Debugger nicht nur, um zu programmieren, sondern auch um eine Debug-Sitzung zu starten. Wählen Sie die Debug-Einstellungen wie in Bild 18, säubern Sie das Projekt und bauen es neu auf.

Bild 18. Debug-Einstellungen.

Wenn Sie Release wählen, kann es sein, dass kein Code zum Debuggen vorhanden ist. Klicken Sie auf das Icon mit dem grünen Käfer (Bild 19), laden Sie den Code hoch und führen ihn aus.

Bild 19. Debug-Symbol.

Mit einem seriellen Terminal wie PuTTY können Sie die Datenausgabe des MAX78000 überwachen. Die erforderlichen Parameter sind: 115.200 Baud, 8 Datenbits, keine Parität, ein Stoppbit. Verbinden Sie sich mit dem COM-Port des Onboard-Debuggers des MAXIM78000FHTR und initialisieren Sie eine serielle Verbindung. Das Ergebnis sollte so wie in Bild 20 aussehen.

Bild 20. Debug-Sitzung, angehalten bei main().

Der Debugger ist angeschlossen, der serielle Monitor ist einsatzbereit und die Ausführung unseres Codes wurde innerhalb der main-Funktion gestoppt. Wenn wir nun auf den Resume-Knopf klicken (Bild 21), erscheinen die Daten in unserem Terminal wie in Bild 22.

Bild 21. Der Resume-Knopf.


 

Erkunden Sie die Peripherie Schritt für Schritt

Ein kleiner Tipp an dieser Stelle: Erkunden Sie die Peripherie des MAX78000 Schritt für Schritt. Dadurch erhalten Sie einen guten Einblick in das System Für alle Peripheriefunktionen gibt es Beispiele. Wenn Sie diese erforschen, sollten Sie mit einem Logik-Analysator oder einem Digital-Scope überprüfen, ob sich das System wie vorgesehen verhält. Sie brauchen Zeit, um mit einem neuen Mikrocontroller vertraut zu werden, besonders wenn Sie Controller anderer Hersteller gewohnt sind. Für alle möglichen Aspekte gibt es Peripheriefunktionen und Tools, die nicht in ein paar Stunden „abgearbeitet“ sind. So etwas benötigt Zeit, mehrere Wochen oder sogar Monate. Wenn Sie Rückschläge erleiden (und das werden Sie!) und wenn sich etwas seltsam verhält, suchen Sie Hilfe auf GitHub und/oder berichten Sie an dieser Stelle von Ihren Problemen!

KI-Beispiele

Etwas, das Sie mit Hilfe des mitgelieferten Assistenten (vorerst) nicht auf Basis bestehender Beispiele durchspielen können, sind die KI-Beispiele für den MAX78000. Die Beispiele sind zwar im SDK enthalten, müssen aber manuell importiert werden. Ein Blick auf [7] zeigt Ihnen, wie Sie diese Beispiele zu Ihrer Eclipse-Arbeitsumgebung hinzufügen können. Hier finden Sie auch die kws20_demo, auf der die Kaffeemaschine basiert.

Bau der Kaffeemaschine

Haben Sie sich mit dem MAX78000 nun ein wenig vertraut gemacht und Ihr erstes Hello World absolviert? Dann können wir fortfahren! Vor Ihnen liegen:
 
  • ein MAX78000FTHR-RevA-Board (Bild 23)
 
Bild 23. Das MAX78000FTHR-Board.
  •  ein Breadboard
  • Jumper-Drähte
  • Ein 2,2-Zoll-TFT-Bildschirm aus dem Elektor-Store (Bild 24)
     
    Bild 24. TFT-Display.

 

Diese Komponenten, verdrahtet wie in Bild 25, sind das absolute Minimum für das Display.

Bild 25. Schaltplan für das Projekt.

Das Display wurde ausgewählt, da das SDK einen fertigen Treiber dafür bereitstellt und wir nicht selbst einen Display-Treiber entwickeln müssen. Die Funktionen, die wir implementieren wollen, sind:

  • Die Maschine soll auf den Namen HAPPY hören
  • Sie soll fragen, ob sie einen Kaffee aufbrühen soll
  • Sie soll sicherstellen, dass eine Tasse bereitgestellt ist
  • Sie soll eine Rückmeldung über das LCD geben

Falls Sie eine echte Kaffeemaschine in dieser Liste vermissen: Seien Sie versichert, dass wir für dieses Projekt keine funktionierende Kaffeemaschinen beschädigen werden. Da es sich nur um einen bei allen Kaffeemaschinen einsetzbaren Versuchsaufbau handelt, haben wir nur eine virtuelle Kaffeemaschine verwendet.
Außerdem benötigen wir das trainierte neuronale Netzwerk, das im ersten Teil erstellt wurde. Sie müssen Zugriff auf die dort generierten Dateien haben, da wir sie später benötigen, um sie (teilweise) in dieses Projekt einzubauen, um die Erkennung unserer neu ausgewählten Wörter zu ermöglichen.

Ändern des Codes

Die Kaffeemaschine basiert auf dem kws20_demo-Projekt in der SDK. Als erstes wollen wir überprüfen, ob unsere neu trainierten Wörter richtig erkannt werden. Wir legen eine Kopie der kws20_demo in unseren Eclipse-Workspace (Standardpfad ist C:\Users\{Benutzername}\eclipse-workspace). Nachdem das Projekt kopiert wurde, können wir es von diesem Ort aus importieren, wie in Bild 26 zu sehen.

 
Bild 26. Projektimport.

Folgen Sie dem Assistenten wie in Bild 27 und Bild 28 dargestellt.

Bild 27. Import-Assistent, Schritt 1.
Bild 27. Import-Assistent, Schritt 2.

Es erscheint ein neues Projekt in Ihrem Arbeitsbereich (Bild 29).

Bild 29. Das importierte Projekt.

Wenn Sie noch das HelloWorld in Ihrem Arbeitsbereich haben, können Sie es jetzt entfernen. Zuerst wird der Code erstellt und auf dem MAX7800-Board getestet, damit wir überprüfen können, ob das mitgelieferte Beispiel funktioniert. Wie beim HelloWorld-Beispiel zuvor müssen wir auch dieses Projekt an das MAX78000FTHR-Board anpassen. In diesem Fall müssen wir die C/C++ Build-Einstellungen und das Build command make -r BOARD=FTHR_RevA ECLIPSE=1 -j8 "" eingeben und übernehmen (Bild 30).
 

Bild 30. Hinzugefügte Zeile zum Build für das MAX78000FTHR-Board.

Damit können Sie die kws20_demo für das MAX78000FTHR-Board kompilieren, anschließend den Code hochladen und debuggen. Mit PuTTY als seriellem Terminal können wir die Ausgabe der erkannten Wörter sehen (Bild 31).

Bild 31. Erkannte Wörter werden in PuTTY angezeigt.

Einsatz des neu trainierten neuronalen Netzwerks

Das Training, das wir im ersten Teil dieser Serie behandelt haben, hat ein neuronales Netzwerk erzeugt, das direkt in dieses Eclipse-Projekt verschoben werden kann. Von unserem trainierten Projekt müssen wir die Dateien cnn.h, cnn.c und weights.h in das kws20_demo-Projekt verschieben und die aktuellen Dateien ersetzen. Nach Clean und Build können wir schon das neue neuronale Netzwerk auf dem MAX78000 testen. Wenn der Code hochgeladen ist und wir das neue Schlüsselwort HAPPY verwenden, erhalten wir ein Ergebnis wie in Bild 32. Wenn Sie sich nun fragen, warum als Schlüsselwort DOWN erkannt wird, müssen Sie einen Blick auf den Code werfen.

Bild 32. Das Schlüsselwort wird nicht wie vorgesehen erkannt.

In unserer main.c (Bild 33) sehen Sie in Zeile 136 eine const char keywords[NUM_OUTPUTS][10], die ein Array von Zeichenketten aufnehmen soll.

Bild 33. Array in main.c.

Wenn Sie sich nun aber Bild 34 ansehen, werden Sie feststellen, dass wir die Schlüsselwörter für das Training des neuronalen Netzes modifiziert haben und die für das Array in unserer main.c nicht passen.

Bild 34. Geändertes Trainingsskript.

Der Grund ist die Art und Weise, wie wir die erkannten Wörter vom CNN-Beschleuniger erhalten. Für jedes Wort, das wir trainiert haben, gibt der Beschleuniger einen Index und eine Wahrscheinlichkeit für ein trainiertes Wort zurück. Um also eine korrekte Ausgabe zu erhalten, müssen wir das Schlüsselwort so anpassen, dass die Elemente im String-Array mit den Indizes der in unserem neuronalen Netzwerk verwendeten Wörter übereinstimmen.

Wenn wir die neuen Schlüsselwörter eingesetzt haben, sieht der Code wie in Bild 35 aus.
 

Bild 35. Aktualisiertes Array für die Schlüsselwort-Ausgabe.

Und wenn wir jetzt HAPPY aufrufen, sehen wir die gewünschte Ausgabe wie in Bild 36.

Bild 36. Die Schlüsselwörter werden wie vorgesehen gemeldet.

Dieser Teil des Codes funktioniert, aber wir sehen eine LC-Anzeige ohne Inhalt. Als schnelle Maßnahme, dies zu ändern, fügen wir einfach #define ENABLE_TFT in Zeile 73 unserer main.c ein und führen einen sauberen Build des Projekts durch. Eine bevorzugte Methode wäre, im Makefile die Auskommentierung der entsprechenden Zeile aufzuheben. Der enthaltene Treiber funktioniert wird mit dem Display gut und wir können ihn für die Kaffeemaschine verwenden. Das Ergebnis ist in Bild 37 zu sehen.

Bild 37. Hard- und Software, betriebsbereit.

Eine GUI-Bibliothek verwenden, die auf fast allem läuft

Wir haben jetzt ein funktionierendes Worterkennungsprojekt, das auch Grafiken auf dem angeschlossenen Display ausgeben kann. Damit wir keine GUI-Bibliothek schreiben müssen, verwenden wir eine bestehende namens LVGL, um unsere Benutzeroberfläche zu erzeugen. Abgesehen davon, dass die Bibliothek sehr portabel ist, können die von ihr verwendeten Ressourcen minimiert werden. Selbst Animationen und Transparenzeffekte verbrauchen nicht viel RAM. Die Frage ist eher, wie schwer es sein kann, die LVGL-Bibliothek in das kws20_demo-Projekt einzubinden.

Da die LVGL auch Makefiles für ihren Build-Code verwendet, sollte die Integration nicht allzu kompliziert sein. Der Code selbst wird in ein Bibliotheksverzeichnis unseres Projekts verschoben, wie in Bild 38 zu sehen ist.
 

Bild 38. Die LVGL-Bibliothek ist hinzugefügt.

Zu diesem Zweck wird auch das Makefile des Projekts geändert, wie Sie in Bild 39 sehen können. Dadurch können unser Projekt und die LVGL erstellt und gelinkt werden.

Bild 39. Modifiziertes Makefile für LVGL-Unterstützung.

Damit die LVGL Daten auf unserem Display anzeigen kann, muss der Treiber in der Lage sein, ein Bündel von Bilddaten zu übertragen. Der mitgelieferte Display-Treiber kann zwar Daten Pixel für Pixel an vorgegebene Positionen schreiben, der dabei entstehende Overhead ist jedoch sehr hoch. Ein schnellerer Weg wäre es, einen Block von Bilddaten auf das Display zu schreiben, wie es für den Kameratreiber implementiert ist. Allerdings erzeugt die LVGL-Bibliothek ihre Anzeigedaten anders, als es diese Funktion erwartet. Den Anzeigetreiber aber mit einer Funktion zu modifizieren, dass er die Daten so wie von der LVGL angeliefert verarbeitet, ist nicht schwer. Und während der Code lief, wurde er dem MAX78000-SDK-Repository als Pull-Request [4] übergeben. Auf diese Weise müssen die SDK-Dateien nicht geändert werden, und jeder kann von der geleisteten Arbeit profitieren.

Alle Teile zusammenfügen

Wir haben jetzt eine GUI-Bibliothek, die mit dem MAX78000 arbeiten kann, und wir können Schlüsselwörter erkennen, es fehlt also nur noch die Logik. Bevor wir fortfahren, müssen wir uns ansehen, wie das Keyword-Spotting funktioniert. Bild 40 zeigt den ursprünglichen Softwareablauf. Wir fangen die erkannten Schlüsselwörter ab und verwenden sie als Eingabe für einen Kaffeemaschinen-Zustandsautomaten, der für die Steuerung des GUI und die Logik sorgt. Bis zu diesem Punkt verlief die Programmierung nach Plan.
 

Bild 40. Ursprünglicher Ablauf der Worterkennung.

Entscheidend für die Worterkennung ist die Audioverarbeitung. Wenn wir zu viel Zeit für andere Tasks aufwenden, werden unsere Schlüsselwörter möglicherweise nicht erkannt, zum Beispiel, wenn Audio-Samples verworfen werden, weil wir die Eingabedaten nicht innerhalb eines bestimmten Zeitrahmens verarbeiten. Und genau das ist uns passiert, als die erste Version der Kaffeemaschine getestet wurde. Der Ablauf in Bild 41 kann also nicht verwendet werden.

Bild 41. Das erste Flussdiagramm.

Wenn das Timing für den Audioteil kritisch ist, warum verschieben wir dann nicht das GUI auf den RISC-V-Kern? Dieser sollte dazu mehr als fähig genug sein. Außerdem könnte die LVGL gut auf diesem Kern laufen, da sie für den Betrieb im Energiesparmodus ausgelegt ist.

Aufgaben für den RISC-V-Kern

Für solche Aufgaben ist der RISC-V-Kern ideal, da dieser das GUI gut handhaben kann und genügend Leistung für die gesamte Erzeugung und das Handling der Daten gemäß den Anforderungen der LVGL bietet. Leider gibt es dabei einen Haken. Wenn man sich das Benutzerhandbuch für den MAX78000 durchliest, findet man einige, teilweise versteckte Hinweise darauf, worauf der RISC-V nicht zugreifen kann, so zum Beispiel auf die AHB-Peripherie wie SPI0 oder das CNN FiFo. Dies stellt ein kleines Problem dar, da das Display und einige andere Peripherie wie das SD-Card-Interface und SPI-RAM an SPI0 angeschlossen sind. Also ist es derzeit keine Hilfe, das GUI komplett vom Cortex-M4 Kern zu entlasten. Außerdem ist der On-Board-Debugger nicht mit dem RISC-V-Kern verbunden, daher können wir ihn nur zum Debuggen des Codes verwenden, der auf dem Cortex-M4 läuft. Wir werden den Dual-Core-Weg deshalb in diesem Artikel nicht verfolgen und ihn vielleicht einem anderen Artikel überlassen. Um eine etwas klarere Vorstellung davon zu bekommen, was Sie ansprechen können, sehen Sie sich das modifizierte Blockdiagramm in Bild 42 an.

Bild 42. Modifiziertes Blockschaltbild des MAX78000.

Bei dem aktuellen Dual-Core-Beispiel müssen Sie sich außerdem bewusst sein, dass Sie die Möglichkeit verlieren, den RISC-V-Kern und den Cortex-M4-Kern zu debuggen. Dies liegt an der Art und Weise, wie die kombinierte ausführbare Datei derzeit generiert wird. Die sollte und wird wahrscheinlich von Maxim in Zukunft verbessert werden.

Kaffeemaschine an den Start!

Da wir den RISC-V-Kern nicht verwenden können, mussten einige Anpassungen am Programmablauf vorgenommen werden. Das neue modifizierte Flussdiagramm ist in Bild 43 zu sehen.

Bild 43. Modifiziertes Flussdiagramm.

In diesem Flussdiagramm wird das GUI nur an zu einem Zeitpunkt aktualisiert, an dem eine Interferenz mit der Audioaufnahme nicht oder kaum zu einem Verlust von Audio-Samples führt. Der resultierende Code kann von der Elektor-GitHub-Seite heruntergeladen werden, um einen besseren Einblick in die Vorgehensweise zu erlangen. Wenn Sie Ihre eigenen Projekte durchführen, sollten Sie den zeitkritischen Datenfluss immer beachten.

Die Kaffeemaschine hört nun auf HAPPY und stellt ein paar Fragen, bevor sie Ihren Kaffee brüht. Es sind einfache YES- oder NO-Fragen, so dass wir nur einen Bruchteil des trainierten Wortschatzes nutzen. Es ist auch noch kein STOP-Befehl implementiert, der zum Beispiel verhindert, dass Ihre Tasse überfüllt wird. Da es sich um ein Beispiel handelt, ist es noch lange nicht perfekt. Um in der Produktion eingesetzt werden zu können, dürfte noch viel Arbeit am Code und am internen Datenfluss nötig sein.

Ein erstes MAX78000-Projekt

Die erste HelloWorld ist in kurzer Zeit fertiggestellt. Das gilt dank der richtigen Hinweise und Tipps auch für eine modifizierte Worterkennungs-Demo. Sich auf den MAX78000 festzulegen und KI zu betreiben, bedeutet derzeit, dass Sie sich mit einer Dokumentation auseinandersetzen müssen, die im Laufe der Zeit erweitert werden soll und wird. Es kann sein, dass Sie einige Bugs oder fehlende Funktionen im SDK finden, da dieses sich genau wie die Dokumentation an einigen Stellen noch im Aufbau befinden.

Mit dem MAX78000FTHR erhalten Sie ein kostengünstiges Werkzeug für den Einstieg in die Welt der KI auf Embedded-Geräten. Maxim hat großartige Arbeit geleistet, indem es eine convolutionale neuronale Netzwerksbeschleunigung in einen Chip integriert, der mit eingeschränkter Stromversorgung arbeitet. Wenn Sie ein paar Tipps und Tricks für uns und alle Leser haben, gehen Sie auf die Seite von Elekor Labs und nutzen Sie die Kommentarfunktion.

Ein MAX78000 Design-Wettbewerb für KI-Pioniere

Mögen Sie Herausforderungen? Hier gibt es eine für Sie: Sie können am MAX78000 AI Design Contest von Maxim Integrated (powered by Elektor) teilnehmen und eine Idee für eine MAX78000-Anwendung einzureichen. Ausgestattet mit einem MAX78000-Board können Sie ein Projekt entwickeln, Ihre Erfahrungen mit unserer Leserschaft teilen und weitere Erfahrungen mit AI sammeln. Dies ist Ihre Chance, ein echter Pionier zu sein! Nutzen Sie die Gelegenheit, um Wissen in einem Bereich zu erlangen, wo Embedded auf AI trifft und in dem noch nicht viele Embedded-Entwickler programmiert haben. Weitere Informationen finden Sie auf der Wettbewerbsseite - elektormagazine.com/ai-contest-max78000. Sollten Sie während des Wettbewerbs Fragen oder Probleme haben, können Sie auch einen der Maxim-Ingenieure um Unterstützung bitten. Damit sollte sichergestellt sein, dass Sie bei der Erstellung Ihres Projekts keine Schwierigkeiten haben.

Wünsche und Träume für zukünftige Verbesserungen

Ein Wunsch für die nahe Zukunft ist die Dokumentation des RISC-V-Kerns und mehr Codebeispiele. Auch sollte es deutlicher herausgestellt werden, dass der Zugriff auf einige Peripheriegeräte vom RISC-V-Kern aus unmöglich ist. Ebenso sollte auch den anderen Einschränkungen bei der Kombination beider Kerne ein eigenes Kapitel im Datenblatt gewidmet werden.

Zum Thema Codebeispiele: Es wäre schön zu demonstrieren, wie man die DMA-Engine nutzen kann. Auch wenn wir nicht direkt auf die SPI0-Peripherie zugreifen können, sollte die DMA-Einheit dazu in der Lage sein. Dies könnte eine Möglichkeit bieten, SPI0 auch mit dem RISC-V-Kern zu nutzen. Auch wenn dies Bestandteil des Handbuches wäre, würden ein paar zusätzliche Beispiele wie Interrupt-Handler für den Cortex-M4- und Risc-V-Kern nicht schaden und das Handbuch noch benutzerfreundlicher machen. Und wenn Maxim schon dabei ist, wäre ein Code für ein Dual-Core-HelloWorld schön, der es uns ermöglicht, den Cortex-M4-Kern zu debuggen und den Code auf dem RISC-V-Kern laufen zu lassen. Dafür haben wir selbst schon einige Ideen, aber wir sind uns im Moment nicht sicher, ob der Weg erfolgversprechend ist.

Was die IDE angeht, ich weiß, das ist Wunschdenken, aber wie wäre es mit einer Integration in Platformio für Visual Studio Code? Oder zumindest offizielle Linux-Unterstützung? Für das Training unserer neuronalen Netze ist ein Linux-System ein bevorzugter Weg, warum nicht auch für die Softwareentwicklung des MAX78000?

KI auf die Spitze treiben

Der MAX78000 bietet Ihnen einen Blick in die Zukunft und bringt KI in die Welt der ressourcenbeschränkten Embedded-Geräte. Wenn Sie gerne noch unausgereifte Bausteine verwenden, ist dieser Controller genau das Richtige für Sie. Mit einem Preis von nur 40 € bietet er Ihnen einen erschwinglichen Einstieg in die Welt der KI und der neuronalen Netze. Die Hardware ist sicherlich spannend, aber seien Sie darauf gefasst, dass Sie sich mit einer (noch) verbesserungswürdigen Dokumentation auseinandersetzen müssen. Wenn Sie neu in der Embedded-Entwicklung sind, könnte es eine Weile dauern, bis Sie den MAX78000 in den Griff bekommen und sein volles Potenzial ausschöpfen können. Aber lassen Sie sich von einer guten technischen Herausforderung nicht abschrecken. Ich bin gespannt, was Maxim in den nächsten Wochen und Monaten noch verbessern wird. Vielleicht gibt es auch bald eine verbesserte Dokumentation mit einem zusätzlichen Kapitel für den RISC-V-Kern ...

Mit einem MAX78000, etwas Kreativität und Ausdauer werden sicher viele von Ihnen in naher Zukunft mit innovativen Projekten aufwarten. Ich möchte Sie ermutigen, Ihre Fähigkeiten unter Beweis zu stellen, indem Sie Ihre Projekte beim Maxim Integrated MAX78000 AI Design Contest einreichen!
 
Anmerkung des Autors: Dieser Artikel entstand unter Beratung der Ingenieure von Maxim Integrated.

 

Haben Sie Fragen oder Kommentare?
Haben Sie technische Fragen oder Kommentare zu diesem Artikel? Schicken Sie eine E-Mail an den Autor unter mathias.claussen@elektor.com oder kontaktieren Sie Elektor unter editor@elektor.com.