I have been watching tutorials on STM32 bare metal programming. I couldn't understand the purpose of the below code
#define RCC_AHB1EN_R (*(volatile unsigned int *)(RCC_BASE + AHB1EN_R_OFFSET))
and why it's different from
#define RCC_AHB1EN_R (volatile unsigned int)(RCC_BASE + AHB1EN_R_OFFSET))
I understand (volatile unsigned int *)
is used to typecast any data, so it code will get its address value, not the data itself, then adding (*)
will pick the data value of the address. I know why volatile is used to tell not to optimize this code for this data.
That's my basic knowledge of pointers, if I wasn't right till now please correct me.
So my question are
Why and what's the purpose of typecasting the data to address(pointer) and then use its value?
Why not we directly use the value itself (of course with volatile typecasting) like
#define RCC_AHB1EN_R (volatile unsigned int)(RCC_BASE + AHB1EN_R_OFFSET))
- If we can use whichever we can, are there any benefits of one over the other?
2 Answers 2
Judging from the context, RCC_BASE
seems to be a preprocessor macro
that expands to the base address of some peripheral called "RCC", and
AHB1EN_R_OFFSET
a similar macro for the offset of the AHB1EN_R
I/O
register relative to this base address. Then,
RCC_BASE + AHB1EN_R_OFFSET
is the memory-mapped address of the register. This address is just a
number. If you cast it to volatile unsigned int
, you still get the
same number. If you want to access the I/O register, you have to tell
the compiler that this number is actually an address (i.e. the numeric
value of a pointer), and then access the memory bus at that address
(i.e. dereference the pointer):
(volatile unsigned int *)
converts the numeric value to a pointer (because of the*
), that points to avolatile unsigned int
the
*
at the front of the macro dereferences the pointer and thus performs the actual access to the I/O register.
-
Okay, please tell me if I get this right.
(*(volatile unsigned int *)(RCC_BASE + AHB1EN_R_OFFSET))
will make(RCC_BASE + AHB1EN_R_OFFSET)
consider as address and get value at this address as there is*
before it. But what I understand from the use ofvolatile
is telling the compiler not to optimize the value of the variable. I got confused withvolatile
with a pointer. So, even in this casevolatile
is given for the value stored at that address, not the address value itself?Just doin Gods work– Just doin Gods work2023年03月09日 06:52:57 +00:00Commented Mar 9, 2023 at 6:52 -
1@JustdoinGodswork: Indeed. A declaration such as
TYPE * volatile p;
would makep
a volatile pointer, whereasvolatile TYPE *p;
makesp
a pointer to volatile data. The cast we see here matches the later declaration.Edgar Bonet– Edgar Bonet2023年03月09日 09:04:24 +00:00Commented Mar 9, 2023 at 9:04
In the first line, RCC_AHB1EN_R is a pointer to location. you got that from the casting.
#define RCC_AHB1EN_R (*(volatile unsigned int *)(RCC_BASE + AHB1EN_R_OFFSET))
In the second line, RCC_AHB1EN_R holds a base address which is an integer.
#define RCC_AHB1EN_R (volatile unsigned int)(RCC_BASE + AHB1EN_R_OFFSET))
hope this give you clarity?