手動Arduino
面倒すぎて死にそう
... WioTerminalを動かすためのライブラリはArduino(やtinygoやrust)くらいしか提供されていないため、Arduino Coreを普通のビルドシステムに載せ替えておく必要がある。しかも、このArduino CoreがWio Terminalの場合LGPLで、これは Atmelの標準ライブラリのライセンスと互換性が無い (Atmelのチップ以外での実行を禁止している) ので混ざらないように注意する必要まである。
Arduinoライブラリの仕様
Arduinoライブラリの仕様は arduino-cli
にドキュメントされている。
要は、
-
EDIT: 無くても良い。。library.properties
のあるディレクトリを検出する - ライブラリのフォーマットを判別する:
src
ディレクトリがあればArduino1.5、無ければレガシー(1.0)フォーマットとなる - Arduino1.5フォーマットライブラリの場合、
src
と そのサブディレクトリ をソースコードとして追加し、src
をインクルードパスに含める - レガシーなライブラリの場合、ルートディレクトリと
utility
ディレクトリをソースコードとして追加し、ルートディレクトリをインクルードパスに含める
仕様ではソースコードとして認識すべきglob式は特に決まっていないが、まぁ常識的に考えて *.c
*.cpp
と *.S
だろう。。(例えば素の *.s
(小文字) はソースコードなんだろうか..?)
.ino
の処理
Arduinoの"スケッチ"(通常のIDEの"プロジェクト"に相当する)は、.ino
の拡張子を持つファイルを含む。この拡張子の由来はArduino 1.0リリースノートにある。
ARDUINO 1.0 - 2011.11.30
[environment]
* The file extension for sketches has changed from .pde to .ino, to avoid
conflicts with the Processing software ("ino" are the last three letters
in "Arduino").
Arduino IDEは自動的に #include <Arduino.h>
と関数プロトタイプを補った上で全体をC++コードとしてコンパイルするようになっている。
If not already present,
#include <Arduino.h>
is added to the sketch. This header file (found in the core folder for the currently selected board) includes all the definitions needed for the standard Arduino core.
Prototypes are generated for all function definitions in .ino/.pde files that don't already have prototypes. In some rare cases, prototype generation may fail for some functions. To work around this, you can provide your own prototypes for these functions.
今回は他人のスケッチをコンパイルする必要は無いので、これらを実装する必要はない(= Arduinoライブラリは、これらのC++拡張部分を使用できない)。
ファイルリストを生成
... あんまり自信が無い。
とりあえずビルドを通す
ここまででビルドが通った。まだリンクしている内容が正しいかはわからんが。。
古いCMSISに依存している
レジスタ値等にCMSIS依存があるようなので追加しておいた。
... これCMSIS4なのか。。CMSISはよくバグってるのでできれば新しいのに追従して欲しいけど。。というかやっぱりバグってんじゃん。。更新。
COPY section type is unsupported
GNU GOLDで /cygdrive/f/wiowork/crosstool-ng/prefix/lib/gcc/arm-unknown-eabi/11.2.0/../../../../arm-unknown-eabi/bin/ld: error: /home/oku/repos/arduinotest/ArduinoCore-samd/variants/wio_terminal/linker_scripts/gcc/flash_with_bootloader.ld:191:9: COPY section type is unsupported
/cygdrive/f/wiowork/crosstool-ng/prefix/lib/gcc/arm-unknown-eabi/11.2.0/../../../../arm-unknown-eabi/bin/ld: error: /home/oku/repos/arduinotest/ArduinoCore-samd/variants/wio_terminal/linker_scripts/gcc/flash_with_bootloader.ld:202:16: COPY section type is unsupported
マジかよ。。 BFDの ld
を使うように修正。
-fuse-ld=bfd
で使うリンカを変更できる(ようにcrosstool-ngをconfigureしてある)。
_gettimeofday
がnewlibとArduinoの両方にある
/cygdrive/f/wiowork/crosstool-ng/prefix/lib/gcc/arm-unknown-eabi/11.2.0/../../../../arm-unknown-eabi/bin/ld.bfd: /cygdrive/f/wiowork/crosstool-ng/prefix/lib/gcc/arm-unknown-eabi/11.2.0/../../../../arm-unknown-eabi/lib/libc.a(lib_a-syscalls.o): in function
_gettimeofday': /cygdrive/f/wiowork/crosstool-ng/.build/arm-unknown-eabi/src/newlib/newlib/libc/sys/arm/syscalls.c:604: multiple definition of
_gettimeofday'; libArduinoCore.a(delay.c.obj):/home/oku/repos/arduinotest/build/../ArduinoCore-samd/cores/arduino/delay.c:55: first defined here
newlibのSyscall stubはLinux用なので要らない。ビルドしないようにする。これはcrosstool-ngで言うところの Disable the syscalls supplied with newlib
オプション、newlibのconfigureで言うと --disable-newlib-supplied-syscalls
にあたる。
getpid
等が必要になる
何故か /cygdrive/f/wiowork/crosstool-ng/prefix/lib/gcc/arm-unknown-eabi/11.2.0/../../../../arm-unknown-eabi/bin/ld.bfd: /cygdrive/f/wiowork/crosstool-ng/prefix/lib/gcc/arm-unknown-eabi/11.2.0/../../../../arm-unknown-eabi/lib/libc.a(lib_a-abort.o): in function
abort': /cygdrive/f/wiowork/crosstool-ng/.build/arm-unknown-eabi/src/newlib/newlib/libc/stdlib/abort.c:59: undefined reference to
_exit'
/cygdrive/f/wiowork/crosstool-ng/prefix/lib/gcc/arm-unknown-eabi/11.2.0/../../../../arm-unknown-eabi/bin/ld.bfd: /cygdrive/f/wiowork/crosstool-ng/prefix/lib/gcc/arm-unknown-eabi/11.2.0/../../../../arm-unknown-eabi/lib/libc.a(lib_a-signalr.o): in function_kill_r': /cygdrive/f/wiowork/crosstool-ng/.build/arm-unknown-eabi/src/newlib/newlib/libc/reent/signalr.c:53: undefined reference to
_kill'
/cygdrive/f/wiowork/crosstool-ng/prefix/lib/gcc/arm-unknown-eabi/11.2.0/../../../../arm-unknown-eabi/bin/ld.bfd: /cygdrive/f/wiowork/crosstool-ng/prefix/lib/gcc/arm-unknown-eabi/11.2.0/../../../../arm-unknown-eabi/lib/libc.a(lib_a-signalr.o): in function_getpid_r': /cygdrive/f/wiowork/crosstool-ng/.build/arm-unknown-eabi/src/newlib/newlib/libc/reent/signalr.c:83: undefined reference to
_getpid'
これはCRTが間違ってるっぽいな。。とりあえずstubを用意してビルドだけ通した。
extern "C"{
void _exit(int bogus){(void)bogus;}
void _kill(void){}
int _getpid(void){return 1;}
}
起動ロジックの確認
ここまでで、C++コードをELF形式のバイナリにすることはできた。実際のWioTerminalで動かすためには、更にCPU内蔵flashに書くバイナリに変換する必要がある。
適当にブートローダやArduinoのコードを確認したところ、単に .text
セクションと .data
セクションを連結すれば十分なようだ。
ブートローダ → Arduino
WioTerminalのブートローダのソースコードがどこにあるのかはわからなかったが、たぶんMSのUF2ローダと同じものなのでそれを確認する。
- UF2ローダーは
APP_START_ADDRESS + 4
に書かれているアドレスをフェッチして、ジャンプ先app_start_address
として保存 する。APP_START_ADDRESS
はブートローダ領域の直後で、APP_START_ADDRESS + 4
=0x4004
はexception_table
の2エントリ目になる - Arduino側の
exception_table
の2エントリ目 は関数Reset_handler
で、これが__etext
(=.text
セクションの終端) から.data
セクションのサイズぶんだけデータをコピーしたり、.bss
部分をゼロクリアしたりする
Flash イメージの生成
↑ のようなイメージは、単にELFを objcopy -O binary
すれば得られる。
イメージの確認
7-zipでELFを開いて .data
セクションを取り出し、
バイナリエディタで末尾を比較する。
書き込み
書き込みは簡単。Bossaを単に呼べばOK。ただ、CygwinのCMakeはWin32向けのパスを出力しないので、カレントディレクトリを変更してパス文字列仕様の違いを隠蔽している。
これで、CMakeでArduinoのビルドとスケッチの書き込みまでができるようになった。