Cortex-m的HardFault信息的本地保存

做项目的过程中难免会遇到各式各样的死机问题,KEIL提供了很多好用的方法,串口打印,debug调试等等。然而有时一些问题往往难以复现,我们可以hardfault中断产生时信息保存在本地从而更好的定位分析问题

一、为什么会产生hardfault

死机问题的原因有多种例如

  1. 电源不稳定导致的死机

  1. 电磁干扰(EMI),静电放电导致的死机

  1. 甚至是一些极端环境(温度,湿度,辐射等)

  1. 或者由于元器件老化,使用寿命完结

  1. 最后是由于编程的不规范,没有按照芯片手册,程序规则来书写代码导致的

前面四种情况,我们暂且不讨论,对于第五种情况,我们可以通过加入看门狗,重启系统来保护我们程序。但是在一些不是很重要的场景这确实效,在一些工控领域,死机重启都是致命的问题,所以我们必须得一一排查问题所在。在Cortex-m处理器中加入了异常中断处理,可以有效的帮助我们定位分析问题。

• MemManage (Memory Management) Fault

• Bus Fault

• Usage Fault

我们开启这些中断后,系统会根据错误异常跳进相应的中断中去,而这些异常中断我们也是能编辑,和更改优先级的。

如上面的图所示这三个异常中断系统是默认关闭的。当这些中断关闭以后,系统会跳过其他的异常中断直接到HardFault中去,所以我们如果在跳入HardFault之前保存好现场信息就能较为容易的定位异常发生的点了,当然你如果想开启这也异常中断逐一分析也是可以的你可以通过这几天指令来开启中断。

SCB->SHCSR j= SCB_SHCSR_MEMFAULTENA_Msk; //Set bit 16

SCB->SHCSR j= SCB_SHCSR_BUSFAULTENA_Msk; //Set bit 17

SCB->SHCSR j= SCB_SHCSR_USGFAULTENA_Msk; //Set bit 18

配置中断优先级

NVIC_SetPriority(MemoryManagement_IRQn, priority);

NVIC_SetPriority(BusFault_IRQn, priority);

NVIC_SetPriority(UsageFault_IRQn, priority);

我们这里就不详细介绍了,主要讨论HardFault中断

二、异常中断发生,保存现场

在Keil我们可以看到这样一栏

这是系统运行时函数的堆栈调用情况,LR指针可以简单的理解为函数当前运行的地址,PC指针为函数接下来要运行的地址,当我们发生异常中断时系统会将LR自动保存

首先当发生异常中断,系统会读取LR中的bit[2]如果是0则判断时MSP指针,如果是1则是PSP指针,然后将指针从上往下压入栈中如上图所示。根据这个思路我们只要读取到xPSR指针我们就能获取我们需要的信息了。

三、修改.s文件将HardFoult_Handler传入xPSR指针

在.s文件中我们可以看到这样一段

这中间的EXPORT HardFault_Handler [WEAK]表示声明一个HardFault_Handle函数(其他的函数也一样)为一个虚函数,虚函数的意思是用户可以定义一个同名的函数,若用户没定义则执行原本的实体,若用户定义了则执行用户的函数实体,末尾则是这样的

这里的HardFault_Handler,表示定义了一个空的HardFault_Handle函数(其他的函数也一样),类似于void HardFault_Handler(void) { };

我们则是要改写这个函数,首先通过;号注释掉原来的函数,然后添加我们自定义HardFault_Handler函数,要顶格书写!!!,当然改写函数名也是可以的你可以改成HardFault_Handler_C之类的.

HardFault_Handler
    TST      LR,#4
    ITE      EQ
    MRSEQ    R0,MSP
    MRSNE    R0,PSP
    MOV      R1,LR
    B        HardFault_Handler_C
    END

解释一下 首先是检查LR寄存器的bit[2]是0还是1之前我们说过,发生异常中断后系统会自动保存L根据LR中的BIT[2]来判断是返回MSP还是PSP指针

然后根据LR中的bit[2]来保存到 R0的地址然后将R0作为形参传入HardFault_Handler函数 ,B HardFault_Handler返回HardFault_Handler函数指针

B相当于 return。

之后我们要在.c文件中重新定义一下HardFault_Handler_C函数

void HardFault_Handler_C(unsignedlong* hardfault_args,unsigned int lr_value){
    unsigned long    stacked_r0;
    unsigned long    stacked_r1;
    unsigned long    stacked_r2;
    unsigned long    stacked_r3;
    unsigned long    stacked_r12;
    unsigned long    stacked_lr;
    unsigned long    stacked_pc;
    unsigned long    stacked_psr;
    unsigned long    cfsr;
    unsigned long    bus_fault_address;
    unsigned long    memmanage_fault_address;

    bus_fault_address = SCB->BFAR;
    memmanage_fault_address = SCB->MMFAR;
    cfsr = SCB->CFSR;
    stacked_r0 = ((unsignedlong)hardfault_args[0]);
    stacked_r1 = ((unsignedlong)hardfault_args[1]);
    stacked_r2 = ((unsignedlong)hardfault_args[2]);
    stacked_r3 = ((unsignedlong)hardfault_args[3]);
    stacked_r12 = ((unsignedlong)hardfault_args[4]);
    stacked_lr = ((unsignedlong)hardfault_args[5]);
    stacked_pc = ((unsignedlong)hardfault_args[6]);
    stacked_psr =((unsignedlong)hardfault_args[7]);
    while(1);
}

然后就可以在HardFault_Handler_C中的信息,通过打印或者写入flash来保存我们的关键信息了,至于获取到这些信息后怎么定位问题,这个又是另一个话题了

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Cortex-M0是一种ARM处理器的核心架构,用于嵌入式系统中。"hardfault"是指在程序运行时发生的硬错误或异常。当Cortex-M0处理器检测到硬错误时,会引发一个硬错误中断,即硬错误中断(HardFault)。 Cortex-M0的硬错误中断(hardfault)通常是由以下情况触发: 1. 无效的指令:当程序执行到一个非法或无效的指令时,会导致硬错误中断。 2. 内存访问错误:当程序试图访问不存在的内存地址、只读内存进行写操作或对只执行内存进行写操作时,会导致硬错误中断。 3. 栈溢出:当程序使用的堆栈空间超过其分配的大小,会导致硬错误中断。 4. 数学运算错误:当程序进行除零或无效的浮点数操作等数学运算时,会引发硬错误中断。 发生硬错误中断后,Cortex-M0处理器会中止当前正在执行的进程,并将程序控制权传递给硬错误中断处理程序(HardFault Handler)。硬错误中断处理程序可以用于处理硬错误的日志记录、调试等操作,并根据具体情况采取相应的纠正措施。 为了解决Cortex-M0硬错误中断问题,应该进行以下步骤: 1. 使用调试工具来定位并修复导致硬错误中断的问题,例如检查程序是否存在无效的指令或内存访问错误。 2. 检查堆栈空间的分配是否合理,确保不会发生栈溢出。 3. 避免发生数学运算错误,例如在进行除法运算前进行零值检查。 通过以上措施,可以有效解决Cortex-M0硬错误中断的问题,确保程序的稳定性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值