I stumbled upon this tidbit while reviewing the ARM online documentation on unaligned access. Upon review the information seems obvious, but I was not aware of the specific alignment rules.
I am quoting here directly from ARM's website. If you are debugging unaligned access issues, I recommend reading the full article.
This is an excerpt from How does the ARM Compiler support unaligned accesses? Any emphasis made below is mine.
As mentioned above, a pointer should contain an address with correct alignment for the type.
uint32_t*requires 4-byte alignment
uint16_t*requires 2-byte alignment
uint8_t*requires 1-byte alignment
For structures, the alignment is that of the most aligned member. The compiler will generate code on the assumption that a pointer is correctly aligned. It does not add code to perform run-time checks. A pointer may contain an incorrectly aligned address for a number of reasons. A common cause is casting:
uint8_t tmp; uint32_t_pMyPointer = (uint32_t_)(&tmp);
This code takes the address of an
uint8_t variable, then casts that address as a
uint32_t pointer. The compiler will still assume that
pMyPointer is correctly aligned for a
uint32_t pointer. The compiler might then generate code that results in an unaligned access unknowingly. This can be avoided using the
__packed uint32_t* pMyPointer = (__packed uint32_t*)(&tmp);