RiscV CPU/CH32V307的hardfault分析

这块文章还比较少,但是用了RiscV一定会用到,目前比较有效的信息如下:


可在HardFault函数中将以下3个状态寄存器的值打印看一下。mepc、mcause、mtval均为CSR寄存器,其中,

mepc寄存器值为当前遇到异常时的指令 PC 值,或中断前下一条预执行的指令 PC 值,退出异常或中断后微处理器的返回地址保存在mepc中。

mcause寄存器值为当前异常种类或中断编号值,可以通过该值查看引起异常的原因或判断中断的来源。

mtval寄存器值主要反映引起当前异常的存储器访问地址或指令编码,当进入异常和中断时,硬件将自动更新mtval的值。

关于这三个CSR寄存器的具体介绍,可参考我们QingKeV4微处理器手册,手册下载链接如下:
http://www.wch.cn/downloads/QingKeV4_Processor_Manual_PDF.html
同时为避免不必要错误LD文件里和下载配置里的FLASH和RAM大小分配要一致。


LYJ博客

其中,mcause在手册定义如下:

LYJ博客


假如mcause=00000004,那么就是Load address misaligned,即数据对齐问题导致hardfault。

如果mepc=000072D6,查看map文件:


LYJ博客


那么极有可能是在ETH_IROHandler中产生的这种异常。


=====================下面是官方文档====================

不少工程师在项目开发过程中会遇到代码运行进HardFault_Handler中断的情况。因进HardFault_Handler中断的原因(RAM溢出/空指针异常/堆栈溢出等等)比较多,情况比较复杂,搞得工程师没有头绪。现提供排查思路如下:

HardFault_Handler定位

可在void HardFault_Handler(void)中断服务函数中添加如下代码:

    printf("mepc  :%08x\r\n", __get_MEPC());

    printf("mcause:%08x\r\n", __get_MCAUSE());

    printf("mtval :%08x\r\n", __get_MTVAL());

while(1);

该操作仅适用于代码串口可用的情况下,如串口不可用但可以仿真,也可通过仿真查看__get_MEPC()__get_MCAUSE()__get_MTVAL();三个函数的返回值。

串口呈现方式:(图一)

LYJ博客

中断呈现方式:(图二)

LYJ博客


仿真操作可参考该帖:

https://blog.csdn.net/qq_36353650/article/details/120441264?spm=1001.2014.3001.5502

https://blog.csdn.net/qq_36353650/article/details/120665601?spm=1001.2014.3001.5502

关于三个函数返回值的介绍:

MCAUSE:反映当前的异常种类或中断的编号,mcause[31]=1 表示为中断,mcause[31]=0 表示为异常。本文仅分析mcause[31]=0的情况。

表一异常编码

LYJ博客

MEPC:机器模式异常指针寄存器,标准定义退出异常或中断后微处理器的返回地址保存在MEPC中。所以当发生异常或中断后,硬件自动更新MEPC 值为当前遇到异常时的指令PC 值,或中断前下一条预执行的指令PC值。

MTVAL:该值即为引起异常的值,有以下几种情况:

1.如果存储器访问引起的异常,硬件会将异常时存储器访问的地址存入mtval

2.如果是非法指令引起的异常,硬件会将该指令的指令编码存入mtval

3.如果是硬件断点引起的异常,硬件会将断点处PC值存入mtval

4.对于其他的异常,硬件将mtval的值设为0,例如ebreakecall 指令引起的异常。

5.进入中断时,硬件将mtval的值设为0

综上所述,我们可以通过MEPC的值确定代码进HardFault_Handler中断的位置,在某些情况下可以方便我们确定报错原因。本文提供两种方法:

 

方法一 仿真法:

以上文图一呈现的HardFault报错信息为例,由打印信息或仿真信息可知MEPC=0x92c,且mcause[31]=0,因此触发HardFault为异常而不是中断,所以出现异常的PC指针地址为0x92c。我们可以在仿真时在0x92c处打断点,如图所示:(图三)

LYJ博客

然后全速运行,代码就会停在出错位置附近,如图所示:(图四)

LYJ博客

方法二 查表法:可在所在工程的.lst文件中搜索MEPC值,即该案例中的92c,如图:(图五)

LYJ博客


lst文件可知报错函数为printf("%x ",*(uint16_t*)( buf+i));如果你是汇编大佬也可以分析一下这段代码,相信你也可以分析出报错原因。如果不是也不要灰心,可以继续往下看。

HardFault_Handler报错原因分析:

由上文可知报错原因可以通过MCAUSEMTVAL确定,该案例中MCAUSE=4MTVAL=20000ca1

由表一可知该案例的报错原因为Load指令访存地址不对齐,结合MTVAL的情况1可知异常时存储器访问的地址为0x20000ca1。显然该地址为RAM地址结合代码可知,该问题是由于定义的数组为8位,但通过16位访问造成的。

LYJ博客


注:如果通过仿真的方式查找问题且应用中有读写FLASH/低功耗/看门狗等操作,需将相关代码注释然后再仿真,否则将无法仿真。本文只是提供了一个查找HardFault_Handler问题的思路,实际情况可能比案例要复杂的多。可根据实际情况灵活处理。

PDF下载:

hardfault查找思路.pdf


本文为3YL原创,转载无需联系,但请注明来自labisart.com。

原创文章不易,如果觉得有帮助,可打赏或点击右侧广告支持:

查看打赏记录

发表评论请遵守党国法律!后台审核后方可显示!
  • 最新评论
  • 总共0条评论
  • Blog v1.1© 2024 labisart.com 版权所有 | 联系:labartwork@163.com