[!简介] HardFault是 Cortex-M 系类内核中的一种严重异常,意味着程序出现严重运行错误,CPU无法正常执行,只能进入HardFault_Handle函数中进行处理

触发Hardfault的常见原因:访问无效内存、栈溢出、执行非法指令…

定位HardFault类BUG

解析栈帧 + 获取 PC 值

无需调试器(可串口打印 / 保存故障信息) 适合栈溢出、中断嵌套异常、量产设备现场故障、复杂 HardFault

当出现HardFault时,硬件会自动把当前正在执行的任务的关键寄存器,按固定顺序压入当前栈指针(SP)指向的内存区域

  • R0~R3:通用寄存器,常用于函数参数 / 临时变量
  • R12:内部暂存寄存器(IP)
  • LR:链接寄存器,保存函数返回地址
  • PC:程序计数器,指向当前指令地址
  • PSR:程序状态寄存器,保存标志位、中断优先级等 基于PC地址查反汇编即可定位绝大多数HardFault类BUG
void HardFault_Handler(void)
{ // 第一步:汇编读取栈指针,传递给 C 函数 
	asm( 
		"tst lr, #4 \n" // 检查 EXC_RETURN,判断用 MSP 还是 PSP 
		"ite eq \n" 
		"mrseq r0, msp \n" // 等于0:用主栈指针 MSP 
		"mrsne r0, psp \n" // 不等于0:用进程栈指针 PSP 
		"b HardFault_CHandler \n" // 跳转到 C 处理函数,r0=栈帧地址
	); 
}
void HardFault_CHandler(HardFaultStackFrame_t *stackFrame) 
{ 
	// 打印关键寄存器值(你可以改成串口输出/保存到内存) 
	// 核心:stackFrame->pc 是触发硬故障的指令地址! 
	uint32_t faultPC = stackFrame->pc; 
	uint32_t faultLR = stackFrame->lr; 
	uint32_t faultPSR = stackFrame->psr; 
	// 串口打印
	printf("HardFault Triggered!\r\n");
	printf("PC: 0x%08X\r\n", faultPC);// 关键!用这个地址查反汇编
	printf("LR: 0x%08X\r\n", faultLR);
	printf("PSR: 0x%08X\r\n", faultPSR); 
	// 死循环(避免返回后再次触发 HardFault) 
	while (1) { }
}

asm(“bx lr”); + 调试器断点

必须连接调试器(ST-Link/J-Link)+ 断点调试 适合快速定位野指针、非法内存访问等简单故障

HardFault 99%是由于野指针和非法内存访问导致的。在HardFault函数内添加一句 asm("bx lr");, 并在此处加上断点。当代码运行至此处时,选择跳出,程序会跳转回出错之前最后一句执行的语句。

void HardFault_Handler(void)
{
  asm("bx lr");
  while (1)  {  }
}