//! Clock Configuration //! //! This module holds configuration types used for the system clocks. For //! configuration of individual peripherals, see [`super::periph_helpers`]. use super::PoweredClock; /// This type represents a divider in the range 1..=256. /// /// At a hardware level, this is an 8-bit register from 0..=255, /// which adds one. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Div8(pub(super) u8); impl Div8 { /// Store a "raw" divisor value that will divide the source by /// `(n + 1)`, e.g. `Div8::from_raw(0)` will divide the source /// by 1, and `Div8::from_raw(255)` will divide the source by /// 256. pub const fn from_raw(n: u8) -> Self { Self(n) } /// Divide by one, or no division pub const fn no_div() -> Self { Self(0) } /// Store a specific divisor value that will divide the source /// by `n`. e.g. `Div8::from_divisor(1)` will divide the source /// by 1, and `Div8::from_divisor(256)` will divide the source /// by 256. /// /// Will return `None` if `n` is not in the range `1..=256`. /// Consider [`Self::from_raw`] for an infallible version. pub const fn from_divisor(n: u16) -> Option { let Some(n) = n.checked_sub(1) else { return None; }; if n > (u8::MAX as u16) { return None; } Some(Self(n as u8)) } /// Convert into "raw" bits form #[inline(always)] pub const fn into_bits(self) -> u8 { self.0 } /// Convert into "divisor" form, as a u32 for convenient frequency math #[inline(always)] pub const fn into_divisor(self) -> u32 { self.0 as u32 + 1 } } /// ```text /// ┌─────────────────────────────────────────────────────────┐ /// │ │ /// │ ┌───────────┐ clk_out ┌─────────┐ │ /// XTAL ──────┼──▷│ System │───────────▷│ │ clk_in │ /// │ │ OSC │ clkout_byp │ MUX │──────────────────┼──────▷ /// EXTAL ──────┼──▷│ │───────────▷│ │ │ /// │ └───────────┘ └─────────┘ │ /// │ │ /// │ ┌───────────┐ fro_hf_root ┌────┐ fro_hf │ /// │ │ FRO180 ├───────┬─────▷│ CG │─────────────────────┼──────▷ /// │ │ │ │ ├────┤ clk_45m │ /// │ │ │ └─────▷│ CG │─────────────────────┼──────▷ /// │ └───────────┘ └────┘ │ /// │ ┌───────────┐ fro_12m_root ┌────┐ fro_12m │ /// │ │ FRO12M │────────┬─────▷│ CG │────────────────────┼──────▷ /// │ │ │ │ ├────┤ clk_1m │ /// │ │ │ └─────▷│1/12│────────────────────┼──────▷ /// │ └───────────┘ └────┘ │ /// │ │ /// │ ┌──────────┐ │ /// │ │000 │ │ /// │ clk_in │ │ │ /// │ ───────────────▷│001 │ │ /// │ fro_12m │ │ │ /// │ ───────────────▷│010 │ │ /// │ fro_hf_root │ │ │ /// │ ───────────────▷│011 │ main_clk │ /// │ │ │───────────────────────────┼──────▷ /// clk_16k ──────┼─────────────────▷│100 │ │ /// │ none │ │ │ /// │ ───────────────▷│101 │ │ /// │ pll1_clk │ │ │ /// │ ───────────────▷│110 │ │ /// │ none │ │ │ /// │ ───────────────▷│111 │ │ /// │ └──────────┘ │ /// │ ▲ │ /// │ │ │ /// │ SCG SCS │ /// │ SCG-Lite │ /// └─────────────────────────────────────────────────────────┘ /// /// /// clk_in ┌─────┐ /// ───────────────▷│00 │ /// clk_45m │ │ /// ───────────────▷│01 │ ┌───────────┐ pll1_clk /// none │ │─────▷│ SPLL │───────────────▷ /// ───────────────▷│10 │ └───────────┘ /// fro_12m │ │ /// ───────────────▷│11 │ /// └─────┘ /// ``` #[non_exhaustive] pub struct ClocksConfig { /// FIRC, FRO180, 45/60/90/180M clock source pub firc: Option, /// SIRC, FRO12M, clk_12m clock source // NOTE: I don't think we *can* disable the SIRC? pub sirc: SircConfig, /// FRO16K clock source pub fro16k: Option, } // FIRC/FRO180M /// ```text /// ┌───────────┐ fro_hf_root ┌────┐ fro_hf /// │ FRO180M ├───────┬─────▷│GATE│──────────▷ /// │ │ │ ├────┤ clk_45m /// │ │ └─────▷│GATE│──────────▷ /// └───────────┘ └────┘ /// ``` #[non_exhaustive] pub struct FircConfig { /// Selected clock frequency pub frequency: FircFreqSel, /// Selected power state of the clock pub power: PoweredClock, /// Is the "fro_hf" gated clock enabled? pub fro_hf_enabled: bool, /// Is the "clk_45m" gated clock enabled? pub clk_45m_enabled: bool, /// Is the "fro_hf_div" clock enabled? Requires `fro_hf`! pub fro_hf_div: Option, } /// Selected FIRC frequency pub enum FircFreqSel { /// 45MHz Output Mhz45, /// 60MHz Output Mhz60, /// 90MHz Output Mhz90, /// 180MHz Output Mhz180, } // SIRC/FRO12M /// ```text /// ┌───────────┐ fro_12m_root ┌────┐ fro_12m /// │ FRO12M │────────┬─────▷│ CG │──────────▷ /// │ │ │ ├────┤ clk_1m /// │ │ └─────▷│1/12│──────────▷ /// └───────────┘ └────┘ /// ``` #[non_exhaustive] pub struct SircConfig { pub power: PoweredClock, // peripheral output, aka sirc_12mhz pub fro_12m_enabled: bool, /// Is the "fro_lf_div" clock enabled? Requires `fro_12m`! pub fro_lf_div: Option, } #[non_exhaustive] pub struct Fro16KConfig { pub vsys_domain_active: bool, pub vdd_core_domain_active: bool, } impl Default for ClocksConfig { fn default() -> Self { Self { firc: Some(FircConfig { frequency: FircFreqSel::Mhz45, power: PoweredClock::NormalEnabledDeepSleepDisabled, fro_hf_enabled: true, clk_45m_enabled: true, fro_hf_div: None, }), sirc: SircConfig { power: PoweredClock::AlwaysEnabled, fro_12m_enabled: true, fro_lf_div: None, }, fro16k: Some(Fro16KConfig { vsys_domain_active: true, vdd_core_domain_active: true, }), } } }