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