STM32上的Lua

你好!

有时,您想在微控制器上快速尝试一些事情,编写一个小的想法原型。如您所知,出于这些目的,脚本语言非常适合。在本文中,我想告诉您如何使用Embox 在STM32上运行Lua解释器(标准而不是eLua)。为了演示,我们使用luasocket库通过网络使LED闪烁,并且还可以使用http进行操作。



Lua是一种脚本编程语言,其解释器非常轻巧,可以轻松集成到其他项目中,并具有免费的MIT许可证。长期以来,我们一直对该语言感兴趣,因此在Embox中,qemu i386上支持Lua。并且由于解释器是轻量级的并且与POSIX兼容,因此提出了以与其他库(例如PjsipOpenCVQt)相同的方式启动Lua的想法

我会立即注意到,由于我们将从luasocket支持入手,因此我们选择不选择stm32f4-discovery(1 MB闪存,192 KB RAM),而是选择更多内容-stm32f7-discovery(1 MB闪存,320 KB RAM和其他SDRAM)。同时,毫无疑问,没有网络支持的Lua基本版本可以轻松地从stm32f4开始(请参见下文)。

首先,让我们准备一个简单的示例-计算第n个斐波那契数:

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

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

让我们先在Linux下启动它,看看它占用了多少内存。然后,我们将其原封不动地转移到Embox。首先,下载新鲜的lua。我下载了5.3.5,并将其编译为“ make linux”。但是实际上,出于我们的目的,您可以将其从存储库中放入。接下来,运行我们的fib.lua:

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

现在,您可以查看fib.out并发现堆中已分配的最大内存量约为30 Kb。当然,在这里我不会说这是最小大小。例如,在“ RAM的要求”部分文章中,给出的要求要少得多,但仅在打开Lua机器时才给出。但是无论如何,30 Kb看起来令人鼓舞-我们有320 Kb。

现在为Embox构建arm / stm32f746g-discovery-lua模板:

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

按照我们的Wiki指示,在主板上构建固件/ base / bin / embox,然后运行:

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

太好了,一切都和Linux完全一样(不足为奇:))。

让任务复杂化,但是现在几乎所有地方都需要网络。在Internet上的某个地方发送HTTP / GET请求。为此,您需要luasocket然后,我没有开始从源代码中收集内容,而是使用了现成的软件包(“ sudo apt-get install lua-socket”)。

要发送HTTP请求,请使用以下简单示例:

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)

同样,可以在Linux上检查所有内容:

lua http_request.lua http://example.com

将返回代码200和页面内容。让我们从内存中看一下。如果再次运行valgrind,则可以看到堆上的峰值内存消耗已增加到242 Kb。因此,在这里我终于发现,如果没有其他优化,stm32f4将不适合。似乎可以使用stm32f7-速度为320 Kb,但是考虑到仍然有一个带文件系统和网络的OS,我决定使用一堆外部SDRAM进行修改。

我们在RAM中打开(在配置中已经包含了)通常的堆,并在SDRAM中打开另一个堆。

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

我们检查stm32f7-discovery,它的工作方式类似于Linux。

最后,让我们“远程”闪烁LED。

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

在这里,我们只是从指定端口获取UDP数据,并将其传递给os.execute()。作为要执行的命令,我们将从客户端发送一个pin命令。这是Embox中控制GPIO的简单命令-例如,对于stm32f7-disco,您需要执行“ pin gpioi 1 toggle”,这意味着将第一行更改为GPIOI。

luasocket的一个标准示例将作为客户端:

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


与往常一样,首先在Linux上进行检查。Valgrind显示,堆上的峰值内存消耗约为70 Kb,这比使用Fibonacci(30 Kb)的情况要多2倍,但比使用HTTP的示例(242 Kb)少得多。

立即演示在Embox上启动的示例。

在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

在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

结论


我们设法在stm32f7-discovery上运行Lua + luasocket。在他们的帮助下,通过网络远程闪烁LED。而且事实证明它很简单,因为如开头所述,脚本语言可以节省原型开发时间。

我还想指出,有一个这样的eLua项目可以在没有操作系统的裸机上运行。但是他有一些细微差别。首先,网络支持有限:不存在UDP,并且文档说网络目前“正在进行中”。其次,我找不到对任何stm'ku类型F3,F4(仅F1)的支持。通常,您必须同意,使用受到广泛支持的项目会更加有用,在这方面,elua当然不如主要项目。

本文中描述的所有示例都在我们的存储库中。

Embox还具有其他脚本语言-python(tinipy),Ruby(mruby),Tcl。但是,这超出了本文的范围:)

我们的联系人:
新闻通讯:embox-ru@googlegroups.com
电报聊天:t.me/embox_chat

All Articles