use crate::clock::Hertz;
use mik32_pac::pm::ahb_mux::{AhbClkMux, ForceMux};
use mik32_pac::pm::cpu_rtc_clk_mux::CpuRtcClkMux;
use mik32_pac::wake_up::clocks_bu::RtcClkMux;
use mik32_pac::wake_up::clocks_sys::Force32kClk;
use mik32_pac::{Peripherals, Pm, WakeUp};
pub const HSI32M_FREQ: Hertz = Hertz(32_000_000); pub const OSC32M_FREQ: Hertz = Hertz(32_000_000); pub const LSI32K_FREQ: Hertz = Hertz(32_768); pub const OSC32K_FREQ: Hertz = Hertz(32_768);
#[derive(Debug, Clone, Copy)]
pub struct Clocks {
ahb: Hertz,
ahb_div: u32,
}
impl Clocks {
pub fn new(ahb: Hertz, ahb_div: u32) -> Self {
Self { ahb, ahb_div }
}
pub fn ahbclk(&self) -> Hertz {
self.ahb
}
pub fn ahb_div_clk(&self) -> u32 {
self.ahb_div
}
}
pub struct FreqMonitor {
pub sys: AhbClkMux, pub force_osc_sys: ForceMux, pub force32k_clk: Force32kClk, }
impl Default for FreqMonitor {
fn default() -> Self {
Self {
sys: AhbClkMux::Osc32m,
force_osc_sys: ForceMux::Unfixed,
force32k_clk: Force32kClk::Automatic,
}
}
}
pub struct RCC {
pub hsi32m: bool, pub osc32m: bool, pub lsi32k: bool, pub osc32k: bool, pub freq_monitor: FreqMonitor,
pub ahb_div: u8,
pub apb_m_div: u8,
pub apb_p_div: u8,
pub hsi32m_calibration_value: u8,
pub lsi32k_calibration_value: u8,
pub rtcclk: RtcClkMux,
pub rtccpuclk: CpuRtcClkMux,
pub clocks: Clocks,
}
impl Default for RCC {
fn default() -> Self {
Self {
hsi32m: true, osc32m: true, lsi32k: true, osc32k: true, freq_monitor: FreqMonitor::default(),
ahb_div: 0,
apb_m_div: 0,
apb_p_div: 0,
hsi32m_calibration_value: 128,
lsi32k_calibration_value: 8,
rtcclk: RtcClkMux::Automatic,
rtccpuclk: CpuRtcClkMux::Osc32k,
clocks: Clocks::new(OSC32M_FREQ, 0), }
}
}
impl RCC {
pub fn init(config: &RCC) {
let wu = unsafe { WakeUp::steal() };
let pm = unsafe { Pm::steal() };
wu.clocks_sys().modify(|_, w| {
w
.hsi32m_en()
.enable()
.osc32m_en()
.enable()
});
wu.clocks_bu().modify(|_, w| {
w
.lsi32k_en()
.enable()
.osc32k_en()
.enable()
});
wu.clocks_sys()
.modify(|_, w| unsafe { w.adj_hsi32m().bits(config.hsi32m_calibration_value) });
wu.clocks_bu()
.modify(|_, w| unsafe { w.adj_lsi32k().bits(config.lsi32k_calibration_value) });
wu.clocks_sys()
.modify(|_, w| match config.freq_monitor.force32k_clk {
Force32kClk::Automatic => w.force_32k_clk().automatic(),
Force32kClk::Lsi32k => w.force_32k_clk().lsi32k(),
Force32kClk::Osc32k => w.force_32k_clk().osc32k(),
});
pm.ahb_mux()
.modify(|_, w| match config.freq_monitor.force_osc_sys {
ForceMux::Unfixed => w.force_mux().unfixed(),
ForceMux::Fixed => w.force_mux().fixed(),
});
pm.ahb_mux().modify(|_, w| match config.freq_monitor.sys {
AhbClkMux::Osc32m => w.ahb_clk_mux().osc32m(),
AhbClkMux::Hsi32m => w.ahb_clk_mux().hsi32m(),
AhbClkMux::Osc32k => w.ahb_clk_mux().osc32k(),
AhbClkMux::Lsi32k => w.ahb_clk_mux().lsi32k(),
});
pm.div_ahb()
.modify(|_, w| unsafe { w.bits(config.ahb_div as u32) });
pm.div_apb_m()
.modify(|_, w| unsafe { w.bits(config.apb_m_div as u32) });
wu.clocks_bu().modify(|_, w| match config.rtcclk {
RtcClkMux::Automatic => w.rtc_clk_mux().automatic(),
RtcClkMux::Lsi32k => w.rtc_clk_mux().lsi32k(),
RtcClkMux::Osc32k => w.rtc_clk_mux().osc32k(),
});
wu.rtc_control().reset();
pm.cpu_rtc_clk_mux().modify(|_, w| match config.rtccpuclk {
CpuRtcClkMux::Osc32k => w.cpu_rtc_clk_mux().osc32k(),
CpuRtcClkMux::Lsi32k => w.cpu_rtc_clk_mux().osc32k(),
});
if !config.osc32m {
wu.clocks_sys().modify(|_, w| w.osc32m_en().disable());
}
if !config.hsi32m {
wu.clocks_sys().modify(|_, w| w.hsi32m_en().disable());
}
if !config.osc32k {
wu.clocks_bu().modify(|_, w| w.osc32k_en().disable());
}
if !config.lsi32k {
wu.clocks_bu().modify(|_, w| w.lsi32k_en().disable());
}
}
}
pub fn system_clock() -> Hertz {
let p = unsafe { Peripherals::steal() };
if p.pm.ahb_mux().read().ahb_clk_mux().is_osc32m() {
OSC32M_FREQ
} else if p.pm.ahb_mux().read().ahb_clk_mux().is_osc32k() {
OSC32K_FREQ
} else if p.pm.ahb_mux().read().ahb_clk_mux().is_hsi32m() {
HSI32M_FREQ
} else {
LSI32K_FREQ
}
}