Accessing memory-mapped peripherals with Arm DS
Tutorial about accessing memory-mapped peripherals with Arm DS
Introduction Arm recommendations Alignment of registers Mapping of variables to specific addresses Code efficiency
Code efficiency
The Arm compiler normally uses a base register plus the immediate offset field to compile struct members or specific array element accesses. The immediate offset is available in the load or store instructions.
In the Arm instruction set, LDR
and STR
word and byte instructions have a 4KB range, but LDRH
and STRH
instructions have a smaller immediate offset of 256 bytes.
Equivalent 16-bit Thumb instructions are much more restricted. LDR
and STR
have a range of 32 words, LDRH
and STRH
have a range of 32 halfwords, and LDRB
and STRB
have a range of 32 bytes. However, 32-bit Thumb instructions offer a significant range improvement. Because of the range restrictions, it is important to group related peripheral registers near to each other if possible. The compiler is generally good at minimizing the number of instructions required to access array elements or structure members. To perform these accesses, the compiler uses base registers.
You can choose between using one large C struct
or array
for the whole I/O space and smaller per-peripheral structs. For the two methods, there is little difference in terms of code efficiency. Using a large struct
might help if:
- For word and byte accesses, your code works with a base pointer with a 4KB range.
- Entire I/O space is <4KB.
But arguably it is more elegant to have one struct
per peripheral. Smaller, per-peripheral struct
s are more maintainable.