HardFault分析


segger官方也有hardFault相關的文檔和代碼,去這個頁面ctrl+F搜索hardfault,可以看到文檔和相關代碼:https://www.segger.com/downloads/application-notes/

參考keil官方文檔和相關代碼 apnt209 :http://www.keil.com/appnotes/docs/apnt_209.asp

以及一個開源的hardFault診斷工具CMBackTrace :https://github.com/armink/CmBacktrace

 

最主要的是,找到 Cortex - M3 Technical Reference Manual。

原來只知道有stm32的datasheet和參考手冊,根本不知道還有這個手冊。。

大概《cortex M3權威指南》翻譯的大部分內容,都是從這本書上來的。

我只是用這個手冊翻了一下,找到一些寄存器的定義。

(因為這些寄存器的定義在stm32的參考手冊里是沒有的,屬於ARM公司規定的CMSIS范疇,不是芯片范疇的)

 

還有一個是stm32官方出示的一個“hardFault診斷”手冊,其實跟apnt209差不多。地址:http://www.stmcu.org/search/?q=hardfault&m=

 

最后我總結一下我在apnt209中截取的一部分:

思路就是在hardFault的ISR中,添加一個死循環,當系統運行到這里時,說明出現了hardfault異常。

下面是apnt209配套的軟件工程:

 1 /******************************************************************************
 2  * @file     HardFault_Handler.c
 3  * @brief    HardFault handler example
 4  * @version  V1.00
 5  * @date     10. July 2017
 6  ******************************************************************************/
 7 /*
 8  * Copyright (c) 2017 ARM Limited. All rights reserved.
 9  *
10  * SPDX-License-Identifier: Apache-2.0
11  *
12  * Licensed under the Apache License, Version 2.0 (the License); you may
13  * not use this file except in compliance with the License.
14  * You may obtain a copy of the License at
15  *
16  * www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
20  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  */
24 
25 #include "RTE_Components.h"             // Component selection
26 #include CMSIS_device_header            // Include device header file from
27 #include "stdio.h"                      // include stdio library for printf output
28 #include "project_configuration.h"      // Header file for test case configuration
29 
30 #if HARDFAULT_HANDLER == 1
31 
32 void HardFault_Handler_C(unsigned long * svc_args, unsigned int lr_value);
33 
34 // HardFault handler wrapper in assembly language.
35 // It extracts the location of stack frame and passes it to the handler written
36 // in C as a pointer. We also extract the LR value as second parameter.
37 __asm void HardFault_Handler(void)
38 {
39     TST    LR, #4     ;測試LR寄存器的bit2是否為1
40     ITE    EQ
41     MRSEQ  R0, MSP    ;如果LR的bit2是0,表示在發生HardFault之前,程序使用的是主進程堆棧Main Stack 42     MRSNE  R0, PSP    ;否則LR的bit2是1,說明在發生HF之前,程序使用是進程堆棧Process Stack
43     MOV    R1, LR
44     B      __cpp(HardFault_Handler_C)  ;把棧的值放入R0,把LR的值放入R1,調用C函數
45 }
46 
47 
48 // HardFault handler in C, with stack frame location and LR value extracted
49 // from the assembly wrapper as input parameters
50 void HardFault_Handler_C(unsigned long * hardfault_args, unsigned int lr_value)  //hardfault_args存的是棧的值,lr_value是LR的值
51 {
52     unsigned long stacked_r0;
53     unsigned long stacked_r1;
54     unsigned long stacked_r2;
55     unsigned long stacked_r3;
56     unsigned long stacked_r12;
57     unsigned long stacked_lr;
58     unsigned long stacked_pc;
59     unsigned long stacked_psr;
60     unsigned long cfsr;
61     unsigned long bus_fault_address;
62     unsigned long memmanage_fault_address;
63 
64     bus_fault_address       = SCB->BFAR;   //BusFaultAddrReg 65     memmanage_fault_address = SCB->MMFAR;  //MemManageAddrReg 66     cfsr                    = SCB->CFSR;   //ConfigerableFaultStatusReg 67 
68     stacked_r0  = ((unsigned long) hardfault_args[0]);  //Stack指向地址的內容,按照自動進棧出棧時的順序
69     stacked_r1  = ((unsigned long) hardfault_args[1]);
70     stacked_r2  = ((unsigned long) hardfault_args[2]);
71     stacked_r3  = ((unsigned long) hardfault_args[3]);
72     stacked_r12 = ((unsigned long) hardfault_args[4]);
73     stacked_lr  = ((unsigned long) hardfault_args[5]);
74     stacked_pc  = ((unsigned long) hardfault_args[6]);
75     stacked_psr = ((unsigned long) hardfault_args[7]);
76 
77     printf ("[HardFault]\n");
78     printf ("- Stack frame:\n");
79     printf (" R0  = %x\n", stacked_r0);
80     printf (" R1  = %x\n", stacked_r1);
81     printf (" R2  = %x\n", stacked_r2);
82     printf (" R3  = %x\n", stacked_r3);
83     printf (" R12 = %x\n", stacked_r12);
84     printf (" LR  = %x\n", stacked_lr);
85     printf (" PC  = %x\n", stacked_pc);  //注意這個是在HardFault發生前的PC地址,說明運行到這里發生HF【定位HF發生的指令】 86     printf (" PSR = %x\n", stacked_psr);
87     printf ("- FSR/FAR:\n");
88     printf (" CFSR = %x\n", cfsr);
89     printf (" HFSR = %x\n", SCB->HFSR);  //HardFaultStatusReg 90     printf (" DFSR = %x\n", SCB->DFSR);  //DebugFaultStatusReg 91     printf (" AFSR = %x\n", SCB->AFSR);  //Auxiliary Fault Status Reg 附加的..具體看Cortex M3 Technical Reference Manual 92     if (cfsr & 0x0080) printf (" MMFAR = %x\n", memmanage_fault_address);
93     if (cfsr & 0x8000) printf (" BFAR = %x\n", bus_fault_address);
94     printf ("- Misc\n");
95     printf (" LR/EXC_RETURN= %x\n", lr_value);
96 
97     while(1); // endless loop
98 }
99 #endif

 

 

所有的診斷過程都是類似的,根據LR的bit2判斷進入HardFault前是哪個Stack

確定了Stack,就讀取Stack指向地址處的幾個寄存器,這幾個寄存器在每次發生中斷和異常都會自動的壓棧出棧

從里面讀出PC,PC指向的地址,就是發生異常的地址。

 

這個地址可以用工具add2line,得到函數名,而不是機器碼的地址。。。

這部分可以看上邊提到的BackTrace開源工具。

它可以回溯包含發生hardfault函數的,所有的函數調用關系!

 

 

keil工具,定性(哪種hardfault)和定位(哪個指令)

 

 

 

 

 

參考:http://blog.csdn.net/zhzht19861011/article/details/8645661


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM