1

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

  1. Why and what's the purpose of typecasting the data to address(pointer) and then use its value?

  2. 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))

  1. If we can use whichever we can, are there any benefits of one over the other?

2 Answers 2

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 a volatile unsigned int

  • the * at the front of the macro dereferences the pointer and thus performs the actual access to the I/O register.

2
  • 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 of volatile is telling the compiler not to optimize the value of the variable. I got confused with volatile with a pointer. So, even in this case volatile is given for the value stored at that address, not the address value itself? Commented Mar 9, 2023 at 6:52
  • 1
    @JustdoinGodswork: Indeed. A declaration such as TYPE * volatile p; would make p a volatile pointer, whereas volatile TYPE *p; makes p a pointer to volatile data. The cast we see here matches the later declaration. Commented Mar 9, 2023 at 9:04
1

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?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.