基于arm-gcc和Makefile,将lua解析器移植到stm32f407
代码移植
下载
从GitHub下载最新lua代码,笔者下载的是5.4.8版本
git clone https://github.com/lua/lua.git
修改代码
笔者的单片机工程是基于Makefile、Kconfig、arm-gcc编译的,和linux内核的编译环境类似。修改步骤如下:
1、删除lua.c和luac.c文件,lua.c是pc上使用的lua入口程序。luac.c是将lua脚本编译成字节码的程序,这个也删掉。
2、增加Makefile文件
C_INC-y += \
-I$(BASE_LUA_DIR)/ \
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lapi.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lcode.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lctype.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/ldebug.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/ldo.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/ldump.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lfunc.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lgc.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/llex.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lmem.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lobject.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lopcodes.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lparser.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lstate.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lstring.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/ltable.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/ltm.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lundump.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lvm.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lzio.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lauxlib.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lbaselib.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lcorolib.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/ldblib.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/liolib.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lmathlib.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/loadlib.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/loslib.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lstrlib.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/ltablib.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/lutf8lib.c
C_SRC-$(CONFIG_BASE_LUA) += $(BASE_LUA_DIR)/linit.c
3、增加Kconfig文件
config BASE_LUA
tristate "add lua support"
default n
help
add lua support.
4、修改链接脚本,加大c代码栈空间
_system_stack_size = 0x1000;
5、修改lauxlib.c中的堆内存分配函数,使用freertos的heap_4实现堆内存分配,给lua解析器预留约32KByte
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
(void)ud; (void)osize; /* not used */
if (nsize == 0) {
kfree(ptr);
return NULL;
}
else
return krealloc(ptr, nsize);
}
6、修改linit.c裁剪部分功能,节省flash空间
static const luaL_Reg loadedlibs[] = {
{LUA_GNAME, luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_COLIBNAME, luaopen_coroutine},
{LUA_TABLIBNAME, luaopen_table},
// {LUA_IOLIBNAME, luaopen_io},
// {LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_UTF8LIBNAME, luaopen_utf8},
// {LUA_DBLIBNAME, luaopen_debug},
{NULL, NULL}
};
7、创建单片机版的lua.c作为运行lua程序的入口,笔者使用fal库管理flash分区,将lua脚本存放在了flash的一个分区中,lua.c实现如下:
#include "shell.h"
#include "string.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "board.h"
#include "heap_4.h"
#include "clib.h"
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "boot.h"
#define LUA_SCRIPT_SIZE (8 * 1024)
extern int check_part(const char *part_name, const char *sys_id, uint32_t *size, uint32_t *crc);
static void lua_exec(int argc, char *argv[])
{
int ret = 0;
const struct fal_partition *part;
uint32_t size, crc;
lua_State *L = NULL;
char *lp = kmalloc(LUA_SCRIPT_SIZE);
if (lp == NULL) {
printf("kmalloc fail!\n");
return;
}
/* 校验data分区 */
ret = check_part(BOOT_DATA_PART_NAME, LUA_ID, &size, &crc);
printf("size=0x%x, crc=0x%x\n", size, crc);
if (size > LUA_SCRIPT_SIZE) {
printf("Lua script cannot be larger than %d!\n", LUA_SCRIPT_SIZE);
}
if (ret == 0) {
part = fal_partition_find(BOOT_DATA_PART_NAME);
if (part == NULL) {
printf("%s part not found.\n", BOOT_DATA_PART_NAME);
goto fail;
}
if (fal_partition_read(part, F_BOOT_CRC_START, (uint8_t *)lp, size) < 0) {
printf("%s part read error!", BOOT_DATA_PART_NAME);
goto fail;
}
lp[size] = '\0'; // 设置结束符
L = luaL_newstate();
luaL_openlibs(L);
printf("running...\n\n");
if (luaL_dostring(L, lp) == LUA_OK) {
const char *result = lua_tostring(L, -1); // 获取返回值
printf("Result: %s\n", result); // 打印结果
} else {
printf("Error in executing code: %s\n", lua_tostring(L, -1));
}
lua_close(L);
}
fail:
kfree(lp);
return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(
SHELL_TYPE_CMD_MAIN) | SHELL_CMD_DISABLE_RETURN, \
lua, lua_exec, lua exec);
以上就完成了lua代码的移植,编译后lua解析器约占200Kbyte
验证执行
编写lua脚本如下:
print("Hello World!");
print(_VERSION);
下载到data分区,使用lua命令运行,结果如下:
*stm32:/$ lua
size=0x27, crc=0x41d32920
running...
Hello World1
Lua 5.4
Result: (null)