Lua auf STM32

Hallo!

Manchmal möchten Sie schnell etwas auf dem Mikrocontroller ausprobieren und einen kleinen funktionierenden Prototyp einer Idee programmieren. Wie Sie wissen, sind Skriptsprachen für diese Zwecke gut geeignet. In diesem Artikel möchte ich erklären, wie Embox verwendet wird, um den Lua- Interpreter (Standard, nicht eLua) auf STM32 auszuführen. Zur Demonstration blinken wir die LED über das Netzwerk mithilfe der Luasocket-Bibliothek und arbeiten auch ein wenig mit http.



Lua ist eine Skript-Programmiersprache, deren Interpreter leicht genug ist, um problemlos in andere Projekte integriert zu werden, sowie eine kostenlose MIT-Lizenz. Wir haben uns schon lange für diese Sprache interessiert, daher gibt es unter Embox Lua-Unterstützung für qemu i386. Und da der Interpreter leicht und POSIX-kompatibel ist, kam die Idee auf, Lua auf die gleiche Weise wie bei anderen Bibliotheken wie Pjsip , OpenCV , Qt zu starten .

Ich werde sofort bemerken, dass wir, da wir mit der Luasocket-Unterstützung beginnen, nicht stm32f4-Discovery (1 MB Flash, 192 KB RAM) wählen , sondern etwas mehr - stm32f7-Discovery(1 MB Flash, 320 KB RAM und zusätzliches SDRAM). Gleichzeitig besteht kein Zweifel daran, dass die Basisversion von Lua ohne Netzwerkunterstützung problemlos auf stm32f4 gestartet werden kann (siehe unten).

Lassen Sie uns zunächst ein einfaches Beispiel vorbereiten - die Berechnung der n-ten Fibonacci-Zahl:

function fib(n)
    if n < 3 then
        return 1
    else
        return fib(n - 1) + fib(n - 2)
    end
end

print("fib(7) = " .. fib(7))

Beginnen wir zuerst unter Linux und sehen, wie viel Speicher benötigt wird. Und dann werden wir es ohne Änderungen an Embox übertragen. Zuerst laden Sie die frische lua. Ich habe 5.3.5 heruntergeladen und als "make linux" kompiliert. Tatsächlich können Sie es für unsere Zwecke aus dem Repository ablegen. Führen Sie als nächstes unsere fib.lua aus:

$ valgrind --tool=massif --massif-out-file=fib.massif lua fib.lua
$ ms_print fib.massif > fib.out

Jetzt können Sie in fib.out nachsehen, dass die maximale Menge des zugewiesenen Speichers im Heap etwa 30 KB beträgt. Hier werde ich natürlich nicht sagen, dass dies die Mindestgröße ist. Zum Beispiel werden im Artikel im Abschnitt „RAM-Anforderungen“ wesentlich weniger Anforderungen angegeben, jedoch nur zum Zeitpunkt des Einschaltens der Lua-Maschine. Aber auf jeden Fall sehen 30 Kb ermutigend aus - wir haben 320 Kb.

Erstellen Sie nun die Vorlage arm / stm32f746g-Discovery-Lua für Embox:

$ make confload-arm/stm32f746g-discovery-lua
$ make -j $(nproc)

Firmware Build / Base / Bin / Embox auf dem Board wie in unserem Wiki angegeben und ausführen:

embox> lua fib.lua 
fib(7) = 13

Großartig, alles ist genau wie unter Linux (nicht überraschend :)).

Lassen Sie uns die Aufgabe komplizieren, aber jetzt ist das Netzwerk fast überall eine Notwendigkeit. Senden Sie eine HTTP / GET-Anfrage irgendwo im Internet. Dazu benötigen Sie die luasocket- Bibliothek . Dann fing ich nicht an, aus Quellcodes zu sammeln, sondern benutzte das fertige Paket ("sudo apt-get install lua-socket").

Verwenden Sie dieses einfache Beispiel, um eine HTTP-Anfrage zu senden:

local http = require("socket.http")

if not arg or not arg[1] then
    print("lua http_request.lua <url>")
    os.exit(0)
end

local body, code = http.request(arg[1])
print(code)
print(body)

os.exit(code == 200)

Auch hier kann alles unter Linux überprüft werden:

lua http_request.lua http://example.com

Gibt Code 200 und Seiteninhalt zurück. Lassen Sie uns das aus dem Gedächtnis sehen. Wenn Sie valgrind erneut ausführen, können Sie feststellen, dass der maximale Speicherverbrauch auf dem Heap auf 242 KB gestiegen ist. Hier habe ich endlich herausgefunden, dass stm32f4 ohne zusätzliche Optimierungen nicht passt. Es scheint möglich zu sein, auf stm32f7 zu kommen - es gibt 320 KB, aber angesichts der Tatsache, dass es immer noch ein Betriebssystem mit einem Dateisystem und einem Netzwerk gibt, habe ich mich ein wenig entschlossen, ein paar externe SDRAMs zu verwenden.

Wir aktivieren (in der Konfiguration ist dies bereits enthalten) den üblichen Heap im RAM und den zusätzlichen im SDRAM.

    include embox.mem.static_heap(heap_size=0x10000)
    include embox.mem.fixed_heap(heap_size=0x40000, heap_start=0x60000000)

Wir überprüfen die stm32f7-Erkennung, sie funktioniert wie unter Linux.

Lassen Sie uns endlich die LED "aus der Ferne" blinken.

local socket = require("socket")

port = arg[1] or 1027
udp = assert(socket.udp())
assert(udp:setsockname('*', port))
print("Lua UDP server started on port " .. port .. "...")
while 1 do
    cmd, ip, port = assert(udp:receivefrom())
    print("Execute '" .. cmd .. "' from " .. ip .. ":" .. port)
    os.execute(cmd)
end

Hier erhalten wir nur die UDP-Daten vom angegebenen Port und übergeben sie an os.execute (). Als Befehl, der ausgeführt wird, senden wir einen Pin-Befehl vom Client. Dies ist ein einfacher Befehl in Embox, der GPIO steuert. Für stm32f7-disco müssen Sie beispielsweise "pin gpioi 1 toggle" ausführen, was bedeutet, dass die erste Zeile in GPIOI geändert wird.

Ein Standardbeispiel von luasocket wird als Client verwendet:

echoclnt.lua
-----------------------------------------------------------------------------
-- UDP sample: echo protocol client
-- LuaSocket sample files
-- Author: Diego Nehab
-----------------------------------------------------------------------------
local socket = require("socket")

host = "localhost"
port = 1027
if arg then
    host = arg[1] or host
    port = arg[2] or port
end

udp = assert(socket.udp())
assert(udp:setpeername(host, port))
print("Using remote host '" ..host.. "' and port " .. port .. "...")
while 1 do
    line = io.read()
    if not line or line == "" then os.exit() end
    assert(udp:send(line))
end


Überprüfen Sie wie gewohnt zuerst Linux. Valgrind zeigt, dass der maximale Speicherverbrauch auf dem Heap etwa 70 KB beträgt, was mehr als das Zweifache des Falles bei Fibonacci (30 KB) ist, jedoch deutlich weniger als im Beispiel bei HTTP (242 KB).

Zeigen Sie sofort ein Beispiel für den Start in Embox.

Unter Linux:

$ lua echoclnt.lua 192.168.0.128 1027
Using remote host '192.168.0.128' and port 1027...
pin gpioi 1 toggle
pin gpioi 1 toggle

Auf Embox:

embox>                                                   
embox>lua udp_server.lua                                                        
Lua UDP server started on port 1027...
Execute 'pin gpioi 1 toggle' from 192.168.0.102:34300
Execute 'pin gpioi 1 toggle' from 192.168.0.102:34300

Fazit


Wir haben es geschafft, Lua + luasocket auf stm32f7-Discovery auszuführen. Blinken Sie mit ihrer Hilfe die LED aus der Ferne über das Netzwerk. Und es stellte sich als recht einfach heraus, da Skriptsprachen, wie eingangs erwähnt, Zeit beim Prototyping sparen können.

Ich möchte auch darauf hinweisen, dass es ein solches eLua- Projekt gibt , das auf Bare Metal ohne Betriebssystem ausgeführt wird. Aber er hat mehrere Nuancen. Erstens eingeschränkte Netzwerkunterstützung: UDP ist nicht vorhanden, und die Dokumentation besagt, dass das Netzwerk derzeit "in Bearbeitung" ist. Zweitens konnte ich keine Unterstützung für stm'ku Typ F3, F4 (nur F1) finden. Und im Allgemeinen müssen Sie zustimmen, dass es viel nützlicher ist, weit verbreitete Projekte zu verwenden, und in dieser Hinsicht ist elua dem Hauptprojekt natürlich unterlegen.

Alle im Artikel beschriebenen Beispiele befinden sich in unserem Repository.

Embox hat auch andere Skriptsprachen - Python (Tinipy), Ruby (Mruby), Tcl. Dies geht jedoch über den Rahmen dieses Artikels hinaus :)

Unsere Kontakte:
Newsletter: embox-ru@googlegroups.com
Telegramm-Chat: t.me/embox_chat

All Articles