DWT
新幹線移動中の開発により、DWTを動作させることができるようになった。
割り込みで処理を追加した後に、正常動作に復帰できるし、これはいい。
純粋にデバッガの動作だけど、オンチップペリフェラルだけで
(アダプタとかプローブの類なしで)実現できるのはありがたい。
スタックの上限(というか余裕を持たせた警告エリアの方がいいが)
にウオッチポイントとアクセス方法(読み、書きの別など)を設定しておく。
スタックが侵食して、アクセスの条件が成立すると、
デバッグベクタに分岐して、通常の割り込みと同様に処理できる。
スタックポインタに余裕を持たせておけば、破綻することなしに
処理が続けられ、スタックの残りが少ないことが
実行されているプログラム自身で把握できる。
------
今回のターゲットはstm32l433だけど、Cortex-M3,M4なら
どれでも使える可能性はありそうだ。
設定例は以下。
プログラムの初期設定部分に記述して、DWTを有効にする。
// デバッグ例外、モニタ制御レジスタ
CoreDebug->DEMCR =
(1 << 24)| // TRCENA
(1 << 16)| // MON_EN
0;
CoreDebug->DHCSR =
(0xa05f << 16) | // 書き込みキー
(1 << 0) |
0;
*(volatile unsigned long*)(0xe0001020) = 0x2000e000; // DWT_COMP0
*(volatile unsigned long*)(0xe0001024) = 0x00000000; // DWT_MASK0
*(volatile unsigned long*)(0xe0001028) = 0x00000007; // DWT_FUNCTION0 書き込み/読み出しのウオッチポイント
*(volatile unsigned long*)(0xe0001000) |= 0x00000001; // DWT_CONTROL
割り込みハンドラも記述する。
//****************************************************************
// デバッグ 割り込みハンドラ
//****************************************************************
void DebugMon_Handler(void) {
static unsigned char temp[32];
volatile int i;
sprintf(temp, "\r\nDebug [%08X]\r\n\r\n", *(volatile unsigned long*)(0xe0001020));
Puts(temp);
stop = 1;
}
DWTがウオッチポイントへのアクセスを検出すると、
ハンドラが呼ばれるので、コンソールにメッセージを出力する。
0xe0001020は、DWTのコンペアレジスタ。
全部で4つあるので、最大4つのアドレス(エリア)を
同時に監視できる。
グローバル変数で定義されているstopにフラグを立てて戻る。
------
テストに、実際にスタックポインタを進めて、
どの辺で止まるか試してみる。
再起呼び出しで、毎回AUTO変数を定義するコードを書く。
一回の呼び出しで、116バイト分の変数を宣言するのだけど
実際のアドレスは、変数の呼び出し分のレジスタ退避エリア
などで、もう20バイト使われて、136バイトづつ消費されるようだ。
スタックの初期値は、0x20010000。
DWTの設定は上記のコードの通り、0x2000e000として、
動作させてみる。
シリアルコンソールに動作状態を出力させてみる。
58回目の呼び出しで、DWTが動作して、再起呼び出しが停止している。
この時のAUTO変数のポインタは、0x2000e0bcあたりを示していて、
DWTの設定値には、もう少しあるようにも見える。
今の場合でnewlib(sprintfとか)が、内部で使っているエリアが、180バイトくらい
あるのかなあ、という印象。
まあ、現実的な処かな?と思うので、なんとなく意図通りの
動きはしているように思える。
------
スタックの監視だけでなく、任意のエリアの不正なアクセスも
実行状態で、オーバヘッドなしにソフトウエアだけで監視できるので、
発見しにくいバグ(アクセス違反)を押さえるのに、大変役立ちそうだ。
標準コマンドとして整備しよう。
にウオッチポイントとアクセス方法(読み、書きの別など)を設定しておく。
スタックが侵食して、アクセスの条件が成立すると、
デバッグベクタに分岐して、通常の割り込みと同様に処理できる。
スタックポインタに余裕を持たせておけば、破綻することなしに
処理が続けられ、スタックの残りが少ないことが
実行されているプログラム自身で把握できる。
------
今回のターゲットはstm32l433だけど、Cortex-M3,M4なら
どれでも使える可能性はありそうだ。
設定例は以下。
プログラムの初期設定部分に記述して、DWTを有効にする。
// デバッグ例外、モニタ制御レジスタ
CoreDebug->DEMCR =
(1 << 24)| // TRCENA
(1 << 16)| // MON_EN
0;
CoreDebug->DHCSR =
(0xa05f << 16) | // 書き込みキー
(1 << 0) |
0;
*(volatile unsigned long*)(0xe0001020) = 0x2000e000; // DWT_COMP0
*(volatile unsigned long*)(0xe0001024) = 0x00000000; // DWT_MASK0
*(volatile unsigned long*)(0xe0001028) = 0x00000007; // DWT_FUNCTION0 書き込み/読み出しのウオッチポイント
*(volatile unsigned long*)(0xe0001000) |= 0x00000001; // DWT_CONTROL
割り込みハンドラも記述する。
//****************************************************************
// デバッグ 割り込みハンドラ
//****************************************************************
void DebugMon_Handler(void) {
static unsigned char temp[32];
volatile int i;
sprintf(temp, "\r\nDebug [%08X]\r\n\r\n", *(volatile unsigned long*)(0xe0001020));
Puts(temp);
stop = 1;
}
DWTがウオッチポイントへのアクセスを検出すると、
ハンドラが呼ばれるので、コンソールにメッセージを出力する。
0xe0001020は、DWTのコンペアレジスタ。
全部で4つあるので、最大4つのアドレス(エリア)を
同時に監視できる。
グローバル変数で定義されているstopにフラグを立てて戻る。
------
テストに、実際にスタックポインタを進めて、
どの辺で止まるか試してみる。
再起呼び出しで、毎回AUTO変数を定義するコードを書く。
一回の呼び出しで、116バイト分の変数を宣言するのだけど
実際のアドレスは、変数の呼び出し分のレジスタ退避エリア
などで、もう20バイト使われて、136バイトづつ消費されるようだ。
スタックの初期値は、0x20010000。
DWTの設定は上記のコードの通り、0x2000e000として、
動作させてみる。
シリアルコンソールに動作状態を出力させてみる。

58回目の呼び出しで、DWTが動作して、再起呼び出しが停止している。
この時のAUTO変数のポインタは、0x2000e0bcあたりを示していて、
DWTの設定値には、もう少しあるようにも見える。
今の場合でnewlib(sprintfとか)が、内部で使っているエリアが、180バイトくらい
あるのかなあ、という印象。
まあ、現実的な処かな?と思うので、なんとなく意図通りの
動きはしているように思える。
------
スタックの監視だけでなく、任意のエリアの不正なアクセスも
実行状態で、オーバヘッドなしにソフトウエアだけで監視できるので、
発見しにくいバグ(アクセス違反)を押さえるのに、大変役立ちそうだ。
標準コマンドとして整備しよう。
| 固定リンク | 0
コメント