【STM32】HAL库调用HAL_SPI_Transmit出现HartFault问题

问题描述:

HAL库调用硬件SPI发送函数HAL_SPI_Transmit会导致程序进入HartFault

// flash 页大小(字节)
#define FLASH_SPI_PAGE_SIZE       (256)

static uint8_t write_buffer[FLASH_SPI_PAGE_SIZE + 4];

spi1_write(W25QXX_CHANNEL, (uint8_t *)write_buffer, (length + 4));

/**
 * @brief SPI写入
 * @param *txBuffer 发送字节集
 * @param txLength 发送长度
 * @return spi发送的长度
 * */
uint32_t spi1_write(SPIChannel channel, uint8_t *txBuffer, uint32_t txLength)
{
  if(channel == W25QXX_CHANNEL)
  {
    W25QXX_CHANNEL_ON;
  }

  HAL_SPI_Transmit(&hspi2, txBuffer, txLength, 500);

  if(channel == W25QXX_CHANNEL)
  {
    W25QXX_CHANNEL_OFF;
  }

  return txLength;
}

原因分析:

Debug发现进入HartFault之前最后一句话是

【STM32】HAL库调用HAL_SPI_Transmit出现HartFault问题_第1张图片
是该揭开它真正面纱的时候了:我们再看出现问题的那条语句:

hspi->Instance->DR = *((uint16_t *)pData);

再看我们数组的定义:uint8_t
出现问
题这条语句把我们定义的uint8_t 数组转换成了uint16_t 同时进行半字的操作(同时操作两个byte)。这样看确实提高了执行效率,但是却也埋下了隐患。

产生这样的问题,我们就不得不扯得更远一点,arm内核对数据的非对齐数据访问。

Arm对内存的访问支持字(4byte)、半字(2byte)、字节(1byte)的直接访问,但是呢他们是有一定的要求的:

存取字时要求地址按对齐,也就是地址要是4的整数倍,如0x0000、0x0004、0x0008(该地址只是举例,mcu的地址分配请参考具体手册的地址映射图)
存取半字是要求地址按半字对齐,也就是地址是2的倍数,这样假如通过0x0001、0x0003这样非2倍数的地址来读取一个半字就会产生错误
存取字节简单,只要地址不超范围就可以

这么看来是不是有点清晰了,我们出现错误的地方不就是在操作一个半字(uint16占用两个byte也就是半字),那么进入到了hardfault应该就是操作了非半字对齐的地址。

下面我们将write_buffer地址打印出来:

rtt_printf("0x%08x\n",write_buffer);

【STM32】HAL库调用HAL_SPI_Transmit出现HartFault问题_第2张图片
很显然,这个地址并不是非半字对齐的地址。


解决方案:

将write_buffer定义成uint32_t即四字节对齐即可。
static uint32_t write_buffer[(FLASH_SPI_PAGE_SIZE + 4 )>>2];

【STM32】HAL库调用HAL_SPI_Transmit出现HartFault问题_第3张图片

你可能感兴趣的:(STM32,HAL库,STM32,SPI,HartFault)