Cortex-M3開発経験(3):スタック情報を印刷HardFault
で:我々は間違った場所を見つけるためにどのように言及し、「のCortex-M3の開発経験(2)HardFaultの局所的な発生を確認してください」。しかし、それはデバッガをリンクしなければならない問題があります。いくつかのケースでは、我々はデバッガを接続することはできませんので、あなたはまだスタック情報を読み取ることができないのだろうか?私たちは、HardFaultは、スタックポインタを取得するに入ることができたときには、シリアルポートを介しての方法、それをプリントアウト?
先に行って、良いアイデアを持って、また自分の考えを検証するための具体的な行動がなければなりません。
スタックポインタを取得する方法は?
私たちは、最初の質問は、スタックポインタを取得する方法である立ち往生。SP ,, PSP(プロセス・スタックポインタ)MSPの値(メインスタックポインタ)Aを取得する方法です。
「のCortex-M3 Definitive Guideの」で、非常に多くの言葉があります:CM3(SPを書く)R13を参照するときには、2つのスタックによってサポートされているように、2つのマイクロコントローラ・コアスタック・ポインタがありますが、現在への参照ですその1(MSPまたはPSP)を使用し、他のアクセス(MRSおよびMSR命令)に特別な命令を使用する必要があります。
言い換えれば、我々は、スタックポインタを取得するために、アセンブラ命令を使用する必要があります。
uint32_t get_msp_addr()
{
__asm("mrs r0, msp");
__asm("bx lr");
}
uint32_t get_psp_addr()
{
__asm("mrs r0, psp");
__asm("bx lr");
}
uint32_t get_sp_addr()
{
__asm("mov r0, sp");
__asm("bx lr");
}
注:Cコンパイラをサポートし、各組み込みアセンブリごとに異なる、いくつかのコンパイラは__asmがサポートされていないことがあります。
カーネルスタックポインタレジスタの値によって取得
uint32_t reg_buff[10];
uint32_t *sp = NULL;
void HardFault_Handler()
{
sp = (uint32_t*)get_msp_addr();
reg_buff[0] = *(sp++);
reg_buff[1] = *(sp++);
reg_buff[2] = *(sp++);
reg_buff[3] = *(sp++);
reg_buff[4] = *(sp++);
reg_buff[5] = *(sp++);
reg_buff[6] = *(sp++);
reg_buff[7] = *(sp++);
reg_buff[8] = *(sp++);
reg_buff[9] = *(sp++);
while(1){}
}
コンパイルして実行します!
結果はやや予想外!
LR値とステッピング前にPCの値は、私たちを好きではありません!12バイトのオフセット。なぜ?後ろを振り返ると、私たちはget_msp_addr HardFaultにこの関数を呼び出して、それがスタック領域を使用することを意味関数を呼び出し、単一のステップを発見しました。私はreg_buff場合は12の以上のバイトを相殺するようHardFaultは、中に入れて!
何より良い方法ああはありません!?
我々はSPポインタの値にHardFault_Handler関数に取得し、それができないHardFault_Handlerに引数として渡す前に?
誰が割り込みハンドラを呼び出しますか?
それは、引数を受け取ることができるように上記の問題を解決するために、我々は、どこ我々は対応する割り込みハンドラを変更することができるように、カーネルの割り込み機能を呼び出すために知っておく必要があります。
「のCortex-M3開発経験(2):HardFaultのローカル発生を確認し、」我々は、中断のエントリアドレスを見つけ、対応する割り込みベクタテーブルを見つける中断し、中断/例外、カーネルを述べました。その後、我々は、ベクタテーブルを中断し何を見て?
最後に、我々はstartup_xxx.Sファイル内のベクタテーブルの定義を見つける1。また、HardFault_Handlerの定義を見つけます
.weak HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
B .
コンパイルが理解できないかもしれないが、私はそれが何を意味するのかわかりませんが、また、意味を推測すること、また、情報を見つけることができます。Bは、ジャンプ命令を発見され、これは、同じ名前のC関数にジャンプしなければなりません。次のようにその後、我々は変更することができます。
.weak HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
MOV r0, lr
MOV r1, sp
BL hardfault_handler
この値はSPとLRの値は行っhardfault_handler関数に渡される2。
コンパイルして実行します!
結果は、私たちが望むものです。