Implementing Bitwise Operations for Register Modification
In this lesson, you will learn how to precisely manipulate individual hardware bits in a microcontroller register without accidentally altering the status of neighboring configuration flags.
When working with peripherals, registers often pack multiple control signals into a single 32-bit integer. For example, a GPIO register might contain mode, speed, and pull-up settings side-by-side. If you simply write a value to the register, you would overwrite every setting at once. To avoid this, we use bitwise operators: & (AND), | (OR), and ~ (NOT).
The Read-Modify-Write Pattern
The standard approach to changing one bit is the Read-Modify-Write cycle:
- Read: Load the current register value.
- Modify: Use bitwise logic to change only the specific bit(s) desired.
- Write: Store the new value back to the hardware address.
Setting a Bit
To turn a bit "on" (set it to 1) without touching other bits, use the Bitwise OR operator (|) with a mask:
// Set bit 5 to 1, leave others unchanged
*GPIO_MODER |= (1 << 5);
The mask (1 << 5) creates a value where only the 5th bit is high. ORing this with the register ensures the 5th bit becomes 1, while any existing 1s remain 1s.
Clearing a Bit
To turn a bit "off" (set it to 0), use the Bitwise AND (&) combined with a Bitwise NOT (~):
// Clear bit 5 to 0, leave others unchanged
*GPIO_MODER &= ~(1 << 5);
The ~ operator inverts our mask, turning 00100000 into 11011111. When you AND this with the register, the 5th bit is forced to 0 because x & 0 is always 0, while all other bits remain unchanged because x & 1 remains x.
This technique allows you to treat a hardware register like a collection of individual switches, ensuring your peripheral configuration remains stable even as you toggle specific features on or off.
Key Takeaway: Use the OR operator to set bits, and the AND-NOT combination to clear bits, to modify specific register flags while preserving the state of all other peripheral settings.