75 lines
2.7 KiB
Rust
75 lines
2.7 KiB
Rust
//! Bit-banding access for peripheral registers
|
|
//!
|
|
//! Accesses to the bit-band region translate to the same-width accesses in the
|
|
//! target region, so it is important to use the correct pointer size for the desired
|
|
//! access.
|
|
//!
|
|
//! Bit-band writes on the Cortex M4F translate to an atomic read/modify/write operation
|
|
|
|
use core::ptr::{write_volatile, read_volatile};
|
|
|
|
/// This is the first address in the SRAM bit-band region.
|
|
const SRAM_BASE: usize = 0x2000_0000;
|
|
/// This is the first address *beyond* the SRAM bit-band region.
|
|
const SRAM_LIMIT: usize = 0x2000_8000;
|
|
|
|
/// This is the first address in the peripheral bit-band region.
|
|
const PERIPHERAL_BASE: usize = 0x4000_0000;
|
|
/// This is the first address *beyond* the peripheral bit-band region.
|
|
const PERIPHERAL_LIMIT: usize = 0x4010_0000;
|
|
|
|
/// Each bit-band alias region starts at this offset from the base of
|
|
/// the region that it aliases.
|
|
const ALIAS_OFFSET: usize = 0x0200_0000;
|
|
|
|
const REGION_MASK: usize = 0xF000_0000;
|
|
const WORD_MASK: usize = 0x0FFF_FFFF;
|
|
|
|
/// Atomically sets (via read/modify/write) a single bit at the given address
|
|
/// without affecting other bits in that memory location.
|
|
#[inline]
|
|
pub unsafe fn set_bit<T>(address: *const T, bit: u8) {
|
|
let address = address as usize;
|
|
let bit_address = bitband_alias_of(address, bit);
|
|
write_volatile(bit_address as *mut u16, 0x01);
|
|
}
|
|
|
|
/// Atomically clears (via read/modify/write) a single bit at the given address
|
|
/// without affecting other bits in that memory location.
|
|
#[inline]
|
|
pub unsafe fn clear_bit<T>(address: *const T, bit: u8) {
|
|
let address = address as usize;
|
|
let bit_address = bitband_alias_of(address, bit);
|
|
write_volatile(bit_address as *mut u16, 0x00);
|
|
}
|
|
|
|
/// Reads a single bit at the given address without affecting other
|
|
/// bits in that memory location.
|
|
#[inline]
|
|
pub unsafe fn read_bit<T>(address: *const T, bit: u8) -> T {
|
|
let address = address as usize;
|
|
let bit_address = bitband_alias_of(address, bit);
|
|
read_volatile(bit_address as *const T)
|
|
}
|
|
|
|
/// Calculate the address in the bitband region of the given bit
|
|
#[inline]
|
|
fn bitband_alias_of(address: usize, bit: u8) -> usize {
|
|
// Only bits 0-31 are valid
|
|
assert!(bit < 32);
|
|
|
|
let region_base = address & REGION_MASK;
|
|
// Ensure the address falls in a bit-band region
|
|
assert!((region_base == SRAM_BASE && address < SRAM_LIMIT) ||
|
|
(region_base == PERIPHERAL_BASE && address < PERIPHERAL_LIMIT));
|
|
|
|
let bit_number = bit as usize;
|
|
let bit_band_base = region_base + ALIAS_OFFSET;
|
|
|
|
let byte_offset = address & WORD_MASK;
|
|
let bit_word_offset = (byte_offset * 32) + (bit_number * 4);
|
|
let bit_word_addr = bit_band_base + bit_word_offset;
|
|
|
|
bit_word_addr
|
|
}
|