EmbeddedRelated.com
Memfault Beyond the Launch

ARM Cortex-M Bit Banding

March 22, 20136 comments Coded in C for the Cortex-M

Bit banding is a feature of ARM Cortex-M processors that maps up-to 1Mb each of on-chip SRAM and peripheral registers to a larger region where each 32 bit address corresponds to a single bit of the physical memory.  Setting the bitband address to zero or non-zero directly and atomically sets the corresponding physical memory bit to zero or one respectively, without the need for read-modify-write operations or critical sections.

This allows for efficient implementation of bit arrays and bitmaps in SRAM, but allows fast atomic manipulation od single-bit fileds in peripheral registers for enabling/disabling interrupts, testing status flags etc.

The function in this example returns the bitband address of the single bit specified by a physical address and a bit offset.  The returned address can be used to access that single bit or as the start address of a bit array (which you should note need not be word or even byte aligned).

Usage examples are provided.

#include <stdint.h>

//! @brief Convert word address + bit position to bitband address.
//!
//! @param address  Word address containing of bit
//! @param bit      Bit offset (0 = LSB,  31 = MSB)
//! @return Address of bit in bitband region.
volatile uint32_t* getBitBandAddress( volatile void* address, int bit )
{
    uint32_t addr = (uint32_t)address ;
    uint32_t word_band_base = addr & 0xf0000000 ;
    uint32_t bit_band_base = word_band_base | 0x02000000 ;
    uint32_t offset = addr - word_band_base ;

    return  (volatile uint32_t*)(bit_band_base + (offset * 32) + (bit * 4)) ;
}

--- EXAMPLES ---

// Example usage 1: 160 bit array
uint32_t physical_memory[5] = {0} ;
uint32_t* bit_array = getBitBandAddress( physical_memory, 0 ) ;
int bit_array_length = sizeof(physical_memory) * CHAR_BIT ;
for( i = 0; i < bit_array_len; i++ )
{
    bit_array[i] = rand() % 2;
}

// Example usage 2: STM32 USART1 Tx Int Enable/Disable
uint32_t* tx_intr_enable_bit_addr = getBitBandAddress( (&(USART1->CR1)), 7 ) ;

*tx_intr_enable_bit_addr = 0 ; // Disable Tx
*tx_intr_enable_bit_addr = 1 ; // Enable Tx

// Example usage 3: C++ reference version of example 2
uint32_t& tx_intr_enable_bit = *getBitBandAddress( (&(USART1->CR1)), 7 ) ;

tx_intr_enable_bit = 0 ; // Disable Tx
tx_intr_enable_bit = 1 ; // Enable Tx

Memfault Beyond the Launch