STM32进入HardFault的调试方法

STM32进入HardFault的调试方法

 

我们在设计STM32程序时,经常由于内存越界等,使得程序意外进入了HardFault中断。但我们一时半会又不知道,这个中断,究竟是代码运行到哪里,才触发的。常规的做法,我们只能在线调试,一步步寻找异常点,但由于发生异常的时机是不确定的,有可能在线调试的时候就不出现异常了,所以相当头疼。但本文介绍一种方法,可以直接定位到异常点,节省排查问题的时间。

 

这个方法的关键是,由于STM32中断前会由硬件保护现场,这个所谓的“现场”正包含了中断前程序运行的位置信息。我们只要在HardFault中断服务程序里面,把这个“现场”读取出来,就能定位到发生异常时,运行程序的位置了。

 

具体应该怎么做呢?

第一步,了解中断保存现场的机制。

可以阅读下图中的内容,详细介绍了中断现场的保存机制。我们主要是拿到PC值即可,因为PC值是中断前,代码的执行位置。

 

根据上图内容,我们要得到中断前PC的值,可以这样做:

在中断服务程序里面,

  1. 取得当前SP值
  2. 以当前SP值加上6*4,得到中断前PC值的地址
  3. 从这个地址取得中断前PC值。

 

第二步,确定SP

图中内容还说了,堆栈寄存器SP实际有两个,一个是MSP,一个是PSP。不同的情况,使用不同的SP。那究竟哪个才是发生中断前,程序正在使用的SP呢?弄清楚这个很重要,因为不同的情况,现场的存储位置是不一样的。

有一种比较简单的方法就是,把MSP和PSP保存的现场都读取出来,由程序员自己去估计哪个现场更有参考价值。

但是还有一种可以判断的方法,那就是LR寄存器。STM32的LR寄存器会在发生中断时被赋值为EXC_RETURN,不同的值代表了保存现场所使用的SP。如下图所示。

 

 

那么判断SP是MSP还是PSP,可以这样做:

在中断服务程序中

  1. 读取当前LR
  2. 根据LR的第2位判断。如果第二位为0,证明现场是保存在MSP指向的位置;否则是PSP指向的位置。

 

如何编写代码取得寄存器LR,MSP,PSP的值,可参看MDK帮助文档。

 

 

那么可以编写函数如下。这是在MDK 5.14的代码,其中 __return_address()是由MDK提供的,功能是得到当前LR寄存器的值;__get_MSP() ,__get_PSP() 是STM32固件库提供的,获得MSP,PSP寄存器的值。

unsigned int Debug_GetPCPreForISR(int ISR_SoftPushBytes,unsigned int lr)

{

 

     

    unsigned int pc_pre = 0;

 

    if((lr  &(1<<2)) == 0)

    {   //6*4是STM32硬件中断保护现场的压栈;

       //ISR_SoftPushBytes是中断服务函数进来时,编译器生成的PUSH指令压栈

       //4*4是在中断服务函数中,调用该函数自身的压栈;

       pc_pre =*(unsigned int*)( __get_MSP() + 6*4 + ISR_SoftPushBytes + 4*4 );

    }

    else

    {

     

       pc_pre =*(unsigned int*)( __get_PSP() + 6*4);

    }

   

     

    return pc_pre;

 

}

要弄清楚压栈过程:

1,当从普通函数进入到中断服务程序时,压栈过程是

用PSP进行硬件中断压栈(使用RTOS时)->中断服务函数使用MSP进行变量压栈-> Debug_GetPCPreForISR函数调用压栈

2,当从一个中断服务程序进入到另一个中断服务程序时,压栈过程是

用MSP进行硬件中断压栈->中断服务函数使用MSP进行变量压栈-> Debug_GetPCPreForISR函数调用压栈

 

其中, 中断服务函数使用MSP进行变量压栈,有的中断存在这个过程,有的没有。需要自己使用编译器的反汇编功能,查看中断服务函数处的汇编代码,看进入函数有没有压栈操作(PUSH指令)。

 

 

 

 

有了PC值之后还不好办吗?打开MDK工程,有一个反汇编调试功能,输入PC值就能定位到C代码所在位置,这就知道发生HardFault的位置了。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值