【嵌入式STM32】HardFault总结
MSP压栈顺序为R0、R1、R2、R3、R12、LR,**此处LR和上面CPU寄存器的LR是不一样的!当进入HardFault时,首先看CPU寄存器信息,这里LR用于异常返回控制,0xFFFFFFF9可以去看MSP主栈寄存器。改为int显示,直接找0x8开头的,也对应了LR。也就是说,Instance非法了,遇到这种情况可以根据map文件进行问题排查。有时候,进入hardfault时,并没有堆栈信
1. HardFault出现的原因
实际应用中大概原因有下面几条:
- 数组越界操作;
- 使用非法指针;
- 堆栈空间不足,ram爆了;
当出现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. 场景模拟1 - 通过堆栈定位
下面将模拟一个越界操作其他地址,导致该地址操作时崩溃的例子。
首先,在spi1句柄对象前定义一个全局变量:
char g_buffer_overstep[128] = {0}; //越界数组测试
SPI_HandleTypeDef hspi1;
为何这样定义呢?这要看map文件了,打开xxx.map文件,找到Global Symbols段落,找到如下内容:
可以看到,
- g_buffer_overstep变量的地址是0x200000dc,占用128字节
- hspi1变量的地址是0x2000015c,占用88字节
两个变量在内存中是紧挨着的,下面就好操作了,越界访问1个字节:
//情况1:越界操作
char *p = g_buffer_overstep;
p[128 + 1] = 0xff;
SPI_FLASH_READ_FLASHID();//操作SPI,参考前面的文章或者随便操作一下
运行一下发现崩到hardfault中了,调用堆栈:
可以跟到这里:
/* Check if the SPI is already enabled */
if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
{
/* Enable SPI peripheral */
__HAL_SPI_ENABLE(hspi);
}
也就是说,Instance非法了,遇到这种情况可以根据map文件进行问题排查。
3. 场景模拟2 - 通过寄存器LR定位
有时候,进入hardfault时,并没有堆栈信息,此时可通过如下方法进行定位。
比如,直接在main中写入下列代码:
//情况2:非法指针
char *p = (char *)0x0000012f;
p[0] = 0xff;
此时虽然有堆栈,但我们不管,这里看CPU的寄存器:
当进入HardFault时,首先看CPU寄存器信息,这里LR用于异常返回控制,0xFFFFFFF9可以去看MSP主栈寄存器。其他情况如下:
MSP压栈顺序为R0、R1、R2、R3、R12、LR,**此处LR和上面CPU寄存器的LR是不一样的!**它存储的是实际的异常地址!两者的区别:
我们可以将MSP地址拷贝的Memory窗口进行查看:
改为int显示,直接找0x8开头的,也对应了LR。将其复制,然后在汇编窗口打开 show…address:
改为0x开头的:
现在问题定位了:
4. 其他
待补充。。
更多推荐



所有评论(0)