use crate::pac::RCC;
use crate::time::{Hertz, U32Ext};
#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
use crate::{
pac::CRS,
syscfg::SYSCFG,
};
#[derive(Clone, Copy)]
pub enum ClockSrc {
MSI(MSIRange),
PLL(PLLSource, PLLMul, PLLDiv),
HSE(Hertz),
HSI16,
}
#[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 {
HSI16,
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 {
#[inline]
fn default() -> Config {
Config {
mux: ClockSrc::MSI(MSIRange::default()),
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
}
}
}
impl Config {
#[inline]
pub fn clock_src(mut self, mux: ClockSrc) -> Self {
self.mux = mux;
self
}
#[inline]
pub fn ahb_pre(mut self, pre: AHBPrescaler) -> Self {
self.ahb_pre = pre;
self
}
#[inline]
pub fn apb1_pre(mut self, pre: APBPrescaler) -> Self {
self.apb1_pre = pre;
self
}
#[inline]
pub fn apb2_pre(mut self, pre: APBPrescaler) -> Self {
self.apb2_pre = pre;
self
}
#[inline]
pub fn hsi16() -> Config {
Config {
mux: ClockSrc::HSI16,
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
}
}
#[inline]
pub fn msi(range: MSIRange) -> Config {
Config {
mux: ClockSrc::MSI(range),
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
}
}
#[inline]
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,
}
}
#[inline]
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,
}
#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
impl Rcc {
pub fn enable_hsi48(&mut self, syscfg: &mut SYSCFG, crs: CRS) -> HSI48 {
self.rb.apb1rstr.modify(|_, w| w.crsrst().set_bit());
self.rb.apb1rstr.modify(|_, w| w.crsrst().clear_bit());
self.rb.apb1enr.modify(|_, w| w.crsen().set_bit());
crs.cfgr.write(|w|
unsafe { w.syncsrc().bits(0b01) }
);
crs.cr.write(|w|
w
.autotrimen().set_bit()
.cen().set_bit()
);
syscfg.syscfg.cfgr3.modify(|_, w|
w
.enref_hsi48().set_bit()
.en_vrefint().set_bit()
);
self.rb.ccipr.modify(|_, w| w.hsi48msel().set_bit());
self.rb.crrcr.modify(|_, w| w.hsi48on().set_bit());
while self.rb.crrcr.read().hsi48rdy().bit_is_clear() {};
HSI48(())
}
}
pub trait RccExt {
fn freeze(self, config: Config) -> Rcc;
}
impl RccExt for RCC {
#[inline]
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| 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::HSI16 => {
self.cr.write(|w| w.hsi16on().set_bit());
while self.cr.read().hsi16rdyf().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::HSI16 => {
self.cr.write(|w| w.hsi16on().set_bit());
while self.cr.read().hsi16rdyf().bit_is_clear() {}
(false, HSI_FREQ)
}
};
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 {
source: cfgr.mux,
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 {
source: ClockSrc,
sys_clk: Hertz,
ahb_clk: Hertz,
apb1_clk: Hertz,
apb1_tim_clk: Hertz,
apb2_clk: Hertz,
apb2_tim_clk: Hertz,
}
impl Clocks {
pub fn source(&self) -> &ClockSrc {
&self.source
}
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
}
}
#[derive(Clone, Copy)]
pub struct HSI48(());