1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
//! Bit banding
//!
//! Support for the manipulation of peripheral registers through bit-banding.
//! Not all peripherals are mapped to the bit-banding alias region, the peripheral bit-band region
//! is from `0x4000_0000` to `0x400F_FFFF`. Bit-banding allows the manipulation of individual bits
//! atomically.
use core::ptr;
// Start address of the peripheral memory region capable of being addressed by bit-banding
const PERI_ADDRESS_START: usize = 0x4000_0000;
const PERI_ADDRESS_END: usize = 0x400F_FFFF;
const PERI_BIT_BAND_BASE: usize = 0x4200_0000;
/// Clears the bit on the provided register without modifying other bits.
///
/// # Safety
///
/// Some registers have reserved bits which should not be modified.
#[inline]
pub unsafe fn clear<T>(register: *const T, bit: u8) {
write(register, bit, false);
}
/// Sets the bit on the provided register without modifying other bits.
///
/// # Safety
///
/// Some registers have reserved bits which should not be modified.
#[inline]
pub unsafe fn set<T>(register: *const T, bit: u8) {
write(register, bit, true);
}
/// Sets or clears the bit on the provided register without modifying other bits.
///
/// # Safety
///
/// Some registers have reserved bits which should not be modified.
#[inline]
pub unsafe fn write<T>(register: *const T, bit: u8, set: bool) {
let addr = register as usize;
assert!((PERI_ADDRESS_START..=PERI_ADDRESS_END).contains(&addr));
assert!(bit < 32);
let bit = bit as usize;
let bb_addr = (PERI_BIT_BAND_BASE + (addr - PERI_ADDRESS_START) * 32) + 4 * bit;
ptr::write_volatile(bb_addr as *mut u32, u32::from(set));
}