Bit Structures

From Embedded Systems Learning Academy
Revision as of 17:22, 18 September 2012 by Preet (talk | contribs) (Created page with "== Bit-masking using Bit Structures == If you've got comfortable with bit-masking, you can also let the compiler handle bit-masking. Let's now modify our example to use bit st...")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Bit-masking using Bit Structures

If you've got comfortable with bit-masking, you can also let the compiler handle bit-masking. Let's now modify our example to use bit structures:

// Declare this 1-bit structure somewhere:
typedef union
{
    // 32-bit structure below overlaps with this 32-bit integer
    // because each var of a union uses same base memory location.
    unsigned int full32bit;

    // : 1 (colon 1) means use only 1 bit size for the variable.
    struct {
        unsigned b0  :1; unsigned b1  :1; unsigned b2  :1; unsigned b3  :1;
        unsigned b4  :1; unsigned b5  :1; unsigned b6  :1; unsigned b7  :1;
        unsigned b8  :1; unsigned b9  :1; unsigned b10 :1; unsigned b11 :1;
        unsigned b12 :1; unsigned b13 :1; unsigned b14 :1; unsigned b15 :1;
        unsigned b16 :1; unsigned b17 :1; unsigned b18 :1; unsigned b19 :1;
        unsigned b20 :1; unsigned b21 :1; unsigned b22 :1; unsigned b23 :1;
        unsigned b24 :1; unsigned b25 :1; unsigned b26 :1; unsigned b27 :1;
        unsigned b28 :1; unsigned b29 :1; unsigned b30 :1; unsigned b31 :1;
    }__attribute__((packed));
    // packed means pack all 1 bit members tightly

} BitStructType;

/**
 * Look how simple the code becomes now:
 * Compiler will read 1-bit and set 1-bit of FIOPIN1 with bit-masking.
 * No need for if/else statements or the AND/OR logic.
 */
    BitStructType *pFioPin1 = &(LPC_GPIO->FIOPIN1);
    pFioPin1->b15 = pFioPin1->b14;


Bit Masking Simplified

Let's assume that you've got the struct above, so let's show you the power of the bit-structures while taking the complexity out:

#define BIT(reg)  (*((BitStructType*)&reg))

void my_foo()
{
    BIT(LPC_GPIO1->FIOPIN).b15 = BIT(LPC_GPIO1->FIOPIN).b14;
}
// Woohoo!  We read bit 14 and set bit 15 of FIOPIN with smart #define


Pitfall

You may be surprised to see that the following code will fail (infinite loop will result):

while(1 != BIT(MY_REG).b0) {
  ; // Wait for b0 to set
}

This has to do with the famous volatile memory problem. Head on over to volatile memory article to find a solution, but for the lazy, if you change unsigned to volatile unsigned for your bit-members, this would fix the problem.



Unions

In the bit-struct example, struct was enclosed inside a union. A union is a structure whose members share memory. In the next example, you should notice that the full32bit overlaps the memory of the structure and the structure size is also 32-bits. The packed attribute is needed such that the compiler will not optimize the structure memory and it will indeed use precisely the bits you requested for each variable. The memory looks like this:
| --------- full32bit ----------- |
| byte3 | byte 2| byte 1 | byte 0 |


Modifying byte 0 will also affect full32bit member. Here is the code:

typedef union
{
    unsigned int full32bit;
    // This assumes Little Endian machine otherwise byte order is swapped.
    struct {
        unsigned int byte0 : 8; // b7  : b0
        unsigned int byte1 : 8; // b15 : b8
        unsigned int byte2 : 8; // b23 : b16
        unsigned int byte3 : 8; // b31 : b24
    }__attribute__((packed));
} BitStructType;

BitStructType var = { 0 };
var.byte0 = 1;
var.byte1 = 1;
printf("%i\n", var.full32bit); // This will print 257

var.byte0 = 0;
printf("%i\n", var.full32bit); // This will print 256