keil v6 编译器体验记录和stm32 hardfault 定位方法和步骤

之前一直是用v5编译,编译速度慢,换成V6编译速度快两倍以上 ,而且 arm 后期只维护v6编译器不再更新v5编译器

Keil MDK自 V5.36 版本之后,默认就不带 Arm Compiler V5版本编译器。如果需要使用 V5 版本编译器,就需要自己下载并安装

V5编译OK的工程,V6有可能编译不过去,就算能过,也不知道会不会出莫名其妙的问题,建议从头开始一个项目的时候使用这个方式。

使用v6编译器需要注意以下:

  • 配置优化选项

    http://t.csdnimg.cn/hqSvT

    http://t.csdnimg.cn/Jgs9T

  • 使用V6编译器有时候不能跳转到定义

    http://t.csdnimg.cn/81A3d

  • DEBUG 过程中发现的一种现象

  • 出现HardFault等bug时,停止运行后黄色光标无法定位到异常中断处

    停止运行

    具体分析如下:

    1. 模拟栈溢出问题

      uint16_t g_arry[5];
      for (int i=0;i<1000000;i++)
      {
          g_arry[i] +=10;
      }
      
    2. 使用V5编译器开启O0等级优化

      出现bug停止运行后,黄色光标正常定位:
      在这里插入图片描述
      ​ debug 栈调用窗口正常显示
      在这里插入图片描述

  • 使用V6编译器且开启O0等级优化:

出现bug停止运行后,黄色光标无法定位,页面停留在启动文件
在这里插入图片描述

即使手动切换到HardFault中断所在的文件,也没看到黄色光标
在这里插入图片描述

​ debug 栈调用窗口正常显示:
在这里插入图片描述

  • 使用V6编译器且开启O1等级优化:
    在这里插入图片描述
    出现bug停止运行后,黄色光标正常定位:
    在这里插入图片描述

  • 总结

    使用 V5 编译器开启O0等级优化黄色光标正常定位

    使用 V6 编译器开启O0等级优化黄色光标无法正常定位,开启O1等级优化黄色光标正常定位

    这时我又试了一下使用 V5 编译器开启O1等级优化,发现黄色光标也能正常定位

在这里插入图片描述
keil配置使用V6 编译器后,默认的优化等级是O1,V5 编译器默认的优化等级是O1,但是我之前使用V5 编译器时都是会手动改成O0,所以最近使用V6 编译器后我都是改成O0,才发现有上述现象,所以使用V6 编译器还是使用默认优化等级O1比较好

  • freertos相关:

    • MDK默认使用的V5编译器,FreeRTOS调用的端口配置信息是RVDS文件夹中的;切换到V6编译器,需要将GCC文件夹中的信息拷贝到RVDS中,进行替换;无需其他修改

    • 在FreeRTOS系统中时钟LWIP功能,且使用MDK的V6编译器;需要做如下修改

      ​ a.cc.h文件中的"#define LWIP_TIMEVAL_PRIVATE 0"和"#include <sys/time.h>“这两句话注释掉;大约在第45行cc.h文件中的”#define LWIP_TIMEVAL_PRIVATE 0"和"#include <sys/time.h>"这两句话注释掉;大约在第45行

      ​ b. LWIP.c文件中的#if defined ( __CC_ARM )和对应的#endf注释掉,用于释放sio_send,sio_open等操作的

hardfault 定位方法和步骤

错误种类

对于Cortex-M内核,架构采用错误异常的机制来检测问题,当核心检测到一个错误时,异常中断会被触发,并且核心会跳转到相应的异常终端处理函数执行,错误异常的终端分为以下四种:

HardFault
MemManage
BusFault
UsageFault

其中hardfault为最常见的错误类型,并且,在没有开启其他异常处理的情况下,默认进入hardfault异常中断处理函数:

void HardFault_Handler(void)
{
    /* USER CODE BEGIN HardFault_IRQn 0 */
    /* USER CODE END HardFault_IRQn 0 */
    while (1)
    {
        /* USER CODE BEGIN W1_HardFault_IRQn 0 */
        /* USER CODE END W1_HardFault_IRQn 0 */
    }
}

2) 可能的原因

从软件角度,产生hardfault的可能原因有:

(1)数组越界
(2)野指针
(3)未初始化硬件却开始操作,或无中断服务函数

(4)任务堆栈溢出

方法1.查看寄存器
  • 查看fault种类

通过菜单栏Peripherals >Core Peripherals >Fault Reports打开fault reports

在这里插入图片描述

在这里插入图片描述

但是查看fault种类有时可能对解决问题并没有直接帮助,关键是如何定位在进入异常中断前执行的代码段

  • 调试定位步骤
  1. 确定当前使用堆栈是MSP还是PSP

    异常发生后会把进入异常前的 R0-R3,R12, LR, PC,PSR 寄存器值栈入 Main Stack 或Process Stack(取决于异常发生时使用的哪个栈)。 进入异常后链接寄存器 LR 中存放异常返回值 EXC_RETURN, 如果其 bit 2=0 那么用的就是 Main Stack,如果 bit 2=1,那么用的就是 Process Stack。
    在这里插入图片描述
    在这里插入图片描述
    由上图和下图可以看出,当前使用的堆栈为MSP

在这里插入图片描述

  1. 找到异常发生代码地址

    在memory中,定位到堆栈地址:0x200014D8,依据:R0~R3、R12、LR、PC、XPRS 顺序,找到LR的值,即第6个寄存器值
    在这里插入图片描述

    LR = 0x08002879

    PC = 0x0800288C

  2. Disassembly反汇编中,查找定位代码

    在反汇编窗口中点击右键,选中show disassembly at address 。

    输入LR地址:为发生异常后调用的下一条指令的地址

    输入PC地址:可以定位到发生异常的调用语句

    在这里插入图片描述

方法2: Call Stack

在仿真状态下,调出Call Stack Window,可直接跳转到调用代码
在这里插入图片描述
在这里插入图片描述

方法3: .map文件

.map文件在keil工程里面随着程序的编译会自动生成,需要正确设置以下选项:

在这里插入图片描述

双击Target位置即可打开.map文件

在这里插入图片描述

在.map文件里我们查找LR = 0x08002879,找到了0x08002865指示是buzzer_device_ops_callback函数,到此我们找到了异常代码所在的位置。

在这里插入图片描述

  • 22
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值