2016-10-11 50 views
4

我已經看到這個問題已經在許多其他問題中討論過,但我無法完全找到我的具體情況的答案。STM32 SPI硬件和嚴格的別名警告

我正在使用STM32F0微控制器。 SPI接收/發送FIFO的頂部可通過內存訪問進行訪問。這個特殊的微控制器允許我從FIFO頂部讀取8位或16位數據。更確切地說,當執行LDRB/STRB指令時,從FIFO中彈出/推送8位數據,並且當執行LDRH/STRH指令時,從FIFO中彈出/推送16位數據。

STMicroelectronic提供的硬件抽象層提出了這種語法來讀取SPI FIFO。

return *(volatile uint8_t*)&_handle->Instance->DR; // Pop 1 byte 
return *(volatile uint16_t*)&_handle->Instance->DR; // Pop 2 byte 

*(volatile uint8_t*)&_handle->Instance->DR = val; // Push 1 byte 
*(volatile uint16_t*)&_handle->Instance->DR = val; // Push 2 bytes 

DRuint32_t*指向上的SPI FIFO

我已經使用這個語法建立我的軟件頂部,它做工精細。唯一的問題是,g ++會拋出很多關於類型竄改的警告。更確切地說:

公司/驅動器/ spi.h中:70:50:警告:提領類型-punned指針將打破嚴格走樣規則[-Wstrict走樣] return *(volatile uint16_t*)&_handle->Instance->DR;

經過一段閱讀它看起來像使用聯合在C++中不是一個好主意。無論如何,我確實嘗試過,但遇到了一些問題。實際上,通過聯合中的指針訪問內存使我的微控制器崩潰,就像未對齊的內存訪問一樣。

的static_cast和reinterpret_cast的拋出薩姆斯警告作爲C樣式轉換

,因爲我的最終目標是使編譯器使用LDRB/STRB和LDRH/STRH指令我不能使用memcpyvoid*

其他提出的解決方案,我發現棧溢出取決於用例。

有什麼建議嗎?

回答

2

我會建議爲這項工作創建兩個特定的指針。您可以在初始化期間或靜態創建它們,因此您不必每次都創建它們。

static uint8_t * const DR_Byte = (uint8_t * const)&_handle->Instance->DR; 
static uint16_t * const DR_Word = (uint16_t * const)&_handle->Instance->DR; 

然後簡單地寫着:

uint8_t read_byte = *DR_Byte; 
uint16_t read_word = *DR_Word; 

,並通過寫:

*DR_Byte = byte_to_write; 
*DR_Word = word_to_write; 

或類似的東西。

1

因此,看起來有一種方法可以讓海灣合作委員會吃掉沒有抱怨的類型雙關語。就像Realtime Rik提到的那樣。我也成功地抑制警告做

void* p = &_handle->Instance->DR; 
(uint8_t*) p = val; 

我向後退了一步,並重新考慮我試圖做最後決定乾脆禁用與FNO嚴格走樣

爲什麼嚴格走樣?根據我的理解,嚴格的別名是一種優化,而不是功能要求。我的軟件設計用於打字,所以嚴格的別名只是一種我無法承受的優化。或者至少,我認爲更好的是禁用它,而不是試圖欺騙編譯器相信我實際上沒有打字。

+0

我不確定我會信任上面的代碼片段。我會建議看看彙編器來檢查它是否正常。同時關閉警告意味着您可能會錯過其他問題。我認爲我的解決方案不是「壓制」警告,而是實際上是以正確和可移植的方式工作。我個人認爲最好避免void指針。 –

1

我用STM代替HAL,使用LL API/STM32F0xx_LL_Driver/inc/stm32f0xx_ll_spi.h文件波紋管的一部分:

/** 
    * @brief Read 8-Bits in the data register 
    * @rmtoll DR   DR   LL_SPI_ReceiveData8 
    * @param SPIx SPI Instance 
    * @retval RxData Value between Min_Data=0x00 and Max_Data=0xFF 
    */ 
__STATIC_INLINE uint8_t LL_SPI_ReceiveData8(SPI_TypeDef *SPIx) 
{ 
    return (uint8_t)(READ_REG(SPIx->DR)); 
} 

/** 
    * @brief Read 16-Bits in the data register 
    * @rmtoll DR   DR   LL_SPI_ReceiveData16 
    * @param SPIx SPI Instance 
    * @retval RxData Value between Min_Data=0x00 and Max_Data=0xFFFF 
    */ 
__STATIC_INLINE uint16_t LL_SPI_ReceiveData16(SPI_TypeDef *SPIx) 
{ 
    return (uint16_t)(READ_REG(SPIx->DR)); 
} 

/** 
    * @brief Write 8-Bits in the data register 
    * @rmtoll DR   DR   LL_SPI_TransmitData8 
    * @param SPIx SPI Instance 
    * @param TxData Value between Min_Data=0x00 and Max_Data=0xFF 
    * @retval None 
    */ 
__STATIC_INLINE void LL_SPI_TransmitData8(SPI_TypeDef *SPIx, uint8_t TxData) 
{ 
    *((__IO uint8_t *)&SPIx->DR) = TxData; 
} 

/** 
    * @brief Write 16-Bits in the data register 
    * @rmtoll DR   DR   LL_SPI_TransmitData16 
    * @param SPIx SPI Instance 
    * @param TxData Value between Min_Data=0x00 and Max_Data=0xFFFF 
    * @retval None 
    */ 
__STATIC_INLINE void LL_SPI_TransmitData16(SPI_TypeDef *SPIx, uint16_t TxData) 
{ 
    *((__IO uint16_t *)&SPIx->DR) = TxData; 
} 

READ_REG/STM32F0xx_LL_Driver/inc/stm32f0xx.h文件的宏,並定義爲:

#define READ_REG(REG)   ((REG)) 

那你的問題,當你訪問這個_handle->Instance->DR建設你SPI數據寄存器已經解引用指針Instance,那裏DRvolatile uint32_t。所以,你只需要施展,這應該工作:

return (uint8_t)_handle->Instance->DR; 
return (uint16_t)_handle->Instance->DR; 

最後約對齊訪問:我不知道這可能是如何得到保證,但它應該與ARM微控制器的工作要做。我的自動生成鏈接腳本有說明. = ALIGN(4);在每一個部分:

.rodata : 
{ 
    . = ALIGN(4); 
    *(.rodata)   /* .rodata sections (constants, strings, etc.) */ 
    *(.rodata*)  /* .rodata* sections (constants, strings, etc.) */ 
    . = ALIGN(4); 
} >FLASH 

我希望這將是對你有幫助。