文章目录
- 前言
- 1. 问题说明
- 2. STM32(Cortex M4内核)的寄存器
- 3. 崩溃问题分析
- 3.1 崩溃信息的来源是哪里?
- 3.2 崩溃信息中的每个关键字代表的含义
- 3.3 利用崩溃信息去查找造成崩溃的点
- 3.4 keil5中怎么根据地址找到问题点
- 3.5 keil5上编译时怎么输出map文件
- 4. 参考链接
前言
近期发现合并了一些其它平台上的代码到STM32上后,出现了崩溃问题,于是想要整体梳理下STM32上崩溃问题排查的原理。
1. 问题说明
上述是一段崩溃打印信息,后经排查发现是FreeRTOS的定时器栈深度设置的多小,定时器运行函数中运行的内容过多,各个局部变量申请的内存来不及释放,最终出现了崩溃情况。
这里说一下FreeRTOS中的定时器,实际上可以理解为是一个task任务,相当于创建了一个线程在不停的计时,然后轮询查询当前的定时器列表,发现哪个定时器运行时间到了,就去执行它。
所以对于定时器也需要配置所使用的内存大小。
2. STM32(Cortex M4内核)的寄存器
R0~R12为通用目的寄存器
R13为栈指针,物理上存在两个栈指针:主栈指针(MSP)为默认的栈指针,在复位后和处理器处于处理模式时,会被选择使用;另一个栈指针为进程栈指针(PSP),只能用于线程模式(有RTOS时)
R14为链接寄存器(LR),用于函数或子程序调用时返回地址的保存。在函数或子程序结束时,程序控制可以通过将LR的数值加载程序计数器(PC)中返回调用程序处并继续执行,在异常处理期间,LR会自动更新为特殊的EXC_RETURN(异常返回)数值。
例如a调用了b,这个时候pc指针中放的是b子函数的地址,LR中方的是a的地址,b执行完之后,从LR中将a的地址放入到PC指针去执行
3. 崩溃问题分析
3.1 崩溃信息的来源是哪里?
arm中崩溃实际上也是一种异常中断,当中断来临时,处理器会将当前的任务状态保存到栈中。
-
栈帧
栈帧(Stack Frame)是指在函数调用过程中,用于保存函数参数、局部变量、返回地址等信息的一块内存区域。当一个函数被调用时,STM32会为其分配一个栈帧,栈帧的大小取决于参数数量、局部变量数量以及编译器的优化设置等因素
结合上面的信息我们可以知道,想要获取函数崩溃时在哪个函数崩溃的,我们就需要找到异常中断触发时,被压栈的栈帧,而这个栈帧就在R13(Stack point)栈指针里面存放着。
我们在崩溃处理函数HardFault_Handler()中想办法获取到R13寄存器的指针所指向的内容,然后将其打印出来即可。
3.2 崩溃信息中的每个关键字代表的含义
STM32 微控制器采用了 ARM Cortex-M 核,该核有两个栈指针,一个是主栈指针(MSP),另一个是进程栈指针(PSP)。
MSP (Main Stack Pointer): 主栈指针 主要用于操作系统内核或者中断服务程序。
PSP (Process Stack Pointer): 进程栈指针 主要用于用户应用程序。
当 Cortex-M 内核退回到 Thread mode 后,根据 CONTROL 寄存器的设置,可以切换回主栈指针 MSP 或者进程栈指针 PSP。
PSP 里面存储的是所运行的用户应用程序相关的上下文。具体包括以下内容:
一些或全部的通用寄存器的值,这些寄存器在用户程序运行时会使用。
Program Counter(PC):指向下一条将要执行的指令。
Processor Status Register(PSR)的值:包含标志位状态。
栈指针:保存上一个栈帧的位置。
通常,在切换任务(或称为上下文切换)时,这些信息会被保存到栈中,新的任务开始,它的上下文信息则会从栈中恢复。
需要注意的是,具体保存了哪些内容,会根据具体的调度策略和操作系统设计有所不同。
3.3 利用崩溃信息去查找造成崩溃的点
确定LR/PC指针的值
首先我们要确定是否使用了RTOS,如果使用了,那么我们的崩溃信息应该就是存放PSP中。
我们需要先将这些信息读出来,然后当知道了LR和PC的值后,可以通过keil5中Debug的方式去寻找崩溃点或者通过编译过程中产生的map文件,找到对应的崩溃点。
3.4 keil5中怎么根据地址找到问题点
在Disassembly窗口单击右键—>选择Show Didassembly at Address—>输入地址
3.5 keil5上编译时怎么输出map文件
打开 Keil Vision。
在菜单中选择 "File" -> "Open Project...",然后选择你的项目文件。
在 Keil Vision IDE 中,点击 "Project" 菜单,选择 "Options for Target"。
在弹出的对话框中,选择 "Listing" 选项卡。
在 "Generate Map File" 选项旁边,确保选中了 "Create ROM/FLASH Map" 和 "Create Object Module List"。
重新编译你的项目。
4. 参考链接
【STM32】HardFault问题详细分析及调试笔记
MDK5(keil)编译信息含义(占用sram,flash空间)与 MAP文件