Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions src/bb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//! 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.
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.
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.
pub unsafe fn write<T>(register: *const T, bit: u8, set: bool) {
let addr = register as usize;

assert!(addr >= PERI_ADDRESS_START && addr <= PERI_ADDRESS_END);
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, if set { 1 } else { 0 });
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub use stm32g4::stm32g484 as stm32;
pub use crate::stm32::interrupt;

// pub mod adc;
pub mod bb;
// pub mod crc;
// pub mod dac;
pub mod delay;
Expand All @@ -72,6 +73,7 @@ pub mod rcc;
// pub mod serial;
// pub mod spi;
// pub mod stopwatch;
pub mod syscfg;
pub mod time;
// pub mod timer;
// pub mod watchdog;
37 changes: 37 additions & 0 deletions src/syscfg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use crate::bb;
use crate::stm32::{RCC, SYSCFG};
use core::ops::Deref;

/// Extension trait that constrains the `SYSCFG` peripheral
pub trait SysCfgExt {
/// Constrains the `SYSCFG` peripheral so it plays nicely with the other abstractions
fn constrain(self) -> SysCfg;
}

impl SysCfgExt for SYSCFG {
fn constrain(self) -> SysCfg {
unsafe {
// NOTE(unsafe) this reference will only be used for atomic writes with no side effects.
let rcc = &(*RCC::ptr());

// Enable clock.
bb::set(&rcc.apb2enr, 0);

// Stall the pipeline to work around erratum 2.1.13 (DM00037591)
cortex_m::asm::dsb();
}

SysCfg(self)
}
}

pub struct SysCfg(SYSCFG);

impl Deref for SysCfg {
type Target = SYSCFG;

#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}