stm32/rcc: change family-specific code from dirs to single files.
Consistent with how other peripherals handle their versions.
This commit is contained in:
		@@ -201,7 +201,7 @@ impl<'d> Rcc<'d> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
 | 
			
		||||
    let clocks = rcc.freeze();
 | 
			
		||||
    set_freqs(clocks);
 | 
			
		||||
@@ -207,7 +207,7 @@ impl<'d> Rcc<'d> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
 | 
			
		||||
    let clocks = rcc.freeze();
 | 
			
		||||
    set_freqs(clocks);
 | 
			
		||||
@@ -54,7 +54,7 @@ struct PllConfig {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Initialize and Set the clock frequencies
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let r = <peripherals::RCC as embassy::util::Steal>::steal();
 | 
			
		||||
    let clocks = Rcc::new(r, config).freeze();
 | 
			
		||||
    set_freqs(clocks);
 | 
			
		||||
@@ -5,9 +5,6 @@ use crate::time::Hertz;
 | 
			
		||||
use core::marker::PhantomData;
 | 
			
		||||
use embassy::util::Unborrow;
 | 
			
		||||
 | 
			
		||||
mod max;
 | 
			
		||||
use max::{PCLK1_MAX, PCLK2_MAX};
 | 
			
		||||
 | 
			
		||||
const HSI: u32 = 16_000_000;
 | 
			
		||||
 | 
			
		||||
/// Clocks configutation
 | 
			
		||||
@@ -88,7 +85,7 @@ impl<'d> Rcc<'d> {
 | 
			
		||||
            .config
 | 
			
		||||
            .pclk1
 | 
			
		||||
            .map(|p| p.0)
 | 
			
		||||
            .unwrap_or_else(|| core::cmp::min(PCLK1_MAX, hclk));
 | 
			
		||||
            .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
 | 
			
		||||
        let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
 | 
			
		||||
            0 => unreachable!(),
 | 
			
		||||
            1 => (0b000, 1),
 | 
			
		||||
@@ -101,13 +98,13 @@ impl<'d> Rcc<'d> {
 | 
			
		||||
 | 
			
		||||
        // Calculate real APB1 clock
 | 
			
		||||
        let pclk1 = hclk / ppre1;
 | 
			
		||||
        assert!(pclk1 <= PCLK1_MAX);
 | 
			
		||||
        assert!(pclk1 <= max::PCLK1_MAX);
 | 
			
		||||
 | 
			
		||||
        let pclk2 = self
 | 
			
		||||
            .config
 | 
			
		||||
            .pclk2
 | 
			
		||||
            .map(|p| p.0)
 | 
			
		||||
            .unwrap_or_else(|| core::cmp::min(PCLK2_MAX, hclk));
 | 
			
		||||
            .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
 | 
			
		||||
        let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
 | 
			
		||||
            0 => unreachable!(),
 | 
			
		||||
            1 => (0b000, 1),
 | 
			
		||||
@@ -120,7 +117,7 @@ impl<'d> Rcc<'d> {
 | 
			
		||||
 | 
			
		||||
        // Calculate real APB2 clock
 | 
			
		||||
        let pclk2 = hclk / ppre2;
 | 
			
		||||
        assert!(pclk2 <= PCLK2_MAX);
 | 
			
		||||
        assert!(pclk2 <= max::PCLK2_MAX);
 | 
			
		||||
 | 
			
		||||
        Self::flash_setup(sysclk);
 | 
			
		||||
 | 
			
		||||
@@ -298,7 +295,7 @@ impl<'d> Rcc<'d> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let r = <peripherals::RCC as embassy::util::Steal>::steal();
 | 
			
		||||
    let clocks = Rcc::new(r, config).freeze();
 | 
			
		||||
    set_freqs(clocks);
 | 
			
		||||
@@ -309,3 +306,27 @@ struct PllResults {
 | 
			
		||||
    pllsysclk: Option<u32>,
 | 
			
		||||
    pll48clk: Option<u32>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod max {
 | 
			
		||||
    #[cfg(stm32f401)]
 | 
			
		||||
    pub(crate) const SYSCLK_MAX: u32 = 84_000_000;
 | 
			
		||||
 | 
			
		||||
    #[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
 | 
			
		||||
    pub(crate) const SYSCLK_MAX: u32 = 168_000_000;
 | 
			
		||||
 | 
			
		||||
    #[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
 | 
			
		||||
    pub(crate) const SYSCLK_MAX: u32 = 100_000_000;
 | 
			
		||||
 | 
			
		||||
    #[cfg(any(
 | 
			
		||||
        stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,
 | 
			
		||||
    ))]
 | 
			
		||||
    pub(crate) const SYSCLK_MAX: u32 = 180_000_000;
 | 
			
		||||
 | 
			
		||||
    #[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
 | 
			
		||||
    pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX;
 | 
			
		||||
 | 
			
		||||
    #[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
 | 
			
		||||
    pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
 | 
			
		||||
 | 
			
		||||
    pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,21 +0,0 @@
 | 
			
		||||
#[cfg(stm32f401)]
 | 
			
		||||
pub(crate) const SYSCLK_MAX: u32 = 84_000_000;
 | 
			
		||||
 | 
			
		||||
#[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
 | 
			
		||||
pub(crate) const SYSCLK_MAX: u32 = 168_000_000;
 | 
			
		||||
 | 
			
		||||
#[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
 | 
			
		||||
pub(crate) const SYSCLK_MAX: u32 = 100_000_000;
 | 
			
		||||
 | 
			
		||||
#[cfg(any(
 | 
			
		||||
    stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,
 | 
			
		||||
))]
 | 
			
		||||
pub(crate) const SYSCLK_MAX: u32 = 180_000_000;
 | 
			
		||||
 | 
			
		||||
#[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
 | 
			
		||||
pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX;
 | 
			
		||||
 | 
			
		||||
#[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
 | 
			
		||||
pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
 | 
			
		||||
 | 
			
		||||
pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2;
 | 
			
		||||
@@ -1,5 +1,3 @@
 | 
			
		||||
mod max;
 | 
			
		||||
 | 
			
		||||
use crate::pac::{FLASH, PWR, RCC};
 | 
			
		||||
use crate::peripherals;
 | 
			
		||||
use crate::rcc::{get_freqs, set_freqs, Clocks};
 | 
			
		||||
@@ -334,7 +332,7 @@ impl<'d> Rcc<'d> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let r = <peripherals::RCC as embassy::util::Steal>::steal();
 | 
			
		||||
    let clocks = Rcc::new(r, config).freeze();
 | 
			
		||||
    set_freqs(clocks);
 | 
			
		||||
@@ -345,3 +343,25 @@ struct PllResults {
 | 
			
		||||
    pllsysclk: Option<u32>,
 | 
			
		||||
    pll48clk: Option<u32>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod max {
 | 
			
		||||
    pub(crate) const HSE_OSC_MIN: u32 = 4_000_000;
 | 
			
		||||
    pub(crate) const HSE_OSC_MAX: u32 = 26_000_000;
 | 
			
		||||
    pub(crate) const HSE_BYPASS_MIN: u32 = 1_000_000;
 | 
			
		||||
    pub(crate) const HSE_BYPASS_MAX: u32 = 50_000_000;
 | 
			
		||||
 | 
			
		||||
    pub(crate) const HCLK_MAX: u32 = 216_000_000;
 | 
			
		||||
    pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 180_000_000;
 | 
			
		||||
 | 
			
		||||
    pub(crate) const SYSCLK_MIN: u32 = 12_500_000;
 | 
			
		||||
    pub(crate) const SYSCLK_MAX: u32 = 216_000_000;
 | 
			
		||||
 | 
			
		||||
    pub(crate) const PCLK1_MIN: u32 = SYSCLK_MIN;
 | 
			
		||||
    pub(crate) const PCLK1_MAX: u32 = SYSCLK_MAX / 4;
 | 
			
		||||
 | 
			
		||||
    pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN;
 | 
			
		||||
    pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
 | 
			
		||||
 | 
			
		||||
    pub(crate) const PLL_48_CLK: u32 = 48_000_000;
 | 
			
		||||
    pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,19 +0,0 @@
 | 
			
		||||
pub(crate) const HSE_OSC_MIN: u32 = 4_000_000;
 | 
			
		||||
pub(crate) const HSE_OSC_MAX: u32 = 26_000_000;
 | 
			
		||||
pub(crate) const HSE_BYPASS_MIN: u32 = 1_000_000;
 | 
			
		||||
pub(crate) const HSE_BYPASS_MAX: u32 = 50_000_000;
 | 
			
		||||
 | 
			
		||||
pub(crate) const HCLK_MAX: u32 = 216_000_000;
 | 
			
		||||
pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 180_000_000;
 | 
			
		||||
 | 
			
		||||
pub(crate) const SYSCLK_MIN: u32 = 12_500_000;
 | 
			
		||||
pub(crate) const SYSCLK_MAX: u32 = 216_000_000;
 | 
			
		||||
 | 
			
		||||
pub(crate) const PCLK1_MIN: u32 = SYSCLK_MIN;
 | 
			
		||||
pub(crate) const PCLK1_MAX: u32 = SYSCLK_MAX / 4;
 | 
			
		||||
 | 
			
		||||
pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN;
 | 
			
		||||
pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
 | 
			
		||||
 | 
			
		||||
pub(crate) const PLL_48_CLK: u32 = 48_000_000;
 | 
			
		||||
pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
 | 
			
		||||
@@ -227,7 +227,7 @@ impl RccExt for RCC {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let r = <peripherals::RCC as embassy::util::Steal>::steal();
 | 
			
		||||
    let clocks = r.freeze(config);
 | 
			
		||||
    set_freqs(clocks);
 | 
			
		||||
@@ -203,7 +203,7 @@ impl RccExt for RCC {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let r = <peripherals::RCC as embassy::util::Steal>::steal();
 | 
			
		||||
    let clocks = r.freeze(config);
 | 
			
		||||
    set_freqs(clocks);
 | 
			
		||||
@@ -13,8 +13,6 @@ use crate::pwr::{Power, VoltageScale};
 | 
			
		||||
use crate::rcc::{set_freqs, Clocks};
 | 
			
		||||
use crate::time::Hertz;
 | 
			
		||||
 | 
			
		||||
mod pll;
 | 
			
		||||
use pll::pll_setup;
 | 
			
		||||
pub use pll::PllConfig;
 | 
			
		||||
 | 
			
		||||
const HSI: Hertz = Hertz(64_000_000);
 | 
			
		||||
@@ -116,11 +114,11 @@ impl<'d> Rcc<'d> {
 | 
			
		||||
 | 
			
		||||
        // NOTE(unsafe) We have exclusive access to the RCC
 | 
			
		||||
        let (pll1_p_ck, pll1_q_ck, pll1_r_ck) =
 | 
			
		||||
            unsafe { pll_setup(srcclk.0, &self.config.pll1, 0) };
 | 
			
		||||
            unsafe { pll::pll_setup(srcclk.0, &self.config.pll1, 0) };
 | 
			
		||||
        let (pll2_p_ck, pll2_q_ck, pll2_r_ck) =
 | 
			
		||||
            unsafe { pll_setup(srcclk.0, &self.config.pll2, 1) };
 | 
			
		||||
            unsafe { pll::pll_setup(srcclk.0, &self.config.pll2, 1) };
 | 
			
		||||
        let (pll3_p_ck, pll3_q_ck, pll3_r_ck) =
 | 
			
		||||
            unsafe { pll_setup(srcclk.0, &self.config.pll3, 2) };
 | 
			
		||||
            unsafe { pll::pll_setup(srcclk.0, &self.config.pll3, 2) };
 | 
			
		||||
 | 
			
		||||
        let sys_ck = if sys_use_pll1_p {
 | 
			
		||||
            Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
 | 
			
		||||
@@ -683,7 +681,7 @@ impl<'d, T: McoInstance> Mco<'d, T> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let mut power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal(), false);
 | 
			
		||||
    let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
 | 
			
		||||
    let core_clocks = rcc.freeze(&mut power);
 | 
			
		||||
@@ -700,3 +698,151 @@ pub unsafe fn init(config: Config) {
 | 
			
		||||
        apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2),
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod pll {
 | 
			
		||||
    use super::{Hertz, RCC};
 | 
			
		||||
 | 
			
		||||
    const VCO_MIN: u32 = 150_000_000;
 | 
			
		||||
    const VCO_MAX: u32 = 420_000_000;
 | 
			
		||||
 | 
			
		||||
    #[derive(Default)]
 | 
			
		||||
    pub struct PllConfig {
 | 
			
		||||
        pub p_ck: Option<Hertz>,
 | 
			
		||||
        pub q_ck: Option<Hertz>,
 | 
			
		||||
        pub r_ck: Option<Hertz>,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(super) struct PllConfigResults {
 | 
			
		||||
        pub ref_x_ck: u32,
 | 
			
		||||
        pub pll_x_m: u32,
 | 
			
		||||
        pub pll_x_p: u32,
 | 
			
		||||
        pub vco_ck_target: u32,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
 | 
			
		||||
        let pll_x_p = if plln == 0 {
 | 
			
		||||
            if output > VCO_MAX / 2 {
 | 
			
		||||
                1
 | 
			
		||||
            } else {
 | 
			
		||||
                ((VCO_MAX / output) | 1) - 1 // Must be even or unity
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // Specific to PLL2/3, will subtract 1 later
 | 
			
		||||
            if output > VCO_MAX / 2 {
 | 
			
		||||
                1
 | 
			
		||||
            } else {
 | 
			
		||||
                VCO_MAX / output
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let vco_ck = output + pll_x_p;
 | 
			
		||||
 | 
			
		||||
        assert!(pll_x_p < 128);
 | 
			
		||||
        assert!(vco_ck >= VCO_MIN);
 | 
			
		||||
        assert!(vco_ck <= VCO_MAX);
 | 
			
		||||
 | 
			
		||||
        (vco_ck, pll_x_p)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// # Safety
 | 
			
		||||
    ///
 | 
			
		||||
    /// Must have exclusive access to the RCC register block
 | 
			
		||||
    unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
 | 
			
		||||
        use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
 | 
			
		||||
 | 
			
		||||
        let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
 | 
			
		||||
 | 
			
		||||
        // Input divisor, resulting in a reference clock in the range
 | 
			
		||||
        // 1 to 2 MHz. Choose the highest reference clock (lowest m)
 | 
			
		||||
        let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
 | 
			
		||||
        assert!(pll_x_m < 64);
 | 
			
		||||
 | 
			
		||||
        // Calculate resulting reference clock
 | 
			
		||||
        let ref_x_ck = pll_src / pll_x_m;
 | 
			
		||||
        assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
 | 
			
		||||
 | 
			
		||||
        RCC.pllcfgr().modify(|w| {
 | 
			
		||||
            w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO);
 | 
			
		||||
            w.set_pllrge(plln, Pllrge::RANGE1);
 | 
			
		||||
        });
 | 
			
		||||
        PllConfigResults {
 | 
			
		||||
            ref_x_ck,
 | 
			
		||||
            pll_x_m,
 | 
			
		||||
            pll_x_p,
 | 
			
		||||
            vco_ck_target,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// # Safety
 | 
			
		||||
    ///
 | 
			
		||||
    /// Must have exclusive access to the RCC register block
 | 
			
		||||
    pub(super) unsafe fn pll_setup(
 | 
			
		||||
        pll_src: u32,
 | 
			
		||||
        config: &PllConfig,
 | 
			
		||||
        plln: usize,
 | 
			
		||||
    ) -> (Option<u32>, Option<u32>, Option<u32>) {
 | 
			
		||||
        use crate::pac::rcc::vals::Divp;
 | 
			
		||||
 | 
			
		||||
        match config.p_ck {
 | 
			
		||||
            Some(requested_output) => {
 | 
			
		||||
                let config_results = vco_setup(pll_src, requested_output.0, plln);
 | 
			
		||||
                let PllConfigResults {
 | 
			
		||||
                    ref_x_ck,
 | 
			
		||||
                    pll_x_m,
 | 
			
		||||
                    pll_x_p,
 | 
			
		||||
                    vco_ck_target,
 | 
			
		||||
                } = config_results;
 | 
			
		||||
 | 
			
		||||
                RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
 | 
			
		||||
 | 
			
		||||
                // Feedback divider. Integer only
 | 
			
		||||
                let pll_x_n = vco_ck_target / ref_x_ck;
 | 
			
		||||
                assert!(pll_x_n >= 4);
 | 
			
		||||
                assert!(pll_x_n <= 512);
 | 
			
		||||
                RCC.plldivr(plln)
 | 
			
		||||
                    .modify(|w| w.set_divn1((pll_x_n - 1) as u16));
 | 
			
		||||
 | 
			
		||||
                // No FRACN
 | 
			
		||||
                RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
 | 
			
		||||
                let vco_ck = ref_x_ck * pll_x_n;
 | 
			
		||||
 | 
			
		||||
                RCC.plldivr(plln)
 | 
			
		||||
                    .modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8)));
 | 
			
		||||
                RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
 | 
			
		||||
 | 
			
		||||
                // Calulate additional output dividers
 | 
			
		||||
                let q_ck = match config.q_ck {
 | 
			
		||||
                    Some(Hertz(ck)) if ck > 0 => {
 | 
			
		||||
                        let div = (vco_ck + ck - 1) / ck;
 | 
			
		||||
                        RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
 | 
			
		||||
                        RCC.pllcfgr().modify(|w| w.set_divqen(plln, true));
 | 
			
		||||
                        Some(vco_ck / div)
 | 
			
		||||
                    }
 | 
			
		||||
                    _ => None,
 | 
			
		||||
                };
 | 
			
		||||
                let r_ck = match config.r_ck {
 | 
			
		||||
                    Some(Hertz(ck)) if ck > 0 => {
 | 
			
		||||
                        let div = (vco_ck + ck - 1) / ck;
 | 
			
		||||
                        RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
 | 
			
		||||
                        RCC.pllcfgr().modify(|w| w.set_divren(plln, true));
 | 
			
		||||
                        Some(vco_ck / div)
 | 
			
		||||
                    }
 | 
			
		||||
                    _ => None,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                (Some(vco_ck / pll_x_p), q_ck, r_ck)
 | 
			
		||||
            }
 | 
			
		||||
            None => {
 | 
			
		||||
                assert!(
 | 
			
		||||
                    config.q_ck.is_none(),
 | 
			
		||||
                    "Must set PLL P clock for Q clock to take effect!"
 | 
			
		||||
                );
 | 
			
		||||
                assert!(
 | 
			
		||||
                    config.r_ck.is_none(),
 | 
			
		||||
                    "Must set PLL P clock for R clock to take effect!"
 | 
			
		||||
                );
 | 
			
		||||
                (None, None, None)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,145 +0,0 @@
 | 
			
		||||
use super::{Hertz, RCC};
 | 
			
		||||
 | 
			
		||||
const VCO_MIN: u32 = 150_000_000;
 | 
			
		||||
const VCO_MAX: u32 = 420_000_000;
 | 
			
		||||
 | 
			
		||||
#[derive(Default)]
 | 
			
		||||
pub struct PllConfig {
 | 
			
		||||
    pub p_ck: Option<Hertz>,
 | 
			
		||||
    pub q_ck: Option<Hertz>,
 | 
			
		||||
    pub r_ck: Option<Hertz>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(super) struct PllConfigResults {
 | 
			
		||||
    pub ref_x_ck: u32,
 | 
			
		||||
    pub pll_x_m: u32,
 | 
			
		||||
    pub pll_x_p: u32,
 | 
			
		||||
    pub vco_ck_target: u32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
 | 
			
		||||
    let pll_x_p = if plln == 0 {
 | 
			
		||||
        if output > VCO_MAX / 2 {
 | 
			
		||||
            1
 | 
			
		||||
        } else {
 | 
			
		||||
            ((VCO_MAX / output) | 1) - 1 // Must be even or unity
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        // Specific to PLL2/3, will subtract 1 later
 | 
			
		||||
        if output > VCO_MAX / 2 {
 | 
			
		||||
            1
 | 
			
		||||
        } else {
 | 
			
		||||
            VCO_MAX / output
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let vco_ck = output + pll_x_p;
 | 
			
		||||
 | 
			
		||||
    assert!(pll_x_p < 128);
 | 
			
		||||
    assert!(vco_ck >= VCO_MIN);
 | 
			
		||||
    assert!(vco_ck <= VCO_MAX);
 | 
			
		||||
 | 
			
		||||
    (vco_ck, pll_x_p)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// # Safety
 | 
			
		||||
///
 | 
			
		||||
/// Must have exclusive access to the RCC register block
 | 
			
		||||
unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
 | 
			
		||||
    use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
 | 
			
		||||
 | 
			
		||||
    let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
 | 
			
		||||
 | 
			
		||||
    // Input divisor, resulting in a reference clock in the range
 | 
			
		||||
    // 1 to 2 MHz. Choose the highest reference clock (lowest m)
 | 
			
		||||
    let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
 | 
			
		||||
    assert!(pll_x_m < 64);
 | 
			
		||||
 | 
			
		||||
    // Calculate resulting reference clock
 | 
			
		||||
    let ref_x_ck = pll_src / pll_x_m;
 | 
			
		||||
    assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
 | 
			
		||||
 | 
			
		||||
    RCC.pllcfgr().modify(|w| {
 | 
			
		||||
        w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO);
 | 
			
		||||
        w.set_pllrge(plln, Pllrge::RANGE1);
 | 
			
		||||
    });
 | 
			
		||||
    PllConfigResults {
 | 
			
		||||
        ref_x_ck,
 | 
			
		||||
        pll_x_m,
 | 
			
		||||
        pll_x_p,
 | 
			
		||||
        vco_ck_target,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// # Safety
 | 
			
		||||
///
 | 
			
		||||
/// Must have exclusive access to the RCC register block
 | 
			
		||||
pub(super) unsafe fn pll_setup(
 | 
			
		||||
    pll_src: u32,
 | 
			
		||||
    config: &PllConfig,
 | 
			
		||||
    plln: usize,
 | 
			
		||||
) -> (Option<u32>, Option<u32>, Option<u32>) {
 | 
			
		||||
    use crate::pac::rcc::vals::Divp;
 | 
			
		||||
 | 
			
		||||
    match config.p_ck {
 | 
			
		||||
        Some(requested_output) => {
 | 
			
		||||
            let config_results = vco_setup(pll_src, requested_output.0, plln);
 | 
			
		||||
            let PllConfigResults {
 | 
			
		||||
                ref_x_ck,
 | 
			
		||||
                pll_x_m,
 | 
			
		||||
                pll_x_p,
 | 
			
		||||
                vco_ck_target,
 | 
			
		||||
            } = config_results;
 | 
			
		||||
 | 
			
		||||
            RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
 | 
			
		||||
 | 
			
		||||
            // Feedback divider. Integer only
 | 
			
		||||
            let pll_x_n = vco_ck_target / ref_x_ck;
 | 
			
		||||
            assert!(pll_x_n >= 4);
 | 
			
		||||
            assert!(pll_x_n <= 512);
 | 
			
		||||
            RCC.plldivr(plln)
 | 
			
		||||
                .modify(|w| w.set_divn1((pll_x_n - 1) as u16));
 | 
			
		||||
 | 
			
		||||
            // No FRACN
 | 
			
		||||
            RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
 | 
			
		||||
            let vco_ck = ref_x_ck * pll_x_n;
 | 
			
		||||
 | 
			
		||||
            RCC.plldivr(plln)
 | 
			
		||||
                .modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8)));
 | 
			
		||||
            RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
 | 
			
		||||
 | 
			
		||||
            // Calulate additional output dividers
 | 
			
		||||
            let q_ck = match config.q_ck {
 | 
			
		||||
                Some(Hertz(ck)) if ck > 0 => {
 | 
			
		||||
                    let div = (vco_ck + ck - 1) / ck;
 | 
			
		||||
                    RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
 | 
			
		||||
                    RCC.pllcfgr().modify(|w| w.set_divqen(plln, true));
 | 
			
		||||
                    Some(vco_ck / div)
 | 
			
		||||
                }
 | 
			
		||||
                _ => None,
 | 
			
		||||
            };
 | 
			
		||||
            let r_ck = match config.r_ck {
 | 
			
		||||
                Some(Hertz(ck)) if ck > 0 => {
 | 
			
		||||
                    let div = (vco_ck + ck - 1) / ck;
 | 
			
		||||
                    RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
 | 
			
		||||
                    RCC.pllcfgr().modify(|w| w.set_divren(plln, true));
 | 
			
		||||
                    Some(vco_ck / div)
 | 
			
		||||
                }
 | 
			
		||||
                _ => None,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            (Some(vco_ck / pll_x_p), q_ck, r_ck)
 | 
			
		||||
        }
 | 
			
		||||
        None => {
 | 
			
		||||
            assert!(
 | 
			
		||||
                config.q_ck.is_none(),
 | 
			
		||||
                "Must set PLL P clock for Q clock to take effect!"
 | 
			
		||||
            );
 | 
			
		||||
            assert!(
 | 
			
		||||
                config.r_ck.is_none(),
 | 
			
		||||
                "Must set PLL P clock for R clock to take effect!"
 | 
			
		||||
            );
 | 
			
		||||
            (None, None, None)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -430,7 +430,7 @@ impl RccExt for RCC {
 | 
			
		||||
#[derive(Clone, Copy)]
 | 
			
		||||
pub struct HSI48(());
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let r = <peripherals::RCC as embassy::util::Steal>::steal();
 | 
			
		||||
    let clocks = r.freeze(config);
 | 
			
		||||
    set_freqs(clocks);
 | 
			
		||||
@@ -254,7 +254,7 @@ impl RccExt for RCC {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let r = <peripherals::RCC as embassy::util::Steal>::steal();
 | 
			
		||||
    let clocks = r.freeze(config);
 | 
			
		||||
    set_freqs(clocks);
 | 
			
		||||
@@ -482,7 +482,7 @@ impl RccExt for RCC {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let r = <peripherals::RCC as embassy::util::Steal>::steal();
 | 
			
		||||
    let clocks = r.freeze(config);
 | 
			
		||||
    set_freqs(clocks);
 | 
			
		||||
@@ -4,6 +4,23 @@ use crate::peripherals;
 | 
			
		||||
use crate::time::Hertz;
 | 
			
		||||
use core::mem::MaybeUninit;
 | 
			
		||||
 | 
			
		||||
#[cfg_attr(any(rcc_f0, rcc_f0x0), path = "f0.rs")]
 | 
			
		||||
#[cfg_attr(rcc_f1, path = "f1.rs")]
 | 
			
		||||
#[cfg_attr(rcc_f3, path = "f3.rs")]
 | 
			
		||||
#[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")]
 | 
			
		||||
#[cfg_attr(rcc_f7, path = "f7.rs")]
 | 
			
		||||
#[cfg_attr(rcc_g0, path = "g0.rs")]
 | 
			
		||||
#[cfg_attr(rcc_g4, path = "g4.rs")]
 | 
			
		||||
#[cfg_attr(any(rcc_h7, rcc_h7ab), path = "h7.rs")]
 | 
			
		||||
#[cfg_attr(rcc_l0, path = "l0.rs")]
 | 
			
		||||
#[cfg_attr(rcc_l1, path = "l1.rs")]
 | 
			
		||||
#[cfg_attr(rcc_l4, path = "l4.rs")]
 | 
			
		||||
#[cfg_attr(rcc_u5, path = "u5.rs")]
 | 
			
		||||
#[cfg_attr(rcc_wb, path = "wb.rs")]
 | 
			
		||||
#[cfg_attr(rcc_wl5, path = "wl5.rs")]
 | 
			
		||||
mod _version;
 | 
			
		||||
pub use _version::*;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy)]
 | 
			
		||||
pub struct Clocks {
 | 
			
		||||
    pub sys: Hertz,
 | 
			
		||||
@@ -59,61 +76,15 @@ static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
 | 
			
		||||
/// Sets the clock frequencies
 | 
			
		||||
///
 | 
			
		||||
/// Safety: Sets a mutable global.
 | 
			
		||||
pub unsafe fn set_freqs(freqs: Clocks) {
 | 
			
		||||
pub(crate) unsafe fn set_freqs(freqs: Clocks) {
 | 
			
		||||
    CLOCK_FREQS.as_mut_ptr().write(freqs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Safety: Reads a mutable global.
 | 
			
		||||
pub unsafe fn get_freqs() -> &'static Clocks {
 | 
			
		||||
pub(crate) unsafe fn get_freqs() -> &'static Clocks {
 | 
			
		||||
    &*CLOCK_FREQS.as_ptr()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cfg_if::cfg_if! {
 | 
			
		||||
    if #[cfg(rcc_h7)] {
 | 
			
		||||
        mod h7;
 | 
			
		||||
        pub use h7::*;
 | 
			
		||||
    } else if #[cfg(rcc_l0)] {
 | 
			
		||||
        mod l0;
 | 
			
		||||
        pub use l0::*;
 | 
			
		||||
    } else if #[cfg(rcc_l1)] {
 | 
			
		||||
        mod l1;
 | 
			
		||||
        pub use l1::*;
 | 
			
		||||
    } else if #[cfg(rcc_l4)] {
 | 
			
		||||
        mod l4;
 | 
			
		||||
        pub use l4::*;
 | 
			
		||||
    } else if #[cfg(rcc_f1)] {
 | 
			
		||||
        mod f1;
 | 
			
		||||
        pub use f1::*;
 | 
			
		||||
    } else if #[cfg(rcc_f3)] {
 | 
			
		||||
        mod f3;
 | 
			
		||||
        pub use f3::*;
 | 
			
		||||
    } else if #[cfg(rcc_f4)] {
 | 
			
		||||
        mod f4;
 | 
			
		||||
        pub use f4::*;
 | 
			
		||||
    } else if #[cfg(rcc_f7)] {
 | 
			
		||||
        mod f7;
 | 
			
		||||
        pub use f7::*;
 | 
			
		||||
    } else if #[cfg(rcc_wb)] {
 | 
			
		||||
        mod wb;
 | 
			
		||||
        pub use wb::*;
 | 
			
		||||
    } else if #[cfg(rcc_wl5)] {
 | 
			
		||||
        mod wl5x;
 | 
			
		||||
        pub use wl5x::*;
 | 
			
		||||
    } else if #[cfg(any(rcc_f0, rcc_f0x0))] {
 | 
			
		||||
        mod f0;
 | 
			
		||||
        pub use f0::*;
 | 
			
		||||
    } else if #[cfg(any(rcc_g0))] {
 | 
			
		||||
        mod g0;
 | 
			
		||||
        pub use g0::*;
 | 
			
		||||
    } else if #[cfg(any(rcc_g4))] {
 | 
			
		||||
        mod g4;
 | 
			
		||||
        pub use g4::*;
 | 
			
		||||
    } else if #[cfg(any(rcc_u5))] {
 | 
			
		||||
        mod u5;
 | 
			
		||||
        pub use u5::*;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) mod sealed {
 | 
			
		||||
    pub trait RccPeripheral {
 | 
			
		||||
        fn frequency() -> crate::time::Hertz;
 | 
			
		||||
 
 | 
			
		||||
@@ -502,7 +502,7 @@ impl RccExt for RCC {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let r = <peripherals::RCC as embassy::util::Steal>::steal();
 | 
			
		||||
    let power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal());
 | 
			
		||||
    let clocks = r.freeze(config, &power);
 | 
			
		||||
@@ -206,7 +206,7 @@ impl RccExt for RCC {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let r = <peripherals::RCC as embassy::util::Steal>::steal();
 | 
			
		||||
    let clocks = r.freeze(config);
 | 
			
		||||
    set_freqs(clocks);
 | 
			
		||||
@@ -229,7 +229,7 @@ impl RccExt for RCC {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe fn init(config: Config) {
 | 
			
		||||
pub(crate) unsafe fn init(config: Config) {
 | 
			
		||||
    let r = <peripherals::RCC as embassy::util::Steal>::steal();
 | 
			
		||||
    let clocks = r.freeze(config);
 | 
			
		||||
    set_freqs(clocks);
 | 
			
		||||
		Reference in New Issue
	
	Block a user