Do I do
volatile unsigned int* GPIO_BASE = (unsigned int*) 0x50000000;
volatile unsigned int* GPIO_OUT = GPIO_BASE + 0x504;
No, you don't. That would mean that the address gets calculated in run-time, because the volatile
qualifier means that the program has to update the variable in run-time whenever it is used.
This is what you should do instead:
// assuming 32 bit registers and 0x504 being the offset in bytes
#define GPIO_BASE 0x50000000u
#define GPIO_OUT (*(volatile uint32_t*)(GPIO_BASE + 0x504u))
#define GPIO_X (*(volatile uint32_t*)(GPIO_BASE + 0x508u)) // some other related register
...
GPIO_OUT = something;
In this example, the register addresses are calculated at compile-time, which is the only correct way of doing it.
By de-referencing the address inside the macro, we can now use GPIO_OUT
almost as if it was an ordinary variable.
It does however seem unlikely that a GPIO peripheral has hundreds of memory-mapped registers, so the value 0x504
is strange.
Also please note that using the default C types like int
and char
in embedded systems is naive. These types come with various portability problems and also have various forms of poorly-defined behavior associated with them. Professional systems only use the types from stdint.h
and never anything else.