STM32 SPI hardware and strong alias warnings

I saw that the topic was discussed in many other issues, but I can not find the answer for my specific case.

I work with the STM32F0 microcontroller. The top of the FIFO receive / transmit SPI is accessible via memory access. This particular microcontroller allows me to read / write 8 bits or 16 bits from the top of the FIFO. More precisely, when the LDRB / STRB command is executed, 8 bits are pushed / moved from / to the FIFO, and when the LDRH / STRH command is executed, 16 bits are unloaded from / to the FIFO.

The hardware abstraction layer provided by STMicroelectronic offers this syntax for reading 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

Where DRis it uint32_t*pointing to the top of the SPI FIFO

I built my software using this syntax and it works great. The only problem is that g ++ warns a lot about punning type. More precisely:

Inc / drivers / SPI.h: 70: 50: warning: dereferenced pointer type will violate strict anti-aliasing rules [-Wstrict-aliasing]   return *(volatile uint16_t*)&_handle->Instance->DR;

After some reads, it seems like using a connection is not a good idea in C ++. I tried to do it anyway, but I had problems. In fact, accessing the memory using a pointer in the connection makes my microcontroller crash, as well as un-smooth access to the memory.

static_cast and reinterpret_cast issues warning alerts as C-style styles

I cannot use memcpywith void*, since my ultimate goal is to force the compiler to use the LDRB / STRB and LDRH / STRH instructions.

Other suggested solutions that I found in Stack Overflow depended on the use case.

Any suggestion?

+4
source share
3 answers

I would suggest creating two specific pointers for the job. You can create them during initialization or statically, so you do not need to create them every time.

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

then just read:

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

and write:

*DR_Byte = byte_to_write;
*DR_Word = word_to_write;

or something similar.

+2
source

, , GCC . , . ,

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

, , , , , fno-strict-aliasing

? , - , . , , - , . , , , , , , , .

+1

LL API STM HAL. /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))

, spi _handle->Instance->DR, Instance DR volatile uint32_t. , :

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

Finally, about non-connected access: I do not know how this can be guaranteed, but it must be done to work with ARM microcontrollers. My automatically generated linker script has instructions . = ALIGN(4);in each section:

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

I hope this will be helpful to you.

+1
source

Source: https://habr.com/ru/post/1657339/


All Articles