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