Die Welle des Interesses an mikroelektronischen Bauelementen und deren Wechselwirkung für industrielle und häusliche Zwecke hat zur Entwicklung einer großen Anzahl von Designern für die Entwicklung auf der Grundlage von ausreichend leistungsfähigen SoC (Systemen auf einem Chip) geführt, die in Bezug auf Mikrocontrollerlösungen eher miniaturisiert sind, aber bereits ein vollwertiges Betriebssystem enthalten. Die Anwendungsentwicklung für solche Designer unterscheidet sich praktisch nicht von der üblichen Serverentwicklung, außer dass das Ressourcenlimit weiterhin berücksichtigt werden sollte.

Mit zunehmender Produktivität und Leistungsfähigkeit gewinnt die Verwendung von hochinterpretierten Sprachen wie Lua, Python und JS für die Anwendungsentwicklung zunehmend an Bedeutung. Einige Sprachen dringen allmählich in die "jüngeren Brüder" ein, Mikrocontroller jedoch in sehr begrenzter Form.
Dafür gibt es mehrere Gründe:
- Rapid Prototyping - Bei allem Respekt vor der C-Sprache, die hauptsächlich Mikrocontroller entwickelt, ist es sehr schwierig, sie als prägnant zu bezeichnen. Mit Hochsprachen können Sie weniger Code schreiben und das Vornehmen von Änderungen an den bereits geschriebenen Sprachen vereinfachen, was im Prototypenstadium sehr wichtig ist.
- Automatische Speicherverwaltung und Zusammenfassung komplexer Berechnungsmechanismen - Ich denke, es sind keine Kommentare erforderlich. Beide manuellen Prozesse mit einem ausreichenden Projektvolumen verursachen viel Kopfzerbrechen.
- Vereinfachung des Debuggens und Testens - Der interpretierte Code kann vor dem Testen vor Ort leichter auf der Workstation überprüft werden.
- Kampf mit der Komplexität - oft führt eine hohe Produktivität zu einem natürlichen pragmatischen Wunsch, mehr Vorverarbeitung und Analyse auf das Gerät zu übertragen, was die Entwicklung nicht einfacher macht.
Leider müssen Sie für alle Annehmlichkeiten bezahlen. In diesem Fall ist der Preis für Bequemlichkeit die wertvollste Ressource, Leistung und Codegröße (in vielen Fällen müssen Sie eine ziemlich umfangreiche Laufzeitumgebung mitführen). Daher ist die Feldanwendung von Hochsprachen in SoC und SoM eine mehrdeutige Sache und an einigen Stellen ein Kompromiss.
Wir verwenden die Erlang-Sprache für die Entwicklung und wenden sie sowohl für den beabsichtigten Zweck (Erstellen von Serveranwendungen und einer Steuerebene) als auch für sehr ungewöhnliche Webanwendungen an. Daher entstand die Idee, die Infrastruktur dieser Sprache zur Erstellung von IoT-Lösungen zu verwenden, lange bevor Boards auftauchten, auf denen die Erlang-Laufzeit problemlos funktionieren konnte.
Die Gründe für die Verwendung von Erlang waren vielfältig, die wichtigsten:
- Erlang ist sehr praktisch zum Parsen und Erstellen von Binärsequenzen. Durch den Mustervergleich in Kombination mit der Bitdatenverarbeitung können Binärprotokolle sehr schnell und wortlos implementiert werden.
- Mangel an globalen Variablen und Unveränderlichkeit für die meisten Daten - ermöglicht es Ihnen, zuverlässige Anwendungen zu schreiben und, nicht weniger wichtig, zu warten, in denen es schwierig ist, versehentlich etwas Falsches zu ändern;
- Leichte Messaging-Prozesse, die denen von Embedded-Entwicklern sehr ähnlich sind. Im Wesentlichen handelt es sich um eine Initialisierungsprozedur und eine Prozedur, die eingehende Nachrichten in einer Endlosschleife verarbeitet und den internen Status ändert. Es ist Arduino sehr ähnlich, nur dass es viele Prozesse geben kann und diese parallel arbeiten. Außerdem kann im Verarbeitungsintervall die Verarbeitungsprozedur im laufenden Betrieb geändert werden (Hot Code Reload). Dies ist sehr praktisch, wenn Sie kleinere Fehler beheben oder das Verhalten anpassen müssen.
- Eine isolierte Umgebung und eine automatische Speicherzuweisung bedürfen meiner Meinung nach keiner Erklärung.
- plattformübergreifender Bytecode für die ERTS-Laufzeit kann auf dem Computer des Entwicklers kompiliert und dann problemlos auf das Zielgerät übertragen werden.
- Hervorragende Introspektionstools - Die Möglichkeit, über das Netzwerk eine Verbindung zu einer laufenden Anwendung herzustellen und festzustellen, dass diese so oft langsamer wird, ist oft sehr nützlich.
Das erste Arbeitsbrett, auf dem wir Erlang ausprobierten, war
Carambola 2 der litauischen Entwickler von
8 Geräten , das auf dem beliebten AR9331-Chip montiert war. Die erste Version dieses Boards hatte leider nicht genügend Flash-Speicher, um zur Laufzeit zu passen. Die zweite Version erlaubte es sich jedoch bereits, sowohl ERTS als auch eine kleine Anwendung aufzunehmen.

Die Installation wurde mit einer klassischen Methode für diese Art von Gerät durchgeführt: Zusammenstellen eines OpenWRT-Images mit Erlang und anschließendes Flashen in den Flash-Speicher des Geräts. Der erste Start der Umwelt führte leider zu Enttäuschungen - alles hing. Ich
habe die Gründe dafür bereits
auf der InoThings 2018-Konferenz erläutert , aber leider, wie sich später herausstellte, meine Kollegen irregeführt, indem ich fälschlicherweise die Quelle eines solchen Verhaltens genannt habe.
Ich werde es kurz nacherzählen. Bei der Arbeit mit Dateien verwendet die virtuelle ERTS-Maschine den Typ
off_t , dessen Größe in der Verteilung berechnet wird, wenn die Assembly
automatisch konfiguriert wird (wenn sie auf der Zielplattform ausgeführt wird) oder aus der Cross-Compilation-Umgebung ersetzt wird, wie dies im Fall von OpenWRT der Fall ist. Es ist nicht klar, warum, aber in den Einstellungen für MIPS-Prozessoren und -Derivate in der Assembly-Konfigurationsdatei ist doppelt so groß wie tatsächlich. Das Problem würde nicht auftreten, wenn der Code der virtuellen Maschine keine Präprozessoranweisungen wie verwenden würde
#if SIZEOF_OFF_T == 4
und eine banale Überprüfung im Code (ich vermute, dass das endgültige Kompilierungsergebnis das gleiche wäre, aber es gab nicht genug Sicherung, um dies zu überprüfen):
if (sizeof(off_t) == 4) {
Infolgedessen erhielt das ERTS, das bei der ersten Iteration beim Versuch, die
Datei ~ / .erlang.cookie (eine Art Kennwort zur Identifizierung während der Netzwerkinteraktion) zu lesen, beim Start erfolgreich Müll in hoher Reihenfolge empfangen und stürzte mit einem Knall ab.
Der Patch-Patch und das Paket mit der vorletzten Version von ERTS für OpenWRT können von
GitHub heruntergeladen werden. Darüber hinaus wurden noch keine Probleme beobachtet, alles funktionierte wie erwartet.
Die zweite Hardwareplattform, auf der wir Erlang ausprobiert haben, war der
LinkIt Smart 7688- Designer von Mediatek und
SeeedStudio , der speziell für das Rapid Prototyping und das Erlernen der Grundlagen entwickelt wurde. Dieses Board ist einfach die Apotheose der Ausschweifung in Bezug auf Ressourcen - die Frequenz des MIPS-Kerns ist um das 1,5-fache gestiegen, mehr RAM (für ERTS ist es wichtig, dass GC nicht einschlafen kann) und mehr Flash-Speicher sowie das Vorhandensein einer microSD-Karte und die Möglichkeit der Verwendung des Atmel-Co-Prozessors Atmega 32U4 in
der Duo-Version für die Arbeit mit Peripheriegeräten.

Im Allgemeinen war die Plattform sehr gut geeignet, um das Bankett fortzusetzen, und das Vorhandensein zusätzlicher Steckvorrichtungen, die ohne Löten angeschlossen werden können, ermöglicht es Ihnen, schnell und bedingt einen Prüfstand auf Ihrem Knie zu montieren.
Die Plattform wird mit Software mit eigener Weboberfläche sowie Python- und NodeJS-Bibliotheken für die Entwicklung geliefert. Das Ökosystem für die Baugruppe hat sich nicht geändert - es ist immer noch OpenWRT. Wenn Sie diese Vielfalt aus irgendeinem Grund überflüssig finden, befinden sich im obigen Repository Pakete mit einem
minimalen Satz erforderlicher Komponenten . Nach dem Zusammenbau wird das Flash-Image auf das Gerät geschrieben und nach dem Neustart können Sie REPL sicher verwenden.
Um Anwendungen auf Erlang für IoT zu erstellen, muss ein Architekturproblem behoben werden.
Die Sprache wurde mit Blick auf das entworfen und entwickelt, was als Kontrollebene dienen wird, d. H. Kontrollschicht, während der Arbeit mit Eisen sollte durch FFI sein. Hierfür stehen drei Arten der Interaktion zur Verfügung:
- Ports (Ports) - separat arbeitende Prozesse, die in einer beliebigen Sprache geschrieben sind und deren Interaktion über Eingabe- / Ausgabestreams erfolgt. Sie können im Falle eines Sturzes neu gestartet werden, aber aufgrund der Interaktionsmethode ist ihre Produktivität in Bezug auf die Kommunikation gering (dies wird uns jedoch ausreichen).
- NIF-Funktionen - sehen aus wie Standardfunktionen der Sprache, aber ihr Aufruf generiert die Ausführung des kompilierten Codes im Raum der Laufzeit. Im Fehlerfall können sie die gesamte virtuelle Maschine hinter sich ziehen.
- C-Knoten - Wenn die gesamte Arbeit in einem separaten Prozess ausgeführt wird und die Interaktion wie in einer separat ausgeführten Laufzeitumgebung über das Netzwerk ausgeführt wird. Wir werden diese Option aufgrund der ausreichend hohen Gemeinkosten im Rahmen eines schwachen Geräts nicht in Betracht ziehen.
Das Dilemma ist folgendes: Wir können nur Dinge zu FFI transportieren (d. H. Unterstützung für GPIO, I2C, SPI, PWM, UART usw.), und wir können direkt mit Sensoren und anderen Geräten auf Erlang oder interagieren Im Gegenteil, um Gerätetreiber vollständig auf den Code externer Module zu übertragen und die Anwendung Rohdaten empfangen und verarbeiten zu lassen, kann es in diesem Fall sinnvoll sein, den bereits geschriebenen Code zu verwenden.
Wir haben uns für die erste Option entschieden. Dafür gibt es mehrere Gründe:
- weil wir können;
- Wie bereits erwähnt, verfügt Erlang über ausreichend leistungsstarke Tools zum Zusammenstellen und Zerlegen von Binärsequenzen, während es sich um eine recht einfache Mathematik handelt, mit der Sie sich keine Gedanken über den Schutz vor Überläufen und anderer Magie machen müssen, die zur Verarbeitung der Ergebnisse verwendet wird. Nicht dass diese Vogelscheuchenmagie, aber sie wirkt sich schockierend auf die Neophyten aus;
- intuitiv schien es, dass Treiber in einer Hochsprache einfacher und zuverlässiger wären (ein abgestürzter Prozess startet den Supervisor neu, was zur Neuinitialisierung des gesteuerten Geräts führt).
Daher wurde schnell die
ErlangALE- Bibliothek gefunden, die bereits implementierte Unterstützung für GPIO, I2C und SPI über die Kernel-Schnittstellen enthielt, und die Entwickler der Hardwareplattform wiederum hatten sich bereits um sie gekümmert.
Die Bibliothek für die Arbeit mit UART wurde bereits getestet.
Außerdem haben wir
erlexec hinzugefügt , eine Anwendung, mit der Sie Betriebssystemprozesse erstellen und verwalten können.
Alle diese Anwendungen verwendeten Ports (separat gestartete Binärprozesse), um mit Geräten und Betriebssystemen zu arbeiten, für die eine Kompilierungsunterstützung für C- und C ++ - Sprachen erforderlich war, für die ein ziemlich
ausgeklügeltes Shell-Skript geschrieben wurde, das die Build-Umgebung für die Verwendung der erforderlichen Compiler konfigurierte.
Um die von uns getroffenen Entscheidungen zu testen, haben wir ein einfaches Gerät aus LinkIt Smart 7866, zwei I2C-Geräte (BMP280-Temperatur- und Drucksensor und 128 OLED-Display mit 64 Pixeln) und ein USB-GPS-Modul zusammengestellt, das Daten über UART sendet. GPIO wurde an der LED auf der Platine getestet, es funktioniert, und das Anschließen des SPI-Displays schien in dieser Phase der Komplikation unnötig.

Es stellte sich heraus, dass es sich um eine ziemlich kompakte und einfache Anwendung handelt. Der
Quellcode kann auf Github angezeigt werden.
Ich werde mich nicht mit Codefragmenten befassen, sondern versuchen, in einer Übersicht zu beschreiben, wie die Anwendung funktioniert.
Die Treiber aller Geräte werden in Form von gen_server-Prozessen erstellt. Dies ist praktisch, da Sie dem Status zusätzliche Parameter und manchmal den Status des Geräts hinzufügen können. Letzteres ist im Beispiel von
uart_gps zu sehen - Daten vom UART
kommen asynchron an, werden
vom Parser NMEA0183 analysiert und die Ergebnisse werden in den Prozessstatus geschrieben, von wo sie auf Anfrage abgerufen werden.
Der
Hauptzyklus der Anwendung wird im Modul
gps_temp_display beschrieben. Jede Sekunde liest der Prozess GPS-Daten und fordert den Temperatur- und Druckstatus vom BMP280 an und zeigt sie auf dem OLED-Display an. Aus Gründen des Interesses können Sie sich
die Display- und
Sensortreiber BMP280 ansehen - alles lief ziemlich prägnant ab, 150-170 Zeilen pro Modul.
Im Allgemeinen dauerte die obige Aufgabe (Schreiben von Treibercode, Kombinieren von allem in einer Anwendung, Zusammenstellen und Testen) ungefähr vier Abende, durchschnittlich zwei Stunden, d. H. Genau genommen ein paar Arbeitstage. Es scheint mir persönlich, dass dies ein guter Indikator ist, um Erlang in komplexeren und seriöseren eingebetteten Anwendungen zu verwenden, für die keine strengen Echtzeitbeschränkungen erforderlich sind.
Natürlich sind unsere Versuche, Erlang für eingebettete Systeme zu verwenden, keineswegs die einzigen. In dieser Hinsicht gibt es mehrere interessante Projekte:
- nerves-project.org - zielt darauf ab, ein eingebettetes Ökosystem basierend auf Elixir zu schaffen;
- www.grisp.org - ein noch radikalerer Ansatz, bei dem ERTS direkt auf der Hardware gestartet wird (Bare-Metal-Erlang-System);
- github.com/bettio/AtomVM und github.com/cloudozer/ling - versucht, eine kompakte Version von ERTS zu erstellen, die für die Verwendung in Mikrocontrollern und schwachem SoC / SoM geeignet ist.