昨日、Mbed-CLI環境が立ち上がり(といっても大した作業はしていませんが)ローカル環境でビルドも成功しました。GCC_ARMのクロスツールチェーンの中を見やればgdbも入っています。これでデバッグできるかといえばさにあらず。WindowsやLinuxの上で自OSの上で動作するプログラムを作るセルフ開発であればgdbでセルフデバッグできますが、マイコン(ROM/RAM積んだマイクロコントローラ、MCU)のクロス開発環境ではそうは問屋が卸しません。リモートデバッグのための準備が必要です。
※「鳥なき里のマイコン屋」投稿順Indexはこちら
リモートデバッグというと真っ先に浮かぶのが、
gdbserver
でしょうか。被デバッグ側のマシンで動かしておいて、それに手元のgdbを接続してリモートのデバッグを行う、と。しかし、1行引用しましょう。
gdbserver is a control program for Unix-like systems,
です。ちっこいマイコン相手には、また別の「デバッグサーバー」が「いろいろ」存在します。マイコンメーカーや、開発ツールメーカーがそれぞれの対応機種に出されているのですが、今回使用させていただくのは、
The Open On Chip Debugger という「無償、無保証」系のツールです。詳しいことはサイトに行ってみてください。調べたところ、非常に多数の会社のMCUやボードに対応しており、今回ターゲットにしているNUCLEO-F072RBボードにも対応。
ざっくり言うと、ボード上にはマイコンとボードのメーカであるST Microのデバッグ用のインタフェース(当然ソフトを含む)が搭載されており、パソコンの上で動作するOpenOCDはこれと通信しながらデバッグを制御するわけです。さらに、その上にデバッグのCUIフロントエンドとして、リモートデバッグモードで動かすgdbが乗り、gdbにコマンドを打ち込むと、OpenOCDに伝わり、それがボード上のデバッグインタフェースに伝わって、最終的にプログラムの動作に介入してデバッグができるという仕組み。随分な階層に見えますが、GUIでデバッグをする場合には(私もgdbのコマンドを直接叩くよりは、GUIで行の頭をクリクリしてブレーク張る方が楽に思える方であります)、さらにこの上にもう一階層重なるわけで、屋上屋を重ねるとはまさにこのことか。
本題に戻ると、Windows上でOpenOCD走らせたい場合、
でインストールするのがお楽なようです。MSYS2はMinGWの系統のw64実装という理解です。こちらも上からホームページにリンク張っておきました。幸か不幸か今回Mbed-CLI環境用に作ったWindowsのコマンドプロンプトには、MSYS2へのパスが切ってありました。別にMSYS2のbashを立ち上げなくとも、MSYS2のpacmanコマンドが使えれば OpenOCDをインストールすることができます。
$ pacman -Ss openocd
とやって、openocdでヒットするインストールパッケージを列挙させます。ここで結構こんがらがるのが、mingw32用とmingw64用の両方が列挙されてくることです。インストールしてあるMSYS2の環境に合わせて適切な方をインストールします。
$ pacman -S インストールパッケージ名
大した時間もかからず、インストールは完了します。ここでちょっと調べるのが、openocdに付属している各種ボードやデバッグインタフェース用の初期化スクリプトファイルの在りかです。私の環境では、インストールしたmingw64の下のshareの中にopenocdのスクリプトやインタフェースのディレクトリが作成されており、その中に NUCLEO-F072RBボードに対応する
st_nucleo_f0.cfg
と、STのデバッグインタフェース用の
stlink-v2-1.cfg
の2つのスクリプトが格納されていました。これさえあればOpenOCDをコンフィギューレションできる筈。なお、OpenOCDのマニュアルをつらつら眺めていると、コンフィギュレーションが終わったら必ず
init
(initするとコンフィギュレーション終了)
そして、
reset init
ターゲットボードはハードresetされて初期化、halt状態で止まる。とかかれています。この辺の設定は、openocd.cfg という初期化ファイルに入れておいてもよいのかもしれませんが、コマンドラインから、スクリプトは-fオプションの引数にして、コマンドは-cオプションの引数で与える(といってBATファイルですが)ことにいたしました。なお、reset initの間にスペースがあるので””で囲うこと必須。
ボードを接続したのち、OpenOCDを起動すれば、起動のメッセージが出てきます。このコマンドウインドウは OpenOCDのメッセージ用になってしまうので、gdbを使うには、もう一つ別なコマンドウインドウを開けてようやく
$ arm-none-eabi-gdb オブジェクトファイル名.elf
とやってgdbを起動(ここでは、ELFファイルが出力されているBUILD結果のフォルダに入って起動している)。勿論、昨日のビルドオプションによりELFファイルにはデバッグ情報がたんと含まれております。
次に、gdbをデバッグサーバたるOpenOCDに接続しないとなりません。
(gdb) target remote localhost:3333
ポート3333はデフォルトのようです。起動オプションで変更できる筈。これでリモートデバッグ用のモードになったので、monitorコマンドを使ってみます。monitorコマンドは引数をそのままデバッグサーバーに送り込むコマンドなのでOpenOCDのコマンドをそのまま書けます。
(gdb) monitor reset halt
とすれば、ボードにハードResetかけて、haltで停止。ブレークした後にでも
(gdb) monitor reg
などとすれば、OpenOCD側でレジスタダンプします。gdbをバイパスして直接ローレベルで操作もできる。でもまずは、オブジェクトをボードに送り込まないと。
(gdb) load
これで、各セクションをどこのアドレスに何バイト送ったとかメッセージがでるので、プログラムの配置完了。さっそくブレークポイントを張ってプログラムを起動。ここで注意は、Flash ROM上のプログラムのデバッグなので、
(gdb) hbreak main
などとハードウエアブレークポイントで設定すること。どうも、OpenOCD側の設定によっては、gdbから送られてくるbreakをhbreakに読み替えるオプションがあるようなので、こちらはお好みで設定した方がよいかも。プログラム側に制御を移すには
(gdb) continue
すると mainに張ったブレークでプロンプトが戻ってきます。とりあえずデバッグの入口までたどり着けた。まだまだ大変そうだけれども。
なお、OpenOCDを止めるには
(gdb) monitor shutdown
とやれば、OpenOCDはshutdownして、そちらのウインドウにプロンプトが返ってきます。gdbの方は
(gdb) quit