#单片机bug调试- HardFault_Handler硬件中断调试解决
目录
[1. HardFault_Handler中断产生的主要原因](#1. HardFault_Handler中断产生的主要原因 "#T_lable1")
[2. HardFault_Handler 关键寄存器说明](#2. HardFault_Handler 关键寄存器说明 "#T_lable2")
[3. 分析HardFault_Handler硬件中断一般步骤](#3. 分析HardFault_Handler硬件中断一般步骤 "#T_lable3")
1. HardFault_Handler中断产生的主要原因
HardFault_Handler硬件中断,是单片机中经常出现的一种异常问题。出现 HardFault_Handler 的原因主要有3类:
- 内存溢出或者访问越界:由于程序中申请的内存超出了系统的可用内存,或者申请的内存在使用过程中未被正确释放。这种情况会导致系统无法为其他请求分配足够的内存,甚至可能导致系统崩溃。访问了数组范围之外的内存位置或使用野指针,也会导致HardFault_Handler错误。
- 堆栈溢出:通常发生在函数调用或数组访问时。当函数内部的数组过大,或者递归调用层次太深时,就可能发生堆栈越界。
- 硬件故障:如果硬件出现故障,例如电源干扰、连接器故障或传感器故障等,可能会导致HardFault_Handler错误。
在单片机的HardFault_Handler 异常处理中,不同的单片机系列处理机制可能会有所不同,这取决于具体的MCU系列和其内部架构,需要看对应的内核手册。 不过STM32系列的异常处理机制大致相似,按照本文方法若不能解决问题,就需要详细查看对应的内核手册(R13、R14、R15的作用)。
2. HardFault_Handler 关键寄存器说明
出现HardFault异常时,会进入HardFault_Handler中断处理程序。此时,MSP和PSP有两个特殊的寄存器,它们用于存储堆栈指针,帮助开发者定位和解决问题。
2.1 MSP寄存器(主堆栈指针)
主要用于非中断相关的操作,如主程序运行、用户任务等。
- 在异常处理过程中,MSP作为栈顶指针使用(主堆栈的初始地址),用于保存和恢复异常发生时的寄存器值。
- 在正常处理过程中,MSP用于临时存储数据、保存函数调用时的参数等。
2.2 PSP寄存器(进程堆栈指针)
主要用于嵌套中断处理和多任务环境。
- 在嵌套中断处理中,PSP用于保存和恢复中断前的堆栈环境,以便中断处理程序能够正确地执行。
- 在多任务环境中,每个任务都有自己的PSP,用于保存任务的上下文(如CPU寄存器),以便任务切换时能够正确地恢复执行。
- 其它正常情况下,PSP也可以用于其他需要临时存储数据的场景。
当发生异常时内核将R0、R1、R2、R3、R12、Returnaddress、PSR、LR寄存器依次入栈到MSP或PSP,以保存当前执行的上下文。
地址解释:
- R0、R1、R2、R3:通用寄存器,通常用于传递参数和保存临时数据;
- R12: 这也是一个通用寄存器,用于保存临时数据;
- Returnaddress: 保存了当前函数调用后的地址,这通常是指发生异常前将要执行的指令的地址;
- PSR (Program Status Register):程序状态寄存器,保存了CPSR的当前值;
- LR (Link Register): 链接寄存器,保存了异常发生前的返回地址。
异常时,内核将当前执行的上下文数据按特定顺序入栈到堆栈指针,只要我们找到Returnaddress
地址的位置,就可定位到出现异常的大致位置。查看保存有异常数据的堆栈指针是MSP,还是PSP,需要根据R14(LR)的数值而定。
3. 分析HardFault_Handler硬件中断一般步骤
Coretex-M3和Coretex-M4架构中,R14(LR)数值及其代表含义:
- LR = 0xFFFFFFF9,MSP指向的地址保存有异常信息;(使用FPU时,LR=0xFFFFFFE9)
- LR = 0xFFFFFFFD,PSP指向的地址保存有异常信息;(使用FPU时,LR=0xFFFFFFED)
- LR = 0xFFFFFFF1,表示中断返回时从MSP堆栈恢复寄存器值,中断返回后进入Handler模式,使用MSP堆栈;(使用FPU时,LR=0xFFFFFFE1)
以下使用Coretex-M3内核架构,进行异常分析,
3.1 保护现场:
出现异常时,不要复位设备,保持当前设备运行的异常环境,能更大概率找到问题。若开启了看门狗,超时就会硬件复位,要复现并找到该问题,需要将看门狗进行关闭并重新烧写程序,等待问题复现。
3.2 使用KEIL进入Debug调试
若进入调试界面后,没有 Registers
窗口,就点击KEIL-->View-->Registers Windown
就会弹出该窗口。
3.3 Registers
窗口查看R14(LR),确认保存异常数据的堆栈指针
3.4 在Memory1窗口 查看栈帧内容
若 Memory1
窗口未显示,就点击KEIL-->View-->Memory Windowns-->Memory1
就会弹出该窗口。
3.5 使用 Disassembly Window 反汇编窗口 定位异常区域
若 Disassembly
反汇编窗口未显示,就点击KEIL-->View-->Disassembly Windown
就会弹出该窗口。
通过MSP堆栈指针指向的地址0x20002B10 记录的上下文信息,查找Returnaddress地址定位到异常程序代码处,可分析出产生HardFault_Handler中断的原因 是由于函数内部数组 buf[50] 只有50个字节大小,但使用buf时操作了100个字节大小,导致了数组越界错误。
3.6 LR寄存器等于其它值
LR寄存器保存了异常发生时的返回地址。如果由于外部信号干扰或电源问题导致异常,这个返回地址可能不准确或MSP的值与预期的函数堆栈位置不匹配,这可能表明异常发生时堆栈已经被破坏。需结合窗口工具 KEIL-->View-->Call Stack ,KEIL-->Peripherals-->Core Peripherals-->Fault Reports 进行具体异常分析。
配置KEIL进行在线调试的参考链接: blog.csdn.net/weixin_4317...
针对某些 xxx.uvprojx
工程,在使用KEIL进行Debug在线调试时,打了断点,当退出调试时KEIL会卡死,需要使用任务管理器强制结束任务才能退出。
出现该问题的原因是,xxx.uvprojx
工程建立不是在本电脑上创建的,是从其他电脑拷贝到本电脑编译运行调试的,存在的配置文件与本电脑不匹配; 或工程路径里面存在中文路径。解决措施:
-
关闭KEIL工程,拷贝一份工程出来并重命名,路径中不包含中文;
-
在
xxx.uvprojx
同目录下,删除文件xxx.scvd
、xxx.uvguix.Administrator
、xxx.uvguix.zuozh
、xxx.uvoptx
;注意不要删除xxx.uvprojx
; -
打开
xxx.uvprojx
工程,进入Target
界面重新对该工程进行配置,并Rebuild
编译;