1. HardFault出现的原因

实际应用中大概原因有下面几条:

  1. 数组越界操作;
  2. 使用非法指针;
  3. 堆栈空间不足,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. 其他

待补充。。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐