【STM32】HAL庫調用HAL_SPI_Transmit出現HartFault問題
2021-09-03 來源:eefocus
問題描述:
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之前最后一句話是
是該揭開它真正面紗的時候了:我們再看出現問題的那條語句:
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%08xn",write_buffer);
很顯然,這個地址并不是非半字對齊的地址。
解決方案:
將write_buffer定義成uint32_t即四字節對齊即可。
static uint32_t write_buffer[(FLASH_SPI_PAGE_SIZE + 4 )>>2];