Lua no STM32

Olá!

Às vezes, você deseja experimentar rapidamente algo no microcontrolador, programar um pequeno protótipo funcional de uma ideia. Para esses fins, como você sabe, as linguagens de script são bem adequadas. Neste artigo, quero dizer como usar o Embox para executar o interpretador Lua (padrão, não o eLua) no STM32. Para demonstrar, piscamos o LED pela rede usando a biblioteca luasocket e também trabalhamos um pouco com http.



Lua é uma linguagem de programação de script cujo intérprete é leve o suficiente para ser facilmente integrado a outros projetos, além de uma licença gratuita do MIT. Estamos interessados ​​neste idioma há muito tempo, portanto, no Embox, há suporte para Lua no qemu i386. E como o intérprete é leve e compatível com POSIX, surgiu a idéia de lançar Lua da mesma maneira que fizemos com outras bibliotecas como Pjsip , OpenCV , Qt .

Observarei imediatamente que, como começaremos com o suporte a luasocket, escolheremos não stm32f4-discovery (1 MB de flash, 192 KB de RAM), mas um pouco mais - stm32f7-discovery(1 MB de flash, 320 KB de RAM e SDRAM adicional). Ao mesmo tempo, não há dúvida de que a versão básica do Lua sem suporte de rede pode facilmente iniciar no stm32f4 (veja abaixo).

Para começar, vamos preparar um exemplo simples - calculando o enésimo número 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))

Vamos iniciá-lo no Linux primeiro e ver quanta memória foi necessária. E então a transferiremos para a Embox sem alterações. Primeiro, faça o download da lua fresca. Eu baixei o 5.3.5 e o compilei como "make linux". Mas, de fato, para nossos propósitos, você pode colocá-lo no repositório. Em seguida, execute nosso fib.lua:

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

Agora você pode procurar em fib.out e descobrir que a quantidade máxima de memória alocada no heap é de cerca de 30 Kb. Aqui, é claro, não direi que esse é o tamanho mínimo. Por exemplo, no artigo na seção “Requisitos para RAM”, são fornecidos substancialmente menos requisitos, mas apenas no momento da ativação da máquina Lua. De qualquer forma, 30 Kb parece encorajador - temos 320 Kb.

Agora crie o modelo arm / stm32f746g-discovery-lua para a Embox:

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

Firmware build / base / bin / embox no quadro conforme indicado em nosso wiki e execute:

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

Ótimo, tudo é exatamente como no Linux (não é surpreendente :)).

Vamos complicar a tarefa, mas agora a rede é uma necessidade em quase todos os lugares. Envie uma solicitação HTTP / GET em algum lugar da Internet. Para fazer isso, você precisa da biblioteca luasocket . Então não comecei a coletar os códigos-fonte, mas usei o pacote pronto ("sudo apt-get install lua-socket").

Para enviar uma solicitação HTTP, use este exemplo simples:

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)

Novamente, tudo pode ser verificado no Linux:

lua http_request.lua http://example.com

Retornará o código 200 e o conteúdo da página. Vamos ver isso de memória. Se você executar o valgrind novamente, poderá ver que o pico de consumo de memória no heap aumentou para 242 Kb. Então, aqui finalmente descobri que o stm32f4 não se ajustará sem otimizações adicionais. Parece ser possível acessar o stm32f7 - há 320 Kb, mas, considerando que ainda existe um sistema operacional com um sistema de arquivos e uma rede, decidi mexer um pouco no uso de um monte de SDRAM externo.

Ativamos (na configuração isso já está incluído) a pilha usual na RAM e a pilha adicional na SDRAM.

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

Verificamos stm32f7-discovery, funciona como no Linux.

Vamos finalmente piscar o LED "remotamente".

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

Aqui, apenas obtemos os dados UDP da porta especificada e os passamos para os.execute (). Como um comando que será executado, enviaremos um comando pin do cliente. Este é um comando simples na Embox que controla o GPIO - por exemplo, para stm32f7-disco, você precisa executar “pin gpioi 1 toggle”, o que significa alterar a 1ª linha para GPIOI.

Um exemplo padrão do luasocket será usado como cliente:

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


Como sempre, primeiro verifique no Linux. Valgrind mostra que o pico de consumo de memória no heap é de cerca de 70 Kb, o que é duas vezes mais que o caso de Fibonacci (30 Kb), mas significativamente menor do que o exemplo com HTTP (242 Kb).

Demonstre imediatamente um exemplo de lançamento na Embox.

No 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

Na 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

Conclusão


Conseguimos executar o Lua + luasocket no stm32f7-discovery. E, com a ajuda deles, pisque o LED remotamente pela rede. E acabou sendo bastante simples, porque, como observado no início, as linguagens de script podem economizar tempo na criação de protótipos.

Eu também quero observar que existe um projeto eLua que é executado no bare metal sem um sistema operacional. Mas ele tem várias nuances. Em primeiro lugar, suporte limitado à rede: o UDP não existe, e a documentação diz que a rede está "em andamento" por enquanto. Em segundo lugar, não consegui encontrar suporte para nenhum stm'ku do tipo F3, F4 (apenas F1). E, em geral, você deve concordar que é muito mais útil usar projetos amplamente suportados e, nesse sentido, elua é obviamente inferior ao projeto principal.

Todos os exemplos descritos no artigo estão em nosso repositório.

A Embox também possui outras linguagens de script - python (tinipy), Ruby (mruby), Tcl. Mas isso está além do escopo deste artigo :)

Nossos contatos:
Newsletter: embox-ru@googlegroups.com
Chat por telegrama: t.me/embox_chat

All Articles