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

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

3天内不再提示

ARM Cortex-M异常-HardFault INVPC置1解决方法

嵌入式那些事 来源:嵌入式那些事 2023-10-16 09:40 次阅读

CPUSTM32F429IGT6

对于其他的stm32芯片或者其他ARM Cortex-M芯片,其实解决方法都相通。建议先完整阅读了本文之后,再对照着你所遇到问题的现象进行调试。

1.基础知识

在ARM Cortex-M系列处理器中,有若干个系统异常专用于 fault 处理。CM3 中的 Faults 可分为以下几类:

(1).总线 faults;

(2).存储器管理 faults;

(3).用法 faults;

(4).硬 fault;

1.1.总线 faults

当 AHB 接口上正在传送数据时,如果回复了一个错误信号(error response),则会产生总线faults,产生的场合可以是:

(1).取指,通常被称作“预取流产”(prefetch abort);

(2).数据读/写,通常被称作“数据流产”(data abort);

在 CM3 中,执行如下动作时,如果地址有误,亦会触发总线异常:

(1).中断处理起始阶段的堆栈 PUSH 动作。此时若发生总线 fault,则称为“入栈错误”;

(2).中断处理收尾阶段的堆栈 POP 动作。此时若发生总线 fault,则称为“出栈错误”;

(3).在处理器启动中断服务序列(sequence)后读取向量时。这是一种极度罕见的特殊情况,被归类为硬 fault。

总线 fault 状态寄存器(BFSR),地址:0xE000_ED29,BFSR的各个位的定义如下:

8a91f8fe-6a69-11ee-939d-92fbcf53809c.png

Snipaste_2020-12-11_14-13-31

1.2.存储器管理 faults

存储器管理 faults 多与 MPU 有关,其诱因常常是某次访问触犯了 MPU 设置的保护规范。另外,某些非法访问,例如,在不可执行的存储器区域试图取指,也会触发一个 MemManage fault,而且在这种场合下,即使没有 MPU 也会触发 MemMange fault。MemManage faults 的常见诱因如下所示:

(1).访问了所有 MPU regions 覆盖范围之外的地址;

(2).访问了没有存储器与之对应的空地址;

(3).往只读 region 写数据;

(4).用户级下访问了只允许在特权级下访问的地址;

存储器管理 fault 状态寄存器(MFSR),地址:0xE000_ED28,MFSR的各个位的定义如下:

8ab019ce-6a69-11ee-939d-92fbcf53809c.png

Snipaste_2020-12-11_14-19-19

1.3.用法 faults

用法 faults 发生的场合可以是:

(1).执行了协处理器指令。Cortex-M3 本身并不支持协处理器,但是通过 fault 异常机制,可以建立一套“软件模拟”的机制,来执行一段程序模拟协处理器的功能,从而可以方便地在其它 Cortex 处理器间移植。

(2).执行了未定义的指令。同上一点的道理,亦可以软件模拟未定义指令的功能。

(3).尝试进入 ARM 状态。因为 CM3 不支持 ARM 状态,所以用法 fault 会在切换时产生。软件可以利用此机制来测试某处理器是否支持 ARM 状态。

(4).无效的中断返回(LR 中包含了无效/错误的值);

(5).使用多重加载/存储指令时,地址没有对齐。

另外,如果需要严格要求程序的质量,还可以让 CM3 在遇到除数为零的时候,以及遇到未对齐访问的时候也产生用法 fault。在 NVIC 中有两个控制位分别与它们对应。通过设置这两个控制位,就可以激活它们。

用法 fault 状态寄存器(UFSR),地址:0xE000_ED2A,UFSR的各个位的定义如下:

8ad56bac-6a69-11ee-939d-92fbcf53809c.png

Snipaste_2020-12-11_14-24-49

1.4.硬 fault

硬 fault 是上文讨论的总线 fault、存储器管理 fault 以及用法 fault 上访的结果。如果这些 fault 的服务例程无法执行,它们就会成为“硬伤” ——上访( escalation)成硬 fault。另外,在取向量(异常处理时对异常向量表的读取)时产生的总线 fault 也按硬 fault 处理。在 NVIC中有一个硬 fault 状态寄存器(HFSR),它指出产生硬 fault 的原因。如果不是由于取向量造成的,则硬 fault 服务例程必须检查其它的 fault 状态寄存器,以最终决定是谁上访的。

硬 fault 状态寄存器(HFSR),地址:0xE000_ED2C,HFSR的各个位的定义如下:

8af02898-6a69-11ee-939d-92fbcf53809c.png

Snipaste_2020-12-11_14-29-38

2.UsageFault INVPC置1解决过程

最近在使用RTOS增加DMA驱动时,在对内存到设备和设备到内存的DMA传输测试时,出现了UsageFault,并且UFSR中的INVPC置1了。最开始,单独测试DMA发送是没有问题的,但是DMA发送和接收一起测试时,就会出现UsageFault(INVPC置1)。这个异常不太好定位出现问题的具体位置,因此就检查DMA驱动,并且逐步调试吧。最终,DMA驱动检查和修改好了,仍然出现UsageFault,实在没法了,还是从为什么会出现UsageFault(INVPC置1)开始分析吧。

2.1.出现UsageFault(INVPC置1)的原因

如果LR中的EXC_RETURN不是合法的值(合法值见下图,包括企图返回ARM状态),则引起用法fault。如果用法fault被除能,也上访成硬fault。此时,用法Fault状态寄存器(UFSR,地址:0xE000_ED2A)中的INVPC位(位偏移:2),或者是INVSTATE位(位偏移:1)置位。

8b0478de-6a69-11ee-939d-92fbcf53809c.png

Snipaste_2020-12-11_15-13-23

上面就是出现该异常的文字分析了。

2.2.UsageFault(INVPC置1)的解决过程

因为该异常是异常响应期间才可能出现的异常(<> 9.8节介绍了下,在9.8.4节进行文字说明),因此,只要在异常或中断的返回处打断点,执行下一步就有可能进入UsageFault异常。(当然了这个方法,是比较笨的,不过在缩小了异常出现的范围之后,可以在每次异常或中断的返回处打断点,然后执行下一步,就有可能进入UsageFault异常)

我这里是每次开始DMA测试之后,就进入UsageFault异常,并且我的系统中目前就打开了SysTick,PendSV,DMA1_STREAM5,DMA1_STREAM6,NMI,HardFault,MemFault,BusFault,UsageFault这些异常和中断。因此我在开始DMA测试的时候打一个断点,在程序运行到DMA测试开始的断点处时,再在DMA1_STREAM5,DMA1_STREAM6,NMI,HardFault,MemFault,BusFault,UsageFault这些函数的入口打断点,在PendSV的返回处打断点,SysTick就暂时先不管。然后全力运行,发现每次都会在PendSV的异常返回断点处停留(因为任务切换嘛)总共在PendSV的断点处停留了大概7到8次,就进入到了UsageFault。

有了上面步骤的铺垫,先去除中断和异常中的断点,还是先在DMA测试开始处打断点,等运行到DMA测试开始处,再在上述的中断和异常相关位置打断点。接下来我就慢慢的调试,在开始DMA测试之后,全速运行,在退出PendSV异常时,执行单步运行到下一步,重复7到8次,从PendSV就进入了UsageFault,在这7到8次中,我看在退出PendSV时,LR寄存器中的值都是0xFFFFFFFD,是合法的啊,当时仔细一想,有可能是退出异常时硬件再将堆栈中的PC赋值给PC时出问题,导致进入了UsageFault。果不其然,在PenSV退出之前,我查看每个PSP(0xFFFFFFFD:返回线程模式,并使用线程堆栈)对应内存数值,能够正常退出PendSV的寄存器和PSP堆栈内容如下图所示:

8b177ca4-6a69-11ee-939d-92fbcf53809c.png

Snipaste_2020-12-11_16-38-20

8b23d8e6-6a69-11ee-939d-92fbcf53809c.png

Snipaste_2020-12-11_16-43-28

进入UsageFault异常之前的寄存器和PSP堆栈内容如下图所示:

8b3b8dc4-6a69-11ee-939d-92fbcf53809c.png

Snipaste_2020-12-11_16-45-35

8b4808ec-6a69-11ee-939d-92fbcf53809c.png

Snipaste_2020-12-11_16-47-17

此处堆栈中的内容,明显的0x20003D94堆栈中的PC值是有问题的,我的程序是烧写到flash中的PC地址应该是08xxxxxx,然而现在堆栈中的PC地址是0x20003DA8,这个地址是SRAM中的地址,SRAM存储的数据而不是代码,出现这个问题的原因,猜想一下,应该就是任务堆栈溢出导致,当我增加任务堆栈的大小之后,哈哈,程序正常运行,世界是如此美好。

3.调试小结

3.1.解决过程小结

其实上面的步骤2,是我自己的一个调试解决问题的过程,这里给大家提供一个比较直接的解决方式。在开始运行程序之前,直接在UsageFault异常入口函数中打一个断点,然后全速运行程序,等程序停止在UsageFault异常函数的断点处时,需要注意以下几点:

(1).如果LR是合法值,那么根据LR判断退出异常时使用的堆栈,然后在Memory查看窗口中,查看堆栈中R0,R1,R2,R3,R12,LR,PC,xPSR这些寄存器的值,根据这些寄存器的值,判断是否是堆栈溢出导致该异常发生;如果不是堆栈溢出导致该异常发生,那么就要根据PC值,在汇编窗口中跳转到PC值对应的代码处,分析导致异常发生的原因;

(2).如果LR不是合法值,就要分析下你的代码中,有哪些地方修改过LR的值,确保修改的值要是合法的。

3.2.关于UsageFault 如何才能让INVPC置1

(1).在退出异常或中断时,执行BX LR时,LR的值是非法的,此时就会触发UsageFault异常,并且INVPC置1。

(2).在退出异常或中断时,执行BX LR时,LR的值是合法的,但是退出异常之后要使用的堆栈中,堆栈里面的PC值是有问题的,此时就有可能触发UsageFault异常,并且INVPC置1。

对于上面的两点的模拟其实也比较好做,在PendSV或者其他异常的退出的地方打一个断点,然后手动修改LR或者堆栈中PC的值,就能触发UsageFault异常,并且INVPC置1。这里注意一下,修改堆栈中PC的值,我这里测试时候,设置PC值为其他值可能引起其他的异常,貌似修改PC的值为RAM中数据区的地址才会出现该异常,不太清楚为什么会这样,可能是数据区是没有执行代码的权限,因此出异常吧,不太确定,有知道的朋友,欢迎留言讲解。








审核编辑:刘清

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

    关注

    134

    文章

    8651

    浏览量

    361777
  • 存储器
    +关注

    关注

    38

    文章

    7148

    浏览量

    161985
  • 中断处理
    +关注

    关注

    0

    文章

    92

    浏览量

    10890
  • Cortex-M
    +关注

    关注

    2

    文章

    224

    浏览量

    29574
  • STM32芯片
    +关注

    关注

    0

    文章

    38

    浏览量

    4311

原文标题:ARM Cortex-M 异常-HardFault(UsageFault) INVPC置1解决过程

文章出处:【微信号:嵌入式那些事,微信公众号:嵌入式那些事】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

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

    AN0028—快速追踪和定位产生HardFault原因的方法概述在使用ARM Cortex-M 系列 MCU时(如AT32 MCU),有时会出现程序运行
    发表于 08-17 09:44

    如何选择正确的Cortex-M处理器?

    系统级特性,调试和追踪功能和性能的比较,欢迎大家一起学习了解。1、简介今天, ARM Cortex-M 处理器家族有8款处理器成员。除此之外,ARM的产品系列还有很多其他的处理器成员。
    发表于 10-22 08:16

    Cortex-M 系列处理特点和区别详解

    Cortex-M行业标准: ARM Cortex-M 处理器是全球微控制器标准,已许可给 40 个以上的 ARM 合作伙伴,包括 NXP Semiconductors
    发表于 01-14 10:13

    cortex-m 单片机在 arm产品中的位置及类别 精选资料分享

    cortex-m 单片机在arm产品中的位置https://developer.arm.com/ip-products/processors 下面有1类 processor
    发表于 07-16 07:59

    ARM Cortex-M处理器详解 精选资料分享

    Cortex-M 系列处理器的指令集和高级中断处理能力,以及 SoC系统级特性,调试和追踪功能和性能的比较。  1、简介  今天, ARM Cortex-M 处理器家族有8款处理器成员
    发表于 07-16 07:57

    cortex-m下各种微架构的区别是什么?

    cortex-m单片机在arm产品中的位置是哪里?cortex-m 单片机的类别有哪些?cortex-m下各种微架构的区别是什么?
    发表于 11-04 06:00

    常用的ARM Cortex-M处理器有哪些?

    常用的ARM Cortex-M处理器有哪些?
    发表于 11-05 07:20

    Cortex-M处理器优化的代码

    生成针对Cortex-M处理器优化的代码。嵌入式编码®Support Package的ARM®的Cortex®-M处理器可以生成使用CMSIS库数学运算的优化代码。将此生成的代码用于
    发表于 12-14 09:10

    ARM Cortex-M堆栈机制介绍

      大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是ARM Cortex-M堆栈机制。  今天给大家分享的这篇依旧是2016年之前痞子衡写的技术文档,花了点时间重新编排了一下
    发表于 12-16 06:26

    ARM Cortex-M内核的相关资料推荐

      大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是ARM Cortex-M功能模块,不过侧重点是三款安全特性处理器。  ARM Cortex-M处理器家族发展至今(2
    发表于 12-27 07:21

    ARM cortex-M上出现HardFault后如何排查呢

    ARM cortex-M上面的fault想必大家都不陌生,我相信还没有谁从来没有出现过fault。但出现fault后如何排查,相信很多人都是一筹莫展。在我的项目中加了一些代码,Fault 后可以打印
    发表于 06-27 14:35

    Arm Cortex-M处理器—Cortex-M85介绍

    Arm发布了新一代的Cortex-M处理器,Cortex-M85。简单粗暴的打个比方:Cortex-M85 ≈ Cortex-M7Trust
    发表于 07-15 14:59

    如何使用Ozone分析Cortex-M故障?

    错误的存储指令。总结Cortex-M处理器异常包含:(1)HardFault异常,是缺省异常,固
    发表于 09-23 11:26

    ARM Cortex-M处理器对比表

    延迟和高确定性操作。 ARM Cortex-M处理器对比表1功能Cortex-M0 Cortex-M0+Cortex-M1
    发表于 08-29 07:00

    Atmel Studio 6软件中如何调试ARM Cortex-M

    Atmel Studio 6软件中如何调试ARM Cortex-M
    的头像 发表于 07-04 10:49 3978次阅读