Arm Cortex-M3、Cortex-M4アプリケーション中の見つけにくいバグを発見する方法
デバッグの作業は、開発において常に大きな割合を占めます。今日、ほとんどの開発者はJTAG/SWDのデバッグプローブを利用可能であり、基本的なデバッグ作業であれば、そういったプローブで充分間に合います。しかし、比較的安価で入手できるトレースプローブを使用すれば、アプリケーションの詳細動作を把握するために、さらに強力な機能を手に入れることができ、デバッグの問題を大幅に簡素化するこができます。
Arm Cortex-M3やCortex-M4コアベースのデバイスを採用した場合、チップ内蔵の便利なデバッグロジックから多くのメリットを得ることができますが、この機能と強力なデバッガを併用すると、アプリケーションの動作を様々な角度から検討することが可能になります。
このデバッグ機能は、図1に示すように5つの部分で構成されています。なお、この中にはETM(Embedded Trace Macrocell)のようなオプションの機能もあるため、使用するデバイスに含まれている機能を確認しておく必要があります。
図1. ARM Cortex-M3およびCortex-M4デバイスのデバッグ機能構成
SWOトレース
計装トレースマクロセル(ITM: Instrumentation Trace Macrocell)は、指定のトレースデータを低速アクセスポートから送る軽量なトレースを提供します。計装トレースは、開発者が常備しているI-jetなどの安価なデバッグプローブを使って行うことができます。ITMはソフトウェアトレース用に32チャネルを備えており、これを使用してソフトウェアが、SWOからデバッガに出力するパケットを生成することができます。ITMを使用した場合、コアはメッセージやデータ出力時に停止する必要がなくなるので、ほとんどオーバーヘッドなしでコードの計装が可能になります。必要な作業は、32個のITMスティムラスレジスタの中の1個に1度書き込むだけなので、命令毎にトレースを行う方法とは比較にならないほど簡単です。
ITMは、別ユニットであるDWT (Data Watchpoint and Trace)によってトリガされるトレースイベントの処理も行います。DWTでは、システムバスから情報を取得するとともに、ITMに対してパケット化、タイムスタンプ、SWOチャネルへの出力を行わせるイベントを生成します。
DWTには、アドレスまたはデータが一致した場合にイベントを生成できる4つの独立した比較器、すなわちウォッチポイントがあります。ウォッチポイントはさまざまな目的で使用可能で、条件の成立時に、ETMのトリガやITMパケットのトリガを発生させたり、コードブレークに使用したりすることができます。実行時間が長いアプリケーションをデバッグする場合は、4つのウォッチポイントの1つをETMのトリガ用に設定すると便利です。この場合、単純なトレース開始・停止ブレークポイントを設定して、指定のアドレスでトレースデータ取得を開始・停止できるだけでなく、変数が所定の値になったときにトレースを開始・停止するといった複雑な条件を設定することもできます。
さらにDWTには、割込みトレース機能やプログラムカウンタレジスタを一定間隔でサンプリングするPCサンプリング機能があります。このサンプリングでは、実行される命令の大半はサンプルされないため、アプリケーションが実行した位置をすべて把握することは不可能ですが、アプリケーションがどの関数に時間を費やしたのかを知ることは可能です。
Embedded Trace Macrocell
ITMもDWTも非常に有用で、大抵の組込みプロジェクトに充分機能しますが、最大の難問に取り組むために、より高機能なデバッグモードが必要となる場合があります。ETM (Embedded Trace Macrocell)を使えば、実行したすべての命令を1つ1つトレースし、MCUの動作に関して極めて高度な知見が提供されるため、他の方法では見つけ難い、あるいは見つけることのできないバグを発見することが可能です。
ETMを使用するには、命令をメモリに格納できる特別なトレース用デバッグプローブが必要です。格納できる命令の数、すなわちサンプル数には、当然のことながらメモリサイズによる制限があります。IARシステムズのトレースプローブI-jet Trace for Arm Cortex-Mは、一度に4ビットのトレースデータを読み、これを1サンプルと呼んでいます。4ビットはArm Cortex-Mデバイスの標準のトレース幅です。I-jet Traceのトレースメモリは、最大32 Mサンプルと大容量ですが、ETMプロトコルは圧縮されているため、サンプル数と命令数は1対1にはなりません。1サンプルあたりの命令数が最も多くなるのは、完全な線形実行時(コード中にジャンプ命令も分岐命令もない)で、7.5命令です。平均すると4ビットサンプルあたり約2命令です。
DWTやITMのイベントトレース機能と異なり、ETMでは、割込みが発生する前にアプリケーションが何を行っていたのか、またISRを実行中に何の動作をしていたのか、さらに割込み処理後に何が生じたのかを知ることができます。この結果、アプリケーションの実行位置やそこに至るまでの状況が正確に通知されます。つまり、アプリケーション動作の一部始終を非侵襲的にリアルタイムで知ることが可能です。
デバッグにおけるトレースデータの使用法として最もわかりやすい例は、プログラムの実行に逸脱が生じた場合に、時間を遡って見直すことです。プログラムの実行が逸れた場合、実行を停止してトレース出力を調べることで問題の発生場所を見つけ出すことができます。
図2: IAR Embedded WorkbenchでETMトレース出力を調べる
ETMトレースには、プログラムを遡って実行状況を調べるというトレースの標準的な使用以外に、有用な機能があります。コードカバレッジ解析機能は、コードのどの部分が実行され、どの部分が実行されなかったかを示してくれます。この情報により、コードが隅々までテストされたことを確認できるため、テスト時に極めて有用です。関数プロファイル機能は、関数ごとに費やされた時間を示すので、コードを最適化して改善するために、どの部分に最も注力すべきかを判断する手がかりとなります。サンプリングしたSWOトレースによる関数プロファイル機能も有用ですが、これは静的プロファイルをベースにしており、ETMトレースで得られるフルトレースデータに基づくものではありません。
これまで説明してきた機能はすべてIAR Embedded Workbenchで利用可能で、ETMトレースを備えたI-jet Traceのようなトレースプローブを使用することで実現できます。