引き続き Raspberry Pi を使った PiTrex プログラムの作成方法について検討します。今回はベアメタル環境でデバッグプリントを表示する方法を調べました。
ベアメタル環境でのエラー
前回の投稿で、ベアメタル版 hello.img をインストールする際に次の手順が含まれていました。
2. /boot/settings ディレクトリを作成します。
sudo mkdir /boot/settings
/boot/settings ディレクトリはベアメタル版バイナリの実行に必須ですが、Makefile では作成されないため手動で作成する必要があります [注]。当初私はこれに気づかなかったため、/boot/settgings ディレクトリがない状態で hello.img プログラムを起動して Vectrex 画面に次のようなエラーメッセージを出していました。
このエラーメッセージは十分な情報を与えてくれないので原因を絞り込めません。さらに悪いことに、この画面でプログラムが停止してしまいます。ベアメタル環境では OS に戻ってあれこれ調べるというわけにもいかず、電源を切る以外にできることはありません。
ひとまず SD カードを PC に接続して /boot/config.txt の設定をベアメタル環境から OS 起動環境に戻しました。Raspberry Pi OS を起動して pitrex リポジトリ全体で文字列 “NO DIRECTORY” を検索したところ、pitrex/vectrex/osWrapper.c に次の記述が見つかりました。
問題のエラーはカレントディレクトリの変更中に発生していることがわかります。行番号 398 の v_error("NO DIRECTORY");
が Vectrex 画面にエラーメッセージを表示しているようです。その上の行(行番号 397)に
printf("NO %s directory found...!\r\n", _dir);
という記述があります。これはいわゆるデバッグプリントで、移動先ディレクトリ名を表示しています。このデバッグプリントを読んで問題となるディレクトリ名を確定したいところですが、残念ながら printf() 関数は Vectrex 画面へは出力されません。printf() の出力は標準出力、つまり Raspberry Pi のコンソールに対する出力になりますが、ベアメタル環境では ssh 端末や HDMI モニタは使えません。OS が走っていないので、特に配慮しなければ Wifi もディスプレイコントローラも初期化されないためです。
シリアルコンソールの追加
実はベアメタル環境でもシリアルインターフェイスだけは初期化されており、printf() 出力は Raspberry Pi Zero W の GPIO UART ピンに出ます。詳細は PiTrex baremetal の作者 Malban 氏の blog で説明されています。UART ピンの設定は
GPIO Header pin8 : TX
GPIO Header pin10 : RX
GPIO Header pin 9 : Gnd
となっており、printf() の内容は RX ピンにシリアル信号として出力されます。
これらの GPIO ピンに USB シリアル変換モジュールを繋げば PC 上の端末ソフトウェアで printf() 関数によるデバッグ出力を確認できます。USB シリアル変換モジュールは Raspberry Pi GPIO 対応のもの、つまり 3.3V レベルのシリアル接続ができるモジュールを選択します。以下のように接続します。 GPIO pin8 (TX) : USB Serial RX
GPIO pin10 (RX) : USB Serial TX
GPIO pin9 Gnd : USB Serial
Gnd
RX と TX はクロス接続します。これはコンピュータ同士をシリアル接続する際の要点です。実態は次の写真のような感じになります。
USB ケーブルの他方の端は PC の USB 端子に接続します。
Malban 氏の blog によるとシリアルコンソールの通信速度は 115200 bps ですので、これに準じて PC のシリアル通信ソフトを設定、起動します。例えば Mac の場合はターミナルウィンドウで次のコマンドを実行します。
screen /dev/tty.usbserial-00000000 115200
“usbserial-00000000
” の部分は使用する USB シリアル変換モジュールによって異なります。
デバッグプリントの確認
以上でデバッグプリントを PC で受信する準備が整ったので、再度 hello.img をベアメタル環境で起動します。Vectrex の電源を入れると前掲のエラー画面で停止しますが、同時に Mac 上のターミナルウィンドウに次の内容が出力されます。
メッセージ中の次の行NO settings directory found...!
が、前述の pitrex/vectrex/osWrapper.c ファイル内の printf() 関数によるデバッグプリントです。つまり失敗した移動先ディレクトリの名前が ‘settings’ であることがわかります。
残念ながらディレクトリのフルパスはここでは表示されません。しかし実行元プログラムである hello.img は /boot/ ディレクトリにありますから、プログラム実行中に作業ディレクトリを移動していなければ期待されるフルパスは /boot/settings です。
Vectrex の電源を切り、Raspberry Pi Zero W から SD カードを抜き出して PC にセットします。boot ディレクトリがマウントされるので、その中に settings ディレクトリを作成します。
SD カードを Raspberry Pi Zero W に戻して Vectrex の電源を入れると、hello.img プログラムが正しく実行されるようになりました。
同じ hello_world プロジェクトを Raspberry Pi OS 環境でビルドした場合は hello_world ディレクトリに hello バイナリが作成されます。hello_world/settings ディレクトリはリポジトリ内に最初から用意されているので、hello バイナリを実行しても ”NO DIRECTORY” エラーは発生しません。つまり settings ディレクトリの欠落はベアメタル環境特有の問題であるため、シリアルコンソールを接続してベアメタル環境でデバッグプリントを確認しない限り見つけるのは困難だったと思われます。
注:あとから調べたところ pitrex-config.sh を実行すると /boot/settings ディレクトリが作成されるようです。