Skip to main content

Command Palette

Search for a command to run...

Bitwise and Bitmasking Operations

Updated
4 min read
Bitwise and Bitmasking Operations
A

As an Electronics and Communications undergrad, I am deeply interested in the design of embedded systems in programmable logic, robotics and problem-solving. These domains excite me and drive my passion for learning and creating innovative solutions.

Bitwise Operations

Bitwise operations are logical operations that are performed on binary representations of numbers. They include AND, OR, XOR, NOT, and shift operations. These operations can help manipulate individual bits in a register and memory and are often used in low-level programming and optimization. Bitwise operations are common in the design of embedded systems as they are many times faster than addition, multiplication and division on resource-constrained devices.

Bitwise Operators in C

  1. Bitwise AND(&), OR(|), NOT(~) and XOR(^): Let reg1 and reg2 be two operand registers. The following examples illustrate the different possible bitwise operations on them.

     reg1 &= reg2               //reg1 = reg1 AND reg2
     reg1 |= reg2               //reg1 = reg1 OR reg2
     reg1 ^= reg2               //reg1 = reg1 XOR reg2
     reg1 = ~reg1               //reg1 = NOT reg1
    
  2. Bit shifts: In these operations, the digits are moved to the left or right. Since registers have finite lengths, some bits may be shifted out or in from either direction. There are wide varieties of bit shifting, such as logical, arithmetic and circular shifts. The logical shift is the most relevant to our discussion and is presented below.

    Logical left shift: In a logical left shift, zeroes are shifted from the right to fill the open spaces created by shifting the bits to the left. A logical left shift by n is mathematically equivalent to multiplying a number by 2^n.

    Logical right shift: In a logical left shift, zeroes are shifted from the left to fill the open spaces created by shifting the bits to the right. A logical right shift by n is mathematically equivalent to multiplying a number by 1/2^n and rounding toward zero.

     uint8_t y, x = 16; int n = 2;
     //Logical left shift
     y = x << 2 ;   //Equivalent to y = 16 * 4
     //Logical left shift
     y = x >> 2 ;   //Equivalent to y = 16 / 4
    

Bitmasking Operations

A bitmask is a binary value that can manipulate individual bits in a register. It is represented by a sequence of ones and zeroes, with each bit position corresponding to a specific bit in the number. Bitmasks are often used with bitwise operations, such as AND, OR, and XOR. Bitmasks are particularly useful in device driver development where setting and unsetting individual or group of bits in a register is a common operation. Common bitmasking operations and the construction of the appropriate bitmasks in C/C++ are Illustrated below.

  • Clearing an individual bit in a position i.

      //Assume ARR is a 32 bit register
      ARR &= 1UL<<i;       //Clears the ith bit 
      ARR &= ~1UL;         //Clears the LSB, bit 0
      ARR &= ~(1UL<<5);    //Clears the 5th bit
    
  • Clearing a group of bits starting from the ith position from the least significant digit(LSB).

      //To  Clear a group of n bits starting from ith position from the LSB, do
      ARR &= ~((2^n - 1)UL <<i); 
      ARR &= ~(7UL<<4);         //Clears the 4th, 5th and 6th bits
    
  • Setting an individual bit in a position i.

      ARR |= 1UL<<i;      //Sets the ith bit
      ARR |= 1UL;         //Sets the LSB, bit 0
      ARR |=  (1UL<<5);   //Sets the 5th bit
    
  • Setting a group of bits starting from the ith position from the LSB.

      //To  Set a group of n bits starting from ith position from the LSB, do
      ARR |= (2^n - 1)UL <<i; 
      ARR |= 7UL<<4;         //Sets the 4th, 5th and 6th bits
    
  • Toggling an individual bit in a position i

      ARR ^= 1UL<<i;      //Toggles the ith bit
      ARR ^=  1UL;        //Toggles the LSB, bit 0
      ARR ^= 1UL<<5;      //Toggles the  5th bit
    
  • Toggling a group of bits starting from the ith position from the LSB.

      //To  Set a group of n bits starting from ith position from the LSB, do
      ARR ^= (2^n - 1)UL <<i; 
      ARR ^= 7UL<<4;         //Sets the 4th, 5th and 6th bits
    
  • Checking bits: We can check if a bit is ON or OFF using bitmasking.

      bit_status = (ARR & 1UL<<i)>0 //retrieves status of bit i 
      bit5_status = (ARR & 1UL<<5)>0; //retrieves status of bit 5
    

It is always a good practice to clear a group of bits before setting them. Also, individual bits should be addressed using the appropriate bitmask to preserve the state of other bits and prevent unexpected behaviour. We will heavily utilize these operations in developing peripheral drivers in the upcoming sections.

Further reading

Embedded Drivers

Part 14 of 18

This series focuses on the design of embedded drivers and high-level APIs for accessing peripheral functions. Here, I share my knowledge and approach to writing portable drivers for MCU peripherals.

Up next

General Purpose I/O: Overview

General Purpose Input/Output are typically pins found on a computer or microcontroller board that can interface with external devices. Software can configure these pins as inputs or outputs at runtime, allowing them to send or receive electrical sign...