LuatOS本着自身的开源特性,可以很轻松的嵌入到很多微处理器和微控制器。今天简要讲下如何移植这套系统,上手比较简单,看完基本就会了。
要想做移植,就要先了解需要移植芯片的SDK,LuatOS依赖于FreeRTOS/RTT这类RTOS系统。如果要移植的芯片SDK中用的有RTOS,那么恭喜你,可以很轻松的将LuatOS移植到芯片上。
我给大家准备了配套的移植模板,请根据Github/Gitee上的模板看这篇移植教程:
本教程主体分为初探、进阶两个部分,下面开始正式讲解。
第一部分:初探
01 编译环境的集成
这是最开始的一步,就是将Lua虚拟机部分集成进芯片,我们要做的就是Ctrl+C、Ctrl+V。要想运行LuatOS,就要把核心的Lua虚拟机部分集成进去。
下面就开始步骤讲解:
1)使用芯片的SDK建立一个空白的工程;
2)将LuatOS仓库里的lua文件夹和luat文件夹复制到新建好的工程里面。
这里根据上图再简要说明一下,lua文件夹里面的文件可以直接复制,luat文件夹里面要复制的有三个部分:
- FreeRTOS或者RTT,这个是调用RTOS的接口,如果芯片使用的是这两种直接复制即可。
如果是freertos, 使用现成的 luat/freertos 目录下的代码, 否则需要实现luat_msgbus.h 和 luat_timer.h; - include文件夹,这是头文件所在的地方;
- modules文件夹,是和用户做交互用的源码所在(第一次集成不需要全部加入,只需加下图这些就够了)。
luat文件夹下的port文件夹,是做接口适配用的,后文会讲。
PS:packages里面的东西,不需要在第一次编译的时候加上,后续慢慢加功能的时候加上就行。(防止编译出错)
3)设置编译
其实就是写Makefile或者Cmake。
$LUATOS
- lua # Lua虚拟机
- luat/module # lua库实现
- luat/port # 接口层实现
以上目录内的.h文件需要加入include配置, .c文件加入到编译路径。以静态库的方式编译进目标就好啦,本文就不详细解释了,相信看这篇文章的都会写。
02 核心功能的适配
这里分两部分做适配,设置主入口和base.c。
1)设置主入口
打开工程的main.c(不同芯片叫法可能不一样),加入以下代码。手机浏览建议横屏查看:
#include "bget.h"
#include "luat\_base.h"
#define LUAT\_HEAP\_SIZE (64\*1024)
uint8\_t luavm\_heap\[LUAT\_HEAP\_SIZE\] = {0};
void app\_main(void)
{
bpool(luavm\_heap, LUAT\_HEAP\_SIZE);
// lua vm需要一块内存用于内部分配, 给出首地址及大小.
luat_main();
// luat_main是LuatOS的主入口, 该方法通常不会返回.
}
这里做一下批注:
define LUAT_HEAP_SIZE () 这个定义是设置LuatOS可以使用的内存堆大小,要根据芯片可用的大小选择,单位是byte。
e.g.
define LUAT_HEAP_SIZE (16*1024)
//代表分配16k 给LuatOS使用
2)设置base.c
这里可以根据本工程配套的示例仓库做。
在ports文件夹内新建一个名为luat_base_xxx.c的文件,所有基础的实现都会在这个文件内找到。
这里简单说以下几个部分吧:
● 设置加载的库(手机浏览建议横屏查看)
static const luaL\_Reg loadedlibs\[\] \= {
{"\_G", luaopen\_base}, // \_G
{LUA\_LOADLIBNAME, luaopen\_package}, // require
{LUA\_COLIBNAME, luaopen\_coroutine}, // coroutine协程库
{LUA\_TABLIBNAME, luaopen\_table}, // table库,操作table类型的数据结构
{LUA\_IOLIBNAME, luaopen\_io}, // io库,操作文件
{LUA\_OSLIBNAME, luaopen\_os}, // os库,已精简
{LUA\_STRLIBNAME, luaopen\_string}, // string库,字符串操作
{LUA\_MATHLIBNAME, luaopen\_math}, // math 数值计算
// {LUA\_UTF8LIBNAME, luaopen\_utf8},
{LUA\_DBLIBNAME, luaopen\_debug}, // debug库,已精简
#if defined(LUA\_COMPAT\_BITLIB)
{LUA\_BITLIBNAME, luaopen\_bit32}, // 不太可能启用
#endif
// 往下是RTT环境下加载的库
{"rtos", luaopen\_rtos}, // rtos底层库, 核心功能是队列和定时器
{"log", luaopen\_log}, // 日志库
{"timer", luaopen\_timer}, // 延时库
{NULL, NULL}};
● 设置bsp的名称
const char \*luat\_os\_bsp(void)
{
return "example"; //example改成芯片的名字
}
● 设置log打印函数
void luat_nprint(char *s, size_t l)
{
printf("%s", s);
}
一般可以用printf()这个函数,如果芯片SDK不支持,请换成对应的或者自行实现。
03 FS的适配
单独把FS这一部分拿出来说一下,lua脚本是存放在FS里面的,所以说要实现luatos正常的运行,还需把FS做好适配。
这里需要在port文件夹内新建一个名为luat_fs_xxx.c的文件,把实现函数放在这个文件夹内。
根据芯片SDK,在芯片Flash中创建FS分区,常见的有spiffs、fatfs、littefs等等,关键函数是int luat_fs_init(void);
如果支持posix风格的,则自带实现;否则需要实现luat_fs.h。
04 开始编译
编译通过刷入芯片,打开串口就能看到LuatOS的log打印了。
ESP32成功编译示例:
如果编译失败,请根据报错查找原因。
第二部分:进阶
外设的的适配
外设通常指gpio/i2c/spi,实现对应的.h文件就可以了,然后在luat_openlibs加载。
加载示例 {“gpio”, luaopen_gpio};
{"rtos", luaopen\_rtos}, // rtos底层库, 核心功能是队列和定时器
{"log", luaopen\_log}, // 日志库
{"timer", luaopen\_timer}, // 延时库
{"gpio", luaopen\_gpio}, // GPIO脚的操作
{"adc", luaopen\_adc}, // ADC库
{"i2c", luaopen\_i2c}, // I2C操作
{"spi", luaopen\_spi}, // SPI操作
{"uart",luaopen\_uart}, // UART操作
{NULL, NULL}};
LuatOS BSP的基础移植,以上这些就够用了。
基础移植成功之后,后面的就是各类外设的适配了,这个过程必定是漫长的,还请各位大佬耐心搞一搞。