
ETMトレースを使用した非侵襲性デバッグ
Embedded Trace Macrocell (以下:ETM)トレースは、アプリケーションで実行されるすべての命令をトレースし、マイクロコントローラの動作を観測する機能を提供します。本記事では、ETMテクノロジーが提供する機能を紹介し、ETMトレースがどのように開発者に役立つのかをサンプルアプリケーションを用いて説明します。
ETMトレースは高速なトレース機能を提供することで、通常のデバッグでは解決が難しい問題を解決するためのパワフルなデバッグを可能にします。ETMトレース最大の特徴のひとつは、非侵襲性(Non-Intrusive)である事です。システムの実行に影響を与える事が無く、CPUコアが実行する全ての命令をトレースする事が出来ます。コードカバレッジ、最適化、デバッグに対して、ETMトレースはコードが実際にどのように動作し、どのように最適化したらよいかについての知見を与えてくれます。この結果、コストと時間の両方を節約することが出来ます。ETMトレースを使用するには、IARシステムズ社のI-jet Traceのように命令をメモリ格納できる、特別なトレース用デバッグプローブが必要です。I-jet TraceはIAR Embedded Workbenchと組み合わせて使うことで様々なトレース機能を提供します。
ここからは、点滅するはずのLEDが点滅しない場合のサンプルアプリケーション例を使って説明します。この、ボリュームは小さいですが完結しているサンプルアプリケーションを使用して、他の方法では見つけ難い不具合を、ETMトレースを使って見つける方法を紹介します。
デバッグを行う前に、前提条件を説明します。ETMトレースを使用する場合、ターゲットボードにETMトレースが利用できるARM Cortexプロセッサが必要です(例えば、ARM Cortex-M3コアの場合、ETMトレースはオプションになります)。同様に、ARM CortexプロセッサのETMトレースピンをターゲットボード上のデバッグコネクタに接続する事が必要です。全ての評価ボードでETMトレースピンが必ずしもデバッグコネクタに接続されているとは限りませんのでご注意ください。
検出し難い不具合発見
このサンプルアプリケーションは、blink_LED関数でLEDを周期的に点滅します。led_state変数はLEDの状態を値0または1で保持し、blink_LED関数を呼び出す度にトグルします。以下の画面を参照してください:
このシンプルなサンプルプログラムは正しく動作するはずですが、実際に動作させると約30秒間LEDは点滅し、その後LEDは消灯します。
main.cを調べましたが、不具合の原因が判りません。おそらく、board_init関数にアプリケーションが誤動作する原因があるかも知れませんが、この関数は、ボードサポートライブラリ(boardlib.a)に含まれており、大きく複雑なライブラリであると考えます。
この問題を調査するために、ETMトレースを利用することが出来ます。I-jet Traceをターゲットボードに接続し、デバッグを開始すると、次のメッセージがデバッグログウィンドウに表示されます:
Probe: I-jet-Trace-ARM detected.
Probe: Opened in USB 3.0 mode
Probe: I-jet-Trace, FW ver 2.5 (2016/08/25, USB 2016/01/25), HW Ver:B
Probe: USB reading speed 384.0 MB/sec Data verified.
Download completed and verification successful.
Trace: ETMv3CM powered-up OK (ETMCR=0xc10)
Trace: Configured to collect ETM trace via MIPI-20 connector, 256MB trace memory used
Trace: Calibration [4-bit,tclk=90.00MHz,auto]: OK=#0, pattern=+++++++++++++++++++++++++++++++C+++++++++++++++++++++++++++++++
Trace: ETM read and validated (256B in 2ms - total 256B kept)
上記のデバッグログウィンドウのメッセージは、高速なUSB3.0を使用していることを示しています。(この場合の読み込みスピードは384 MB/second)また、フラッシュダウンロード終了後、ベリファイを実施しています。Trace: Calibrationという行は、プローブが90MHzのETMクロックを正常に検出したことを示しています。
その後、LEDが点滅しなくなるまで、アプリケーションを実行してみます。 LEDが点滅を止めた後に、ブレークポイントを以下のblink_LED関数に設定します:
この時、ブレークポイントがトリガされた時のウォッチウィンドウにてled_state変数が(常に)0になっており、想定した値であることが確認できます。それでは何故LEDが点滅しないのでしょうか?
調査をするには、メインメニューから、I-jet/JTAGjet > 関数トレースを選択し、関数トレースウィンドウで、アプリケーションでここに到達するまでに何が発生したかを確認します。関数トレースウィンドウをダブルクリックすることで、ブラウズモードを有効にすることが出来ます。ブラウズモードでは、ウィンドウが黄色に変わり、キーボードの矢印ボタンを使用して前後に移動できます:
関数トレースデータ上にて矢印ボタンで複数ステップ戻ることで、これまで確認していないSysTick_Handler関数に移動します:
ここで問題点を発見する事が出来ました。タイマ割り込みが定周期動作する様に設定されますが、約30秒後には割込みハンドラ起動されるたびに条件が成立して0x20000004番地に整数値「1」を書き込みます。このアドレスは、 led_state変数のアドレスです。led_state変数をタイマ割り込みが繰り返し上書きする事で、見た目LEDが点滅しなくなります。
この例は、とても簡単なひとつの例にすぎませんが、アプリケーション開発中に不可思議な問題が発生した場合にトレースが有効なツールであることを示しました。