2016-10-11 24 views
4

この件については他の多くの質問で議論されていることがわかりましたが、私の場合は答えを見つけることができません。STM32 SPIのハードウェアと厳密なエイリアシングの警告

私はSTM32F0マイクロコントローラを使用しています。 SPI受信/送信FIFOの最上部は、メモリアクセスによってアクセス可能である。この特定のマイクロコントローラを使用すると、FIFOの先頭から8ビットまたは16ビットを読み書きすることができます。より正確には、LDRB/STRB命令が実行されると8ビットがFIFOからポップ/プッシュされ、LDRH/STRH命令が実行されるとFIFOから16ビットがポップ/プッシュされます。

STMicroelectronicが提供するハードウェアアブストラクションレイヤは、SPI FIFOを読み取るためにこの構文を提案しています。

DRが、私はこの構文を使用して、私のソフトウェアを構築してきましたし、それが正常に動作しないSPI FIFO

の上uint32_t*ポインティングある

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 

。唯一の問題は、g ++が型打ちに関する多くの警告を出すことです。より正確には:

INC /ドライバ/ SPI.h:70:50:警告:厳密なエイリアシング規則を破るであろう型punnedポインタを逆参照[-Wstrictエイリアシング] return *(volatile uint16_t*)&_handle->Instance->DR;

いくつかの後ユニオンを使用しているように見えるのは、C++では良い考えではありません。とにかく試してみましたが、いくつか問題がありました。実際には、ユニオン内のポインタを介してメモリにアクセスすると、アライメントされていないメモリアクセスと同じように、マイコンがクラッシュします。 C-スタイルは

を唱えるよう

はstatic_castとreinterpret_castは私の最終目標は、コンパイラがLDRB/STRBとLDRH/STRH命令を使用することですので、私はvoid*memcpyを使用することはできません警告samesをスローします。

スタックオーバーフローで見つかったその他の提案された解決策は、ユースケースに依存していました。

提案がありますか?

答えて

2

私は仕事のための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

GCCに不平を言うことなく型打ちをする方法があるようです。リアルタイムRikのように言及。また、私は戻って一歩を踏み出したと私は最終的に、単に

なぜFNO-厳しいエイリアシングと厳しいエイリアシングを無効にすることを決定するために行うとしていたものを再検討

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

をやって警告を抑制することに成功しましたか?私の理解から、厳密なエイリアシングは最適化であり、関数の要件ではありません。私のソフトウェアは型打ちを行うように設計されているので、厳密なエイリアシングは単純に私が余裕がない最適化です。あるいは、少なくとも私は、私が実際に行っている間に型打ちをしないと信じてコンパイラを騙そうとするのではなく、それを無効にする方がよいと考えます。

+0

私は上記のコードスニペットを信頼するとは確信していません。私はそれがOKであることを確認するためにアセンブラを見ることをお勧めします。また、警告をオフにすると、他の問題が発生する可能性があります。私は私の解決策が警告を "抑制"しているとは思えないが、実際には正確で移植性のある定義された方法で作業している。個人的には、ボイドポインタを避けるのが最善だと思います。 –

1

私は、HALの代わりにSTMによって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ファイルからのマクロであり、以下のように定義される:あなたはこの_handle->Instance->DR建設あなたによってSPIデータレジスタにアクセスするとき

あなたの問題について
#define READ_REG(REG)   ((REG)) 

そして、何、既に参照解除ポインタInstanceがあり、そこにDRがあるのはvolatile 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 

私はそれがあなたのために役立つことを願っています。

関連する問題