stm32H7进入HardFault_Handler机制

异常和中断区别:

在Cortex-M7中,所有能打断CPU正常执行流程的事件统称为异常。而中断是异常的一个子集,特指由外设信号或软件触发的事件

Cortex-M7支持最多256个异常,其中前16个是系统异常,从编号16开始是外部中断(IRQ)。

异常编号 异常类型 优先级 描述
1 Reset -3 (最高) 系统复位。优先级固定,不可配置。
2 NMI -2 不可屏蔽中断。通常用于看门狗或安全警报等最高优先级的硬件事件。
3 HardFault -1 硬件错误。当其他故障处理程序无法处理时触发,是最后一道防线。
4 MemManage 可配置 内存管理错误。由MPU(内存保护单元)检测到的违规访问引发。
5 BusFault 可配置 总线错误。发生在指令或数据访问的总线传输阶段。
6 UsageFault 可配置 用法错误。由执行未定义指令、非对齐访问等非法操作引发。
7-10 - - 保留
11 SVCall 可配置 系统服务调用。由执行SVC指令触发,常用于操作系统内核服务。
12 Debug Monitor 可配置 调试监视器。用于调试功能。
13 - - 保留
14 PendSV 可配置 可挂起的系统调用。常用于操作系统的上下文切换,优先级通常设为最低。
15 SysTick 可配置 系统节拍定时器。为操作系统提供时间基准。
16 及以上 IRQ0 ~ IRQn 可配置 外部中断。由芯片厂商定义的具体外设中断,如GPIO、UART、定时器等

STM32H753(基于 Cortex-M7 内核),进入 HardFault_Handler() 的机制和故障分级,比普通内核更严谨、更精细。它的核心是一个优先级固定、不可屏蔽的"终极异常",主要用于兜底那些其他异常机制处理不了的严重错误。

进入HardFault_Handler()触发条件:

1.错误升级(Fault Escalation)------ 最常见原因

UsageFault,BusFault和 MemManage Fault可以进行配置,提前拦截,不用进入HardFault

A. 用法错误 (UsageFault)

B. 总线错误 (BusFault)

C. 内存管理错误 (MemManage Fault)

2.直接触发的 HardFault(无法被屏蔽的硬错误)

3.STM32H753 (Cortex-M7) 独有的/高发的陷阱

代码现象与触发来源对应关系:

HardFault Status Register, HFSR

如何追溯到HardFault_Hanler()产生来源:

方式1:借助 IDE 寄存器窗口手动追溯(最基础直观)

方式2:编写智能捕获代码(汇编提取栈上下文 + C语言解析)

cpp 复制代码
volatile uint32_t g_HF_R0;
volatile uint32_t g_HF_R1;
volatile uint32_t g_HF_R2;
volatile uint32_t g_HF_R3;
volatile uint32_t g_HF_R12;
volatile uint32_t g_HF_LR;   /* Return address of the faulting instruction's caller */
volatile uint32_t g_HF_PC;   /* Faulting instruction address */
volatile uint32_t g_HF_PSR;
volatile uint32_t g_HF_CFSR;  /* Configurable Fault Status Register */
volatile uint32_t g_HF_HFSR;  /* HardFault Status Register */
volatile uint32_t g_HF_MMFAR; /* MemManage Fault Address Register */
volatile uint32_t g_HF_BFAR;  /* BusFault Address Register */
volatile uint32_t g_HF_AFSR;  /* Auxiliary Fault Status Register */
cpp 复制代码
__asm void HardFault_Handler(void)  
{
  IMPORT HardFault_C_Handler
  TST LR, #4
  ITE EQ
  MRSEQ R0, MSP
  MRSNE R0, PSP
  B HardFault_C_Handler
}
/*
//__asm是一个编译器关键字,告诉编译器不要当作c语言处理,直接翻译成ARM机器码
*/

/**
  * @brief  Captures fault diagnostics into globals and halts on a breakpoint.
  * @param  hardfault_args Pointer to the exception stack frame
  *         (r0, r1, r2, r3, r12, lr, pc, psr).
  */
void HardFault_C_Handler(uint32_t *hardfault_args)
{
  /* USER CODE BEGIN HardFault_IRQn 0 */
  g_HF_R0  = hardfault_args[0];
  g_HF_R1  = hardfault_args[1];
  g_HF_R2  = hardfault_args[2];
  g_HF_R3  = hardfault_args[3];
  g_HF_R12 = hardfault_args[4];
     //= hardfault_args[5];
  g_HF_PC  = hardfault_args[6];
  g_HF_PSR = hardfault_args[7];

  g_HF_CFSR  = SCB->CFSR;
  g_HF_HFSR  = SCB->HFSR;
  g_HF_MMFAR = SCB->MMFAR;
  g_HF_BFAR  = SCB->BFAR;
  g_HF_AFSR  = SCB->AFSR;

  __BKPT(0);
  /* USER CODE END HardFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_HardFault_IRQn 0 */
    /* USER CODE END W1_HardFault_IRQn 0 */
  }
}
/*
寄存器数据是如何进入 fault_args 数组的:
这是利用了 ARM 函数传参标准 (AAPCS):
汇编代码 (MRSEQ R0...) 将提取到的栈指针物理地址放进了 R0 寄存器。
ARM 标准规定,C 函数的第一个参数强制对应 R0 寄存器。
因此跳转到 C 函数后,R0 里的栈首地址直接传给了指针参数 fault_args。栈里面硬件自动压入的 8 个寄存器连续存放在这个地址后,在 C 语言看来,就顺理成章地变成了 fault_args[0] 到 fault_args[7] 的数组元素。
*/

Configurable Fault Status Register, CFSR

from:Arm® v7-M Architecture Reference Manual

SCB->CFSR(可配置错误状态寄存器)是"案情鉴定书",它告诉你死因(WHAT) ;

SCB->BFAR(总线错误地址寄存器)或 SCB->MMFAR 是"案发地点",它告诉你惹祸的地址(WHERE)。

在 Cortex-M7 中,CFSR 是一个 32 位的寄存器,从物理上分为三部分:

UFSR(用法错误):高 16 位 (Bit 16~31)

BFSR(总线错误):中 8 位 (Bit 8~15)

MMFSR(内存管理错误):低 8 位 (Bit 0~7)

代码现象与寄存器标志映射关系:

指针与内存管理类

  • 1.1.2 指针操作错误 (野指针/空指针)
    • CFSR 表现: BFSR 区域的 PRECISERR (精确数据总线错误,Bit 9) 置 1。
    • BFAR 表现: 有效(BFARVALID 置 1) 。BFAR 寄存器里保存的,就是那个空指针(0x00000000)或野指针(如 0x2009ABCD)的地址。
  • 1.1.5 存储器管理问题 (越界/非法区域)
    • CFSR 表现: MMFSR 区域的 DACCVIOL (数据访问违例,Bit 1) 置 1。
    • BFAR/MMFAR 表现: MMFAR 里保存了试图访问的受 MPU 保护或不可访问的内存地址。

栈与 RTOS 崩溃类

  • 1.1.1 堆栈溢出
    • CFSR 表现: 如果是发生中断压栈时溢出,BFSR 区域的 STKERR (压栈错误,Bit 12) 或 MMFSR 的 MSTKERR (压栈内存违例,Bit 4) 会置 1。
    • (注:普通的局部变量导致栈溢出,通常表现为修改了其他数据区,后续引发 1.1.2 的指针错误)
  • 1.1.3 中断优先级配置错误 & 1.1.9 RTOS 栈与优先级问题
    • 现象本质:由于 FreeRTOS 临界段被破坏,导致寄存器上下文错乱,中断返回时给 PC/LR 赋了乱码。
    • CFSR 表现: UFSR 区域的 INVSTATE (无效状态,Bit 24) 或 INVPC (无效PC,Bit 18) 置 1。表示试图跳转到无效地址执行,或没有处于 Thumb 模式。
  • 1.1.10 FPU 与栈对齐
    • 现象本质:M7 对浮点的多字操作必须 8 字节对齐,如果 RTOS 任务栈未对齐就执行了 FPU 代码。
    • CFSR 表现: UFSR 区域的 UNALIGNED (非对齐访问,Bit 24) 置 1。

H7 (Cortex-M7) 特有硬件/外设类

  • 1.1.4 外设错误配置 (没开时钟就初始化)
    • CFSR 表现: 通常是 BFSR 的 IMPRECISERR (不精确数据总线错误,Bit 10) ,或者是 PRECISERR (精确错误,Bit 9) 置 1。
    • BFAR 表现: 如果是精确错误,BFAR 会明确指出你配置出错的那个外设寄存器地址(例如 GPIOB 的 0x40020400)。
  • 1.1.7 时钟配置错误 (主频太高,Flash读不过来)
    • CFSR 表现: BFSR 的 IBUSERR (指令总线错误,Bit 8) 置 1。
    • 解释:CPU 试图从 Flash 取指令,但 Flash 控制器没有返回正确数据,导致指令总线报错。
  • 1.1.11 DMA 与缓存一致性 & 1.1.13 MPU 缺失
    • 现象本质:CPU 读到了 Cache 中的脏数据,把它当成了正常数据去跑,导致程序跑飞。
    • CFSR 表现: 非常随机! 极可能是 PRECISERR(脏数据变成了野指针),也可能是 UNDEFINSTR (未定义指令,Bit 16)(脏数据变成了错误的代码指令)。
    • BFAR 表现: 会指明跑飞后访问的那个奇怪地址。

代码逻辑优化类

  • 1.1.6 代码逻辑错误 (除以 0 等)
    • CFSR 表现: UFSR 区域的 DIVBYZERO (除以零,Bit 25) (前提是 SCB 中使能了除零异常) 或 UNDEFINSTR (未定义指令,Bit 16) 置 1。
  • 1.1.12 编译优化与未定义行为
    • 现象本质:强制类型转换被 O2/O3 优化为了 LDM/STM 或 LDRD 双字读取。
    • CFSR 表现: UFSR 区域的 UNALIGNED (非对齐访问,Bit 24) 将坚定地置 1
相关推荐
Zw-awa21 分钟前
计算机视觉:让板子从“看见”到“看懂”
stm32
黑妹天下第一乖4 小时前
第 08 讲:阿加犀 AidGenSE 端侧大模型服务化与 OpenAI 兼容接口
人工智能·嵌入式硬件·深度学习·机器人·iot
辰哥单片机设计4 小时前
漏水传感器(STM32)
stm32·单片机·嵌入式硬件
恶魔泡泡糖4 小时前
stm32F103C8T6标准库串口接收之多串口基础应用5
stm32·单片机·嵌入式硬件
木子单片机5 小时前
基于51单片机计步器—无线蓝牙APP上传
单片机·嵌入式硬件·51单片机·keil
智者知已应修善业5 小时前
【51单片机只有一个8*8点阵数据如何滚动起来一片595+一组IO+花样】2022-1-15
c++·经验分享·笔记·单片机·蓝桥杯·硬件架构
恒锐丰科技林技术员5 小时前
EG2123A 三相独立半桥驱动芯片解析与工程应用
经验分享·嵌入式硬件·硬件工程
硅基手札5 小时前
【Linux 内核专栏 13】快IO层
linux·服务器·嵌入式硬件
李日华大战鸡红6 小时前
滑膜观测器(学习记录)
stm32·单片机·学习·matlab·机器人
白搞电子6 小时前
ESP32-S31 项目如何制作 Windows 一键烧录包:完整镜像、esptool 与数据边界
windows·stm32·单片机