Try Kernel を eclipse 抜きでビルドする(1)

CQ出版のインターフェース誌7月号で「ラズパイPicoで1500行 ゼロから作るOS」という特集記事があり、面白そうなので購入してみた。

https://interface.cqpub.co.jp/magazine/202307/

Raspberry Pi pico にRTOSを自前で実装しようという試みで、ブートストラップの流れもていねいに書かれており、RTOSの勉強にもなるし、理解があやふやだったマイコンの起動の仕組みもわかるかと思い、書籍に従って実験しようと思った。

ただ、読み進めていくと開発環境として Windows 上の eclipse を使うことが書かれている。医者に eclipse の使用を固く禁じられている身としては同じように試せない。そこで、eclipse を使わず、ubuntu 22.04 上でビルドする方法を考えてみた。

Try Kernel ソースの準備

Try Kernel のコードは github から最新版を入手できるので、クローンしておく。

https://github.com/ytoyoyama/interface_trykernel

git clone https://github.com/ytoyoyama/interface_trykernel.git

章ごとにフォルダが別れており、順に実装しながら学べるようになっている。まずは、最初の一歩として第2部第3章のLチカのプログラムをビルドしてみる。

このサンプルでは電源オン時のリセットハンドラから、マイコンの初期化を行い、Lチカのメインプログラムを実行するまでのプログラムがコンパクトに書かれている。

コードは interface_trykernel/part_2/sect_3 ディレクトリに以下の構造で格納されている。

$ tree .
.
├── application
│   └── main.c
├── boot
│   ├── boot2.c
│   ├── reset_hdr.c
│   └── vector_tbl.c
├── include
│   ├── knldef.h
│   ├── sysdef.h
│   ├── syslib.h
│   └── typedef.h
└── linker
    └── pico_memmap.ld

4 directories, 9 files

シンプルなディレクトリ構成で、applicationディレクトリにアプリ本体のソースが、bootディレクトリに必要なブートストラップやライブラリソースが、includeディレクトリに定義ファイルがそれぞれ格納されている。linker ディレクトリにはリンクマップの定義ファイルが格納されている。

開発環境の準備

上記コードのビルドには、ARMのクロスコンパイラが必要となるが、Raspberry Pi pico のSDKの開発環境が以下の github に一式整えられており、導入方法の説明も書かれているので参考にする。

https://github.com/raspberrypi/pico-sdk

この github では、cmake と gcc cross compiler が必要とあり、以下のようにパッケージをインストールするよう書かれている。

sudo apt install cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib

自分の環境では全てのパッケージがインストール済みだったので何もする必要はなかったが、Try Kernel のビルドには gcc-arm-none-eabi だけあれば何とかなるんじゃないかと思う。

とりあえずコンパイル&リンク

まずはコンパイルしてどんな感じになるか確認することにした。

$ cd interface_trykernel/part_2/sect_3
$ /usr/bin/arm-none-eabi-gcc -I include -mthumb -mcpu=cortex-m0plus -c application/*.c boot/*.c

コンパイルオプションはググって適当に設定してみたものだが、特に何のエラーも出なかった。幸先よし。

次に、オブジェクトをリンクしてみる。

$ /usr/bin/arm-none-eabi-gcc -nostartfiles -Wl,--script=linker/pico_memmap.ld -Wl,-z,max-page-size=4096 -Wl,--gc-sections *.o -o out.elf
/usr/lib/gcc/arm-none-eabi/10.3.1/../../../arm-none-eabi/bin/ld: main.o: in function `delay_ms':
main.c:(.text+0x3a): undefined reference to `__aeabi_uidiv'
/usr/lib/gcc/arm-none-eabi/10.3.1/../../../arm-none-eabi/bin/ld: reset_hdr.o: in function `init_pll':
reset_hdr.c:(.text+0xaa): undefined reference to `__aeabi_uidiv'
/usr/lib/gcc/arm-none-eabi/10.3.1/../../../arm-none-eabi/bin/ld: reset_hdr.c:(.text+0xc8): undefined reference to `__aeabi_uidiv'
/usr/lib/gcc/arm-none-eabi/10.3.1/../../../arm-none-eabi/bin/ld: reset_hdr.o: in function `clock_config':
reset_hdr.c:(.text+0x1b4): undefined reference to `__aeabi_uldivmod'
collect2: error: ld returned 1 exit status

こちらのリンカオプションはあれこれ検索してやっとたどり着いたもの。特に –script オプションでリンクマップを指定する方法がわからなくて苦労した。

とはいえ、__aeabi_uidiv と __aeabi_uldivmod が実装されていないというエラーが出てしまっているのがわかる。標準的なライブラリをリンクしておらず、非負整数の割り算を行う関数がないために発生したエラーなので、何らかの形で用意しなければならない。

記事が長くなったので、とりあえずここまで。次回はちゃんとコードを用意してビルドを行う。