Keil V6编译器体验分享及STM32硬件故障定位方法详解

之前一直是用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函数,到此我们找到了异常代码所在的位置。

    作者:cccnz

    物联沃分享整理
    物联沃-IOTWORD物联网 » Keil V6编译器体验分享及STM32硬件故障定位方法详解

    发表回复