Wednesday, November 30, 2011

Bit field structures in C – Microcontroller Programming

Theory


When you are working with Microcontrollers you often have to keep status flags for certain events, e-g when you are using a timer, you need to keep track of how much time in milliseconds or seconds have elapsed, but your timers only allows ticks in microseconds, so you count the number of microseconds say 1000 microseconds and “Set” the flag “one_ms” indicating one millisecond has elapsed. And more than likely, this flag “one_ms” is either a “char” type or an “int”. In either case, a char will take one whole byte and an int will take 16/32 bits depending on the architecture. But if you notice, what you needed to convey could have easily been conveyed or kept record of in one bit only. So for one status flag of one bit wide, you pay a price of unused extra bits. That is not all, you also end up having multiple status flag variables, meaning you are wasting a lot of useful resource (memory). And the code gets messy too.
However, there is a better way to keep status flags without wasting the memory or without making the code a mess. And that is by the use of “bit fields”  in C programming.

Bit fields are a special structure member type. A bit field is of type integer but its width is specified by the programmer. For example, ARM7 is has a 32-bit integer, but when I use this “int” data type for a bit field, I can specify the actual size this integer will occupy in memory by specifying the size after a “:”.


struct normal_integer
{
unsigned int millisecond;  //occupies 32 bits in memory
}obj;
===================================================
struct bitField
{
unsigned int millisecond : 4 ;  //occupies 4 bits in memory
}obj;


Bit Fields can be of type “signed integer” , “unsigned integer” or a “bool”.
Keep in mind, the specified size cannot exceed maximum default size of that data type. And, for portability and other holy reasons always specify if you want your bit fields signed or unsigned.

Useful example of Bit Fields

Suppose you are designing a stop watch you have one hardware timer which is capable of counting ticks in microseconds. But you want time in seconds and milliseconds. So what do you do ? You wait and count.
For the stop watch example:


int tick_counter ; //global tick counter
struct lap_time
{
    unsigned int start : 1 ; //one bit flag indicating whether the lap time has started or not
    unsigned int millisecond : 1;  //one bit flag indicating 1 millisecond
    unsigned int ten_millisecond : 1; //one bit flag indicating 10 milliseconds
    unsigned int second : 1;  //one bit flag indicating 1 second
    unsigned int laps_elapsed : 4; //4 bit wide elapsed laps counter

} lap;
void timer_isr( )    //ticks every 10 microsecond
{
    //disable low / equal priority interrupts
    if (lap.start)
    {
        tick_counter ++;
        if(tick_counter == 100)
        {
            lap.millisecond = 1;
        }
        if(tick_counter == 1000)
        {
            lap.ten_millisecond = 1;
        }
        if(tick_counter == 10000)
        {
            lap.second = 1;

           tick_counter = 0;
        }
    }
    //enable low / equal priority interrupts



}
The isr written above is only generic code for the specified example, it does not assume any specific sort of hardware. That is why I have placed comments at the start and end of the ISR for hardware specific routines you need to do.
Link: Bit Fields on wikipedia
Technorati Tags: ,,

3 comments:

  1. So, can we use bitfields and bitwise operators interchangeably for flags ? As i understand it, bitfields is highly dependent on the compiler, also the memory map, how a bit is stored in memory. So in that case it may create a problem when multiple resources try to access a memory location where bitfields are also mapped. For example:

    struct bitfields
    {
    unsigned int alarm_flag : 1;
    unsigned int alarm_count : 31;
    };

    In this case, if one thread is fiddling with the alarm_flag and other thread is changing the counter, don't you think there will be a problem?

    Correct me if i'm wrong.

    ReplyDelete
  2. @Hassan, "In this case, if one thread is fiddling with the alarm_flag and other thread is changing the counter, don't you think there will be a problem?" Np, why don't u do something useful...

    ReplyDelete
  3. @Hassan, it has nothing to do with how the memory works, since you'll be referring to the specific bit field as you were accessing a member variable of a structure.
    For 2nd question,there are no threads. counter is being incremented in the ISR only. It is the responsibility of the user-space which is using the flags to read and reset the flag.

    oR is also highly dependent on how the actual code works, The example i gave are only to make the concept clear.

    ReplyDelete