HardFault IAR定位方式
·
HardFault(硬错误) 是一种 系统级异常(System Exception), 在 Cortex-M 架构中,表示内核检测到严重故障且无法交给其他 Fault 处理器处理时触发。
参考: https://blog.csdn.net/weixin_43684318/article/details/120857170
在 STM32H7 的异常向量表中:
| 异常 | 名称 | 向量号 | 优先级(固定) |
|---|---|---|---|
| Reset | 复位 | 1 | — |
| NMI | 不可屏蔽中断 | 2 | 高 |
| HardFault | 硬错误 | 3 | 固定最高(仅次于 NMI) |
一、HardFault 的常见触发原因
| 类型 | 说明 | 典型示例 |
|---|---|---|
| 非法内存访问 | 访问不存在或未映射的地址 | *(uint32_t*)0xFFFFFFF0 = 0; |
| 空指针/野指针 | 指针未初始化或被破坏 | p = NULL; *p = 1; |
| 栈溢出或栈越界 | 任务栈空间不够或栈被破坏 | RTOS任务或递归太深 |
| 执行非法指令 | 跳转到无效指令区 | 函数指针出错、堆栈破坏 |
| 未对齐访问 | 按 4 字节访问未对齐地址 | LDR R0, [R1, #1] 且 R1 未对齐 |
| 除零操作 | 除数为零且 DIV_0_TRP 置位 | / 0 |
| 总线错误(BusFault)上报 | 严重总线访问错误 | 访问 Flash/外设时序异常 |
| 内存管理错误上报 | MPU 检测非法区域访问 | 非法访问受保护内存 |
| 使用非法返回地址 | PC/LR 被破坏 | 栈损坏后 BX LR 跳错地址 |
二、Fault 分类结构(在 Cortex-M7 中)
| Fault 类型 | 含义 | 是否能屏蔽 | 常引起的 HardFault |
|---|---|---|---|
| MemManage Fault | 内存保护错误(MPU) | 可屏蔽 | 是 |
| BusFault | 总线访问错误 | 可屏蔽 | 是 |
| UsageFault | 指令或数据使用错误 | 可屏蔽 | 是 |
| HardFault | 无法分类或升级错误 | 不可屏蔽 | 否(最高) |
当以上三种 Fault 没有被单独开启或无法处理时,会自动升级为 HardFault。
三、HardFault 时 CPU 的堆栈内容
当 HardFault 发生时,CPU 自动将以下寄存器压栈(在当前 SP 指向的栈):
| 压栈顺序 | 内容 | 说明 |
|---|---|---|
| 1 | R0 | 参数或通用寄存器 |
| 2 | R1 | 参数或通用寄存器 |
| 3 | R2 | 参数或通用寄存器 |
| 4 | R3 | 参数或通用寄存器 |
| 5 | R12 | 临时寄存器 |
| 6 | LR | 返回地址 |
| 7 | PC | 出错指令地址 |
| 8 | xPSR | 程序状态寄存器 |
四、如何定位 HardFault 位置(调试方法)
方法 1:使用调试器(IAR)
当进入 HardFault_Handler 时:
-
打开 寄存器窗口,可以通过读取 CONTROL 寄存器 来判断:

📘 CONTROL[1] 位:
-
0→ 使用 MSP(主堆栈指针) -
1→ 使用 PSP(进程堆栈指针)
2. 打开Memory窗口,搜索相应的栈指针地址(四字节查看)

3. 找到栈指针里面存的被卡死的PC地址(栈顶指针偏移7位),因为顺序是R0,R1,R2,R3,R12,LR,PC

4. 在反汇编里面获取PC对应的函数。

5. 根据汇编定位分析问题。
以我这个举例就是去非法获取123456地址的值。
方法 2:在 HardFault_Handler 中提取出错现场。程序调试
void HardFault_Handler(void)
{
__asm volatile
(
"TST lr, #4 \n" // 检查使用 MSP 还是 PSP
"ITE EQ \n"
"MRSEQ r0, MSP \n"
"MRSNE r0, PSP \n"
"B hard_fault_handler_c\n"
);
}
void hard_fault_handler_c(uint32_t *stacked_addr)
{
uint32_t stacked_r0 = stacked_addr[0];
uint32_t stacked_r1 = stacked_addr[1];
uint32_t stacked_r2 = stacked_addr[2];
uint32_t stacked_r3 = stacked_addr[3];
uint32_t stacked_r12 = stacked_addr[4];
uint32_t stacked_lr = stacked_addr[5];
uint32_t stacked_pc = stacked_addr[6]; // 出错指令地址
uint32_t stacked_psr = stacked_addr[7];
printf("HardFault!\n");
printf("R0 = 0x%08lx\n", stacked_r0);
printf("R1 = 0x%08lx\n", stacked_r1);
printf("R2 = 0x%08lx\n", stacked_r2);
printf("R3 = 0x%08lx\n", stacked_r3);
printf("R12 = 0x%08lx\n", stacked_r12);
printf("LR = 0x%08lx\n", stacked_lr);
printf("PC = 0x%08lx\n", stacked_pc);
printf("PSR = 0x%08lx\n", stacked_psr);
while(1);
}
在调试终端中即可看到 出错的 PC 地址 然后在 .map 文件或反汇编窗口中查找该地址属于哪个函数即可定位问题。
总结
| 分类 | 含义 | 定位方法 |
|---|---|---|
| 原因 | 非法访问 / 栈破坏 / 指令错误 | 由 CPU 自动进入 HardFault |
| 入口 | HardFault_Handler |
在向量表中定义 |
| 分析 | 查看 PC、LR、CFSR、BFAR | 定位代码位置 |
| 修复 | 校验指针、检查栈、任务、FPU 设置 | 防止再次发生 |
更多推荐

所有评论(0)