C++ STM32 SPI硬件和严格别名警告

C++ STM32 SPI硬件和严格别名警告,c++,microcontroller,stm32,hal,type-punning,C++,Microcontroller,Stm32,Hal,Type Punning,我已经看到这个问题已经在许多其他问题中讨论过了,但我不能完全找到我的具体案例的答案 我正在使用STM32F0微控制器。SPI接收/传输FIFO的顶部可通过存储器访问。这个特殊的微控制器允许我从FIFO顶部读/写8位或16位。更准确地说,当执行LDRB/STRB指令时,8位从FIFO弹出/推送到FIFO;当执行LDRH/STRH指令时,16位从FIFO弹出/推送到FIFO STMicroelectronic提供的硬件抽象层提出了这种语法来读取SPI FIFO return *(volatile u

我已经看到这个问题已经在许多其他问题中讨论过了,但我不能完全找到我的具体案例的答案

我正在使用STM32F0微控制器。SPI接收/传输FIFO的顶部可通过存储器访问。这个特殊的微控制器允许我从FIFO顶部读/写8位或16位。更准确地说,当执行LDRB/STRB指令时,8位从FIFO弹出/推送到FIFO;当执行LDRH/STRH指令时,16位从FIFO弹出/推送到FIFO

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
其中,
DR
是指向SPI FIFO顶部的
uint32\u t*

我已经用这种语法构建了我的软件,它确实工作得很好。唯一的问题是,g++对类型双关抛出了很多警告。更准确地说:

Inc/drivers/SPI.h:70:50:警告:取消引用类型双关指针将破坏严格的别名规则[-Wstrict aliasing]
return*(volatile uint16\u t*)&u handle->Instance->DR

在一些读数看来,使用CUnion不是C++的好主意。我确实试过了,但遇到了一些问题。实际上,通过联合中的指针访问内存会使我的微控制器崩溃,就像未对齐的内存访问一样

static_cast和reinterpret_cast抛出与C风格cast相同的警告

我不能将
memcpy
void*
一起使用,因为我的最终目标是使编译器使用LDRB/STRB和LDRH/STRH指令

我在堆栈溢出上发现的其他建议解决方案取决于用例


有什么建议吗?

我建议为该作业创建两个特定的指针。您可以在初始化过程中创建它们,也可以静态创建,这样就不必每次都创建它们

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;

或者类似的东西。

看来有一种方法可以让GCC毫无怨言地接受双关语。就像实时里克提到的。我还成功地压制了这种警告

void* p = &_handle->Instance->DR;
(uint8_t*) p = val;
我退了一步,重新考虑了我试图做的事情,最终决定使用fno strict aliasing禁用严格别名


为什么??根据我的理解,严格别名是一种优化,而不是功能要求。我的软件设计用于进行类型双关,所以严格的别名只是一种优化,我负担不起。或者至少,我认为更好的是禁用它,而不是试图欺骗编译器相信我不做类型双关,而我实际上这样做。< /P> < P>我使用“强> LL API < /强>由STM而不是HAL。
/STM32F0xx\u LL\u Driver/inc/STM32F0xx\u LL\u 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\u REG
是来自
/STM32F0xx\u LL\u Driver/inc/STM32F0xx.h
文件的宏,定义为:

#define READ_REG(REG)         ((REG))
那么您的问题呢,当您通过这个
\u句柄->实例->DR
构造访问spi数据寄存器时,您已经取消了对指针
实例的引用,并且
DR
volatile uint32\t
。所以你只需要施放,这应该可以:

return (uint8_t)_handle->Instance->DR;
return (uint16_t)_handle->Instance->DR;
最后,关于未对齐的访问:我不知道如何保证它,但对于使用ARM微控制器的工作,应该这样做。我的自动生成的链接器脚本包含指令
=对齐(4)在每个部分中:

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

我希望它能对您有所帮助。

我不确定我会相信上面的代码片段。我建议看一下汇编程序,检查它是否正常。此外,关闭警告意味着您可能会错过其他问题。我认为我的解决方案不是“抑制”警告,而是以一种正确的、可移植的方式工作。就我个人而言,我认为最好避免空洞的指针。