Lua sur STM32

salut!

Parfois, vous voulez essayer rapidement quelque chose sur le microcontrôleur, programmer un petit prototype fonctionnel d'une idée. À ces fins, comme vous le savez, les langages de script sont bien adaptés. Dans cet article, je veux dire comment utiliser Embox pour exécuter l'interpréteur Lua (standard, pas eLua) sur STM32. Pour démontrer, nous clignotons la LED sur le réseau en utilisant la bibliothèque luasocket, et travaillons également un peu avec http.



Lua est un langage de programmation de script dont l'interpréteur est suffisamment léger pour être facilement intégré dans d'autres projets, plus une licence MIT gratuite. Nous nous intéressons à cette langue depuis longtemps, donc, sous Embox, il existe un support Lua sur qemu i386. Et puisque l'interpréteur est léger et compatible POSIX, l'idée est venue de lancer Lua de la même manière que nous l'avons fait avec d'autres bibliothèques comme Pjsip , OpenCV , Qt .

Je noterai tout de suite que puisque nous commencerons par la prise en charge de Luasocket, nous choisirons non pas stm32f4-discovery (1 Mo de mémoire flash, 192 Ko de RAM), mais un peu plus - stm32f7-discovery(1 Mo de mémoire flash, 320 Ko de RAM et SDRAM supplémentaire). Dans le même temps, il ne fait aucun doute que la version de base de Lua sans prise en charge réseau peut facilement démarrer sur stm32f4 (voir ci-dessous).

Pour commencer, préparons un exemple simple - calcul du nième nombre de Fibonacci:

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

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

Commençons d'abord par Linux et voyons combien de mémoire cela a pris. Et puis nous le transférerons à Embox sans modifications. Tout d'abord, téléchargez la nouvelle lua. J'ai téléchargé 5.3.5 et l'ai compilé en tant que «make linux». Mais en fait, pour nos besoins, vous pouvez le mettre à partir du référentiel. Ensuite, exécutez notre fib.lua:

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

Vous pouvez maintenant regarder dans fib.out et découvrir que la quantité maximale de mémoire allouée dans le tas est d'environ 30 Ko. Ici, bien sûr, je ne dirai pas que c'est la taille minimale. Par exemple, dans l' article de la section «Besoins en RAM», les besoins sont nettement moins nombreux, mais uniquement au moment de la mise sous tension de la machine Lua. Mais en tout cas, 30 Ko semblent encourageants - nous avons 320 Ko.

Maintenant, créez le modèle arm / stm32f746g-discovery-lua pour Embox:

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

Construisez le firmware / base / bin / embox sur la carte comme indiqué sur notre wiki et lancez:

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

GĂ©nial, tout est exactement comme sous Linux (pas surprenant :)).

Compliquons la tâche, mais maintenant le réseau est une nécessité presque partout. Envoyez une demande HTTP / GET quelque part sur Internet. Pour ce faire, vous avez besoin de la bibliothèque luasocket . Ensuite, je n'ai pas commencé à collecter à partir des codes sources, mais j'ai utilisé le package prêt à l'emploi ("sudo apt-get install lua-socket").

Pour envoyer une demande HTTP, utilisez cet exemple simple:

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)

Encore une fois, tout peut être vérifié sur Linux:

lua http_request.lua http://example.com

Renvoie le code 200 et le contenu de la page. Voyons cela de mémoire. Si vous exécutez à nouveau valgrind, vous pouvez voir que la consommation de mémoire de pointe sur le tas a augmenté à 242 Ko. J'ai donc finalement découvert que stm32f4 ne s'adapterait pas sans optimisations supplémentaires. Il semble possible d'obtenir sur stm32f7 - il y a 320 Ko, mais compte tenu du fait qu'il existe toujours un système d'exploitation avec un système de fichiers et un réseau, j'ai décidé de bricoler un peu en utilisant un tas de SDRAM externes.

Nous activons (dans la config cela est déjà inclus) le tas habituel en RAM, et le supplémentaire en SDRAM.

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

Nous vérifions sur stm32f7-discovery, cela fonctionne comme sous Linux.

Clignotons enfin la LED "Ă  distance".

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

Ici, nous obtenons simplement les données UDP du port spécifié et les transmettons à os.execute (). En tant que commande qui sera exécutée, nous enverrons une commande de broche du client. Il s'agit d'une simple commande dans Embox qui contrôle GPIO - par exemple, pour stm32f7-disco, vous devez exécuter "pin gpioi 1 toggle", ce qui signifie changer la 1ère ligne en GPIOI.

Un exemple standard de luasocket sera pris en tant que client:

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


Comme d'habitude, vérifiez d'abord sur Linux. Valgrind montre que la consommation de mémoire maximale sur le tas est d'environ 70 Ko, ce qui est plus de 2 fois plus que dans le cas de Fibonacci (30 Ko), mais nettement moins que dans l'exemple avec HTTP (242 Ko).

Démontrez immédiatement un exemple de lancement sur Embox.

Sous 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

Sur 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

Conclusion


Nous avons réussi à exécuter Lua + luasocket sur stm32f7-discovery. Et avec leur aide, faites clignoter la LED à distance sur le réseau. Et cela s'est avéré assez simple, car comme indiqué au début, les langages de script peuvent gagner du temps sur le prototypage.

Je veux également noter qu'il existe un tel projet eLua qui fonctionne sur du métal nu sans système d'exploitation. Mais il a plusieurs nuances. Premièrement, prise en charge réseau limitée: UDP n'est pas là, et la documentation indique que le réseau est «en cours» pour l'instant. Deuxièmement, je n'ai pu trouver de support pour aucun type stm'ku F3, F4 (uniquement F1). Et en général, vous devez être d'accord, il est beaucoup plus utile d'utiliser des projets largement soutenus, et à cet égard, elua est bien sûr inférieur au projet principal.

Tous les exemples décrits dans l'article se trouvent dans notre référentiel.

Embox a également d'autres langages de script - python (tinipy), Ruby (mruby), Tcl. Mais cela dépasse le cadre de cet article :)

Nos contacts:
Newsletter: embox-ru@googlegroups.com
Chat télégramme: t.me/embox_chat

All Articles