From the Embedded Systems Learning Academy at San Jose State University
Bit-masking is a technique to selectively modify individual bits without affecting other bits.
To set a bit, we need to use the OR operator. This is just like an OR logical gate you should've learnt in Digital Design course. To set a bit, you would OR a memory with a bit number and the bit number with which you will OR will end up getting set.
// Assume we want to set Bit#7 of a register called: REGREG = REG | 0x80;
// Let's set bit#31:REG = REG | 0x80000000;
// Let's show you the easier way:// (1 << 31) means 1 gets shifted left 31 times to produce 0x80000000REG = REG | (1 << 31);
// Simplify further:REG |= (1 << 31);
// Set Bit#21 and Bit# 23wdd aqX:REG |= (1 << 21) | (1 << 23);
To reset a bit, the logic is similar, but instead of ORing a bit, we will AND a bit. Remember that AND gate resets a bit if you AND it with 0 so we need to use a tilde (~) to come up with the correct logic:
// Assume we want to reset Bit#7 of a register called: REG
REG = REG & 0x7F;
REG = REG & ~(0x80); // Same thing as above, but using ~ is easier
// Let's reset bit#31:REG = REG & ~(0x80000000);
// Let's show you the easier way:REG = REG & ~(1 << 31);
// Simplify further:REG &= ~(1 << 31);
// Reset Bit#21 and Bit# 23:REG &= ~( (1 << 21) | (1 << 23) );
Suppose you want to wait for a register's bit#7 to set:
// One way:while( (1<<7) != (REG & (1 << 7))) {};
// Easier way:while( ! (REG & (1 << 7)) );
Now let's work through another example in which we want to wait until bit#9 is 0
// One way:while(REG & (1 << 9) != 0);
// Easier way:while(REG & (1 << 9));
In this example, we will work with an imaginary circuit of a switch and an LED. For a given port, the following registers will apply:
Each bit of FIODIR1
corresponds to each external pin of PORT1
. So, bit0
of FIODIR1
controls direction of physical pin P1.0
and bit31
of FIODIR2
controls physical pin P2.31
. Similarly, each bit of IOPIN1
or IOPIN2
controls output high/low of physical ports P1
and P2
. IOPIN
not only allows you to set an output pin, but it allows you to read input values as sensed on the physical pins.
Suppose a switch is connected to GPIO
Port P1.14
and an LED is connected to Port P1.15
. Note that if a bit is set of FIODIR register, the pin is OUTPUT
otherwise the pin is INPUT
. So... 1=OUTPUT
, 0=INPUT
// Set P1.14 as INPUT for the switch:LPC_GPIO1->FIODIR &= ~(1 << 14);
// Set P1.15 as OUTPUT for the LED:LPC_GPIO1->FIODIR |= (1 << 15);
// Read value of the switch:if(LPC_GPIO1->FIOPIN & (1 << 14)) { // Light up the LED: LPC_GPIO1->FIOPIN |= (1 << 15);} else { // Else turn off the LED: LPC_GPIO1->FIOPIN &= << 15);}
LPC also has dedicated registers to set or reset an IOPIN
with hardware AND
/ OR
logic:
if(LPC_GPIO1->FIOPIN & (1 << 14)) { // No need for |= LPC_GPIO1->IOSET = (1 << 15);}else { // turn off the LED // No need for &= LPC_GPIO1->IOCLR = (1 << 15);}
You can read the advanced bit-masking over at the Bit structure and union page