欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > 如何在MCU工程中启用HardFault硬错误中断

如何在MCU工程中启用HardFault硬错误中断

2025/3/24 9:29:42 来源:https://blog.csdn.net/Dustinthewine/article/details/146430347  浏览:    关键词:如何在MCU工程中启用HardFault硬错误中断

文章目录

  • 一、HardFault出现场景
  • 二、启动HardFault
  • 三、C代码示例


一、HardFault出现场景

HardFault(硬故障) 错误中断是 ARM Cortex-M 系列微控制器中一个较为严重的错误中断,一旦触发,表明系统遇到了无法由其他异常处理机制解决的问题。
HardFault 错误中断常见于以下几种触发情况:

  • 内存访问错误

    1. 访问非法地址
      当代码尝试访问未映射的内存区域,例如访问一个超出芯片内存范围的地址,就会触发 HardFault。比如,使用了一个未初始化的指针,该指针指向一个随机的无效地址,当对这个地址进行读写操作时,就会产生错误。访问受保护的内存区域也会引发问题。一些内存区域可能被设置为只读或者受特殊权限保护,若代码试图对其进行写操作,就会触发 HardFault。
    2. 内存对齐错误
      ARM Cortex - M 处理器对某些数据类型有内存对齐要求。例如,32 位的数据访问需要在 4 字节对齐的地址上进行。如果代码试图在非对齐的地址上进行 32 位数据的读写操作,就可能触发 HardFault。
  • 总线错误

    1. 总线传输错误
      在数据通过总线进行传输时,可能会因为电气干扰、信号衰减、硬件故障等原因,导致数据传输错误。比如,在外部存储器读写操作中,由于总线线路故障,数据无法正确传输,就会触发 HardFault。
    2. 总线仲裁失败
      当多个主设备同时请求使用总线时,需要进行总线仲裁。如果仲裁机制出现问题,导致某个主设备无法正常获得总线使用权,就可能引发总线错误,进而触发 HardFault。
  • 堆栈溢出或损坏

    1. 堆栈溢出
      堆栈用于保存函数调用时的局部变量、返回地址等信息。如果函数调用层次过深或者局部变量占用空间过大,就可能导致堆栈溢出。当堆栈溢出发生时,新的数据会覆盖其他重要的内存区域,从而引发 HardFault。
    2. 堆栈损坏
      代码中对堆栈指针的错误操作,例如意外修改了堆栈指针的值,会导致堆栈结构被破坏。后续的函数调用和返回操作就会出现异常,最终触发 HardFault。
  • 异常处理错误

    1. 异常向量表错误
      异常向量表存储了各个异常处理函数的入口地址。如果异常向量表被错误修改,或者其地址设置不正确,当发生异常时,处理器无法正确跳转到相应的异常处理函数,就可能触发 HardFault。
    2. 异常嵌套错误
      在异常处理过程中,如果发生了新的异常,并且异常嵌套处理机制出现问题,例如嵌套层数超过了处理器的限制,就会导致系统混乱,触发 HardFault。
  • 指令执行错误

    1. 未定义指令
      当处理器执行到一条未定义的指令时,会触发 HardFault。这可能是由于代码中包含了无效的机器码,或者是在程序加载过程中出现了错误。
    2. 非法指令访问
      某些指令可能需要特定的权限才能执行。如果代码在不具备相应权限的情况下尝试执行这些指令,就会触发 HardFault。
  • 硬件故障

    1. 时钟故障
      处理器的正常运行依赖于稳定的时钟信号。如果时钟源出现故障,例如晶振停振、时钟频率偏移过大,会导致处理器的指令执行和数据处理出现异常,从而触发 HardFault。
    2. 电源故障
      电源电压不稳定、过压或欠压等情况,可能会影响处理器内部电路的正常工作,导致数据处理错误,最终引发 HardFault。

二、启动HardFault

1. 打开启动文件(.s文件)
在这里插入图片描述
在启动文件中,定义中断向量表,为 HardFault 提供占位符处理程序

__Vectors       DCD     __initial_sp                        ; 栈顶指针(Top of Stack)DCD     HardFault_Handler                   ; HardFault 处理程序

__initial_sp 是栈顶指针的初始化值,在复位时由处理器自动加载到 SP 寄存器。
HardFault_HandlerHardFault 的中断服务程序,在 CPU 触发 HardFault 时会执行这个函数。

2. 占位符的弱定义

HardFault_Handler\PROCEXPORT  HardFault_Handler                   [WEAK]B       .ENDP

EXPORT HardFault_Handler [WEAK] 将 HardFault_Handler 导出,并标记为弱定义(WEAK)。
B . 代表无限循环,相当于死循环,防止处理器进入未知状态。

Tips: 由于该 HardFault_Handler只是一个占位符,用户可以在 C 代码中重新定义 HardFault_Handler,而不会与启动文件冲突。

3. 定义源文件 HardFault 处理程序
在 C 代码中,需要实现 HardFault_Handler 以便进行错误分析和调试。

void HardFault_Handler_t(uint8_t  * hardfault_args)
{......while(1);
}

在HardFault 中断中一般可以去查看相关寄存器的数值用于分析错误原因,常见寄存器参考如下:

R0 ~ R3:通用寄存器
R12:特殊寄存器
LR(Link Register):返回地址
PC(Program Counter):导致 HardFault 的指令地址
PSR(Program Status Register):状态寄存器Cortex-M 的故障状态寄存器:
BFAR(Bus Fault Address Register):总线错误的地址
CFSR(Configurable Fault Status Register):配置错误状态寄存器
HFSR(Hard Fault Status Register):硬错误状态寄存器
DFSR(Debug Fault Status Register):调试故障状态寄存器
AFSR(Auxiliary Fault Status Register):辅助故障状态寄存器

4. 汇编代码提取堆栈帧

__asm void hard_fault_handler_asm(void)
{IMPORT  HardFault_Handler_tTST      LR, #4          ; 检查异常发生时使用的堆栈ITE      EQMRSEQ   R0, MSP          ; 如果是主堆栈,获取 MSPMRSNE   R0, PSP          ; 如果是进程堆栈,获取 PSPB        HardFault_Handler_t
}

TST LR, #4:检查 LR(异常返回指针)的 bit 2,判断异常发生时使用的堆栈:

  • 0:使用主堆栈(MSP)
  • 1:使用进程堆栈(PSP)

ITE EQ:条件执行语句

  • MRSEQ R0, MSP:如果使用 MSP,则将 MSP 传入 R0
  • MRSNE R0, PSP:如果使用 PSP,则将 PSP 传入 R0

B HardFault_Handler_t:跳转到 HardFault_Handler_t,并将 R0 作为参数传递。


综上:

  • Cortex-M 发生 HardFault 时,处理器跳转到 HardFault_Handler。
  • HardFault_Handler由 startup.s 文件定义,但只是一个占位符。
  • hard_fault_handler_asm 通过汇编代码获取当前堆栈指针,并传递给 HardFault_Handler_t。
  • HardFault_Handler_t解析故障信息,读取寄存器内容,调试解错。

启动文件 负责 定义中断向量表,并提供一个默认的弱定义 HardFault_Handler,允许用户在 C 代码中覆盖它。
汇编代码 负责 提取故障发生时的堆栈帧 并传递给 C 代码。C 代码 负责 解析寄存器信息并打印故障信息,便于调试和分析故障原因。

三、C代码示例

C代码示例可参考如下:

__asm void hard_fault_handler_asm(void)
{IMPORT  HardFault_Handler_tTST      LR, #4          ; 检查异常发生时使用的堆栈ITE      EQMRSEQ   R0, MSP          ; 如果是主堆栈,获取 MSPMRSNE   R0, PSP          ; 如果是进程堆栈,获取 PSPB        HardFault_Handler_t
}typedef struct 
{uint8_t  r0;uint8_t  r12;uint8_t  lr;uint8_t  pc;uint8_t  psr;
} hardfault_t;
hardfault_t hardfault;void HardFault_Handler_t(unint8_t  * hardfault_args)
{hardfault.stacked_r0 = ((uint32_t) hardfault_args[0]);hardfault.stacked_r12 = ((uint32_t) hardfault_args[4]);hardfault.stacked_lr  = ((uint32_t) hardfault_args[5]);hardfault.stacked_pc  = ((uint32_t) hardfault_args[6]);hardfault.stacked_psr = ((uint32_t) hardfault_args[7]);printf("HardFault_Handler_t!\r\n");printf("R0 = %x\r\n", hardfault.r0);printf("R12 = %x\r\n", hardfault.r12);printf("LR = %x\r\n", hardfault.lr);printf("PC = %x\r\n", hardfault.pc);printf("PSR = %x\r\n", hardfault.psr);while(1);
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词