A bit field is a software/firmware variable that stores many bits in a consecutive memory structure.
Bit masking is the process of masking (selecting) specific bits in a bit field (a multi-bit software/firmware variable), e.g. a 32-bit integer, or
uint32_t) to manipulate, without modifying the value of any bits that where not selected.
Bit masking is thought-of as a low-level operation, and is normally only seen in languages such C and C++ (higher level languages may still use bit masking, but the code is likely to be abstracted away from the user). C and C++ bit masking usually makes extensive use of pre-processor macros.
The bit-wise OR operation (
|) can be used to set bits in a variable to 1. The bits in the bit field which you wish to set to 1 are ORed with 1, while those you wish to leave unchanged are ORed with 0.
uint8_t bitField1 = 0b10110011; // Using the bitwise OR operator to set bits 4-7 to 1 bitField |= 0b11110000; // bitField = 0b11110011;
The bit-wise AND operation (
&) can be used to set bits in a variable to 0. The bits in the bitfield which you wish to clear are ANDed with 0, while those you wish to leave unchanged are ANDed with 1.
uint8_t bitField1 = 0b10110011; // Using the bitwise AND operator to keep only bits 4-7 (bits 0-3 will // be cleared) bitField &= 0b11110000; // bitField = 0b10110000;
Creating A Multi-Bit Bit Mask
This following example uses a macro to perform the masking and setting of bits. A function could be used, but macros are generally more efficient due to the lack of a function call.
//! @brief The maximum width (in bits) that the following bit field manipulation macros can work with. #define MAX_BIT_FIELD_WIDTH_BITS 32 //! @brief Creates a "MAX_BIT_FIELD_WIDTH_BITS"-wide bit mask for the specified bit range a to b (inclusive). //! @details Example: //! BIT_MASK(5, 12) returns the value (if MAX_BIT_FIELD_WIDTH_BITS = 32). //! 0b 0000 0000 0000 0000 0011 1111 1110 0000 //! @warning ONLY WORKS WITH UP TO "MAX_BIT_FIELD_WIDTH_BITS" WIDE BIT FIELDS #define BIT_MASK(a, b) (((unsigned) -1 >> ((MAX_BIT_FIELD_WIDTH_BITS - 1) - (b))) & ~((1U << (a)) - 1)) //! @brief Use this macro to set a number of bits within a bit field. //! @details Example: //! SET_BITS(myUint16, 12, 3, 0b101) //! will set bits 12 through to 14 with 1, 0 and 1 respectively. //! @warning ONLY WORKS WITH UP TO "MAX_BIT_FIELD_WIDTH_BITS" WIDE BIT FIELDS #define SET_BITS(var, startBit, numBits, val) \ var = var & ~BIT_MASK(startBit, startBit + numBits - 1); \ var = var | (val << startBit);
You can then use it as in the following:
uint8_t aRegister = 0x00; SET_BITS(aRegister, 2, 4, 0b1011); // aRegister = 0b00101100; SET_BITS(aRegister, 0, 3, 0b011); // aRegister = 0b00101011;
Use In The Industry
Many microcontroller manufactures (e.g. Atmel), provide firmware libraries and example code which make extensive use of bitfield manipulation to modify the registers which control the hardware peripherals (e.g the register(s) which configures the baud rate, parity and num. stop bits for a UART).