Cortex-M3/4的Fault异常是由于非法的存储器访问(比如访问0地址、写只读存储位置等)和非法的程序行为(比如除以0等)等造成的。常见的4种异常及产生异常的情况如下:
Bus Fault:在fetch指令、数据读写、fetch中断向量或中断时存储恢复寄存器栈情况下,检测到内存访问错误则产生Bus Fault。
Memory Management Fault:访问了内存管理单元(MPU)定义的不合法的内存区域,比如向只读区域写入数据。
Usage Fault:检测到未定义指令或在存取内存时有未对齐。还可以通过软件配置是否检测到除0和其它未对齐内存访问也产生该异常,默认关闭,需要在工程初始化时配置:
Hard Fault:在调试程序过程中,这种异常最常见。上面三种异常发生任何一种异常都会引起Hard Fault,在上面的三种异常未使能的情况下,默认发生异常时进入Hard Fault中断服务程序。使能前三种异常也要在初始化时配置:
在默认复位初始化时,Hard Fault使能,其它三者不使能,因此当程序中出现不合法内存访问(一般是指针错误引起)或非法的程序行为(一般就是数学里面常见的除0)时都将产生Hard Fault中断。
假设IDE环境为Keil,芯片为STM32F103。
在stm32f10x_it.c中,添加软件断点,一旦调试时出现Hard Fault则会在停在__breakpoint(0)处。
当进入Hard Fault断点后,菜单栏Peripherals >Core Peripherals >Fault Reports打开异常发生的报告,查看发生异常的原因。
上面的报告发生了BUS FAULT,并将Fault的中断服务转向Hard Fault。
相对于检测发生了什么异常,定位异常发生位置显得更重要。
(1)打开Call Stack窗口(如下图左侧,断点停在Hard Fault服务程序中)
(2)在Call Stack的HardFault_Handler上右键Show Caller Code(有的Keil版本也可以直接双击)
这时将跳转到发生异常的源代码位置(如上图),异常发生在p->hour=0这一行。这里错误很明显:指针p尚未为成员变量分配内存空间,直接访问未分配的内粗空间肯定出错。
再说明2点:
[1] 在复杂的情况下,即使定位了异常发生位置也很难容易的改正错误,要学会使用Watch窗口对发生错误的指针变量进行跟踪;
[2] 在问题不明晰的情况下,尝试分析反汇编代码,就自己遇到的,部分情况下的异常发生在BL等跳转指令处,BL跳转到了不合法的内存地址产生异常
-------------------------------------------------------------------------------------------------------
在没有JTAG的情况下,通过串口打印出堆栈信息:
1 /* Private typedef -----------------------------------------------------------*/ 2 enum { r0, r1, r2, r3, r12, lr, pc, psr}; 3 4 /* Private define ------------------------------------------------------------*/ 5 /* Private macro -------------------------------------------------------------*/ 6 /* Private variables ---------------------------------------------------------*/ 7 extern __IO uint16_t ADC_InjectedConvertedValueTab[32]; 8 uint32_t Index = 0; 9 10 /* Private function prototypes -----------------------------------------------*/ 11 void Hard_Fault_Handler(uint32_t stack[]); 12 13 /* Private functions ---------------------------------------------------------*/ 14 15 static void printUsageErrorMsg(uint32_t CFSRValue) 16 { 17 printf("Usage fault: \r\n"); 18 CFSRValue >>= 16; // right shift to lsb 19 20 if((CFSRValue & (1<<9)) != 0) { 21 printf("Divide by zero \r\n"); 22 } 23 if((CFSRValue & (1<<8)) != 0) { 24 printf("Unaligned access \r\n"); 25 } 26 } 27 28 static void printBusFaultErrorMsg(uint32_t CFSRValue) 29 { 30 printf("Bus fault: \r\n"); 31 CFSRValue = ((CFSRValue & 0x0000FF00) >> 8); // mask and right shift to lsb 32 } 33 34 static void printMemoryManagementErrorMsg(uint32_t CFSRValue) 35 { 36 printf("Memory Management fault: \r\n"); 37 CFSRValue &= 0x000000FF; // mask just mem faults 38 } 39 40 static void stackDump(uint32_t stack[]) 41 { 42 static char msg[80]; 43 sprintf(msg, "R0 = 0x%08x\r\n", stack[r0]); printf(msg); 44 sprintf(msg, "R1 = 0x%08x\r\n", stack[r1]); printf(msg); 45 sprintf(msg, "R2 = 0x%08x\r\n", stack[r2]); printf(msg); 46 sprintf(msg, "R3 = 0x%08x\r\n", stack[r3]); printf(msg); 47 sprintf(msg, "R12 = 0x%08x\r\n", stack[r12]); printf(msg); 48 sprintf(msg, "LR = 0x%08x\r\n", stack[lr]); printf(msg); 49 sprintf(msg, "PC = 0x%08x\r\n", stack[pc]); printf(msg); 50 sprintf(msg, "PSR = 0x%08x\r\n", stack[psr]); printf(msg); 51 } 52 53 void Hard_Fault_Handler(uint32_t stack[]) 54 { 55 static char msg[80]; 56 //if((CoreDebug->DHCSR & 0x01) != 0) { 57 printf("\r\nIn Hard Fault Handler\r\n"); 58 sprintf(msg, "SCB->HFSR = 0x%08x\r\n", SCB->HFSR); 59 printf(msg); 60 if ((SCB->HFSR & (1 << 30)) != 0) { 61 printf("Forced Hard Fault\r\n"); 62 sprintf(msg, "SCB->CFSR = 0x%08x\r\n", SCB->CFSR ); 63 printf(msg); 64 if((SCB->CFSR & 0xFFFF0000) != 0) { 65 printUsageErrorMsg(SCB->CFSR); 66 } 67 if((SCB->CFSR & 0xFF00) != 0) { 68 printBusFaultErrorMsg(SCB->CFSR); 69 } 70 if((SCB->CFSR & 0xFF) != 0) { 71 printMemoryManagementErrorMsg(SCB->CFSR); 72 } 73 } 74 stackDump(stack); 75 __ASM volatile("BKPT #01"); 76 //} 77 while(1); 78 } 79 80 81 __ASM void HardFault_Handler_a(void) 82 { 83 IMPORT Hard_Fault_Handler 84 85 TST lr, #4 86 ITE EQ 87 MRSEQ r0, MSP 88 MRSNE r0, PSP 89 B Hard_Fault_Handler 90 } 91 92 /** 93 * @brief This function handles Hard Fault exception. 94 * @param None 95 * @retval None 96 */ 97 void HardFault_Handler(void) 98 { 99 /* Go to infinite loop when Hard Fault exception occurs */ 100 HardFault_Handler_a(); 101 }