I've seen that the subject has been discussed in many other questions, but I can't quite find the answer for my particular case.
I am working with a STM32F0 microcontroller. The top of the SPI reception/transmit FIFO are accessible by a memory access. This particular microcontroller allows me to read/write 8bits or 16bits from the top of the FIFO. More precisely, when a LDRB/STRB instruction is executed, 8bits are popped/pushed from/to the FIFO and when a LDRH/STRH instruction is executed, 16 bits are popped/pushed from/to the FIFO.
The Hardware Abstraction Layer provided by STMicroelectronic proposes this syntax to read the 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 DR
is a uint32_t*
pointing on the top of the SPI FIFO
I've built my software using this syntax and it does work fine. The only problem, is that g++ throws a lot of warning about type punning. More precisely:
Inc/drivers/SPI.h:70:50: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
return *(volatile uint16_t*)&_handle->Instance->DR;
After some readings it looks like using union is not a good idea in C++. I did try it anyway but got some problems. Actually accessing the memory through a pointer in a union makes my microcontroller crashes just like an unaligned memory access.
static_cast and reinterpret_cast throws the sames warning as the C-style cast
I cannot use memcpy
with void*
since my final goal is to make the compiler uses a LDRB/STRB and LDRH/STRH instruction.
Others proposed solutions that I found on Stack Overflow were dependent on the use-case.
Any suggestion?
I would suggest creating two specific pointers for the job. You can create them during initialisation or statically so you don't have to create them each 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 simply read by:
uint8_t read_byte = *DR_Byte;
uint16_t read_word = *DR_Word;
and write by:
*DR_Byte = byte_to_write;
*DR_Word = word_to_write;
or something similar.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With