use core::cmp;
use cast::u32;
use crate::pac::{rcc, RCC, PWR};
use crate::flash::ACR;
use crate::time::Hertz;
use crate::backup_domain::BackupDomain;
pub trait RccExt {
fn constrain(self) -> Rcc;
}
impl RccExt for RCC {
fn constrain(self) -> Rcc {
Rcc {
ahb: AHB { _0: () },
apb1: APB1 { _0: () },
apb2: APB2 { _0: () },
cfgr: CFGR {
hse: None,
hclk: None,
pclk1: None,
pclk2: None,
sysclk: None,
adcclk: None,
},
bkp: BKP { _0: () },
}
}
}
pub struct Rcc {
pub ahb: AHB,
pub apb1: APB1,
pub apb2: APB2,
pub cfgr: CFGR,
pub bkp: BKP,
}
pub struct AHB {
_0: (),
}
impl AHB {
#[allow(dead_code)]
pub(crate) fn enr(&mut self) -> &rcc::AHBENR {
unsafe { &(*RCC::ptr()).ahbenr }
}
}
pub struct APB1 {
_0: (),
}
impl APB1 {
pub(crate) fn enr(&mut self) -> &rcc::APB1ENR {
unsafe { &(*RCC::ptr()).apb1enr }
}
pub(crate) fn rstr(&mut self) -> &rcc::APB1RSTR {
unsafe { &(*RCC::ptr()).apb1rstr }
}
}
pub struct APB2 {
_0: (),
}
impl APB2 {
pub(crate) fn enr(&mut self) -> &rcc::APB2ENR {
unsafe { &(*RCC::ptr()).apb2enr }
}
pub(crate) fn rstr(&mut self) -> &rcc::APB2RSTR {
unsafe { &(*RCC::ptr()).apb2rstr }
}
}
const HSI: u32 = 8_000_000;
pub struct CFGR {
hse: Option<u32>,
hclk: Option<u32>,
pclk1: Option<u32>,
pclk2: Option<u32>,
sysclk: Option<u32>,
adcclk: Option<u32>,
}
impl CFGR {
pub fn use_hse<F>(mut self, freq: F) -> Self
where
F: Into<Hertz>,
{
self.hse = Some(freq.into().0);
self
}
pub fn hclk<F>(mut self, freq: F) -> Self
where
F: Into<Hertz>,
{
self.hclk = Some(freq.into().0);
self
}
pub fn pclk1<F>(mut self, freq: F) -> Self
where
F: Into<Hertz>,
{
self.pclk1 = Some(freq.into().0);
self
}
pub fn pclk2<F>(mut self, freq: F) -> Self
where
F: Into<Hertz>,
{
self.pclk2 = Some(freq.into().0);
self
}
pub fn sysclk<F>(mut self, freq: F) -> Self
where
F: Into<Hertz>,
{
self.sysclk = Some(freq.into().0);
self
}
pub fn adcclk<F>(mut self, freq: F) -> Self
where
F: Into<Hertz>,
{
self.adcclk = Some(freq.into().0);
self
}
pub fn freeze(self, acr: &mut ACR) -> Clocks {
let pllsrcclk = self.hse.unwrap_or(HSI / 2);
let pllmul = self.sysclk.unwrap_or(pllsrcclk) / pllsrcclk;
let pllmul = cmp::min(cmp::max(pllmul, 1), 16);
let (pllmul_bits, sysclk) = if pllmul == 1 {
(None, self.hse.unwrap_or(HSI))
} else {
(Some(pllmul as u8 - 2), pllsrcclk * pllmul)
};
assert!(sysclk <= 72_000_000);
let hpre_bits = self
.hclk
.map(|hclk| match sysclk / hclk {
0 => unreachable!(),
1 => 0b0111,
2 => 0b1000,
3...5 => 0b1001,
6...11 => 0b1010,
12...39 => 0b1011,
40...95 => 0b1100,
96...191 => 0b1101,
192...383 => 0b1110,
_ => 0b1111,
})
.unwrap_or(0b0111);
let hclk = sysclk / (1 << (hpre_bits - 0b0111));
assert!(hclk <= 72_000_000);
let ppre1_bits = self
.pclk1
.map(|pclk1| match hclk / pclk1 {
0 => unreachable!(),
1 => 0b011,
2 => 0b100,
3...5 => 0b101,
6...11 => 0b110,
_ => 0b111,
})
.unwrap_or(0b011);
let ppre1 = 1 << (ppre1_bits - 0b011);
let pclk1 = hclk / u32(ppre1);
assert!(pclk1 <= 36_000_000);
let ppre2_bits = self
.pclk2
.map(|pclk2| match hclk / pclk2 {
0 => unreachable!(),
1 => 0b011,
2 => 0b100,
3...5 => 0b101,
6...11 => 0b110,
_ => 0b111,
})
.unwrap_or(0b011);
let ppre2 = 1 << (ppre2_bits - 0b011);
let pclk2 = hclk / u32(ppre2);
assert!(pclk2 <= 72_000_000);
#[cfg(feature = "stm32f103")]
unsafe {
acr.acr().write(|w| {
w.latency().bits(if sysclk <= 24_000_000 {
0b000
} else if sysclk <= 48_000_000 {
0b001
} else {
0b010
})
})
}
let (usbpre, usbclk_valid) = match (self.hse, pllmul_bits, sysclk) {
(Some(_), Some(_), 72_000_000) => (false, true),
(Some(_), Some(_), 48_000_000) => (true, true),
_ => (true, false),
};
let apre_bits = self
.adcclk
.map(|adcclk| match pclk2 / adcclk {
0...2 => 0b00,
3...4 => 0b01,
5...7 => 0b10,
_ => 0b11,
})
.unwrap_or(0b11);
let apre = (apre_bits + 1) << 1;
let adcclk = pclk2 / u32(apre);
assert!(adcclk <= 14_000_000);
let rcc = unsafe { &*RCC::ptr() };
if self.hse.is_some() {
rcc.cr.modify(|_, w| w.hseon().set_bit());
while rcc.cr.read().hserdy().bit_is_clear() {}
}
if let Some(pllmul_bits) = pllmul_bits {
rcc.cfgr.modify(|_, w| unsafe {
w.pllmul()
.bits(pllmul_bits)
.pllsrc()
.bit(if self.hse.is_some() { true } else { false })
});
rcc.cr.modify(|_, w| w.pllon().set_bit());
while rcc.cr.read().pllrdy().bit_is_clear() {}
}
#[cfg(feature = "stm32f103")]
rcc.cfgr.modify(|_, w| unsafe {
w.adcpre().bits(apre_bits);
w.ppre2()
.bits(ppre2_bits)
.ppre1()
.bits(ppre1_bits)
.hpre()
.bits(hpre_bits)
.usbpre()
.bit(usbpre)
.sw()
.bits(if pllmul_bits.is_some() {
0b10
} else if self.hse.is_some() {
0b1
} else {
0b0
})
});
#[cfg(any(
feature = "stm32f100",
feature = "stm32f101"
))]
rcc.cfgr.modify(|_, w| unsafe {
w.adcpre().bits(apre_bits);
w.ppre2()
.bits(ppre2_bits)
.ppre1()
.bits(ppre1_bits)
.hpre()
.bits(hpre_bits)
.sw()
.bits(if pllmul_bits.is_some() {
0b10
} else if self.hse.is_some() {
0b1
} else {
0b0
})
});
Clocks {
hclk: Hertz(hclk),
pclk1: Hertz(pclk1),
pclk2: Hertz(pclk2),
ppre1,
ppre2,
sysclk: Hertz(sysclk),
adcclk: Hertz(adcclk),
usbclk_valid,
}
}
}
pub struct BKP {
_0: ()
}
impl BKP {
pub fn constrain(self, bkp: crate::pac::BKP, apb1: &mut APB1, pwr: &mut PWR) -> BackupDomain {
apb1.enr().modify(|_r, w| {
w
.bkpen().set_bit()
.pwren().set_bit()
});
pwr.cr.modify(|_r, w| {
w
.dbp().set_bit()
});
BackupDomain {
_regs: bkp,
}
}
}
#[derive(Clone, Copy)]
pub struct Clocks {
hclk: Hertz,
pclk1: Hertz,
pclk2: Hertz,
ppre1: u8,
ppre2: u8,
sysclk: Hertz,
adcclk: Hertz,
usbclk_valid: bool,
}
impl Clocks {
pub fn hclk(&self) -> Hertz {
self.hclk
}
pub fn pclk1(&self) -> Hertz {
self.pclk1
}
pub fn pclk2(&self) -> Hertz {
self.pclk2
}
pub fn pclk1_tim(&self) -> Hertz {
Hertz(self.pclk1.0 * if self.ppre1() == 1 { 1 } else { 2 })
}
pub fn pclk2_tim(&self) -> Hertz {
Hertz(self.pclk2.0 * if self.ppre2() == 1 { 1 } else { 2 })
}
pub(crate) fn ppre1(&self) -> u8 {
self.ppre1
}
#[allow(dead_code)]
pub(crate) fn ppre2(&self) -> u8 {
self.ppre2
}
pub fn sysclk(&self) -> Hertz {
self.sysclk
}
pub fn adcclk(&self) -> Hertz {
self.adcclk
}
pub fn usbclk_valid(&self) -> bool {
self.usbclk_valid
}
}