0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

ES32F36xx芯片发生HardFault异常时的函数调用关系及问题定位

jf_pJlTbmA9 来源:东软载波微电子 作者:东软载波微电子 2023-11-06 17:13 次阅读

1、引言

Cortex-M3微控制器因其功能强大、性价比高以及易用性好,在嵌入式体系结构中得到了广泛应用。然而,在实际开发过程中,如果程序很大或运行很久后可能会遇到HardFault异常。为了快速有效地解决HardFault异常,本文将讨论定位HardFault问题的方法。

2、常见引发HardFault原因

1)访问非法内存地址:编程中处理指针时可能导致访问未定义的内存地址,特别是在数组越界、非法指针解引用等情况下。

2)叠栈溢出:程序运行过程中如果栈溢出,会导致栈上数据错误,从而引发异常。

3)寄存器未正确初始化:寄存器配置和使用不正确,可能导致硬件异常。

4)除0运算:当程序试图执行除0运算时,可能发生硬件故障异常。

5)总线错误:外设总线通信发生错误,可能引起硬件故障。

3、软件触发HardFault异常

ES32F36xx是Cortex-M3内核,当被除数为0时,硬件将触发一个异常,导致系统进入Hard Fault异常状态。这种情况下,处理器不能正常运行,并且不能恢复,直到硬件或软件采取措施使得系统回到正常状态。在ES32_SDK中,ES32F36xx 的KEY_LED_ADC例程中增加如下程序:

//B函数
voidB_Function(void)
{
printf_e("EnterBfunctionrn");
C_Function(0);
printf_e("ExitBfunctionrn");
}
//A函数
voidA_Function(void)
{
printf_e("EnterAfunctionrn");
B_Function();
printf_e("ExitAfunctionrn");
}
//C函数
intC_Function(intval)
{
return100/val;
}
//D函数
voidD_Function(void)
{
printf_e("EnterDfunctionrn");
C_Function(1);
printf_e("ExitDfunctionrn");
}
//TestDebug函数
voidTestDebug(void)
{
//使能除0异常
volatileint*CCR=(volatileint*)0xE000ED14;
*CCR|=(1<< 4);
    
    A_Function();
    D_Function();
}
// 主函数
int main(void)
{   
    uart_stdio_init();
    
    TestDebug();
    while(1);
}

如图 1所示,工程文件中,User选项中增加“fromelf -a -c --output=all.dis .objout.axf“,生成汇编文件。

wKgaomUDxBeAK4_TAAEfG65R5WU979.png

图1 MDK工程生成汇编文件配置

4、HardFault异常函数调用关系及问题定位

上述程序运行过程中会发生hardfault异常,发生hardfault异常瞬间,程序立刻中止运行,硬件自动保存“调用者保存寄存器“的值到栈,同时跳转到异常向量表执行异常处理函数。如图 2所示为发生异常瞬间,硬件自动保存xPSR、ReturnAddress、LR、R12、R3、R2、R1及R0寄存器。

wKgZomUDxBiAGc5uAACAI7BbLss327.png

图2 处理器进入异常时的栈帧

硬件仅保存了部分寄存器,为了保存发生异常瞬间所有寄存器值,程序跳转到中断向量处需要执行如下的汇编代码:

;getcurrentcontext
TSTlr,#0x04;if(!EXC_RETURN[2])
ITEEQ
;[2]=0==>Z=1,getfaultcontextfromhandler
MRSEQr0,msp
;[2]=1==>Z=0,getfaultcontextfromthread
MRSNEr0,psp

STMFDr0!,{r4-r11};pushr4-r11register
STMFDr0!,{lr};将EXC_RETURN值压栈

TSTlr,#0x04;if(!EXC_RETURN[2])
ITEEQ
;R0为栈值,作为hw_hardfault_exception函数首个参数
MSREQmsp,r0
;[2]=1==>Z=0,getfaultcontextfromthread
MSRNEpsp,r0

;再次将EXC_RETURN值压栈
PUSH{lr}
;跳转至hw_hardfault_exception函数
BLhw_hardfault_exception
POP{lr}
ORRlr,lr,#0x04
BXlr
ENDP

上述汇编代码的主要功能是获取栈(SP)地址,并将R4 ~ R11压栈,跳转执行hw_hardfault_exception函数。压栈后栈中的数据情况如图 3所示:

wKgaomUDxBmAcZlKAAAQVJsR_nw292.png

图3 hardfault异常瞬间栈中完整寄存器

Return Address是发生异常指令点,LR是发生异常指令所在函数的下一条指令地址。在hw_hardfault_exception函数中将栈中的寄存器值都通过串口打印出来。

voidhw_hardfault_exception(structexception_info*exception_info)
{
uint32_t*app_sp=NULL;
inti=0;
/*sp指向发生hardfault前栈地址*/
app_sp=(uint32_t*)(exception_info+1);/*context+16*4*/

printf_e("psr:0x%08xrn",exception_info->psr);
printf_e("r00:0x%08xrn",exception_info->r0);
printf_e("r01:0x%08xrn",exception_info->r1);
printf_e("r02:0x%08xrn",exception_info->r2);
printf_e("r03:0x%08xrn",exception_info->r3);
printf_e("r04:0x%08xrn",exception_info->r4);
printf_e("r05:0x%08xrn",exception_info->r5);
printf_e("r06:0x%08xrn",exception_info->r6);
printf_e("r07:0x%08xrn",exception_info->r7);
printf_e("r08:0x%08xrn",exception_info->r8);
printf_e("r09:0x%08xrn",exception_info->r9);
printf_e("r10:0x%08xrn",exception_info->r10);
printf_e("r11:0x%08xrn",exception_info->r11);
printf_e("r12:0x%08xrn",exception_info->r12);
printf_e("lr:0x%08xrn",exception_info->lr);
printf_e("pc:0x%08xrn",exception_info->pc);

printf_e("stacks:rn");

for(i=0;i< 1024; ++i)
    {
        printf_e("%08x ", *app_sp);
        app_sp++;
        ++i;
        if (i % 16 == 0)
            printf_e("rn");
    }
    printf_e("rn");
    while(1);
}

在hw_hardfault_handler函数中打印出了所有相关寄存器,如图 4所示:

wKgZomUDxByABKeUAAGrKbriSUo660.png

图4 发生异常时栈数据

从打出来的返回地址值(PC)为0x00000644,在生成的all.dis汇编文件搜索该地址,如图 5所示,该地址是C_Function函数中的一个除法指令,R0寄存器值除以R1寄存器值,并将结果存放R0中。R0为0x64,确认R1寄存器值即可。

wKgaomUDxB2AeAsNAABnyZlmSdg999.png

图5 发生hardfault异常瞬间执行的指令

图 4中,LR的值为0x0000060f,all.dis无法搜索到该地址。由于Cortex-M3使用的是Thumb指令集,bit0置位指示该地址地址指令是Thumb指令。bit0复位,搜索0x0000060e,如图 6所示,该地址在B_Function函数中。B_Function函数调用了C_Function函数,R0为传递的参数0。由此可知,图 5中,R1的除数值0,故程序会发生hardfault异常。

wKgZomUDxB-AdZjCAADELUA_Ks8798.png

图6 B_Function函数的汇编代码

图 6中,调用C_Function函数前,R4和LR寄存器被压入了栈中。即图 7中,LR的值为0x000005D1,R4的值为0xe000ed14。

wKgaomUDxCCAR4KWAADcafAHGSY602.png

图 7 B_Function函数压栈值

如图 8所示,在all.dis文件搜索0x000005D0地址在A_Function函数中,在执行A_Function函数前,对R4和LR进行了压栈。A_Function函数调用了B_Function函数。

wKgZomUDxCGAUMNiAAC3dEkj5O4879.png

图 8 A_Function函数汇编代码

如图 9所示,A_Function函数压入的R4值为0xe000ed14,LR值为0x000006a1。

wKgaomUDxCKAV_lzAAEG1TGFmCY233.png

图 9 A_Function函数压栈值

如图 10,在all.dis文件中,搜索0x000006a0,发现该地址在TestDebug函数中,且该函数将R4和LR压入栈中。

wKgZomUDxCWAeGnWAACnRuXnAWk374.png

图 10 TestDebug函数汇编代码

如图 11所示,A_Function函数压入的R4值为0xe0001c18,LR值为0x00001ab9。

wKgZomUDxCaAKLWLAADHbLwMPJ4442.png

图 11 TestDebug函数压栈值

如图 12所示,在all.dis文件中,搜索0x00001ab8,该地址在main函数中。

wKgZomUDxCiAZCblAABe4kBCRpI591.png

图 12 main函数的汇编代码

至此,如图 13所示为发生hardfault异常时函数的调用关系,在C_Function函数中,被除数为0是导致进入hardfault异常的原因。

wKgaomUDxCmADZmHAAALmSLOJcA155.png

图 13 发生hardfault时的函数调用关系

来源:东软载波微电子

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 微控制器
    +关注

    关注

    48

    文章

    6812

    浏览量

    147659
  • 寄存器
    +关注

    关注

    30

    文章

    5036

    浏览量

    117763
  • 程序
    +关注

    关注

    114

    文章

    3631

    浏览量

    79552
  • Cortex-M3
    +关注

    关注

    9

    文章

    268

    浏览量

    59165
收藏 人收藏

    评论

    相关推荐

    【经验】飞思卡尔工程师教你如何定位Kinetis MCU Hard Fault 异常

    时会产生一个“unexpected”中断,内核就会自动调用异常处理函数,同时也将运行用户自定义的处理函数,来实现特殊故障的定位方法。 默认情
    发表于 01-31 22:06

    【转载】快速追踪和定位产生HardFault原因的方法

    AN0028—快速追踪和定位产生HardFault原因的方法概述在使用ARM Cortex-M 系列 MCU时(如AT32 MCU),有时会出现程序运行异常。当通过编译器在debug模式查原因
    发表于 08-17 09:44

    灵动微课堂 (第173讲) | HardFault定位方法和步骤

    根据上述的定位手段可以查找是哪一种情况造成的异常,在编程过程中需要避免出现上述异常情况,但是在恶劣复杂的环境下,可能会小概率触发HardFault中断,可以在
    发表于 07-02 15:20

    如何快速定位HardFault

    1、背景程序运行,发现程序跑飞到HardFault,但不清楚为什么会跑到HardFault中断处理函数去。2、分析要想知道为什么会跑到HardFault_Handler中去,就很有必要
    发表于 01-27 06:20

    HardFault错误调试的定位方法是什么

    HardFault 错误调试定位方法1、首先更改 startup.s 的启动文件,把里面的 HardFault_Handler 代码段换成下面的代码:HardFault
    发表于 02-15 07:22

    cortex内核hardfault错误的定位方法实战

    单片机一般是cortex-m3之类的内核,其实其他内核也是一个道理。hardfault错误一般是操作了不该操作的内存,或者执行了不该执行的动作,例如一个非法的函数指针,你非要去调用。调试这个错误
    发表于 12-01 13:36 10次下载
    cortex内核<b class='flag-5'>hardfault</b>错误的<b class='flag-5'>定位</b>方法实战

    S32K1XX调试--快速定位HardFault

    1、背景程序运行,发现程序跑飞到HardFault,但不清楚为什么会跑到HardFault中断处理函数去。2、分析要想知道为什么会跑到HardFault_Handler中去,就很有必要
    发表于 12-03 15:21 5次下载
    S32K1<b class='flag-5'>XX</b>调试--快速<b class='flag-5'>定位</b><b class='flag-5'>HardFault</b>

    ES32F36xx USB例程应用笔记

    电子发烧友网站提供《ES32F36xx USB例程应用笔记.pdf》资料免费下载
    发表于 09-22 11:02 1次下载
    <b class='flag-5'>ES32F36xx</b> USB例程应用笔记

    ES32F36xx Bootloader应用笔记

    电子发烧友网站提供《ES32F36xx Bootloader应用笔记.pdf》资料免费下载
    发表于 09-22 11:01 0次下载
    <b class='flag-5'>ES32F36xx</b> Bootloader应用笔记

    ES32F36xx应用笔记

    电子发烧友网站提供《ES32F36xx应用笔记.pdf》资料免费下载
    发表于 09-22 10:59 1次下载
    <b class='flag-5'>ES32F36xx</b>应用笔记

    C语言使用函数调用在内存中究竟发生了什么?

    C语言使用函数调用,我们再熟悉不过了,但是函数调用在内存中究竟发生了什么真的清楚吗?只有搞清楚内存里的内幕,才算完全搞懂
    的头像 发表于 01-13 14:09 749次阅读

    AT32讲堂009 | 基于CmBacktrace库,如何快速追踪和定位产生HardFault的原因

    概述在使用ARMCortex-M系列MCU时(如AT32MCU),有时会出现程序运行异常。当通过编译器在debug模式查原因时,会发现程序跑到HardFault_Handler函数中,产生
    的头像 发表于 06-15 10:44 2609次阅读
    AT32讲堂009 | 基于CmBacktrace库,如何快速追踪和<b class='flag-5'>定位</b>产生<b class='flag-5'>HardFault</b>的原因

    ES32F36xx芯片发生HardFault异常时的函数调用关系及问题定位

    Cortex-M3微控制器因其功能强大、性价比高以及易用性好,在嵌入式体系结构中得到了广泛应用。然而,在实际开发过程中,如果程序很大或运行很久后可能会遇到HardFault异常
    的头像 发表于 06-20 09:30 444次阅读
    <b class='flag-5'>ES32F36xx</b><b class='flag-5'>芯片</b><b class='flag-5'>发生</b><b class='flag-5'>HardFault</b><b class='flag-5'>异常</b>时的<b class='flag-5'>函数</b><b class='flag-5'>调用</b><b class='flag-5'>关系</b>及问题<b class='flag-5'>定位</b>

    一个地址未对齐引起的HardFault异常

    一个地址未对齐引起的 HardFault 异常
    的头像 发表于 09-18 10:57 438次阅读
    一个地址未对齐引起的<b class='flag-5'>HardFault</b><b class='flag-5'>异常</b>

    基于CmBacktrace库,如何快速追踪和定位产生HardFault的原因

    基于CmBacktrace库,如何快速追踪和定位产生HardFault的原因
    的头像 发表于 10-27 09:51 810次阅读
    基于CmBacktrace库,如何快速追踪和<b class='flag-5'>定位</b>产生<b class='flag-5'>HardFault</b>的原因