use crate::stm32::RCC;
use crate::time::{Hertz, U32Ext};
pub enum ClockSrc {
MSI(MSIRange),
PLL(PLLSource, PLLMul, PLLDiv),
HSE(Hertz),
HSI,
}
#[derive(Clone, Copy)]
pub enum MSIRange {
Range0 = 0,
Range1 = 1,
Range2 = 2,
Range3 = 3,
Range4 = 4,
Range5 = 5,
Range6 = 6,
}
impl Default for MSIRange {
fn default() -> MSIRange {
MSIRange::Range5
}
}
#[derive(Clone, Copy)]
pub enum PLLDiv {
Div2 = 1,
Div3 = 2,
Div4 = 3,
}
#[derive(Clone, Copy)]
pub enum PLLMul {
Mul3 = 0,
Mul4 = 1,
Mul6 = 2,
Mul8 = 3,
Mul12 = 4,
Mul16 = 5,
Mul24 = 6,
Mul32 = 7,
Mul48 = 8,
}
#[derive(Clone, Copy)]
pub enum AHBPrescaler {
NotDivided = 0,
Div2 = 0b1000,
Div4 = 0b1001,
Div8 = 0b1010,
Div16 = 0b1011,
Div64 = 0b1100,
Div128 = 0b1101,
Div256 = 0b1110,
Div512 = 0b1111,
}
#[derive(Clone, Copy)]
pub enum APBPrescaler {
NotDivided = 0,
Div2 = 0b100,
Div4 = 0b101,
Div8 = 0b110,
Div16 = 0b111,
}
#[derive(Clone, Copy)]
pub enum PLLSource {
HSI,
HSE(Hertz),
}
pub const HSI_FREQ: u32 = 16_000_000;
pub struct Config {
mux: ClockSrc,
ahb_pre: AHBPrescaler,
apb1_pre: APBPrescaler,
apb2_pre: APBPrescaler,
}
impl Default for Config {
fn default() -> Config {
Config {
mux: ClockSrc::MSI(MSIRange::default()),
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
}
}
}
impl Config {
pub fn clock_src(mut self, mux: ClockSrc) -> Self {
self.mux = mux;
self
}
pub fn ahb_pre(mut self, pre: AHBPrescaler) -> Self {
self.ahb_pre = pre;
self
}
pub fn apb1_pre(mut self, pre: APBPrescaler) -> Self {
self.apb1_pre = pre;
self
}
pub fn apb2_pre(mut self, pre: APBPrescaler) -> Self {
self.apb2_pre = pre;
self
}
pub fn hsi() -> Config {
Config {
mux: ClockSrc::HSI,
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
}
}
pub fn msi(range: MSIRange) -> Config {
Config {
mux: ClockSrc::MSI(range),
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
}
}
pub fn pll(pll_src: PLLSource, pll_mul: PLLMul, pll_div: PLLDiv) -> Config {
Config {
mux: ClockSrc::PLL(pll_src, pll_mul, pll_div),
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
}
}
pub fn hse<T>(freq: T) -> Config
where
T: Into<Hertz>,
{
Config {
mux: ClockSrc::HSE(freq.into()),
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
}
}
}
pub struct Rcc {
pub clocks: Clocks,
pub(crate) rb: RCC,
}
pub trait RccExt {
fn freeze(self, config: Config) -> Rcc;
}
impl RccExt for RCC {
fn freeze(self, cfgr: Config) -> Rcc {
let (sys_clk, sw_bits) = match cfgr.mux {
ClockSrc::MSI(range) => {
let range = range as u8;
self.icscr.write(|w| unsafe { w.msirange().bits(range) });
self.cr.write(|w| w.msion().set_bit());
while self.cr.read().msirdy().bit_is_clear() {}
let freq = 32_768 * (1 << (range + 1));
(freq, 0)
}
ClockSrc::HSI => {
self.cr.write(|w| w.hsion().set_bit());
while self.cr.read().hsirdy().bit_is_clear() {}
(HSI_FREQ, 1)
}
ClockSrc::HSE(freq) => {
self.cr.write(|w| w.hseon().set_bit());
while self.cr.read().hserdy().bit_is_clear() {}
(freq.0, 2)
}
ClockSrc::PLL(src, mul, div) => {
let (src_bit, freq) = match src {
PLLSource::HSE(freq) => {
self.cr.write(|w| w.hseon().set_bit());
while self.cr.read().hserdy().bit_is_clear() {}
(true, freq.0)
}
PLLSource::HSI => {
self.cr.write(|w| w.hsion().set_bit());
while self.cr.read().hsirdy().bit_is_clear() {}
(false, 15_998_976)
}
};
self.cr.write(|w| w.pllon().clear_bit());
while self.cr.read().pllrdy().bit_is_set() {}
let mul_bytes = mul as u8;
let div_bytes = div as u8;
let freq = match mul {
PLLMul::Mul3 => freq * 3,
PLLMul::Mul4 => freq * 4,
PLLMul::Mul6 => freq * 6,
PLLMul::Mul8 => freq * 8,
PLLMul::Mul12 => freq * 12,
PLLMul::Mul16 => freq * 16,
PLLMul::Mul24 => freq * 24,
PLLMul::Mul32 => freq * 32,
PLLMul::Mul48 => freq * 48,
};
let freq = match div {
PLLDiv::Div2 => freq / 2,
PLLDiv::Div3 => freq / 3,
PLLDiv::Div4 => freq / 4,
};
assert!(freq <= 24.mhz().0);
self.cfgr.write(move |w| unsafe {
w.pllmul()
.bits(mul_bytes)
.plldiv()
.bits(div_bytes)
.pllsrc()
.bit(src_bit)
});
self.cr.write(|w| w.pllon().set_bit());
while self.cr.read().pllrdy().bit_is_clear() {}
(freq, 3)
}
};
self.cfgr.modify(|_, w| unsafe {
w.sw()
.bits(sw_bits)
.hpre()
.bits(cfgr.ahb_pre as u8)
.ppre1()
.bits(cfgr.apb1_pre as u8)
.ppre2()
.bits(cfgr.apb2_pre as u8)
});
let ahb_freq = match cfgr.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
pre => sys_clk / (1 << (pre as u8 - 7)),
};
let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
let clocks = Clocks {
sys_clk: sys_clk.hz(),
ahb_clk: ahb_freq.hz(),
apb1_clk: apb1_freq.hz(),
apb2_clk: apb2_freq.hz(),
apb1_tim_clk: apb1_tim_freq.hz(),
apb2_tim_clk: apb2_tim_freq.hz(),
};
Rcc { rb: self, clocks }
}
}
#[derive(Clone, Copy)]
pub struct Clocks {
sys_clk: Hertz,
ahb_clk: Hertz,
apb1_clk: Hertz,
apb1_tim_clk: Hertz,
apb2_clk: Hertz,
apb2_tim_clk: Hertz,
}
impl Clocks {
pub fn sys_clk(&self) -> Hertz {
self.sys_clk
}
pub fn ahb_clk(&self) -> Hertz {
self.ahb_clk
}
pub fn apb1_clk(&self) -> Hertz {
self.apb1_clk
}
pub fn apb1_tim_clk(&self) -> Hertz {
self.apb1_tim_clk
}
pub fn apb2_clk(&self) -> Hertz {
self.apb2_clk
}
pub fn apb2_tim_clk(&self) -> Hertz {
self.apb2_tim_clk
}
}