mod enable;
#[cfg(any(feature = "f103", feature = "connectivity"))]
use crate::time::MHz;
use crate::{
backup_domain::BackupDomain,
common::holder::StaticHolder,
flash::ACR,
fugit::{HertzU32, RateExtU32},
pac::{
BKP, PWR, RCC,
rcc::{self, RegisterBlock as RccRB},
},
};
use core::ops::{Deref, DerefMut};
static CLOCKS: StaticHolder<Clocks> = StaticHolder::new(Clocks::new());
pub trait RccInit {
fn init(self) -> Rcc;
}
impl RccInit for RCC {
fn init(self) -> Rcc {
CLOCKS.set(Clocks::default());
Rcc { rb: self }
}
}
pub struct Rcc {
pub(crate) rb: RCC,
}
impl Rcc {
#[allow(unused_variables)]
#[inline(always)]
pub fn freeze(self, cfg: impl Into<RawConfig>, acr: &mut ACR) -> Self {
let cfg = cfg.into();
let clocks = cfg.get_clocks();
#[cfg(any(feature = "f103", feature = "connectivity"))]
unsafe {
acr.acr().write(|w| {
w.latency().bits(if clocks.sysclk <= MHz(24) {
0b000
} else if clocks.sysclk <= MHz(48) {
0b001
} else {
0b010
})
});
}
let rcc = unsafe { &*RCC::ptr() };
if cfg.hse.is_some() {
rcc.cr().modify(|_, w| {
if cfg.hse_bypass {
w.hsebyp().bypassed();
}
w.hseon().set_bit()
});
while rcc.cr().read().hserdy().bit_is_clear() {}
}
if let Some(pllmul_bits) = cfg.pllmul {
#[allow(unused_unsafe)]
rcc.cfgr().modify(|_, w| unsafe {
w.pllmul().bits(pllmul_bits).pllsrc().bit(cfg.hse.is_some())
});
rcc.cr().modify(|_, w| w.pllon().set_bit());
while rcc.cr().read().pllrdy().bit_is_clear() {}
}
#[cfg(feature = "connectivity")]
rcc.cfgr().modify(|_, w| unsafe {
w.adcpre().variant(cfg.adcpre);
w.ppre2().bits(cfg.ppre2 as u8);
w.ppre1().bits(cfg.ppre1 as u8);
w.hpre().bits(cfg.hpre as u8);
w.otgfspre().variant(cfg.usbpre);
w.sw().bits(if cfg.pllmul.is_some() {
0b10
} else if cfg.hse.is_some() {
0b1
} else {
0b0
})
});
#[cfg(feature = "f103")]
rcc.cfgr().modify(|_, w| unsafe {
w.adcpre().variant(cfg.adcpre);
w.ppre2().bits(cfg.ppre2 as u8);
w.ppre1().bits(cfg.ppre1 as u8);
w.hpre().bits(cfg.hpre as u8);
w.usbpre().variant(cfg.usbpre);
w.sw().bits(if cfg.pllmul.is_some() {
0b10
} else {
u8::from(cfg.hse.is_some())
})
});
#[cfg(any(feature = "f100", feature = "f101"))]
rcc.cfgr().modify(|_, w| unsafe {
w.adcpre().variant(cfg.adcpre);
w.ppre2().bits(cfg.ppre2 as u8);
w.ppre1().bits(cfg.ppre1 as u8);
w.hpre().bits(cfg.hpre as u8);
w.sw().bits(if cfg.pllmul.is_some() {
0b10
} else if cfg.hse.is_some() {
0b1
} else {
0b0
})
});
CLOCKS.set(clocks);
Self { rb: self.rb }
}
pub fn enable<T: Enable>(&mut self, _periph: &T) {
T::enable(self);
}
pub fn reset<T: Reset>(&mut self, _periph: &T) {
T::reset(self);
}
#[inline(always)]
pub fn clocks(&self) -> &Clocks {
unsafe { CLOCKS.get() }
}
}
impl Deref for Rcc {
type Target = RCC;
fn deref(&self) -> &Self::Target {
&self.rb
}
}
impl DerefMut for Rcc {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.rb
}
}
pub fn get_clocks() -> &'static Clocks {
unsafe { CLOCKS.get() }
}
macro_rules! bus_struct {
($($busX:ident => ($EN:ident, $en:ident, $($RST:ident, $rst:ident,)? $doc:literal),)+) => {
$(
#[doc = $doc]
#[non_exhaustive]
pub struct $busX;
impl $busX {
pub(crate) fn enr(rcc: &RccRB) -> &rcc::$EN {
rcc.$en()
}
$(
pub(crate) fn rstr(rcc: &RccRB) -> &rcc::$RST {
rcc.$rst()
}
)?
}
)+
};
}
bus_struct! {
APB1 => (APB1ENR, apb1enr, APB1RSTR, apb1rstr, "Advanced Peripheral Bus 1 (APB1) registers"),
APB2 => (APB2ENR, apb2enr, APB2RSTR, apb2rstr, "Advanced Peripheral Bus 2 (APB2) registers"),
AHB => (AHBENR, ahbenr, "Advanced High-performance Bus (AHB) registers"),
}
const HSI: u32 = 8_000_000;
#[derive(Debug, Default, PartialEq, Eq)]
pub struct Config {
hse: Option<u32>,
hse_bypass: bool,
hclk: Option<u32>,
pclk1: Option<u32>,
pclk2: Option<u32>,
sysclk: Option<u32>,
adcclk: Option<u32>,
}
impl Config {
pub const DEFAULT: Self = Self {
hse: None,
hse_bypass: false,
hclk: None,
pclk1: None,
pclk2: None,
sysclk: None,
adcclk: None,
};
pub fn hsi() -> Self {
Self::DEFAULT
}
pub fn hse(freq: HertzU32) -> Self {
Self::DEFAULT.use_hse(freq)
}
#[inline(always)]
pub fn use_hse(mut self, freq: HertzU32) -> Self {
self.hse = Some(freq.raw());
self
}
pub fn bypass_hse_oscillator(self) -> Self {
Self {
hse_bypass: true,
..self
}
}
#[inline(always)]
pub fn hclk(mut self, freq: HertzU32) -> Self {
self.hclk = Some(freq.raw());
self
}
#[inline(always)]
pub fn pclk1(mut self, freq: HertzU32) -> Self {
self.pclk1 = Some(freq.raw());
self
}
#[inline(always)]
pub fn pclk2(mut self, freq: HertzU32) -> Self {
self.pclk2 = Some(freq.raw());
self
}
#[inline(always)]
pub fn sysclk(mut self, freq: HertzU32) -> Self {
self.sysclk = Some(freq.raw());
self
}
#[inline(always)]
pub fn adcclk(mut self, freq: HertzU32) -> Self {
self.adcclk = Some(freq.raw());
self
}
}
pub trait BkpInit {
fn init(self, pwr: &mut PWR, rcc: &mut RCC) -> BackupDomain;
}
impl BkpInit for BKP {
fn init(self, pwr: &mut PWR, rcc: &mut RCC) -> BackupDomain {
BKP::enable(rcc);
PWR::enable(rcc);
pwr.cr().modify(|_r, w| w.dbp().set_bit());
BackupDomain { _regs: self }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Clocks {
hclk: HertzU32,
pclk1: HertzU32,
pclk2: HertzU32,
ppre1: u8,
ppre2: u8,
sysclk: HertzU32,
adcclk: HertzU32,
#[cfg(any(feature = "f103", feature = "connectivity"))]
usbclk_valid: bool,
}
impl Clocks {
const fn new() -> Self {
let freq = HertzU32::from_raw(HSI);
Self {
hclk: freq,
pclk1: freq,
pclk2: freq,
ppre1: 1,
ppre2: 1,
sysclk: freq,
adcclk: HertzU32::from_raw(HSI / 2),
#[cfg(any(feature = "f103", feature = "connectivity"))]
usbclk_valid: false,
}
}
}
impl Default for Clocks {
fn default() -> Clocks {
Self::new()
}
}
impl Clocks {
pub const fn hclk(&self) -> HertzU32 {
self.hclk
}
pub const fn pclk1(&self) -> HertzU32 {
self.pclk1
}
pub const fn pclk2(&self) -> HertzU32 {
self.pclk2
}
pub const fn pclk1_tim(&self) -> HertzU32 {
HertzU32::from_raw(self.pclk1.raw() * if self.ppre1() == 1 { 1 } else { 2 })
}
pub const fn pclk2_tim(&self) -> HertzU32 {
HertzU32::from_raw(self.pclk2.raw() * if self.ppre2() == 1 { 1 } else { 2 })
}
pub(crate) const fn ppre1(&self) -> u8 {
self.ppre1
}
#[allow(dead_code)]
pub(crate) const fn ppre2(&self) -> u8 {
self.ppre2
}
pub const fn sysclk(&self) -> HertzU32 {
self.sysclk
}
pub const fn adcclk(&self) -> HertzU32 {
self.adcclk
}
#[cfg(any(feature = "f103", feature = "connectivity"))]
pub const fn usbclk_valid(&self) -> bool {
self.usbclk_valid
}
}
pub trait BusClock {
fn clock(clocks: &Clocks) -> HertzU32;
}
impl BusClock for AHB {
#[inline(always)]
fn clock(clocks: &Clocks) -> HertzU32 {
clocks.hclk
}
}
impl BusClock for APB1 {
#[inline(always)]
fn clock(clocks: &Clocks) -> HertzU32 {
clocks.pclk1
}
}
impl BusClock for APB2 {
#[inline(always)]
fn clock(clocks: &Clocks) -> HertzU32 {
clocks.pclk2
}
}
pub trait GetClock: RccBus {
fn get_clock(&self) -> HertzU32;
}
impl<T> GetClock for T
where
T: RccBus,
T::Bus: BusClock,
{
#[inline(always)]
fn get_clock(&self) -> HertzU32 {
T::Bus::clock(unsafe { CLOCKS.get() })
}
}
pub trait BusTimerClock {
fn timer_clock(clocks: &Clocks) -> HertzU32;
}
impl BusTimerClock for APB1 {
#[inline(always)]
fn timer_clock(clocks: &Clocks) -> HertzU32 {
clocks.pclk1_tim()
}
}
impl BusTimerClock for APB2 {
#[inline(always)]
fn timer_clock(clocks: &Clocks) -> HertzU32 {
clocks.pclk2_tim()
}
}
pub trait GetTimerClock: RccBus {
fn get_timer_clock(&self) -> HertzU32;
}
impl<T> GetTimerClock for T
where
T: RccBus,
T::Bus: BusTimerClock,
{
#[inline(always)]
fn get_timer_clock(&self) -> HertzU32 {
T::Bus::timer_clock(unsafe { CLOCKS.get() })
}
}
pub trait RccBus {
type Bus;
}
pub trait Enable: RccBus {
fn enable(rcc: &mut RCC);
fn disable(rcc: &mut RCC);
fn is_enabled() -> bool;
#[inline]
fn is_disabled() -> bool {
!Self::is_enabled()
}
unsafe fn enable_unchecked() {
let mut rcc = unsafe { RCC::steal() };
Self::enable(&mut rcc);
}
unsafe fn disable_unchecked() {
let mut rcc = unsafe { RCC::steal() };
Self::disable(&mut rcc);
}
}
pub trait Reset: RccBus {
fn reset(rcc: &mut RCC);
unsafe fn reset_unchecked() {
let mut rcc = unsafe { RCC::steal() };
Self::reset(&mut rcc);
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct RawConfig {
pub hse: Option<u32>,
pub hse_bypass: bool,
pub pllmul: Option<u8>,
pub hpre: HPre,
pub ppre1: PPre,
pub ppre2: PPre,
#[cfg(any(feature = "f103", feature = "connectivity"))]
pub usbpre: UsbPre,
pub adcpre: AdcPre,
pub allow_overclock: bool,
}
impl Default for RawConfig {
fn default() -> Self {
Self {
hse: None,
hse_bypass: false,
pllmul: None,
hpre: HPre::Div1,
ppre1: PPre::Div1,
ppre2: PPre::Div1,
#[cfg(any(feature = "f103", feature = "connectivity"))]
usbpre: UsbPre::Div1_5,
adcpre: AdcPre::Div2,
allow_overclock: false,
}
}
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum HPre {
Div1 = 7,
Div2 = 8,
Div4 = 9,
Div8 = 10,
Div16 = 11,
Div64 = 12,
Div128 = 13,
Div256 = 14,
Div512 = 15,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum PPre {
Div1 = 3,
Div2 = 4,
Div4 = 5,
Div8 = 6,
Div16 = 7,
}
#[cfg(feature = "f103")]
pub type UsbPre = rcc::cfgr::USBPRE;
#[cfg(feature = "connectivity")]
pub type UsbPre = rcc::cfgr::OTGFSPRE;
pub type AdcPre = rcc::cfgr::ADCPRE;
impl From<Config> for RawConfig {
#[inline(always)]
fn from(cfgr: Config) -> Self {
Self::from_cfgr(cfgr)
}
}
impl RawConfig {
pub const fn from_cfgr(cfgr: Config) -> Self {
let hse = cfgr.hse;
let hse_bypass = cfgr.hse_bypass;
let pllsrcclk = if let Some(hse) = hse { hse } else { HSI / 2 };
let pllmul = if let Some(sysclk) = cfgr.sysclk {
sysclk / pllsrcclk
} else {
1
};
let (pllmul_bits, sysclk) = if pllmul == 1 {
(None, if let Some(hse) = hse { hse } else { HSI })
} else {
#[cfg(not(feature = "connectivity"))]
let pllmul = match pllmul {
1..=16 => pllmul,
0 => 1,
_ => 16,
};
#[cfg(feature = "connectivity")]
let pllmul = match pllmul {
4..=9 => pllmul,
0..=3 => 4,
_ => 9,
};
(Some(pllmul as u8 - 2), pllsrcclk * pllmul)
};
let hpre_bits = if let Some(hclk) = cfgr.hclk {
match sysclk / hclk {
0..=1 => HPre::Div1,
2 => HPre::Div2,
3..=5 => HPre::Div4,
6..=11 => HPre::Div8,
12..=39 => HPre::Div16,
40..=95 => HPre::Div64,
96..=191 => HPre::Div128,
192..=383 => HPre::Div256,
_ => HPre::Div512,
}
} else {
HPre::Div1
};
let hclk = if hpre_bits as u8 >= 0b1100 {
sysclk / (1 << (hpre_bits as u8 - 0b0110))
} else {
sysclk / (1 << (hpre_bits as u8 - 0b0111))
};
let pclk1 = if let Some(pclk1) = cfgr.pclk1 {
pclk1
} else if hclk < 36_000_000 {
hclk
} else {
36_000_000
};
let ppre1_bits = match hclk.div_ceil(pclk1) {
0 | 1 => PPre::Div1,
2 => PPre::Div2,
3..=5 => PPre::Div4,
6..=11 => PPre::Div8,
_ => PPre::Div16,
};
let ppre2_bits = if let Some(pclk2) = cfgr.pclk2 {
match hclk / pclk2 {
0..=1 => PPre::Div1,
2 => PPre::Div2,
3..=5 => PPre::Div4,
6..=11 => PPre::Div8,
_ => PPre::Div16,
}
} else {
PPre::Div1
};
let ppre2 = 1 << (ppre2_bits as u8 - 0b011);
let pclk2 = hclk / (ppre2 as u32);
#[cfg(any(feature = "f103", feature = "connectivity"))]
let usbpre = match (hse, pllmul_bits, sysclk) {
(Some(_), Some(_), 72_000_000) => UsbPre::Div1_5,
_ => UsbPre::Div1,
};
let apre_bits = if let Some(adcclk) = cfgr.adcclk {
match pclk2 / adcclk {
0..=2 => AdcPre::Div2,
3..=4 => AdcPre::Div4,
5..=7 => AdcPre::Div6,
_ => AdcPre::Div8,
}
} else {
AdcPre::Div8
};
Self {
hse,
hse_bypass,
pllmul: pllmul_bits,
hpre: hpre_bits,
ppre1: ppre1_bits,
ppre2: ppre2_bits,
#[cfg(any(feature = "f103", feature = "connectivity"))]
usbpre,
adcpre: apre_bits,
allow_overclock: false,
}
}
fn get_clocks(&self) -> Clocks {
let sysclk = if let Some(pllmul_bits) = self.pllmul {
let pllsrcclk = if let Some(hse) = self.hse {
hse
} else {
HSI / 2
};
pllsrcclk * (pllmul_bits as u32 + 2)
} else if let Some(hse) = self.hse {
hse
} else {
HSI
};
let hclk = if self.hpre as u8 >= 0b1100 {
sysclk / (1 << (self.hpre as u8 - 0b0110))
} else {
sysclk / (1 << (self.hpre as u8 - 0b0111))
};
let ppre1 = 1 << (self.ppre1 as u8 - 0b011);
let pclk1 = hclk / (ppre1 as u32);
let ppre2 = 1 << (self.ppre2 as u8 - 0b011);
let pclk2 = hclk / (ppre2 as u32);
let apre = (self.adcpre as u8 + 1) << 1;
let adcclk = pclk2 / (apre as u32);
#[cfg(any(feature = "f103", feature = "connectivity"))]
let usbclk_valid = matches!(
(self.hse, self.pllmul, sysclk),
(Some(_), Some(_), 72_000_000) | (Some(_), Some(_), 48_000_000)
);
assert!(
self.allow_overclock
|| (sysclk <= 72_000_000
&& hclk <= 72_000_000
&& pclk1 <= 36_000_000
&& pclk2 <= 72_000_000
&& adcclk <= 14_000_000)
);
Clocks {
hclk: hclk.Hz(),
pclk1: pclk1.Hz(),
pclk2: pclk2.Hz(),
ppre1,
ppre2,
sysclk: sysclk.Hz(),
adcclk: adcclk.Hz(),
#[cfg(any(feature = "f103", feature = "connectivity"))]
usbclk_valid,
}
}
}
#[test]
fn rcc_config_usb() {
let cfgr = Config::default()
.use_hse(8.MHz())
.sysclk(48.MHz())
.pclk1(24.MHz());
let config = RawConfig::from_cfgr(cfgr);
let config_expected = RawConfig {
hse: Some(8_000_000),
hse_bypass: false,
pllmul: Some(4),
hpre: HPre::Div1,
ppre1: PPre::Div2,
ppre2: PPre::Div1,
#[cfg(any(feature = "f103", feature = "connectivity"))]
usbpre: UsbPre::Div1,
adcpre: AdcPre::Div8,
allow_overclock: false,
};
assert_eq!(config, config_expected);
let clocks = config.get_clocks();
let clocks_expected = Clocks {
hclk: 48.MHz(),
pclk1: 24.MHz(),
pclk2: 48.MHz(),
ppre1: 2,
ppre2: 1,
sysclk: 48.MHz(),
adcclk: 6.MHz(),
#[cfg(any(feature = "f103", feature = "connectivity"))]
usbclk_valid: true,
};
assert_eq!(clocks, clocks_expected);
}