use crate::mco;
use crate::pac::rcc::cfgr::{MCOPRE_A, MCOSEL_A};
use crate::pac::RCC;
use crate::pwr::PWR;
use embedded_time::rate::{Extensions, Hertz};
#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
use crate::{pac::CRS, syscfg::SYSCFG};
mod enable;
#[derive(Clone, Copy)]
pub enum ClockSrc {
MSI(MSIRange),
PLL(PLLSource, PLLMul, PLLDiv),
HSE(Hertz),
HSI16(HSI16Div),
}
#[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 HSI16Div {
Div1 = 1,
Div4 = 4,
}
#[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(HSI16Div),
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(HSI16Div::Div1),
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,
}
impl core::ops::Deref for Rcc {
type Target = RCC;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.rb
}
}
impl Rcc {
pub fn enable_lse(&mut self, _: &PWR) -> LSE {
self.rb.csr.modify(|_, w| {
w.lseon().set_bit()
});
while self.rb.csr.read().lserdy().bit_is_clear() {}
LSE(())
}
}
#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
impl Rcc {
pub fn enable_hsi48(&mut self, syscfg: &mut SYSCFG, crs: CRS) -> HSI48 {
CRS::enable(self);
CRS::reset(self);
crs.cfgr.write(|w|
unsafe { w.syncsrc().bits(0b01) });
crs.cr
.modify(|_, 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(())
}
}
impl Rcc {
pub fn configure_mco<P>(
&mut self,
source: MCOSEL_A,
prescaler: MCOPRE_A,
output_pin: P,
) -> MCOEnabled
where
P: mco::Pin,
{
output_pin.into_mco();
self.rb.cfgr.modify(|_, w| {
w.mcosel().variant(source);
w.mcopre().variant(prescaler)
});
MCOEnabled(())
}
}
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(div) => {
let freq: u32 = match div {
HSI16Div::Div4 => {
self.cr
.write(|w| w.hsi16diven().set_bit().hsi16on().set_bit());
HSI_FREQ / 4
}
HSI16Div::Div1 => {
self.cr.write(|w| w.hsi16on().set_bit());
HSI_FREQ
}
};
while self.cr.read().hsi16rdyf().bit_is_clear() {}
(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(div) => {
let freq: u32 = match div {
HSI16Div::Div4 => {
self.cr
.write(|w| w.hsi16diven().set_bit().hsi16on().set_bit());
HSI_FREQ / 4
}
HSI16Div::Div1 => {
self.cr.write(|w| w.hsi16on().set_bit());
HSI_FREQ
}
};
while self.cr.read().hsi16rdyf().bit_is_clear() {}
(false, freq)
}
};
self.cr.modify(|_, 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 <= 32_000_000);
self.cfgr.write(move |w| unsafe {
w.pllmul()
.bits(mul_bytes)
.plldiv()
.bits(div_bytes)
.pllsrc()
.bit(src_bit)
});
self.cr.modify(|_, 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(());
#[derive(Clone, Copy)]
pub struct MCOEnabled(());
#[derive(Clone, Copy)]
pub struct LSE(());
pub trait RccBus: crate::Sealed {
type Bus;
}
pub trait Enable: RccBus {
fn enable(rcc: &mut Rcc);
fn disable(rcc: &mut Rcc);
fn is_enabled() -> bool;
fn is_disabled() -> bool;
unsafe fn enable_unchecked();
unsafe fn disable_unchecked();
}
pub trait SMEnable: RccBus {
fn enable_in_sleep_mode(rcc: &mut Rcc);
fn disable_in_sleep_mode(rcc: &mut Rcc);
fn is_enabled_in_sleep_mode() -> bool;
fn is_disabled_in_sleep_mode() -> bool;
unsafe fn enable_in_sleep_mode_unchecked();
unsafe fn disable_in_sleep_mode_unchecked();
}
pub trait Reset: RccBus {
fn reset(rcc: &mut Rcc);
unsafe fn reset_unchecked();
}
use crate::pac::rcc::{self, RegisterBlock as RccRB};
macro_rules! bus_struct {
($($busX:ident => ($EN:ident, $en:ident, $SMEN:ident, $smen:ident, $RST:ident, $rst:ident, $doc:literal),)+) => {
$(
#[doc = $doc]
pub struct $busX {
_0: (),
}
impl $busX {
#[inline(always)]
fn enr(rcc: &RccRB) -> &rcc::$EN {
&rcc.$en
}
#[inline(always)]
fn smenr(rcc: &RccRB) -> &rcc::$SMEN {
&rcc.$smen
}
#[inline(always)]
fn rstr(rcc: &RccRB) -> &rcc::$RST {
&rcc.$rst
}
}
)+
};
}
bus_struct! {
AHB => (AHBENR, ahbenr, AHBSMENR, ahbsmenr, AHBRSTR, ahbrstr, "AMBA High-performance Bus (AHB) registers"),
APB1 => (APB1ENR, apb1enr, APB1SMENR, apb1smenr, APB1RSTR, apb1rstr, "Advanced Peripheral Bus 1 (APB1) registers"),
APB2 => (APB2ENR, apb2enr, APB2SMENR, apb2smenr, APB2RSTR, apb2rstr, "Advanced Peripheral Bus 2 (APB2) registers"),
IOP => (IOPENR, iopenr, IOPSMEN, iopsmen, IOPRSTR, ioprstr, "Input-Output Peripheral Bus (IOP) registers"),
}