use core::mem::MaybeUninit;
#[cfg(mco)]
mod mco;
use critical_section::CriticalSection;
#[cfg(mco)]
pub use mco::*;
use crate::pac::RCC;
pub use crate::_generated::mux;
use crate::time::Hertz;
#[cfg_attr(rcc_f002b, path = "f002b.rs")]
#[cfg_attr(not(rcc_f002b), path = "f0.rs")]
mod _version;
pub use _version::*;
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Clocks {
pub hclk1: crate::time::MaybeHertz,
pub pclk1: crate::time::MaybeHertz,
pub pclk1_tim: crate::time::MaybeHertz,
pub sys: crate::time::MaybeHertz,
pub hsi: crate::time::MaybeHertz,
pub lse: crate::time::MaybeHertz,
#[cfg(not(rcc_f002b))]
pub pll: crate::time::MaybeHertz,
}
static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
pub(crate) unsafe fn set_freqs(freqs: Clocks) {
debug!("rcc: {:?}", freqs);
CLOCK_FREQS = MaybeUninit::new(freqs);
}
pub(crate) unsafe fn get_freqs() -> &'static Clocks {
(*core::ptr::addr_of_mut!(CLOCK_FREQS)).assume_init_ref()
}
pub(crate) trait SealedRccPeripheral {
fn frequency() -> Hertz;
const RCC_INFO: RccInfo;
}
#[allow(private_bounds)]
pub trait RccPeripheral: SealedRccPeripheral + 'static {}
pub(crate) struct RccInfo {
reset_offset_or_0xff: u8,
reset_bit: u8,
enable_offset: u8,
enable_bit: u8,
refcount_idx_or_0xff: u8,
}
impl RccInfo {
pub(crate) const unsafe fn new(
reset_offset_and_bit: Option<(u8, u8)>,
enable_offset_and_bit: (u8, u8),
refcount_idx: Option<u8>,
) -> Self {
let (reset_offset_or_0xff, reset_bit) = match reset_offset_and_bit {
Some((offset, bit)) => (offset, bit),
None => (0xff, 0xff),
};
let (enable_offset, enable_bit) = enable_offset_and_bit;
let refcount_idx_or_0xff = match refcount_idx {
Some(idx) => idx,
None => 0xff,
};
Self {
reset_offset_or_0xff,
reset_bit,
enable_offset,
enable_bit,
refcount_idx_or_0xff,
}
}
pub(crate) fn enable_and_reset_with_cs(&self, _cs: CriticalSection) {
if self.refcount_idx_or_0xff != 0xff {
let refcount_idx = self.refcount_idx_or_0xff as usize;
if let Some(refcount) = unsafe {
(*core::ptr::addr_of_mut!(crate::_generated::REFCOUNTS)).get_mut(refcount_idx)
} {
*refcount += 1;
if *refcount > 1 {
return;
}
} else {
panic!("refcount_idx out of bounds: {}", refcount_idx)
}
}
let reset_ptr = self.reset_ptr();
if let Some(reset_ptr) = reset_ptr {
unsafe {
let val = reset_ptr.read_volatile();
reset_ptr.write_volatile(val | 1u32 << self.reset_bit);
}
}
let enable_ptr = self.enable_ptr();
unsafe {
let val = enable_ptr.read_volatile();
enable_ptr.write_volatile(val | 1u32 << self.enable_bit);
}
let _ = unsafe { enable_ptr.read_volatile() };
cortex_m::asm::dsb();
if let Some(reset_ptr) = reset_ptr {
unsafe {
let val = reset_ptr.read_volatile();
reset_ptr.write_volatile(val & !(1u32 << self.reset_bit));
}
}
}
pub(crate) fn disable_with_cs(&self, _cs: CriticalSection) {
if self.refcount_idx_or_0xff != 0xff {
let refcount_idx = self.refcount_idx_or_0xff as usize;
if let Some(refcount) = unsafe {
(*core::ptr::addr_of_mut!(crate::_generated::REFCOUNTS)).get_mut(refcount_idx)
} {
*refcount -= 1;
if *refcount > 0 {
return;
}
} else {
panic!("refcount_idx out of bounds: {}", refcount_idx)
}
}
let enable_ptr = self.enable_ptr();
unsafe {
let val = enable_ptr.read_volatile();
enable_ptr.write_volatile(val & !(1u32 << self.enable_bit));
}
}
pub(crate) fn enable_and_reset(&self) {
critical_section::with(|cs| self.enable_and_reset_with_cs(cs))
}
pub(crate) fn disable(&self) {
critical_section::with(|cs| self.disable_with_cs(cs))
}
fn reset_ptr(&self) -> Option<*mut u32> {
if self.reset_offset_or_0xff != 0xff {
Some(unsafe { (RCC.as_ptr() as *mut u32).add(self.reset_offset_or_0xff as _) })
} else {
None
}
}
fn enable_ptr(&self) -> *mut u32 {
unsafe { (RCC.as_ptr() as *mut u32).add(self.enable_offset as _) }
}
}
#[allow(unused)]
mod util {
use crate::time::Hertz;
pub fn calc_pclk<D>(hclk: Hertz, ppre: D) -> (Hertz, Hertz)
where
Hertz: core::ops::Div<D, Output = Hertz>,
{
let pclk = hclk / ppre;
let pclk_tim = if hclk == pclk { pclk } else { pclk * 2u32 };
(pclk, pclk_tim)
}
pub fn all_equal<T: Eq>(mut iter: impl Iterator<Item = T>) -> bool {
let Some(x) = iter.next() else { return true };
if !iter.all(|y| y == x) {
return false;
}
true
}
pub fn get_equal<T: Eq>(mut iter: impl Iterator<Item = T>) -> Result<Option<T>, ()> {
let Some(x) = iter.next() else {
return Ok(None);
};
if !iter.all(|y| y == x) {
return Err(());
}
Ok(Some(x))
}
}
pub fn frequency<T: RccPeripheral>() -> Hertz {
T::frequency()
}
pub fn enable_and_reset_with_cs<T: RccPeripheral>(cs: CriticalSection) {
T::RCC_INFO.enable_and_reset_with_cs(cs);
}
pub fn disable_with_cs<T: RccPeripheral>(cs: CriticalSection) {
T::RCC_INFO.disable_with_cs(cs);
}
pub fn enable_and_reset<T: RccPeripheral>() {
T::RCC_INFO.enable_and_reset();
}
pub fn disable<T: RccPeripheral>() {
T::RCC_INFO.disable();
}