pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange, Plldiv, Pllm, Plln, Ppre as APBPrescaler}; use crate::pac::rcc::vals::{Msirgsel, Pllmboost, Pllrge, Pllsrc, Sw}; use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub use crate::pac::pwr::vals::Vos as VoltageScale; #[derive(Copy, Clone)] pub enum ClockSrc { /// Use an internal medium speed oscillator (MSIS) as the system clock. MSI(Msirange), /// Use the external high speed clock as the system clock. /// /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must /// never exceed 50 MHz. HSE(Hertz), /// Use the 16 MHz internal high speed oscillator as the system clock. HSI16, /// Use PLL1 as the system clock. PLL1R(PllConfig), } impl Default for ClockSrc { fn default() -> Self { // The default system clock source is MSIS @ 4 MHz, per RM0456 § 11.4.9 ClockSrc::MSI(Msirange::RANGE_4MHZ) } } #[derive(Clone, Copy)] pub struct PllConfig { /// The clock source for the PLL. pub source: PllSrc, /// The PLL prescaler. /// /// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz. pub m: Pllm, /// The PLL multiplier. /// /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544 /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`. pub n: Plln, /// The divider for the R output. /// /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default /// `Config { voltage_range }`. pub r: Plldiv, } impl PllConfig { /// A configuration for HSI16 / 1 * 10 / 1 = 160 MHz pub const fn hsi16_160mhz() -> Self { PllConfig { source: PllSrc::HSI16, m: Pllm::DIV1, n: Plln::MUL10, r: Plldiv::DIV1, } } /// A configuration for MSIS @ 48 MHz / 3 * 10 / 1 = 160 MHz pub const fn msis_160mhz() -> Self { PllConfig { source: PllSrc::MSIS(Msirange::RANGE_48MHZ), m: Pllm::DIV3, n: Plln::MUL10, r: Plldiv::DIV1, } } } #[derive(Clone, Copy)] pub enum PllSrc { /// Use an internal medium speed oscillator as the PLL source. MSIS(Msirange), /// Use the external high speed clock as the system PLL source. /// /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must /// never exceed 50 MHz. HSE(Hertz), /// Use the 16 MHz internal high speed oscillator as the PLL source. HSI16, } impl Into for PllSrc { fn into(self) -> Pllsrc { match self { PllSrc::MSIS(..) => Pllsrc::MSIS, PllSrc::HSE(..) => Pllsrc::HSE, PllSrc::HSI16 => Pllsrc::HSI16, } } } impl Into for ClockSrc { fn into(self) -> Sw { match self { ClockSrc::MSI(..) => Sw::MSIS, ClockSrc::HSE(..) => Sw::HSE, ClockSrc::HSI16 => Sw::HSI16, ClockSrc::PLL1R(..) => Sw::PLL1_R, } } } pub struct Config { pub mux: ClockSrc, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, pub apb3_pre: APBPrescaler, pub hsi48: bool, /// The voltage range influences the maximum clock frequencies for different parts of the /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks /// exceeding 55 MHz require at least `RANGE2`. /// /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits. pub voltage_range: VoltageScale, pub ls: super::LsConfig, } impl Config { unsafe fn init_hsi16(&self) -> Hertz { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} HSI_FREQ } unsafe fn init_hse(&self, frequency: Hertz) -> Hertz { // Check frequency limits per RM456 § 11.4.10 match self.voltage_range { VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => { assert!(frequency.0 <= 50_000_000); } VoltageScale::RANGE4 => { assert!(frequency.0 <= 25_000_000); } } // Enable HSE, and wait for it to stabilize RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} frequency } unsafe fn init_msis(&self, range: Msirange) -> Hertz { // Check MSI output per RM0456 § 11.4.10 match self.voltage_range { VoltageScale::RANGE4 => { assert!(msirange_to_hertz(range).0 <= 24_000_000); } _ => {} } // RM0456 § 11.8.2: spin until MSIS is off or MSIS is ready before setting its range loop { let cr = RCC.cr().read(); if cr.msison() == false || cr.msisrdy() == true { break; } } RCC.icscr1().modify(|w| { w.set_msisrange(range); w.set_msirgsel(Msirgsel::RCC_ICSCR1); }); RCC.cr().write(|w| { w.set_msipllen(false); w.set_msison(true); }); while !RCC.cr().read().msisrdy() {} msirange_to_hertz(range) } } impl Default for Config { fn default() -> Self { Self { mux: ClockSrc::default(), ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, apb3_pre: APBPrescaler::DIV1, hsi48: false, voltage_range: VoltageScale::RANGE3, ls: Default::default(), } } } pub(crate) unsafe fn init(config: Config) { // Ensure PWR peripheral clock is enabled RCC.ahb3enr().modify(|w| { w.set_pwren(true); }); RCC.ahb3enr().read(); // synchronize // Set the requested power mode PWR.vosr().modify(|w| { w.set_vos(config.voltage_range); }); while !PWR.vosr().read().vosrdy() {} let sys_clk = match config.mux { ClockSrc::MSI(range) => config.init_msis(range), ClockSrc::HSE(freq) => config.init_hse(freq), ClockSrc::HSI16 => config.init_hsi16(), ClockSrc::PLL1R(pll) => { // Configure the PLL source let source_clk = match pll.source { PllSrc::MSIS(range) => config.init_msis(range), PllSrc::HSE(hertz) => config.init_hse(hertz), PllSrc::HSI16 => config.init_hsi16(), }; // Calculate the reference clock, which is the source divided by m let reference_clk = source_clk / pll.m; // Check limits per RM0456 § 11.4.6 assert!(Hertz::mhz(4) <= reference_clk && reference_clk <= Hertz::mhz(16)); // Calculate the PLL1 VCO clock and PLL1 R output clock let pll1_clk = reference_clk * pll.n; let pll1r_clk = pll1_clk / pll.r; // Check system clock per RM0456 § 11.4.9 assert!(pll1r_clk <= Hertz::mhz(160)); // Check PLL clocks per RM0456 § 11.4.10 match config.voltage_range { VoltageScale::RANGE1 => { assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544)); assert!(pll1r_clk <= Hertz::mhz(208)); } VoltageScale::RANGE2 => { assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544)); assert!(pll1r_clk <= Hertz::mhz(110)); } VoltageScale::RANGE3 => { assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(330)); assert!(pll1r_clk <= Hertz::mhz(55)); } VoltageScale::RANGE4 => { panic!("PLL is unavailable in voltage range 4"); } } // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler // value that results in an output between 4 and 16 MHz for the PWR EPOD boost let mboost = if pll1r_clk >= Hertz::mhz(55) { // source_clk can be up to 50 MHz, so there's just a few cases: if source_clk > Hertz::mhz(32) { // Divide by 4, giving EPOD 8-12.5 MHz Pllmboost::DIV4 } else if source_clk > Hertz::mhz(16) { // Divide by 2, giving EPOD 8-16 MHz Pllmboost::DIV2 } else { // Bypass, giving EPOD 4-16 MHz Pllmboost::DIV1 } } else { // Nothing to do Pllmboost::DIV1 }; // Disable the PLL, and wait for it to disable RCC.cr().modify(|w| w.set_pllon(0, false)); while RCC.cr().read().pllrdy(0) {} // Configure the PLL RCC.pll1cfgr().write(|w| { // Configure PLL1 source and prescaler w.set_pllsrc(pll.source.into()); w.set_pllm(pll.m); // Configure PLL1 input frequncy range let input_range = if reference_clk <= Hertz::mhz(8) { Pllrge::FREQ_4TO8MHZ } else { Pllrge::FREQ_8TO16MHZ }; w.set_pllrge(input_range); // Set the prescaler for PWR EPOD w.set_pllmboost(mboost); // Enable PLL1R output w.set_pllren(true); }); // Configure the PLL divisors RCC.pll1divr().modify(|w| { // Set the VCO multiplier w.set_plln(pll.n); // Set the R output divisor w.set_pllr(pll.r); }); // Do we need the EPOD booster to reach the target clock speed per § 10.5.4? if pll1r_clk >= Hertz::mhz(55) { // Enable the booster PWR.vosr().modify(|w| { w.set_boosten(true); }); while !PWR.vosr().read().boostrdy() {} } // Enable the PLL RCC.cr().modify(|w| w.set_pllon(0, true)); while !RCC.cr().read().pllrdy(0) {} pll1r_clk } }; if config.hsi48 { RCC.cr().modify(|w| w.set_hsi48on(true)); while !RCC.cr().read().hsi48rdy() {} } // The clock source is ready // Calculate and set the flash wait states let wait_states = match config.voltage_range { // VOS 1 range VCORE 1.26V - 1.40V VoltageScale::RANGE1 => { if sys_clk.0 < 32_000_000 { 0 } else if sys_clk.0 < 64_000_000 { 1 } else if sys_clk.0 < 96_000_000 { 2 } else if sys_clk.0 < 128_000_000 { 3 } else { 4 } } // VOS 2 range VCORE 1.15V - 1.26V VoltageScale::RANGE2 => { if sys_clk.0 < 30_000_000 { 0 } else if sys_clk.0 < 60_000_000 { 1 } else if sys_clk.0 < 90_000_000 { 2 } else { 3 } } // VOS 3 range VCORE 1.05V - 1.15V VoltageScale::RANGE3 => { if sys_clk.0 < 24_000_000 { 0 } else if sys_clk.0 < 48_000_000 { 1 } else { 2 } } // VOS 4 range VCORE 0.95V - 1.05V VoltageScale::RANGE4 => { if sys_clk.0 < 12_000_000 { 0 } else { 1 } } }; FLASH.acr().modify(|w| { w.set_latency(wait_states); }); // Switch the system clock source RCC.cfgr1().modify(|w| { w.set_sw(config.mux.into()); }); // RM0456 § 11.4.9 specifies maximum bus frequencies per voltage range, but the maximum bus // frequency for each voltage range exactly matches the maximum permitted PLL output frequency. // Given that: // // 1. Any bus frequency can never exceed the system clock frequency; // 2. We checked the PLL output frequency if we're using it as a system clock; // 3. The maximum HSE frequencies at each voltage range are lower than the bus limits, and // we checked the HSE frequency if configured as a system clock; and // 4. The maximum frequencies from the other clock sources are lower than the lowest bus // frequency limit // // ...then we do not need to perform additional bus-related frequency checks. // Configure the bus prescalers RCC.cfgr2().modify(|w| { w.set_hpre(config.ahb_pre); w.set_ppre1(config.apb1_pre); w.set_ppre2(config.apb2_pre); }); RCC.cfgr3().modify(|w| { w.set_ppre3(config.apb3_pre); }); let ahb_freq = sys_clk / config.ahb_pre; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let freq = ahb_freq / pre; (freq, freq * 2u32) } }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let freq = ahb_freq / pre; (freq, freq * 2u32) } }; let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let freq = ahb_freq / pre; (freq, freq * 2u32) } }; let rtc = config.ls.init(); set_freqs(Clocks { sys: sys_clk, ahb1: ahb_freq, ahb2: ahb_freq, ahb3: ahb_freq, apb1: apb1_freq, apb2: apb2_freq, apb3: apb3_freq, apb1_tim: apb1_tim_freq, apb2_tim: apb2_tim_freq, rtc, }); } fn msirange_to_hertz(range: Msirange) -> Hertz { match range { Msirange::RANGE_48MHZ => Hertz(48_000_000), Msirange::RANGE_24MHZ => Hertz(24_000_000), Msirange::RANGE_16MHZ => Hertz(16_000_000), Msirange::RANGE_12MHZ => Hertz(12_000_000), Msirange::RANGE_4MHZ => Hertz(4_000_000), Msirange::RANGE_2MHZ => Hertz(2_000_000), Msirange::RANGE_1_33MHZ => Hertz(1_330_000), Msirange::RANGE_1MHZ => Hertz(1_000_000), Msirange::RANGE_3_072MHZ => Hertz(3_072_000), Msirange::RANGE_1_536MHZ => Hertz(1_536_000), Msirange::RANGE_1_024MHZ => Hertz(1_024_000), Msirange::RANGE_768KHZ => Hertz(768_000), Msirange::RANGE_400KHZ => Hertz(400_000), Msirange::RANGE_200KHZ => Hertz(200_000), Msirange::RANGE_133KHZ => Hertz(133_000), Msirange::RANGE_100KHZ => Hertz(100_000), } }