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时,停止运行后黄色光标无法定位到异常中断处
具体分析如下:
-
模拟栈溢出问题
uint16_t g_arry[5]; for (int i=0;i<1000000;i++) { g_arry[i] +=10; }
-
使用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.查看寄存器
通过菜单栏Peripherals >Core Peripherals >Fault Reports打开fault reports
但是查看fault种类有时可能对解决问题并没有直接帮助,关键是如何定位在进入异常中断前执行的代码段
-
确定当前使用堆栈是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
-
找到异常发生代码地址
在memory中,定位到堆栈地址:0x200014D8,依据:R0~R3、R12、LR、PC、XPRS 顺序,找到LR的值,即第6个寄存器值
LR = 0x08002879
PC = 0x0800288C
-
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