Modifying led toggle exercise with structures and bit fields
In the previous article, we created different typedef structures. Let’s understand what to do with those typedef structures. Our goal is to configure the peripheral registers of a peripheral.
In this case, our peripheral is GPIOD.
We also know that we configure a peripheral register using its address.
For example, let’s consider the typedef struct which we created for the GPIO_MODE register.
- Create a pointer variable → GPIOx_MODE_t *pGpiodMode;
- And then initialize that pointer variable with the address of the GPIOD_MODE register.
pGpiodMode = (GPIOx_MODE_t*) 0x40020C00; → this is a initialization. So, the pGpiodMode pointer variable is now properly initialized.
- 0x40020C00 is a register address.
It is very simple. Just dereference the pointer variable and select the appropriate member elements.
For example, if I want to configure the mode value for the pin_0, then I would dereference the pointer variable, as shown in Figure 2.
pGpiodMode -> pin_0 = 1; Select the appropriate member element and just store the mode value.
If you do this the first two bits of this memory location(0x4002_0C00) will be programmed, which happens to be the place of pin_0. So, pin_0 will be referring to the first two bit positions, and pin_1 will be referring to the next 2 bit positions, like that.
Initialize the pointer variable, select the appropriate member element, and store the value. That’s all you have to do.
If you want to configure the mode for pin_1, then just select the member element pin_1 and store your value. (Figure 3)
If you want to configure the 15th pin, then select the member element pin_15 and configure the value, whatever mode value you want to configure.
Now let’s analyze this statement → pGPIOdMode -> pin_15 = 3;
Let’s see how exactly this statement works.
Internally compiler converts pGPIOdMode -> pin_15 = 3 this statement to *(0x4002_0C00)|= (3<< 30) this statement. So, the compiler will generate the instructions to program the appropriate bit positions in the peripheral register address.
Previously we used bitwise operators to program the appropriate bit positions of the peripheral register. With this method, you just shifted that work to the compiler. That’s the only difference. The compiler will use various bit manipulation instructions to do something like this. The bit manipulation is still required, but you just shifted that work to the compiler now.
So, that’s how you configure various bit positions of a peripheral register using structures and bit fields.
I will give you some hints and based on that you can do that.
#include "main.h" int main(void) { RCC_AHB1ENR_t volatile *const pClkCtrlReg = (RCC_AHB1ENR_t*) 0x40023830; //1. enable the clock for GPOID peripheral in the AHB1ENR (SET the 3rd bit position) pClkCtrlReg->gpiod_en = 1;
First, create a pointer variable for the RCC_AHB1ENR structure. Create a pointer variable pClkCtrlReg, then you have to initialize this with the address(0x40023830). You have to properly typecast. How do you typecast? RCC AHB1ENR_t *. So, you just initialized the pointer variable (line 19).
Now use the pointer and dereference that and select the appropriate member element. In this case, it is GPIOD. To enable the clock, you have to make this as 1(line 21).
Here, pClkCtrlReg is a pointer variable. So, we can also safeguard this using const, I would use const here, which is optional but you can use that.
And also this is a memory-mapped register. From our volatile discussion use volatile generously while accessing the memory-mapped registers. That’s why let’s use volatile here.
So, the constant pointer programmer should not change the value of the pClkCtrlReg pointer variable and volatile data.
You have to continue for other code statements, and modify all these things with structure pointer access, and I will see you in the following article.
FastBit Embedded Brain Academy Courses
Click here: https://fastbitlab.com/course1