Microcontroller Embedded C Programming Lecture 159| Bit-field exercise : Creating bit-field structure for peripheral registers

  • Post author:
  • Post category:Blog

 

Bit-field exercise : Creating bit-field structure for peripheral registers

 

In the previous articles, we explored the structures and the bit fields. And we also did one packet extraction exercise using structures and bit fields.

Let’s see more examples of bit fields, and how to use structures and bit fields with our embedded code.

Figure 1. Bit-fields
Figure 1. Bit-fields

 

What is the need to introduce structures and bit fields? 

Structures and bit fields are used in embedded code heavily to bring abstraction.

For example, consider the below code statement. 

#include<stdint.h>

int main(void)
{
uint32_t *pClkCtrlReg = (uint32_t*)0x40023830;
uint32_t *pPortDModeReg = (uint32_t*)0x40020C00;
uint32_t *pPortDOutReg = (uint32_t*)0x40020C14;

//1. enable the clock for GPOID peripheral in the AHB1ENR (SET the 3rd bit position)
*pClkCtrlReg |= ( 1 << 3);

Here in step 1, what are you trying to do? 

You are trying to change the bit position, that is the 3rd-bit position of *pClkCtrlReg peripheral register. This happens to be the address of the RCC AHB1ENR register.

Now the question is, how come you know you have to change the 3rd-bit position of that register?

This information you derived from the datasheet or the reference manual of the microcontroller. That means to code this you should have a reference manual.

Let’s say you are writing some middleware or driver for the user. So, let’s say you are the developer and you have to give some code, or interfaces, or a middleware stack, or something like that to your customer or your user. And he is going to write an application for the LED  based on your driver, middleware, or interface, whatever you call it. You cannot tell the user to go and explore the datasheet or user manual of the microcontroller to write some simple application like turning on the LED. That’s why you have to abstract all this information that you are seeing here. Like changing the 24th-bit position, changing the third position of this register, and changing some other bit positions of some other peripheral register.

All this information now you have to abstract from the user. You give a very simple interface for the user, so that he can write the applications quickly. So, that’s all about abstraction.  

That’s a reason why we use structures and bit fields to bring abstraction. 

In the previous exercise, we created a structure and bit fields to extract various bit positions of this packet and later we store those different values into different member elements of the structure.

 

Now you have to create a similar structure with bit fields, but in this case for the peripheral register.

Can you convert this register information into a structure with bit fields? Figure 2 is similar to Figure 1. It also has various positions.

Bit-field exercise : Creating bit-field structure for peripheral registers
Figure 2. RCC AHB1 peripheral clock enable register

For example, the bit position 0 is to enable the GPIOA peripheral, I mean the clock for the GPIOA peripheral. The bit position 8 is for enable the clock for the GPIOE peripheral. So, the bit position 22 is to enable the clock for the DMA2 peripheral and here there are some bits are Reserved.

 

Now I create a structure with bit fields to encode all this information of a peripheral register. I will show you an example.

Bit-field exercise : Creating bit-field structure for peripheral registers
Figure 3. Creating bit-field structure for peripheral registers

You have to create a typedef structure for a peripheral register or non-typedef structure, it doesn’t matter actually. You can go with a typedef structure if you want. Here, RCC_AHB1ENR_t is the name of the type of structure of the RCC_AHB1ENR register.  

And please notice how I have written this. I’ve used all capital letters to write this name. We usually use capital letters to write typedef structure names, so you can use that method or you can use lowercase doesn’t matter actually. Take a look here, this is terminated with _t, which is not mandatory remember that. So, this just signifies that this is a typedef name. 

RCC_AHB1ENR →  a peripheral name (RCC) followed by its associated register name(AHB1ENR). RCC is one of the internal peripherals of the microcontroller and AHB1ENR is its associated register. The same name you can also find on the reference manual.

 

Now you have to create different bit field structures for different peripheral registers. So, like RCC_AHB1ENR_t, GPIOx_MODE_t, GPIOx_ODR_t, which is for output data register, mode register, and like that. So, create different bit field structures.

Bit-field exercise : Creating bit-field structure for peripheral registers
Figure 4. create different bit field structures for different peripheral registers

What should be the member elements of these structures? 

Again you have to take a look at the peripheral register information(Figure 2). Those are the member elements, including all the Reserved everything. 

The first member element name would be GPIOAEN.  Use the same name that you are seeing here(Figure 2), you need not to think about selecting the member elements name. Don’t think too much, so use whatever there in this register information.

But for the member elements, while writing member elements don’t use capital letters, you can use small letters. 

 

Let me show you one example.

#ifndef MAIN_H_
#define MAIN_H_

#include<stdint.h>

typedef struct
{
    uint32_t gpioa_en :1;
    uint32_t gpiob_en :1;
    uint32_t gpioc_en :1;
    uint32_t gpiod_en :1;
    uint32_t gpioe_en :1;
    uint32_t gpiof_en :1;
    uint32_t gpiog_en :1;
    uint32_t gpioh_en :1;
    uint32_t gpioi_en :1;
    uint32_t reserved :3;

}RCC_AHB1ENR_t;

First, let’s create a typedef struct for the RCC_AHB1ENR. 

Let’s start writing the member elements. For that, you have to open up the reference manual and go to the respective peripheral register. In this case, it is AHB1ENR.

The first member element is GPIOAEN. So, you have to first select the data type. That depends on what you are trying to do. Here we are trying to encode the information of a 32-bit memory area. So, the size of this register is 32 bits. And on that 32-bit memory area we are going to encode all this information using bit fields. That’s a reason it makes sense to use uint32_t here as a data type. The first member element is gpioa_en colon 1 and semicolon. Because it consumes a one-bit position. 

So, I coded all the way from GPIOA to GPIOI for these bit positions. 

And after that 9, 10, and 11 are reserved. What do you do? For that let’s create a member element called reserved. The width of the bit field is 3. So, colon 3. 

After that proceed with the next one, CRC enable. Again reserved, after that all these bit positions everything you have to encode. 

 

FastBit Embedded Brain Academy Courses

Click here: https://fastbitlab.com/course1

 

FastBitLab

The FastBit Embedded Brain Academy uses the power of internet to bring the online courses related to the field of embedded system programming, Real time operating system, Embedded Linux systems, etc at your finger tip with very low cost. Backed with strong experience of industry, we have produced lots of courses with the customer enrolment over 3000+ across 100+ countries.