定位ARM Hard Fault 的方法
1,??用Keil的話,可以做如下操作:
先將fault中斷函數的內容改為:
HardFault_Handler\
????????????????PROC
????????????????;EXPORT??HardFault_Handler?????????[WEAK]
????????????????;B??????????????????.
????????????????????????????????IMPORT hard_fault_handler_c ?
????????????????????????????????TST LR, #4??
????????????????????????????????ITE EQ??
????????????????????????????????MRSEQ R0, MSP??
????????????????????????????????MRSNE R0, PSP??
????????????????????????????????B hard_fault_handler_c??
????????????????ENDP
************************************************insert start*************************************************
摘抄自Triton.zhang——eeworld
1. MSP和PSP 的含義是Main_Stack_Pointer 和Process_Stack_Pointer,在邏輯地址上他們都是R13
2. 權威手冊上說的很清楚PSP主要是在Handler的模式下使用,MSP主要在線程模式下使用(當然你在線程模式下也可以調用PSP,需要你做特殊的處理).
3. 這意味著同一個邏輯地址,實際上有兩個物理寄存器,一個為MSP,一個為PSP,在不同的工作模式調用不同的物理寄存器。舉一個簡單的例子,很多MCU的的UART只有一個BUFF,TXBUFF和RXBUFF都是一個地址,當你寫BUFF時寫入的是TXBUFF, 讀操作時調用的是RXBUFF。基本原理就是這樣。
4. 至于為什么這么設計,我想是為了在進行模式轉換的時候,減少堆棧的保存工作。同時也可以為不同權限的工作模式設置不同的堆棧。
************************************************insert end***************************************************
然后在源程序里添加下面的函數代碼:
// hard fault handler in C,??
// with stack frame location as input parameter??
void hard_fault_handler_c(unsigned int * hardfault_args)??
{??
unsigned int stacked_r0;??
unsigned int stacked_r1;??
unsigned int stacked_r2;??
unsigned int stacked_r3;??
unsigned int stacked_r12;??
unsigned int stacked_lr;??
unsigned int stacked_pc;??
unsigned int stacked_psr;??
stacked_r0 = ((unsigned long) hardfault_args[0]);??
stacked_r1 = ((unsigned long) hardfault_args[1]);??
stacked_r2 = ((unsigned long) hardfault_args[2]);??
stacked_r3 = ((unsigned long) hardfault_args[3]);??
stacked_r12 = ((unsigned long) hardfault_args[4]);??
stacked_lr = ((unsigned long) hardfault_args[5]);??
stacked_pc = ((unsigned long) hardfault_args[6]);??
stacked_psr = ((unsigned long) hardfault_args[7]);??
printf ("[Hard fault handler]\n");??
printf ("R0 = %x\n", stacked_r0);??
printf ("R1 = %x\n", stacked_r1);??
printf ("R2 = %x\n", stacked_r2);??
printf ("R3 = %x\n", stacked_r3);??
printf ("R12 = %x\n", stacked_r12);??
printf ("LR = %x\n", stacked_lr);??
printf ("PC = %x\n", stacked_pc);??
printf ("PSR = %x\n", stacked_psr);??
printf ("BFAR = %x\n", (*((volatile unsigned long *)(0xE000ED38))));??
printf ("CFSR = %x\n", (*((volatile unsigned long *)(0xE000ED28))));??
printf ("HFSR = %x\n", (*((volatile unsigned long *)(0xE000ED2C))));??
printf ("DFSR = %x\n", (*((volatile unsigned long *)(0xE000ED30))));??
printf ("AFSR = %x\n", (*((volatile unsigned long *)(0xE000ED3C))));??
???
while(1)
{
????????;;
}
}??
如果使用調試器,則可以在第一個printf處設置斷點.沒有的話看串口打印結果
通過查看stacked_lr的內容可以知道程序運行到哪個位置出現fault
然后查看編譯后匯編代碼,可以知道源程序是哪個函數哪一步出現問題,
配合其它寄存器的內容來分析找出原因
2.用IAR的話,把startup_ewarm.c文件中的FaultISR()函數的內容改為:
volatile unsigned int stacked_r0;??
volatile unsigned int stacked_r1;??
volatile unsigned int stacked_r2;??
volatile unsigned int stacked_r3;??
volatile unsigned int stacked_r12;??
volatile unsigned int stacked_lr;??
volatile unsigned int stacked_pc;??
volatile unsigned int stacked_psr;??
//unsigned long cc;
stacked_r0 = ((unsigned long) hardfault_args[0]);??
stacked_r1 = ((unsigned long) hardfault_args[1]);??
stacked_r2 = ((unsigned long) hardfault_args[2]);??
stacked_r3 = ((unsigned long) hardfault_args[3]);??
stacked_r12 = ((unsigned long) hardfault_args[4]);??
stacked_lr = ((unsigned long) hardfault_args[5]);??
stacked_pc = ((unsigned long) hardfault_args[6]);??
stacked_psr = ((unsigned long) hardfault_args[7]);??
printf ("[Hard fault handler]\n");??
printf ("R0 = %x\n", stacked_r0);??
printf ("R1 = %x\n", stacked_r1);??
printf ("R2 = %x\n", stacked_r2);??
printf ("R3 = %x\n", stacked_r3);??
printf ("R12 = %x\n", stacked_r12);??
printf ("LR = %x\n", stacked_lr);??
printf ("PC = %x\n", stacked_pc);??
printf ("PSR = %x\n", stacked_psr);??
printf ("BFAR = %x\n", (*((volatile unsigned long *)(0xE000ED38))));??
printf ("CFSR = %x\n", (*((volatile unsigned long *)(0xE000ED28))));??
printf ("HFSR = %x\n", (*((volatile unsigned long *)(0xE000ED2C))));??
printf ("DFSR = %x\n", (*((volatile unsigned long *)(0xE000ED30))));??
printf ("AFSR = %x\n", (*((volatile unsigned long *)(0xE000ED3C))));??
???
??while(1)
??{
??????????;;
??}
如果使用調試器,則可以在第一個printf處設置斷點.沒有的話看串口打印結果
通過查看stacked_lr的內容可以知道程序運行到哪個位置出現fault
然后查看編譯后匯編代碼,可以知道源程序是哪個函數哪一步出現問題,
配合其它寄存器的內容來分析找出原因
另一種方法:
? ? 默認的HardFaudler 處理方法不是死循環么?將它改成BX LR直接返回的形式。然后再這條語句打個斷點,一旦在斷點中停下來,說明出錯了,然后再返回,就可以返回到出錯的位置的下一條語句哪里。
_asm void wait()
{
? ? BX lr ?//BX無條件轉移指令
}
void HardFault_Handler(void)
{
? ? wait();
}
【ARM 匯編基礎速成6】ARM匯編之條件執行與分支 - 簡書
ARM 指令舉例
總結
以上是生活随笔為你收集整理的定位ARM Hard Fault 的方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cortex-M3基本知识点(手册)
- 下一篇: 嵌入式中主动触发hardfault