microbit 上で Luaを動かす

3 min読了の目安(約3000字TECH技術記事

はじめに

Luaをmicrobitで動かす時に実施した内容を記載します。
といってもまだ、qemu上での動作を確認したのみです。

動作している様子は以下。

コードは以下においています。

https://github.com/SaitoYutaka/lua-on-microbit

やったこと

必要なライブラリの取得

起動まで

まずは、起動(電源を入れてからmain関数がよばれるまで)の処理を用意します。
自前で用意するのは大変なので、既存のものを利用します。

利用するのは以下の2つ。

https://github.com/NordicSemiconductor/nrfx
https://github.com/ARM-software/CMSIS_5

Luaのビルド

Luaで使用しているライブラリをどうするか最初はわかりませんでしたが、
以下Newlibが利用できそうなことがわかりました。

https://sourceware.org/newlib/

上記に含まれるヘッダファイルを利用すれば、Luaのビルド(liblua.aのビルド)が
できると考えていたのですが、できませんでした。
何が原因だったかというと、ビルド時に以下のように-nostdincをつけていることにより
エラーとなっていました。

# https://github.com/SaitoYutaka/lua-on-microbit/blob/main/lua-5.4.1/src/Makefile#L10
CFLAGS= -O2 -Wall -Wextra -nostdinc -mcpu=cortex-m0 -mthumb -mabi=aapcs \

必要なヘッダはNewlibにすべて含まれているかと思っていたのですが、
Newlib内のヘッダに以下のような記載がありました。

#if defined __GNUC__ && !defined _GCC_LIMITS_H_
/* `_GCC_LIMITS_H_' is what GCC's file defines.  */
# include_next <limits.h>
#endif /* __GNUC__ && !_GCC_LIMITS_H_ */

# include_nextって知らなかったのですが、
ドキュメントに以下の記載がありました。

https://gcc.gnu.org/onlinedocs/cpp/Wrapper-Headers.html

# include_nextのコメントに_GCC_LIMITS_H_' is what GCC's file defines.
あるようにgccのソースツリーに含まれるlimits.hをインクルードしていることがわかりました。また、ヘッダファイルの置き場所をあまり意識していなかったのですが、
gccのソースツリーに置かれているヘッダ(かつLuaでインクルードしている)は
上記 limits.h以外にもありました。

ざっと見た感じ、ファイル単体で完結しているようだったので
(さらに、別のファイルをインクルードしているとかなさそうだったので)
まとめてincludeフォルダを作成してそこに置くことにしました。

https://github.com/SaitoYutaka/lua-on-microbit/tree/main/include

Luaの修正

いきなり、全てビルドすると絶対ハマると思ったので、
以下のように最低限のライブラリをロードするように修正。

linit.c内のloadedlibsをluaopen_base以外すべてコメントアウトしました

/*
** these libs are loaded by lua.c and are readily available to any Lua
** program
*/
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}
};

Makefileも以下のように修正

LIB_O=	lauxlib.o lbaselib.o linit.o

printf

標準出力へfwriteしている箇所をprintf_変更しました

printf_ は以下を使用しています。

https://github.com/mpaland/printf

簡易Luaインタプリタ

自分で作ったのはほぼmain.cだけ。
参考にしたコードはこちらです
シリアル入出力設定、nrfx を使用しているので簡単にできました。

今後の予定

現状は簡易インタプリタが動いているだけなので
(ここまでくるのも結構たいへんでしたが)、
LEDの点灯とかLuaスクリプトから制御できるようにしていこうと、考えています。