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

Comments:

baranov
Said:
is CHAR_BIT defined at "stdint.h" in all compilers?
7 years ago
0
Reply
Sorry, you need javascript enabled to post any comments.
Clifford
Said:
@baranov: No it is in or in C++ - the example was intended as a fragment, separate from the "snippet" code which is complete. Unfortunately there is no means to separate code and example in this forum. Regard the examples as "fragments" for illustration, not complete code.
7 years ago
0
Reply
Sorry, you need javascript enabled to post any comments.
cpns
Replied:
Sorry 5 years on, but just noticed that the text in angle-brackets was interpreted as mark-up in previous comment.
For clarity: limits.h in C, or climits in C++, or in C++ limits and then `std::numeric_limits::digits` instead of CHAR_BIT.
1 year ago
0
cpns
Replied:
Defeated again: `
std::numeric_limits::digits
` instead of CHAR_BIT.
1 year ago
0
cpns
Replied:
Try again;
std::numeric_limits&ltint&gt::digits instead of CHAR_BIT.  If that is not now correct, you work it out.  Lack of preview and comment edit is a deficiency of this site.
1 year ago
0
Clifford
Said:
@baranov: Since this is specifically Cortex-M code you can be reasonably certain that CHAR_BIT is 8. The portability afforded by the use of CHAR_BIT is in fact defeated by the specificity of the code to one architecture. I used it out of habit since I also work on TMS320C55x where it is CHAR_BIT is 16.
7 years ago
0
Reply
Sorry, you need javascript enabled to post any comments.
Sorry, you need javascript enabled to post any comments.