Bit banding is a feature in ARM Cortex-M3 and newer Cortex-M processor cores that allows atomic bit-level access to memory mapped peripherals without the need for locks or semaphores. This can simplify software design and improve performance in multi-threaded applications that need to safely share hardware resources.
Overview of Bit Banding
Normally, when accessing a peripheral register, you need to read the entire 32-bit or 16-bit register into a CPU register, modify the relevant bits, then write the entire value back. This requires the read-modify-write operation to be atomic, otherwise another thread could modify the register between the read and write.
Bit banding maps a bit in a peripheral register to a full byte in the bit-band region. A read or write to this byte then sets or clears just the mapped bit in the peripheral register. The processor guarantees atomic single-byte accesses to the bit-band region, making the read-modify-write sequence atomic without any locking.
Enabling Bit Banding
Bit banding is enabled by default in Cortex-M3. The bit-band region in memory is defined from 0x20000000 to 0x200FFFFF for peripherals and 0x40000000 to 0x400FFFFF for SRAM. Each word in this region aliases to one bit in the target memory.
To use bit-banding, you need to know the address of the peripheral register and bit number you want to access. Then apply a formula to convert this to a byte address in the bit-band region. This byte can then be safely read and written to set and clear the target bit atomically.
Bit Banding Address Mapping
The formula to convert a peripheral register address and bit number to a bit-band alias address is:
- Bit-band Base = 0x20000000 for peripherals, 0x40000000 for SRAM
- Byte Offset = (Register Address – Peripheral Base Address) * 32 + (Bit Number * 4)
- Bit-Band Alias = Bit-Band Base + Byte Offset
For example, to atomically set bit 5 in peripheral register 0x4000C020:
- Register Address = 0x4000C020
- Bit Number = 5
- Peripheral Base Address = 0x40000000
- Byte Offset = (0x4000C020 – 0x40000000) * 32 + 5 * 4 = 0x000C0190
- Bit-Band Alias = 0x20000000 + 0x000C0190 = 0x200C0190
To set the bit, write 1 to the byte address 0x200C0190. Clearing the bit can be done by writing 0 to the same address.
Advantages of Using Bit Banding
There are several benefits to using bit banding instead of traditional read-modify-write code:
- No need for locking mechanisms like mutexes or spinlocks.
- Can safely update bits from multiple threads without race conditions.
- Single cycle atomic access from the Cortex-M3 core.
- Cleaner code compared to read-modify-write sequences.
- Allows event flags and semaphores to be implemented without locks.
For registers that are frequently accessed from multiple contexts, bit banding can reduce software complexity and improve performance.
Example Uses of Bit Banding
Some common use cases that can benefit from bit banding include:
- Shared Status Flags – Having multiple threads wait on status bits to be set.
- Resource Counting Semaphores – Atomic increment/decrement of resource counts.
- Event Flags – Threads can efficiently wait on and signal events.
- Peripheral Enabling – Atomically power up shared hardware blocks.
- Interrupt Enabling – Safely enable interrupts from multiple sources.
Shared Status Flags
A common multi-threading task is having threads wait for a certain status bit to be set by another thread before continuing. For example, Thread A may need to wait for a “Data Ready” bit to be set by Thread B when some data processing has completed. Without bit banding, this would require using a mutex or semaphore to protect access to the status register.
With bit banding, Thread A can just read from the bit-band alias address mapped to the “Data Ready” bit in a loop. Thread B can set the bit by writing to the alias address. No locking is required as the bit-band access is atomic.
Resource Counting Semaphores
A counting semaphore allows threads to lock and unlock access to a set of limited resources. This requires atomically incrementing and decrementing a counter each time a resource is acquired or released.
By using bit banding aliases for each bit in the counter, it can be implemented without any locking. Each thread increments the counter by setting the appropriate bits, and decrements it by clearing bits. The bit-band accesses handle the atomic read-modify-write sequence.
Event flags allow threads to efficiently wait for events from other threads or hardware using a bitmask. The waiting thread can choose to wait for any bit or combination of bits to be set in the event flags register.
By mapping each flag bit to a bit-band alias, threads can wait on and signal events without any additional locking. Setting or clearing bits in the alias addresses will update the flags register atomically.
Peripheral and Interrupt Enabling
Many peripherals have enable bits that must be set before the peripheral can be used. It is often necessary to power up peripherals from multiple threads in a system.
Similarly, multiple sources may need to enable or disable certain interrupts in the NVIC during operation. In both cases, bit banding can be used to guarantee atomic access and avoid race conditions between threads.
Limitations of Bit Banding
While bit banding is useful in many cases, there are some limitations to be aware of:
- Only single bit accesses are atomic, not read-modify-write of multiple bits.
- Bit banding consumes some memory – up to 32KB for peripherals.
- Can’t use with registers that aren’t memory mapped.
- Only available on Cortex-M3 and newer cores.
- Peripheral register addresses must be known in advance.
For counters, flags or enables that require read-modify-write of multiple bits, traditional locking is still needed. Bit banding is not a complete replacement for all synchronization primitives.
The bit banding feature of Cortex-M3 allows setting and clearing individual bits in peripheral registers atomically without locks. This can simplify coding for multi-threaded firmware and improve performance through faster bit access.
By using the provided address mapping, developers can implement communication mechanisms like status flags, semaphores and event flags in a lock-free manner. Bit banding reduces software complexity in many cases by handling the atomicity in hardware.
However, traditional locking is still required in some situations. Overall, bit banding is a useful technique for firmware engineers writing optimized drivers and RTOS kernels on ARM Cortex-M3 platforms.