I\'m working on a developing board that has a 32-bit ARM based microntroller on it (namely the board is Atmel SAM D21J18A). I\'m still at the learning phase and I have a lot
Generally you can access a hardware register in C in this manner:
#define PORT (*(volatile uint8_t*)0x1234)
0x1234
is the register addressuint8_t
is the type of the register, in this case 1 byte large.volatile
is required so that the compiler knows it cannot optimize such a variable, but that each read or write to the variable stated in the code must actually be done. (volatile uint8_t*)
casts the integer literal to an address of the desired type.*
then take the contents of that address, so that the macro can be used just as if PORT was a regular variable.Note that this does not allocate anything! It just assumes that there is a hardware register present at the given address, which can be accessed by the type specified (uint8_t
).
Using the same method you can also have other C data types to correspond directly hardware registers. For example by using a handy struct, you can map the whole register area of a particular hardware peripheral. Such code is however a bit dangerous and questionable, since it must take things like alignment/struct padding and aliasing in account.
As for the specific code in your example, it is a typical awful register map for a particular hardware peripheral (looks like a plain general-purpose I/O port) on a certain microcontroller. One such beast is typically provided with each compiler supporting the MCU.
Such register maps are sadly always written in awful, completely non-portable ways. For example, two underscores __
is a forbidden identifier in C. Neither the compiler nor the programmer is allowed to declare such identifiers (7.1.3).
What's really strange is that they have omitted the volatile
keyword. This means that you have one of these scenarios here:
Port
definition. Most likely this is the case, orvolatile
go away.I would investigate this further.
As for struct padding and aliasing, the compiler vendor has likely implicitly assumed that only their compiler is to be used. They have no interest in providing you with a portable register map, so that you can switch the the competitor's compiler for the same MCU.
Nothing happens, because you only present some declarations. I'm not entirely sure what the question actually is, but to briefly explain that code:
0x41004400UL
is obviously an address in I/O space (not regular memory) where a port starts (a set of I/O registers)
This Port consists of two groups with a similar arrangement of single registers
struct PortGroup
models these registers exactly in the layout present on the hardware
To know the meaning of the Registers, look up the hardware documentation.