diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index c8a0e170..117f3ed2 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -43,8 +43,6 @@ pub mod i2c; #[cfg(crc)] pub mod crc; pub mod pwm; -#[cfg(pwr)] -pub mod pwr; #[cfg(rng)] pub mod rng; #[cfg(sdmmc)] diff --git a/embassy-stm32/src/pwr/f3.rs b/embassy-stm32/src/pwr/f3.rs deleted file mode 100644 index 8b137891..00000000 --- a/embassy-stm32/src/pwr/f3.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/embassy-stm32/src/pwr/f4.rs b/embassy-stm32/src/pwr/f4.rs deleted file mode 100644 index 8b137891..00000000 --- a/embassy-stm32/src/pwr/f4.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/embassy-stm32/src/pwr/f7.rs b/embassy-stm32/src/pwr/f7.rs deleted file mode 100644 index 8b137891..00000000 --- a/embassy-stm32/src/pwr/f7.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/embassy-stm32/src/pwr/g0.rs b/embassy-stm32/src/pwr/g0.rs deleted file mode 100644 index 8b137891..00000000 --- a/embassy-stm32/src/pwr/g0.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/embassy-stm32/src/pwr/g4.rs b/embassy-stm32/src/pwr/g4.rs deleted file mode 100644 index 8b137891..00000000 --- a/embassy-stm32/src/pwr/g4.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/embassy-stm32/src/pwr/h7.rs b/embassy-stm32/src/pwr/h7.rs deleted file mode 100644 index 37b049a8..00000000 --- a/embassy-stm32/src/pwr/h7.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::pac::{PWR, RCC, SYSCFG}; -use crate::peripherals; - -/// Voltage Scale -/// -/// Represents the voltage range feeding the CPU core. The maximum core -/// clock frequency depends on this value. -#[derive(Copy, Clone, PartialEq)] -pub enum VoltageScale { - /// VOS 0 range VCORE 1.26V - 1.40V - Scale0, - /// VOS 1 range VCORE 1.15V - 1.26V - Scale1, - /// VOS 2 range VCORE 1.05V - 1.15V - Scale2, - /// VOS 3 range VCORE 0.95V - 1.05V - Scale3, -} - -/// Power Configuration -/// -/// Generated when the PWR peripheral is frozen. The existence of this -/// value indicates that the voltage scaling configuration can no -/// longer be changed. -pub struct Power { - pub(crate) vos: VoltageScale, -} - -impl Power { - pub fn new(_peri: peripherals::PWR, enable_overdrive: bool) -> Self { - // NOTE(unsafe) we have the PWR singleton - unsafe { - // NB. The lower bytes of CR3 can only be written once after - // POR, and must be written with a valid combination. Refer to - // RM0433 Rev 7 6.8.4. This is partially enforced by dropping - // `self` at the end of this method, but of course we cannot - // know what happened between the previous POR and here. - #[cfg(pwr_h7)] - PWR.cr3().modify(|w| { - w.set_scuen(true); - w.set_ldoen(true); - w.set_bypass(false); - }); - - #[cfg(pwr_h7smps)] - PWR.cr3().modify(|w| { - // hardcode "Direct SPMS" for now, this is what works on nucleos with the - // default solderbridge configuration. - w.set_sden(true); - w.set_ldoen(false); - }); - - // Validate the supply configuration. If you are stuck here, it is - // because the voltages on your board do not match those specified - // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset - // VOS = Scale 3, so check that the voltage on the VCAP pins = - // 1.0V. - while !PWR.csr1().read().actvosrdy() {} - - // Go to Scale 1 - PWR.d3cr().modify(|w| w.set_vos(0b11)); - while !PWR.d3cr().read().vosrdy() {} - - let vos = if !enable_overdrive { - VoltageScale::Scale1 - } else { - critical_section::with(|_| { - RCC.apb4enr().modify(|w| w.set_syscfgen(true)); - - SYSCFG.pwrcr().modify(|w| w.set_oden(1)); - }); - while !PWR.d3cr().read().vosrdy() {} - VoltageScale::Scale0 - }; - Self { vos } - } - } -} diff --git a/embassy-stm32/src/pwr/l1.rs b/embassy-stm32/src/pwr/l1.rs deleted file mode 100644 index 8b137891..00000000 --- a/embassy-stm32/src/pwr/l1.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/embassy-stm32/src/pwr/mod.rs b/embassy-stm32/src/pwr/mod.rs deleted file mode 100644 index d948c398..00000000 --- a/embassy-stm32/src/pwr/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[cfg_attr(any(pwr_h7, pwr_h7smps), path = "h7.rs")] -#[cfg_attr(pwr_f3, path = "f3.rs")] -#[cfg_attr(pwr_f4, path = "f4.rs")] -#[cfg_attr(pwr_f7, path = "f7.rs")] -#[cfg_attr(pwr_wl5, path = "wl5.rs")] -#[cfg_attr(pwr_g0, path = "g0.rs")] -#[cfg_attr(pwr_g4, path = "g4.rs")] -#[cfg_attr(pwr_l1, path = "l1.rs")] -#[cfg_attr(pwr_u5, path = "u5.rs")] -#[cfg_attr(pwr_wb55, path = "wb55.rs")] -mod _version; - -pub use _version::*; diff --git a/embassy-stm32/src/pwr/u5.rs b/embassy-stm32/src/pwr/u5.rs deleted file mode 100644 index a90659d9..00000000 --- a/embassy-stm32/src/pwr/u5.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::peripherals; - -/// Voltage Scale -/// -/// Represents the voltage range feeding the CPU core. The maximum core -/// clock frequency depends on this value. -#[derive(Copy, Clone, PartialEq)] -pub enum VoltageScale { - // Highest frequency - Range1, - Range2, - Range3, - // Lowest power - Range4, -} - -/// Power Configuration -/// -/// Generated when the PWR peripheral is frozen. The existence of this -/// value indicates that the voltage scaling configuration can no -/// longer be changed. -pub struct Power { - pub(crate) vos: VoltageScale, -} - -impl Power { - pub fn new(_peri: peripherals::PWR) -> Self { - Self { - vos: VoltageScale::Range4, - } - } -} diff --git a/embassy-stm32/src/pwr/wb55.rs b/embassy-stm32/src/pwr/wb55.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/embassy-stm32/src/pwr/wl5.rs b/embassy-stm32/src/pwr/wl5.rs deleted file mode 100644 index 8b137891..00000000 --- a/embassy-stm32/src/pwr/wl5.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs index 07a28cc3..1527afa0 100644 --- a/embassy-stm32/src/rcc/f0.rs +++ b/embassy-stm32/src/rcc/f0.rs @@ -1,9 +1,5 @@ -use core::marker::PhantomData; - -use embassy::util::Unborrow; - +use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Sw, Usbsw}; use crate::pac::{FLASH, RCC}; -use crate::peripherals; use crate::time::Hertz; use super::{set_freqs, Clocks}; @@ -28,181 +24,151 @@ pub struct Config { pub pclk: Option, } -pub struct Rcc<'d> { - inner: PhantomData<&'d ()>, - config: Config, -} - -impl<'d> Rcc<'d> { - pub fn new(_rcc: impl Unborrow + 'd, config: Config) -> Self { - Self { - inner: PhantomData, - config, - } - } - - pub fn freeze(self) -> Clocks { - use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Sw, Usbsw}; - - let sysclk = self.config.sys_ck.map(|v| v.0).unwrap_or(HSI); - - let (src_clk, use_hsi48) = self.config.hse.map(|v| (v.0, false)).unwrap_or_else(|| { - #[cfg(rcc_f0)] - if self.config.hsi48 { - return (48_000_000, true); - } - (HSI, false) - }); - - let (pllmul_bits, real_sysclk) = if sysclk == src_clk { - (None, sysclk) - } else { - let prediv = if self.config.hse.is_some() { 1 } else { 2 }; - let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2; - let pllmul = pllmul.max(2).min(16); - - let pllmul_bits = pllmul as u8 - 2; - let real_sysclk = pllmul * src_clk / prediv; - (Some(pllmul_bits), real_sysclk) - }; - - let hpre_bits = self - .config - .hclk - .map(|hclk| match real_sysclk / hclk.0 { - 0 => unreachable!(), - 1 => 0b0111, - 2 => 0b1000, - 3..=5 => 0b1001, - 6..=11 => 0b1010, - 12..=39 => 0b1011, - 40..=95 => 0b1100, - 96..=191 => 0b1101, - 192..=383 => 0b1110, - _ => 0b1111, - }) - .unwrap_or(0b0111); - let hclk = real_sysclk / (1 << (hpre_bits - 0b0111)); - - let ppre_bits = self - .config - .pclk - .map(|pclk| match hclk / pclk.0 { - 0 => unreachable!(), - 1 => 0b011, - 2 => 0b100, - 3..=5 => 0b101, - 6..=11 => 0b110, - _ => 0b111, - }) - .unwrap_or(0b011); - - let ppre: u8 = 1 << (ppre_bits - 0b011); - let pclk = hclk / u32::from(ppre); - - let timer_mul = if ppre == 1 { 1 } else { 2 }; - - // NOTE(safety) Atomic write - unsafe { - FLASH.acr().write(|w| { - let latency = if real_sysclk <= 24_000_000 { - 0 - } else if real_sysclk <= 48_000_000 { - 1 - } else { - 2 - }; - w.latency().0 = latency; - }); - } - - // NOTE(unsafe) We have exclusive access to the RCC - unsafe { - match (self.config.hse.is_some(), use_hsi48) { - (true, _) => { - RCC.cr().modify(|w| { - w.set_csson(true); - w.set_hseon(true); - - if self.config.bypass_hse { - w.set_hsebyp(Hsebyp::BYPASSED); - } - }); - while !RCC.cr().read().hserdy() {} - - if pllmul_bits.is_some() { - RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV)) - } - } - (false, true) => { - // use_hsi48 will always be false for rcc_f0x0 - #[cfg(rcc_f0)] - RCC.cr2().modify(|w| w.set_hsi48on(true)); - #[cfg(rcc_f0)] - while !RCC.cr2().read().hsi48rdy() {} - - #[cfg(rcc_f0)] - if pllmul_bits.is_some() { - RCC.cfgr() - .modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV)) - } - } - _ => { - RCC.cr().modify(|w| w.set_hsion(true)); - while !RCC.cr().read().hsirdy() {} - - if pllmul_bits.is_some() { - RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2)) - } - } - } - - if self.config.usb_pll { - RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK)); - } - // TODO: Option to use CRS (Clock Recovery) - - if let Some(pllmul_bits) = pllmul_bits { - RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits))); - - RCC.cr().modify(|w| w.set_pllon(true)); - while !RCC.cr().read().pllrdy() {} - - RCC.cfgr().modify(|w| { - w.set_ppre(Ppre(ppre_bits)); - w.set_hpre(Hpre(hpre_bits)); - w.set_sw(Sw::PLL) - }); - } else { - RCC.cfgr().modify(|w| { - w.set_ppre(Ppre(ppre_bits)); - w.set_hpre(Hpre(hpre_bits)); - - if self.config.hse.is_some() { - w.set_sw(Sw::HSE); - } else if use_hsi48 { - #[cfg(rcc_f0)] - w.set_sw(Sw::HSI48); - } else { - w.set_sw(Sw::HSI) - } - }) - } - } - - Clocks { - sys: Hertz(real_sysclk), - apb1: Hertz(pclk), - apb2: Hertz(pclk), - apb1_tim: Hertz(pclk * timer_mul), - apb2_tim: Hertz(pclk * timer_mul), - ahb: Hertz(hclk), - } - } -} - pub(crate) unsafe fn init(config: Config) { - let rcc = Rcc::new(::steal(), config); - let clocks = rcc.freeze(); - set_freqs(clocks); + let sysclk = config.sys_ck.map(|v| v.0).unwrap_or(HSI); + + let (src_clk, use_hsi48) = config.hse.map(|v| (v.0, false)).unwrap_or_else(|| { + #[cfg(rcc_f0)] + if config.hsi48 { + return (48_000_000, true); + } + (HSI, false) + }); + + let (pllmul_bits, real_sysclk) = if sysclk == src_clk { + (None, sysclk) + } else { + let prediv = if config.hse.is_some() { 1 } else { 2 }; + let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2; + let pllmul = pllmul.max(2).min(16); + + let pllmul_bits = pllmul as u8 - 2; + let real_sysclk = pllmul * src_clk / prediv; + (Some(pllmul_bits), real_sysclk) + }; + + let hpre_bits = config + .hclk + .map(|hclk| match real_sysclk / hclk.0 { + 0 => unreachable!(), + 1 => 0b0111, + 2 => 0b1000, + 3..=5 => 0b1001, + 6..=11 => 0b1010, + 12..=39 => 0b1011, + 40..=95 => 0b1100, + 96..=191 => 0b1101, + 192..=383 => 0b1110, + _ => 0b1111, + }) + .unwrap_or(0b0111); + let hclk = real_sysclk / (1 << (hpre_bits - 0b0111)); + + let ppre_bits = config + .pclk + .map(|pclk| match hclk / pclk.0 { + 0 => unreachable!(), + 1 => 0b011, + 2 => 0b100, + 3..=5 => 0b101, + 6..=11 => 0b110, + _ => 0b111, + }) + .unwrap_or(0b011); + + let ppre: u8 = 1 << (ppre_bits - 0b011); + let pclk = hclk / u32::from(ppre); + + let timer_mul = if ppre == 1 { 1 } else { 2 }; + + FLASH.acr().write(|w| { + let latency = if real_sysclk <= 24_000_000 { + 0 + } else if real_sysclk <= 48_000_000 { + 1 + } else { + 2 + }; + w.latency().0 = latency; + }); + + match (config.hse.is_some(), use_hsi48) { + (true, _) => { + RCC.cr().modify(|w| { + w.set_csson(true); + w.set_hseon(true); + + if config.bypass_hse { + w.set_hsebyp(Hsebyp::BYPASSED); + } + }); + while !RCC.cr().read().hserdy() {} + + if pllmul_bits.is_some() { + RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV)) + } + } + (false, true) => { + // use_hsi48 will always be false for rcc_f0x0 + #[cfg(rcc_f0)] + RCC.cr2().modify(|w| w.set_hsi48on(true)); + #[cfg(rcc_f0)] + while !RCC.cr2().read().hsi48rdy() {} + + #[cfg(rcc_f0)] + if pllmul_bits.is_some() { + RCC.cfgr() + .modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV)) + } + } + _ => { + RCC.cr().modify(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + + if pllmul_bits.is_some() { + RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2)) + } + } + } + + if config.usb_pll { + RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK)); + } + // TODO: Option to use CRS (Clock Recovery) + + if let Some(pllmul_bits) = pllmul_bits { + RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits))); + + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} + + RCC.cfgr().modify(|w| { + w.set_ppre(Ppre(ppre_bits)); + w.set_hpre(Hpre(hpre_bits)); + w.set_sw(Sw::PLL) + }); + } else { + RCC.cfgr().modify(|w| { + w.set_ppre(Ppre(ppre_bits)); + w.set_hpre(Hpre(hpre_bits)); + + if config.hse.is_some() { + w.set_sw(Sw::HSE); + } else if use_hsi48 { + #[cfg(rcc_f0)] + w.set_sw(Sw::HSI48); + } else { + w.set_sw(Sw::HSI) + } + }) + } + + set_freqs(Clocks { + sys: Hertz(real_sysclk), + apb1: Hertz(pclk), + apb2: Hertz(pclk), + apb1_tim: Hertz(pclk * timer_mul), + apb2_tim: Hertz(pclk * timer_mul), + ahb: Hertz(hclk), + }); } diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs index c9d09ee3..d44544d2 100644 --- a/embassy-stm32/src/rcc/f1.rs +++ b/embassy-stm32/src/rcc/f1.rs @@ -1,14 +1,10 @@ use core::convert::TryFrom; -use core::marker::PhantomData; - -use embassy::util::Unborrow; - -use crate::pac::flash::vals::Latency; -use crate::pac::{FLASH, RCC}; -use crate::peripherals; -use crate::time::Hertz; use super::{set_freqs, Clocks}; +use crate::pac::flash::vals::Latency; +use crate::pac::rcc::vals::{Adcpre, Hpre, Pllmul, Pllsrc, Ppre1, Sw, Usbpre}; +use crate::pac::{FLASH, RCC}; +use crate::time::Hertz; const HSI: u32 = 8_000_000; @@ -26,189 +22,158 @@ pub struct Config { pub adcclk: Option, } -pub struct Rcc<'d> { - inner: PhantomData<&'d ()>, - config: Config, -} - -impl<'d> Rcc<'d> { - pub fn new(_rcc: impl Unborrow + 'd, config: Config) -> Self { - Self { - inner: PhantomData, - config, - } - } - - pub fn freeze(self) -> Clocks { - use crate::pac::rcc::vals::{Adcpre, Hpre, Pllmul, Pllsrc, Ppre1, Sw, Usbpre}; - - let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI / 2); - let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); - let pllmul = sysclk / pllsrcclk; - - let (pllmul_bits, real_sysclk) = if pllmul == 1 { - (None, self.config.hse.map(|hse| hse.0).unwrap_or(HSI)) - } else { - let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16); - (Some(pllmul as u8 - 2), pllsrcclk * pllmul) - }; - - assert!(real_sysclk <= 72_000_000); - - let hpre_bits = self - .config - .hclk - .map(|hclk| match real_sysclk / hclk.0 { - 0 => unreachable!(), - 1 => 0b0111, - 2 => 0b1000, - 3..=5 => 0b1001, - 6..=11 => 0b1010, - 12..=39 => 0b1011, - 40..=95 => 0b1100, - 96..=191 => 0b1101, - 192..=383 => 0b1110, - _ => 0b1111, - }) - .unwrap_or(0b0111); - - let hclk = if hpre_bits >= 0b1100 { - real_sysclk / (1 << (hpre_bits - 0b0110)) - } else { - real_sysclk / (1 << (hpre_bits - 0b0111)) - }; - - assert!(hclk <= 72_000_000); - - let ppre1_bits = self - .config - .pclk1 - .map(|pclk1| match hclk / pclk1.0 { - 0 => unreachable!(), - 1 => 0b011, - 2 => 0b100, - 3..=5 => 0b101, - 6..=11 => 0b110, - _ => 0b111, - }) - .unwrap_or(0b011); - - let ppre1 = 1 << (ppre1_bits - 0b011); - let pclk1 = hclk / u32::try_from(ppre1).unwrap(); - let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; - - assert!(pclk1 <= 36_000_000); - - let ppre2_bits = self - .config - .pclk2 - .map(|pclk2| match hclk / pclk2.0 { - 0 => unreachable!(), - 1 => 0b011, - 2 => 0b100, - 3..=5 => 0b101, - 6..=11 => 0b110, - _ => 0b111, - }) - .unwrap_or(0b011); - - let ppre2 = 1 << (ppre2_bits - 0b011); - let pclk2 = hclk / u32::try_from(ppre2).unwrap(); - let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; - - assert!(pclk2 <= 72_000_000); - - // Only needed for stm32f103? - // NOTE(safety) Atomic write - unsafe { - FLASH.acr().write(|w| { - w.set_latency(if real_sysclk <= 24_000_000 { - Latency(0b000) - } else if real_sysclk <= 48_000_000 { - Latency(0b001) - } else { - Latency(0b010) - }); - }) - } - - // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the - // PLL output frequency is a supported one. - // usbpre == false: divide clock by 1.5, otherwise no division - let (usbpre, _usbclk_valid) = match (self.config.hse, pllmul_bits, real_sysclk) { - (Some(_), Some(_), 72_000_000) => (false, true), - (Some(_), Some(_), 48_000_000) => (true, true), - _ => (true, false), - }; - - let apre_bits: u8 = self - .config - .adcclk - .map(|adcclk| match pclk2 / adcclk.0 { - 0..=2 => 0b00, - 3..=4 => 0b01, - 5..=7 => 0b10, - _ => 0b11, - }) - .unwrap_or(0b11); - - let apre = (apre_bits + 1) << 1; - let adcclk = pclk2 / unwrap!(u32::try_from(apre)); - - assert!(adcclk <= 14_000_000); - - unsafe { - if self.config.hse.is_some() { - // enable HSE and wait for it to be ready - RCC.cr().modify(|w| w.set_hseon(true)); - while !RCC.cr().read().hserdy() {} - } - - if let Some(pllmul_bits) = pllmul_bits { - // enable PLL and wait for it to be ready - RCC.cfgr().modify(|w| { - w.set_pllmul(Pllmul(pllmul_bits)); - w.set_pllsrc(Pllsrc(self.config.hse.is_some() as u8)); - }); - - RCC.cr().modify(|w| w.set_pllon(true)); - while !RCC.cr().read().pllrdy() {} - } - - // Only needed for stm32f103? - RCC.cfgr().modify(|w| { - w.set_adcpre(Adcpre(apre_bits)); - w.set_ppre2(Ppre1(ppre2_bits)); - w.set_ppre1(Ppre1(ppre1_bits)); - w.set_hpre(Hpre(hpre_bits)); - w.set_usbpre(Usbpre(usbpre as u8)); - w.set_sw(Sw(if pllmul_bits.is_some() { - // PLL - 0b10 - } else if self.config.hse.is_some() { - // HSE - 0b1 - } else { - // HSI - 0b0 - })); - }); - } - - Clocks { - sys: Hertz(real_sysclk), - apb1: Hertz(pclk1), - apb2: Hertz(pclk2), - apb1_tim: Hertz(pclk1 * timer_mul1), - apb2_tim: Hertz(pclk2 * timer_mul2), - ahb: Hertz(hclk), - adc: Hertz(adcclk), - } - } -} - pub(crate) unsafe fn init(config: Config) { - let rcc = Rcc::new(::steal(), config); - let clocks = rcc.freeze(); - set_freqs(clocks); + let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI / 2); + let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); + let pllmul = sysclk / pllsrcclk; + + let (pllmul_bits, real_sysclk) = if pllmul == 1 { + (None, config.hse.map(|hse| hse.0).unwrap_or(HSI)) + } else { + let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16); + (Some(pllmul as u8 - 2), pllsrcclk * pllmul) + }; + + assert!(real_sysclk <= 72_000_000); + + let hpre_bits = config + .hclk + .map(|hclk| match real_sysclk / hclk.0 { + 0 => unreachable!(), + 1 => 0b0111, + 2 => 0b1000, + 3..=5 => 0b1001, + 6..=11 => 0b1010, + 12..=39 => 0b1011, + 40..=95 => 0b1100, + 96..=191 => 0b1101, + 192..=383 => 0b1110, + _ => 0b1111, + }) + .unwrap_or(0b0111); + + let hclk = if hpre_bits >= 0b1100 { + real_sysclk / (1 << (hpre_bits - 0b0110)) + } else { + real_sysclk / (1 << (hpre_bits - 0b0111)) + }; + + assert!(hclk <= 72_000_000); + + let ppre1_bits = config + .pclk1 + .map(|pclk1| match hclk / pclk1.0 { + 0 => unreachable!(), + 1 => 0b011, + 2 => 0b100, + 3..=5 => 0b101, + 6..=11 => 0b110, + _ => 0b111, + }) + .unwrap_or(0b011); + + let ppre1 = 1 << (ppre1_bits - 0b011); + let pclk1 = hclk / u32::try_from(ppre1).unwrap(); + let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; + + assert!(pclk1 <= 36_000_000); + + let ppre2_bits = config + .pclk2 + .map(|pclk2| match hclk / pclk2.0 { + 0 => unreachable!(), + 1 => 0b011, + 2 => 0b100, + 3..=5 => 0b101, + 6..=11 => 0b110, + _ => 0b111, + }) + .unwrap_or(0b011); + + let ppre2 = 1 << (ppre2_bits - 0b011); + let pclk2 = hclk / u32::try_from(ppre2).unwrap(); + let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; + + assert!(pclk2 <= 72_000_000); + + // Only needed for stm32f103? + FLASH.acr().write(|w| { + w.set_latency(if real_sysclk <= 24_000_000 { + Latency(0b000) + } else if real_sysclk <= 48_000_000 { + Latency(0b001) + } else { + Latency(0b010) + }); + }); + + // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the + // PLL output frequency is a supported one. + // usbpre == false: divide clock by 1.5, otherwise no division + let (usbpre, _usbclk_valid) = match (config.hse, pllmul_bits, real_sysclk) { + (Some(_), Some(_), 72_000_000) => (false, true), + (Some(_), Some(_), 48_000_000) => (true, true), + _ => (true, false), + }; + + let apre_bits: u8 = config + .adcclk + .map(|adcclk| match pclk2 / adcclk.0 { + 0..=2 => 0b00, + 3..=4 => 0b01, + 5..=7 => 0b10, + _ => 0b11, + }) + .unwrap_or(0b11); + + let apre = (apre_bits + 1) << 1; + let adcclk = pclk2 / unwrap!(u32::try_from(apre)); + + assert!(adcclk <= 14_000_000); + + if config.hse.is_some() { + // enable HSE and wait for it to be ready + RCC.cr().modify(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + } + + if let Some(pllmul_bits) = pllmul_bits { + // enable PLL and wait for it to be ready + RCC.cfgr().modify(|w| { + w.set_pllmul(Pllmul(pllmul_bits)); + w.set_pllsrc(Pllsrc(config.hse.is_some() as u8)); + }); + + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} + } + + // Only needed for stm32f103? + RCC.cfgr().modify(|w| { + w.set_adcpre(Adcpre(apre_bits)); + w.set_ppre2(Ppre1(ppre2_bits)); + w.set_ppre1(Ppre1(ppre1_bits)); + w.set_hpre(Hpre(hpre_bits)); + w.set_usbpre(Usbpre(usbpre as u8)); + w.set_sw(Sw(if pllmul_bits.is_some() { + // PLL + 0b10 + } else if config.hse.is_some() { + // HSE + 0b1 + } else { + // HSI + 0b0 + })); + }); + + set_freqs(Clocks { + sys: Hertz(real_sysclk), + apb1: Hertz(pclk1), + apb2: Hertz(pclk2), + apb1_tim: Hertz(pclk1 * timer_mul1), + apb2_tim: Hertz(pclk2 * timer_mul2), + ahb: Hertz(hclk), + adc: Hertz(adcclk), + }); } diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 7b5e0cce..e16e1e49 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -1,23 +1,11 @@ -use core::marker::PhantomData; -use embassy::util::Unborrow; - -use crate::pac::{ - flash::vals::Latency, - rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}, - FLASH, RCC, -}; -use crate::peripherals; +use crate::pac::flash::vals::Latency; +use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; +use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; const HSI: u32 = 8_000_000; -/// RCC peripheral -pub struct Rcc<'d> { - config: Config, - phantom: PhantomData<&'d mut peripherals::RCC>, -} - /// Clocks configutation #[non_exhaustive] #[derive(Default)] @@ -55,259 +43,228 @@ struct PllConfig { /// Initialize and Set the clock frequencies pub(crate) unsafe fn init(config: Config) { - let r = ::steal(); - let clocks = Rcc::new(r, config).freeze(); - set_freqs(clocks); + // Calculate the real System clock, and PLL configuration if applicable + let (Hertz(sysclk), pll_config) = get_sysclk(&config); + assert!(sysclk <= 72_000_000); + + // Calculate real AHB clock + let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk); + let (hpre_bits, hpre_div) = match sysclk / hclk { + 0 => unreachable!(), + 1 => (Hpre::DIV1, 1), + 2 => (Hpre::DIV2, 2), + 3..=5 => (Hpre::DIV4, 4), + 6..=11 => (Hpre::DIV8, 8), + 12..=39 => (Hpre::DIV16, 16), + 40..=95 => (Hpre::DIV64, 64), + 96..=191 => (Hpre::DIV128, 128), + 192..=383 => (Hpre::DIV256, 256), + _ => (Hpre::DIV512, 512), + }; + let hclk = sysclk / hpre_div; + assert!(hclk <= 72_000_000); + + // Calculate real APB1 clock + let pclk1 = config.pclk1.map(|p| p.0).unwrap_or(hclk); + let (ppre1_bits, ppre1) = match hclk / pclk1 { + 0 => unreachable!(), + 1 => (Ppre::DIV1, 1), + 2 => (Ppre::DIV2, 2), + 3..=5 => (Ppre::DIV4, 4), + 6..=11 => (Ppre::DIV8, 8), + _ => (Ppre::DIV16, 16), + }; + let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; + let pclk1 = hclk / ppre1; + assert!(pclk1 <= 36_000_000); + + // Calculate real APB2 clock + let pclk2 = config.pclk2.map(|p| p.0).unwrap_or(hclk); + let (ppre2_bits, ppre2) = match hclk / pclk2 { + 0 => unreachable!(), + 1 => (Ppre::DIV1, 1), + 2 => (Ppre::DIV2, 2), + 3..=5 => (Ppre::DIV4, 4), + 6..=11 => (Ppre::DIV8, 8), + _ => (Ppre::DIV16, 16), + }; + let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; + let pclk2 = hclk / ppre2; + assert!(pclk2 <= 72_000_000); + + // Set latency based on HCLK frquency + FLASH.acr().write(|w| { + w.set_latency(if hclk <= 24_000_000 { + Latency::WS0 + } else if hclk <= 48_000_000 { + Latency::WS1 + } else { + Latency::WS2 + }); + }); + + // Enable HSE + if config.hse.is_some() { + RCC.cr().write(|w| { + w.set_hsebyp(if config.bypass_hse { + Hsebyp::BYPASSED + } else { + Hsebyp::NOTBYPASSED + }); + // We turn on clock security to switch to HSI when HSE fails + w.set_csson(true); + w.set_hseon(true); + }); + while !RCC.cr().read().hserdy() {} + } + + // Enable PLL + if let Some(ref pll_config) = pll_config { + RCC.cfgr().write(|w| { + w.set_pllmul(pll_config.pll_mul); + w.set_pllsrc(pll_config.pll_src); + }); + if let Some(pll_div) = pll_config.pll_div { + RCC.cfgr2().write(|w| w.set_prediv(pll_div)); + } + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} + } + + if config.pll48 { + let usb_pre = get_usb_pre(&config, sysclk, pclk1, &pll_config); + RCC.cfgr().write(|w| { + w.set_usbpre(usb_pre); + }); + } + + // Set prescalers + RCC.cfgr().write(|w| { + w.set_ppre2(ppre2_bits); + w.set_ppre1(ppre1_bits); + w.set_hpre(hpre_bits); + }); + + // Wait for the new prescalers to kick in + // "The clocks are divided with the new prescaler factor from + // 1 to 16 AHB cycles after write" + cortex_m::asm::delay(16); + + RCC.cfgr().write(|w| { + w.set_sw(match (pll_config, config.hse) { + (Some(_), _) => Sw::PLL, + (None, Some(_)) => Sw::HSE, + (None, None) => Sw::HSI, + }) + }); + + set_freqs(Clocks { + sys: Hertz(sysclk), + apb1: Hertz(pclk1), + apb2: Hertz(pclk2), + apb1_tim: Hertz(pclk1 * timer_mul1), + apb2_tim: Hertz(pclk2 * timer_mul2), + ahb: Hertz(hclk), + }); } -impl<'d> Rcc<'d> { - pub fn new(_rcc: impl Unborrow + 'd, config: Config) -> Self { - Self { - config, - phantom: PhantomData, +#[inline] +fn get_sysclk(config: &Config) -> (Hertz, Option) { + match (config.sysclk, config.hse) { + (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None), + (Some(sysclk), None) if sysclk.0 == HSI => (Hertz(HSI), None), + // If the user selected System clock is different from HSI or HSE + // we will have to setup PLL clock source + (Some(sysclk), _) => { + let (sysclk, pll_config) = calc_pll(config, sysclk); + (sysclk, Some(pll_config)) } + (None, Some(hse)) => (hse, None), + (None, None) => (Hertz(HSI), None), } +} - fn freeze(self) -> Clocks { - // Calculate the real System clock, and PLL configuration if applicable - let (Hertz(sysclk), pll_config) = self.get_sysclk(); - assert!(sysclk <= 72_000_000); - - // Calculate real AHB clock - let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk); - let (hpre_bits, hpre_div) = match sysclk / hclk { - 0 => unreachable!(), - 1 => (Hpre::DIV1, 1), - 2 => (Hpre::DIV2, 2), - 3..=5 => (Hpre::DIV4, 4), - 6..=11 => (Hpre::DIV8, 8), - 12..=39 => (Hpre::DIV16, 16), - 40..=95 => (Hpre::DIV64, 64), - 96..=191 => (Hpre::DIV128, 128), - 192..=383 => (Hpre::DIV256, 256), - _ => (Hpre::DIV512, 512), - }; - let hclk = sysclk / hpre_div; - assert!(hclk <= 72_000_000); - - // Calculate real APB1 clock - let pclk1 = self.config.pclk1.map(|p| p.0).unwrap_or(hclk); - let (ppre1_bits, ppre1) = match hclk / pclk1 { - 0 => unreachable!(), - 1 => (Ppre::DIV1, 1), - 2 => (Ppre::DIV2, 2), - 3..=5 => (Ppre::DIV4, 4), - 6..=11 => (Ppre::DIV8, 8), - _ => (Ppre::DIV16, 16), - }; - let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; - let pclk1 = hclk / ppre1; - assert!(pclk1 <= 36_000_000); - - // Calculate real APB2 clock - let pclk2 = self.config.pclk2.map(|p| p.0).unwrap_or(hclk); - let (ppre2_bits, ppre2) = match hclk / pclk2 { - 0 => unreachable!(), - 1 => (Ppre::DIV1, 1), - 2 => (Ppre::DIV2, 2), - 3..=5 => (Ppre::DIV4, 4), - 6..=11 => (Ppre::DIV8, 8), - _ => (Ppre::DIV16, 16), - }; - let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; - let pclk2 = hclk / ppre2; - assert!(pclk2 <= 72_000_000); - - // Set latency based on HCLK frquency - // NOTE(safety) Atomic write - unsafe { - FLASH.acr().write(|w| { - w.set_latency(if hclk <= 24_000_000 { - Latency::WS0 - } else if hclk <= 48_000_000 { - Latency::WS1 +#[inline] +fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { + // Calculates the Multiplier and the Divisor to arrive at + // the required System clock from PLL source frequency + let get_mul_div = |sysclk, pllsrcclk| { + let common_div = gcd(sysclk, pllsrcclk); + let mut multiplier = sysclk / common_div; + let mut divisor = pllsrcclk / common_div; + // Minimum PLL multiplier is two + if multiplier == 1 { + multiplier *= 2; + divisor *= 2; + } + assert!(multiplier <= 16); + assert!(divisor <= 16); + (multiplier, divisor) + }; + // Based on the source of Pll, we calculate the actual system clock + // frequency, PLL's source identifier, multiplier and divisor + let (act_sysclk, pll_src, pll_mul, pll_div) = match config.hse { + Some(Hertz(hse)) => { + let (multiplier, divisor) = get_mul_div(sysclk, hse); + ( + Hertz((hse / divisor) * multiplier), + Pllsrc::HSE_DIV_PREDIV, + into_pll_mul(multiplier), + Some(into_pre_div(divisor)), + ) + } + None => { + cfg_if::cfg_if! { + // For some chips PREDIV is always two, and cannot be changed + if #[cfg(any( + feature="stm32f302xd", feature="stm32f302xe", feature="stm32f303xd", + feature="stm32f303xe", feature="stm32f398xe" + ))] { + let (multiplier, divisor) = get_mul_div(sysclk, HSI); + ( + Hertz((hse / divisor) * multiplier), + Pllsrc::HSI_DIV_PREDIV, + into_pll_mul(multiplier), + Some(into_pre_div(divisor)), + ) } else { - Latency::WS2 - }); - }) - } - - // Enable HSE - if self.config.hse.is_some() { - // NOTE(unsafe) We own the peripheral block - unsafe { - RCC.cr().write(|w| { - w.set_hsebyp(if self.config.bypass_hse { - Hsebyp::BYPASSED - } else { - Hsebyp::NOTBYPASSED - }); - // We turn on clock security to switch to HSI when HSE fails - w.set_csson(true); - w.set_hseon(true); - }); - while !RCC.cr().read().hserdy() {} - } - } - - // Enable PLL - if let Some(ref pll_config) = pll_config { - // NOTE(unsafe) We own the peripheral block - unsafe { - RCC.cfgr().write(|w| { - w.set_pllmul(pll_config.pll_mul); - w.set_pllsrc(pll_config.pll_src); - }); - if let Some(pll_div) = pll_config.pll_div { - RCC.cfgr2().write(|w| w.set_prediv(pll_div)); - } - RCC.cr().modify(|w| w.set_pllon(true)); - while !RCC.cr().read().pllrdy() {} - } - } - - if self.config.pll48 { - let usb_pre = self.get_usb_pre(sysclk, pclk1, &pll_config); - // NOTE(unsafe) We own the peripheral block - unsafe { - RCC.cfgr().write(|w| { - w.set_usbpre(usb_pre); - }); - } - } - - // Set prescalers - unsafe { - // NOTE(unsafe) We own the peripheral block - RCC.cfgr().write(|w| { - w.set_ppre2(ppre2_bits); - w.set_ppre1(ppre1_bits); - w.set_hpre(hpre_bits); - }); - - // Wait for the new prescalers to kick in - // "The clocks are divided with the new prescaler factor from - // 1 to 16 AHB cycles after write" - cortex_m::asm::delay(16); - - // NOTE(unsafe) We own the peripheral block - RCC.cfgr().write(|w| { - w.set_sw(match (pll_config, self.config.hse) { - (Some(_), _) => Sw::PLL, - (None, Some(_)) => Sw::HSE, - (None, None) => Sw::HSI, - }) - }); - } - - Clocks { - sys: Hertz(sysclk), - apb1: Hertz(pclk1), - apb2: Hertz(pclk2), - apb1_tim: Hertz(pclk1 * timer_mul1), - apb2_tim: Hertz(pclk2 * timer_mul2), - ahb: Hertz(hclk), - } - } - - #[inline] - fn get_sysclk(&self) -> (Hertz, Option) { - match (self.config.sysclk, self.config.hse) { - (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None), - (Some(sysclk), None) if sysclk.0 == HSI => (Hertz(HSI), None), - // If the user selected System clock is different from HSI or HSE - // we will have to setup PLL clock source - (Some(sysclk), _) => { - let (sysclk, pll_config) = self.calc_pll(sysclk); - (sysclk, Some(pll_config)) - } - (None, Some(hse)) => (hse, None), - (None, None) => (Hertz(HSI), None), - } - } - - #[inline] - fn calc_pll(&self, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { - // Calculates the Multiplier and the Divisor to arrive at - // the required System clock from PLL source frequency - let get_mul_div = |sysclk, pllsrcclk| { - let common_div = gcd(sysclk, pllsrcclk); - let mut multiplier = sysclk / common_div; - let mut divisor = pllsrcclk / common_div; - // Minimum PLL multiplier is two - if multiplier == 1 { - multiplier *= 2; - divisor *= 2; - } - assert!(multiplier <= 16); - assert!(divisor <= 16); - (multiplier, divisor) - }; - // Based on the source of Pll, we calculate the actual system clock - // frequency, PLL's source identifier, multiplier and divisor - let (act_sysclk, pll_src, pll_mul, pll_div) = match self.config.hse { - Some(Hertz(hse)) => { - let (multiplier, divisor) = get_mul_div(sysclk, hse); - ( - Hertz((hse / divisor) * multiplier), - Pllsrc::HSE_DIV_PREDIV, - into_pll_mul(multiplier), - Some(into_pre_div(divisor)), - ) - } - None => { - cfg_if::cfg_if! { - // For some chips PREDIV is always two, and cannot be changed - if #[cfg(any( - feature="stm32f302xd", feature="stm32f302xe", feature="stm32f303xd", - feature="stm32f303xe", feature="stm32f398xe" - ))] { - let (multiplier, divisor) = get_mul_div(sysclk, HSI); - ( - Hertz((hse / divisor) * multiplier), - Pllsrc::HSI_DIV_PREDIV, - into_pll_mul(multiplier), - Some(into_pre_div(divisor)), - ) - } else { - let pllsrcclk = HSI / 2; - let multiplier = sysclk / pllsrcclk; - assert!(multiplier <= 16); - ( - Hertz(pllsrcclk * multiplier), - Pllsrc::HSI_DIV2, - into_pll_mul(multiplier), - None, - ) - } + let pllsrcclk = HSI / 2; + let multiplier = sysclk / pllsrcclk; + assert!(multiplier <= 16); + ( + Hertz(pllsrcclk * multiplier), + Pllsrc::HSI_DIV2, + into_pll_mul(multiplier), + None, + ) } } - }; - ( - act_sysclk, - PllConfig { - pll_src, - pll_mul, - pll_div, - }, - ) - } + } + }; + ( + act_sysclk, + PllConfig { + pll_src, + pll_mul, + pll_div, + }, + ) +} - #[inline] - fn get_usb_pre(&self, sysclk: u32, pclk1: u32, pll_config: &Option) -> Usbpre { - cfg_if::cfg_if! { - // Some chips do not have USB - if #[cfg(any(stm32f301, stm32f318, stm32f334))] { - panic!("USB clock not supported by the chip"); - } else { - let usb_ok = self.config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000); - match (usb_ok, sysclk) { - (true, 72_000_000) => Usbpre::DIV1_5, - (true, 48_000_000) => Usbpre::DIV1, - _ => panic!( - "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz" - ), - } +#[inline] +fn get_usb_pre(config: &Config, sysclk: u32, pclk1: u32, pll_config: &Option) -> Usbpre { + cfg_if::cfg_if! { + // Some chips do not have USB + if #[cfg(any(stm32f301, stm32f318, stm32f334))] { + panic!("USB clock not supported by the chip"); + } else { + let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000); + match (usb_ok, sysclk) { + (true, 72_000_000) => Usbpre::DIV1_5, + (true, 48_000_000) => Usbpre::DIV1, + _ => panic!( + "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz" + ), } } } diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index 58a08adb..aba8fc0e 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -1,9 +1,8 @@ +use super::sealed::RccPeripheral; +use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; -use crate::peripherals; -use crate::rcc::{get_freqs, set_freqs, Clocks}; +use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; -use core::marker::PhantomData; -use embassy::util::Unborrow; const HSI: u32 = 16_000_000; @@ -21,284 +20,240 @@ pub struct Config { pub pll48: bool, } -/// RCC peripheral -pub struct Rcc<'d> { - config: Config, - phantom: PhantomData<&'d mut peripherals::RCC>, +unsafe fn setup_pll( + pllsrcclk: u32, + use_hse: bool, + pllsysclk: Option, + pll48clk: bool, +) -> PllResults { + use crate::pac::rcc::vals::{Pllp, Pllsrc}; + + let sysclk = pllsysclk.unwrap_or(pllsrcclk); + if pllsysclk.is_none() && !pll48clk { + RCC.pllcfgr() + .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); + + return PllResults { + use_pll: false, + pllsysclk: None, + pll48clk: None, + }; + } + // Input divisor from PLL source clock, must result to frequency in + // the range from 1 to 2 MHz + let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000; + let pllm_max = pllsrcclk / 1_000_000; + + // Sysclk output divisor must be one of 2, 4, 6 or 8 + let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1); + + let target_freq = if pll48clk { + 48_000_000 + } else { + sysclk * sysclk_div + }; + + // Find the lowest pllm value that minimize the difference between + // target frequency and the real vco_out frequency. + let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| { + let vco_in = pllsrcclk / pllm; + let plln = target_freq / vco_in; + target_freq - vco_in * plln + })); + + let vco_in = pllsrcclk / pllm; + assert!((1_000_000..=2_000_000).contains(&vco_in)); + + // Main scaler, must result in >= 100MHz (>= 192MHz for F401) + // and <= 432MHz, min 50, max 432 + let plln = if pll48clk { + // try the different valid pllq according to the valid + // main scaller values, and take the best + let pllq = unwrap!((4..=9).min_by_key(|pllq| { + let plln = 48_000_000 * pllq / vco_in; + let pll48_diff = 48_000_000 - vco_in * plln / pllq; + let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs(); + (pll48_diff, sysclk_diff) + })); + 48_000_000 * pllq / vco_in + } else { + sysclk * sysclk_div / vco_in + }; + + let pllp = (sysclk_div / 2) - 1; + + let pllq = (vco_in * plln + 47_999_999) / 48_000_000; + let real_pll48clk = vco_in * plln / pllq; + + RCC.pllcfgr().modify(|w| { + w.set_pllm(pllm as u8); + w.set_plln(plln as u16); + w.set_pllp(Pllp(pllp as u8)); + w.set_pllq(pllq as u8); + w.set_pllsrc(Pllsrc(use_hse as u8)); + }); + + let real_pllsysclk = vco_in * plln / sysclk_div; + + PllResults { + use_pll: true, + pllsysclk: Some(real_pllsysclk), + pll48clk: if pll48clk { Some(real_pll48clk) } else { None }, + } } -impl<'d> Rcc<'d> { - pub fn new(_rcc: impl Unborrow + 'd, config: Config) -> Self { - Self { - config, - phantom: PhantomData, - } - } +unsafe fn flash_setup(sysclk: u32) { + use crate::pac::flash::vals::Latency; - fn freeze(mut self) -> Clocks { - use super::sealed::RccPeripheral; - use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw}; + // Be conservative with voltage ranges + const FLASH_LATENCY_STEP: u32 = 30_000_000; - peripherals::PWR::enable(); - - let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI); - let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); - let sysclk_on_pll = sysclk != pllsrcclk; - - let plls = self.setup_pll( - pllsrcclk, - self.config.hse.is_some(), - if sysclk_on_pll { Some(sysclk) } else { None }, - self.config.pll48, - ); - - if self.config.pll48 { - let freq = unwrap!(plls.pll48clk); - - assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32); - } - - let sysclk = if sysclk_on_pll { - unwrap!(plls.pllsysclk) - } else { - sysclk - }; - - // AHB prescaler - let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk); - let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk { - 0 => unreachable!(), - 1 => (Hpre::DIV1, 1), - 2 => (Hpre::DIV2, 2), - 3..=5 => (Hpre::DIV4, 4), - 6..=11 => (Hpre::DIV8, 8), - 12..=39 => (Hpre::DIV16, 16), - 40..=95 => (Hpre::DIV64, 64), - 96..=191 => (Hpre::DIV128, 128), - 192..=383 => (Hpre::DIV256, 256), - _ => (Hpre::DIV512, 512), - }; - - // Calculate real AHB clock - let hclk = sysclk / hpre_div; - - let pclk1 = self - .config - .pclk1 - .map(|p| p.0) - .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk)); - - let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 { - 0 => unreachable!(), - 1 => (0b000, 1), - 2 => (0b100, 2), - 3..=5 => (0b101, 4), - 6..=11 => (0b110, 8), - _ => (0b111, 16), - }; - let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; - - // Calculate real APB1 clock - let pclk1 = hclk / ppre1; - assert!(pclk1 <= max::PCLK1_MAX); - - let pclk2 = self - .config - .pclk2 - .map(|p| p.0) - .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk)); - let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 { - 0 => unreachable!(), - 1 => (0b000, 1), - 2 => (0b100, 2), - 3..=5 => (0b101, 4), - 6..=11 => (0b110, 8), - _ => (0b111, 16), - }; - let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; - - // Calculate real APB2 clock - let pclk2 = hclk / ppre2; - assert!(pclk2 <= max::PCLK2_MAX); - - Self::flash_setup(sysclk); - - if self.config.hse.is_some() { - // NOTE(unsafe) We own the peripheral block - unsafe { - RCC.cr().modify(|w| { - w.set_hsebyp(Hsebyp(self.config.bypass_hse as u8)); - w.set_hseon(true); - }); - while !RCC.cr().read().hserdy() {} - } - } - - if plls.use_pll { - unsafe { - RCC.cr().modify(|w| w.set_pllon(true)); - - if hclk > max::HCLK_OVERDRIVE_FREQUENCY { - PWR.cr1().modify(|w| w.set_oden(true)); - while !PWR.csr1().read().odrdy() {} - - PWR.cr1().modify(|w| w.set_odswen(true)); - while !PWR.csr1().read().odswrdy() {} - } - - while !RCC.cr().read().pllrdy() {} - } - } - - unsafe { - RCC.cfgr().modify(|w| { - w.set_ppre2(Ppre(ppre2_bits)); - w.set_ppre1(Ppre(ppre1_bits)); - w.set_hpre(hpre_bits); - }); - - // Wait for the new prescalers to kick in - // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write" - cortex_m::asm::delay(16); - - RCC.cfgr().modify(|w| { - w.set_sw(if sysclk_on_pll { - Sw::PLL - } else if self.config.hse.is_some() { - Sw::HSE - } else { - Sw::HSI - }) - }); - } - - Clocks { - sys: Hertz(sysclk), - apb1: Hertz(pclk1), - apb2: Hertz(pclk2), - - apb1_tim: Hertz(pclk1 * timer_mul1), - apb2_tim: Hertz(pclk2 * timer_mul2), - - ahb1: Hertz(hclk), - ahb2: Hertz(hclk), - ahb3: Hertz(hclk), - - pll48: plls.pll48clk.map(Hertz), - } - } - - // Safety: RCC init must have been called - pub fn clocks(&self) -> &'static Clocks { - unsafe { get_freqs() } - } - - fn setup_pll( - &mut self, - pllsrcclk: u32, - use_hse: bool, - pllsysclk: Option, - pll48clk: bool, - ) -> PllResults { - use crate::pac::rcc::vals::{Pllp, Pllsrc}; - - let sysclk = pllsysclk.unwrap_or(pllsrcclk); - if pllsysclk.is_none() && !pll48clk { - // NOTE(unsafe) We have a mutable borrow to the owner of the RegBlock - unsafe { - RCC.pllcfgr() - .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); - } - - return PllResults { - use_pll: false, - pllsysclk: None, - pll48clk: None, - }; - } - // Input divisor from PLL source clock, must result to frequency in - // the range from 1 to 2 MHz - let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000; - let pllm_max = pllsrcclk / 1_000_000; - - // Sysclk output divisor must be one of 2, 4, 6 or 8 - let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1); - - let target_freq = if pll48clk { - 48_000_000 - } else { - sysclk * sysclk_div - }; - - // Find the lowest pllm value that minimize the difference between - // target frequency and the real vco_out frequency. - let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| { - let vco_in = pllsrcclk / pllm; - let plln = target_freq / vco_in; - target_freq - vco_in * plln - })); - - let vco_in = pllsrcclk / pllm; - assert!((1_000_000..=2_000_000).contains(&vco_in)); - - // Main scaler, must result in >= 100MHz (>= 192MHz for F401) - // and <= 432MHz, min 50, max 432 - let plln = if pll48clk { - // try the different valid pllq according to the valid - // main scaller values, and take the best - let pllq = unwrap!((4..=9).min_by_key(|pllq| { - let plln = 48_000_000 * pllq / vco_in; - let pll48_diff = 48_000_000 - vco_in * plln / pllq; - let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs(); - (pll48_diff, sysclk_diff) - })); - 48_000_000 * pllq / vco_in - } else { - sysclk * sysclk_div / vco_in - }; - - let pllp = (sysclk_div / 2) - 1; - - let pllq = (vco_in * plln + 47_999_999) / 48_000_000; - let real_pll48clk = vco_in * plln / pllq; - - unsafe { - RCC.pllcfgr().modify(|w| { - w.set_pllm(pllm as u8); - w.set_plln(plln as u16); - w.set_pllp(Pllp(pllp as u8)); - w.set_pllq(pllq as u8); - w.set_pllsrc(Pllsrc(use_hse as u8)); - }); - } - - let real_pllsysclk = vco_in * plln / sysclk_div; - - PllResults { - use_pll: true, - pllsysclk: Some(real_pllsysclk), - pll48clk: if pll48clk { Some(real_pll48clk) } else { None }, - } - } - - fn flash_setup(sysclk: u32) { - use crate::pac::flash::vals::Latency; - - // Be conservative with voltage ranges - const FLASH_LATENCY_STEP: u32 = 30_000_000; - - critical_section::with(|_| unsafe { - FLASH - .acr() - .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); - }); - } + critical_section::with(|_| { + FLASH + .acr() + .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); + }); } pub(crate) unsafe fn init(config: Config) { - let r = ::steal(); - let clocks = Rcc::new(r, config).freeze(); - set_freqs(clocks); + crate::peripherals::PWR::enable(); + + let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI); + let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); + let sysclk_on_pll = sysclk != pllsrcclk; + + let plls = setup_pll( + pllsrcclk, + config.hse.is_some(), + if sysclk_on_pll { Some(sysclk) } else { None }, + config.pll48, + ); + + if config.pll48 { + let freq = unwrap!(plls.pll48clk); + + assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32); + } + + let sysclk = if sysclk_on_pll { + unwrap!(plls.pllsysclk) + } else { + sysclk + }; + + // AHB prescaler + let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk); + let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk { + 0 => unreachable!(), + 1 => (Hpre::DIV1, 1), + 2 => (Hpre::DIV2, 2), + 3..=5 => (Hpre::DIV4, 4), + 6..=11 => (Hpre::DIV8, 8), + 12..=39 => (Hpre::DIV16, 16), + 40..=95 => (Hpre::DIV64, 64), + 96..=191 => (Hpre::DIV128, 128), + 192..=383 => (Hpre::DIV256, 256), + _ => (Hpre::DIV512, 512), + }; + + // Calculate real AHB clock + let hclk = sysclk / hpre_div; + + let pclk1 = config + .pclk1 + .map(|p| p.0) + .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk)); + + let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 { + 0 => unreachable!(), + 1 => (0b000, 1), + 2 => (0b100, 2), + 3..=5 => (0b101, 4), + 6..=11 => (0b110, 8), + _ => (0b111, 16), + }; + let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; + + // Calculate real APB1 clock + let pclk1 = hclk / ppre1; + assert!(pclk1 <= max::PCLK1_MAX); + + let pclk2 = config + .pclk2 + .map(|p| p.0) + .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk)); + let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 { + 0 => unreachable!(), + 1 => (0b000, 1), + 2 => (0b100, 2), + 3..=5 => (0b101, 4), + 6..=11 => (0b110, 8), + _ => (0b111, 16), + }; + let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; + + // Calculate real APB2 clock + let pclk2 = hclk / ppre2; + assert!(pclk2 <= max::PCLK2_MAX); + + flash_setup(sysclk); + + if config.hse.is_some() { + RCC.cr().modify(|w| { + w.set_hsebyp(Hsebyp(config.bypass_hse as u8)); + w.set_hseon(true); + }); + while !RCC.cr().read().hserdy() {} + } + + if plls.use_pll { + RCC.cr().modify(|w| w.set_pllon(true)); + + if hclk > max::HCLK_OVERDRIVE_FREQUENCY { + PWR.cr1().modify(|w| w.set_oden(true)); + while !PWR.csr1().read().odrdy() {} + + PWR.cr1().modify(|w| w.set_odswen(true)); + while !PWR.csr1().read().odswrdy() {} + } + + while !RCC.cr().read().pllrdy() {} + } + + RCC.cfgr().modify(|w| { + w.set_ppre2(Ppre(ppre2_bits)); + w.set_ppre1(Ppre(ppre1_bits)); + w.set_hpre(hpre_bits); + }); + + // Wait for the new prescalers to kick in + // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write" + cortex_m::asm::delay(16); + + RCC.cfgr().modify(|w| { + w.set_sw(if sysclk_on_pll { + Sw::PLL + } else if config.hse.is_some() { + Sw::HSE + } else { + Sw::HSI + }) + }); + + set_freqs(Clocks { + sys: Hertz(sysclk), + apb1: Hertz(pclk1), + apb2: Hertz(pclk2), + + apb1_tim: Hertz(pclk1 * timer_mul1), + apb2_tim: Hertz(pclk2 * timer_mul2), + + ahb1: Hertz(hclk), + ahb2: Hertz(hclk), + ahb3: Hertz(hclk), + + pll48: plls.pll48clk.map(Hertz), + }); } struct PllResults { diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs index d29ba31f..1a053029 100644 --- a/embassy-stm32/src/rcc/f7.rs +++ b/embassy-stm32/src/rcc/f7.rs @@ -1,9 +1,9 @@ +use super::sealed::RccPeripheral; +use crate::pac::pwr::vals::Vos; +use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; -use crate::peripherals; -use crate::rcc::{get_freqs, set_freqs, Clocks}; +use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; -use core::marker::PhantomData; -use embassy::util::Unborrow; const HSI: u32 = 16_000_000; @@ -21,318 +21,274 @@ pub struct Config { pub pll48: bool, } -/// RCC peripheral -pub struct Rcc<'d> { - config: Config, - phantom: PhantomData<&'d mut peripherals::RCC>, +unsafe fn setup_pll( + pllsrcclk: u32, + use_hse: bool, + pllsysclk: Option, + pll48clk: bool, +) -> PllResults { + use crate::pac::rcc::vals::{Pllp, Pllsrc}; + + let sysclk = pllsysclk.unwrap_or(pllsrcclk); + if pllsysclk.is_none() && !pll48clk { + RCC.pllcfgr() + .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); + + return PllResults { + use_pll: false, + pllsysclk: None, + pll48clk: None, + }; + } + // Input divisor from PLL source clock, must result to frequency in + // the range from 1 to 2 MHz + let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000; + let pllm_max = pllsrcclk / 1_000_000; + + // Sysclk output divisor must be one of 2, 4, 6 or 8 + let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1); + + let target_freq = if pll48clk { + 48_000_000 + } else { + sysclk * sysclk_div + }; + + // Find the lowest pllm value that minimize the difference between + // target frequency and the real vco_out frequency. + let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| { + let vco_in = pllsrcclk / pllm; + let plln = target_freq / vco_in; + target_freq - vco_in * plln + })); + + let vco_in = pllsrcclk / pllm; + assert!((1_000_000..=2_000_000).contains(&vco_in)); + + // Main scaler, must result in >= 100MHz (>= 192MHz for F401) + // and <= 432MHz, min 50, max 432 + let plln = if pll48clk { + // try the different valid pllq according to the valid + // main scaller values, and take the best + let pllq = unwrap!((4..=9).min_by_key(|pllq| { + let plln = 48_000_000 * pllq / vco_in; + let pll48_diff = 48_000_000 - vco_in * plln / pllq; + let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs(); + (pll48_diff, sysclk_diff) + })); + 48_000_000 * pllq / vco_in + } else { + sysclk * sysclk_div / vco_in + }; + + let pllp = (sysclk_div / 2) - 1; + + let pllq = (vco_in * plln + 47_999_999) / 48_000_000; + let real_pll48clk = vco_in * plln / pllq; + + RCC.pllcfgr().modify(|w| { + w.set_pllm(pllm as u8); + w.set_plln(plln as u16); + w.set_pllp(Pllp(pllp as u8)); + w.set_pllq(pllq as u8); + w.set_pllsrc(Pllsrc(use_hse as u8)); + }); + + let real_pllsysclk = vco_in * plln / sysclk_div; + + PllResults { + use_pll: true, + pllsysclk: Some(real_pllsysclk), + pll48clk: if pll48clk { Some(real_pll48clk) } else { None }, + } } -impl<'d> Rcc<'d> { - pub fn new(_rcc: impl Unborrow + 'd, config: Config) -> Self { - if let Some(hse) = config.hse { - if config.bypass_hse { - assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0)); - } else { - assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0)); - } - } - Self { - config, - phantom: PhantomData, - } - } +unsafe fn flash_setup(sysclk: u32) { + use crate::pac::flash::vals::Latency; - fn freeze(mut self) -> Clocks { - use super::sealed::RccPeripheral; - use crate::pac::pwr::vals::Vos; - use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw}; + // Be conservative with voltage ranges + const FLASH_LATENCY_STEP: u32 = 30_000_000; - peripherals::PWR::enable(); - - let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI); - let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); - let sysclk_on_pll = sysclk != pllsrcclk; - - assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk)); - - let plls = self.setup_pll( - pllsrcclk, - self.config.hse.is_some(), - if sysclk_on_pll { Some(sysclk) } else { None }, - self.config.pll48, - ); - - if self.config.pll48 { - let freq = unwrap!(plls.pll48clk); - - assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32); - } - - let sysclk = if sysclk_on_pll { - unwrap!(plls.pllsysclk) - } else { - sysclk - }; - - // AHB prescaler - let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk); - let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk { - 0 => unreachable!(), - 1 => (Hpre::DIV1, 1), - 2 => (Hpre::DIV2, 2), - 3..=5 => (Hpre::DIV4, 4), - 6..=11 => (Hpre::DIV8, 8), - 12..=39 => (Hpre::DIV16, 16), - 40..=95 => (Hpre::DIV64, 64), - 96..=191 => (Hpre::DIV128, 128), - 192..=383 => (Hpre::DIV256, 256), - _ => (Hpre::DIV512, 512), - }; - - // Calculate real AHB clock - let hclk = sysclk / hpre_div; - - assert!(hclk < max::HCLK_MAX); - - let pclk1 = self - .config - .pclk1 - .map(|p| p.0) - .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk)); - - let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 { - 0 => unreachable!(), - 1 => (0b000, 1), - 2 => (0b100, 2), - 3..=5 => (0b101, 4), - 6..=11 => (0b110, 8), - _ => (0b111, 16), - }; - let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; - - // Calculate real APB1 clock - let pclk1 = hclk / ppre1; - assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1)); - - let pclk2 = self - .config - .pclk2 - .map(|p| p.0) - .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk)); - let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 { - 0 => unreachable!(), - 1 => (0b000, 1), - 2 => (0b100, 2), - 3..=5 => (0b101, 4), - 6..=11 => (0b110, 8), - _ => (0b111, 16), - }; - let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; - - // Calculate real APB2 clock - let pclk2 = hclk / ppre2; - assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2)); - - Self::flash_setup(sysclk); - - if self.config.hse.is_some() { - // NOTE(unsafe) We own the peripheral block - unsafe { - RCC.cr().modify(|w| { - w.set_hsebyp(Hsebyp(self.config.bypass_hse as u8)); - w.set_hseon(true); - }); - while !RCC.cr().read().hserdy() {} - } - } - - if plls.use_pll { - unsafe { - RCC.cr().modify(|w| w.set_pllon(false)); - - // enable PWR and setup VOSScale - - RCC.apb1enr().modify(|w| w.set_pwren(true)); - - let vos_scale = if sysclk <= 144_000_000 { - 3 - } else if sysclk <= 168_000_000 { - 2 - } else { - 1 - }; - PWR.cr1().modify(|w| { - w.set_vos(match vos_scale { - 3 => Vos::SCALE3, - 2 => Vos::SCALE2, - 1 => Vos::SCALE1, - _ => panic!("Invalid VOS Scale."), - }) - }); - - RCC.cr().modify(|w| w.set_pllon(true)); - - if hclk > max::HCLK_OVERDRIVE_FREQUENCY { - PWR.cr1().modify(|w| w.set_oden(true)); - while !PWR.csr1().read().odrdy() {} - - PWR.cr1().modify(|w| w.set_odswen(true)); - while !PWR.csr1().read().odswrdy() {} - } - - while !RCC.cr().read().pllrdy() {} - } - } - - unsafe { - RCC.cfgr().modify(|w| { - w.set_ppre2(Ppre(ppre2_bits)); - w.set_ppre1(Ppre(ppre1_bits)); - w.set_hpre(hpre_bits); - }); - - // Wait for the new prescalers to kick in - // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write" - cortex_m::asm::delay(16); - - RCC.cfgr().modify(|w| { - w.set_sw(if sysclk_on_pll { - Sw::PLL - } else if self.config.hse.is_some() { - Sw::HSE - } else { - Sw::HSI - }) - }); - } - - Clocks { - sys: Hertz(sysclk), - apb1: Hertz(pclk1), - apb2: Hertz(pclk2), - - apb1_tim: Hertz(pclk1 * timer_mul1), - apb2_tim: Hertz(pclk2 * timer_mul2), - - ahb1: Hertz(hclk), - ahb2: Hertz(hclk), - ahb3: Hertz(hclk), - - pll48: plls.pll48clk.map(Hertz), - } - } - - // Safety: RCC init must have been called - pub fn clocks(&self) -> &'static Clocks { - unsafe { get_freqs() } - } - - fn setup_pll( - &mut self, - pllsrcclk: u32, - use_hse: bool, - pllsysclk: Option, - pll48clk: bool, - ) -> PllResults { - use crate::pac::rcc::vals::{Pllp, Pllsrc}; - - let sysclk = pllsysclk.unwrap_or(pllsrcclk); - if pllsysclk.is_none() && !pll48clk { - // NOTE(unsafe) We have a mutable borrow to the owner of the RegBlock - unsafe { - RCC.pllcfgr() - .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); - } - - return PllResults { - use_pll: false, - pllsysclk: None, - pll48clk: None, - }; - } - // Input divisor from PLL source clock, must result to frequency in - // the range from 1 to 2 MHz - let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000; - let pllm_max = pllsrcclk / 1_000_000; - - // Sysclk output divisor must be one of 2, 4, 6 or 8 - let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1); - - let target_freq = if pll48clk { - 48_000_000 - } else { - sysclk * sysclk_div - }; - - // Find the lowest pllm value that minimize the difference between - // target frequency and the real vco_out frequency. - let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| { - let vco_in = pllsrcclk / pllm; - let plln = target_freq / vco_in; - target_freq - vco_in * plln - })); - - let vco_in = pllsrcclk / pllm; - assert!((1_000_000..=2_000_000).contains(&vco_in)); - - // Main scaler, must result in >= 100MHz (>= 192MHz for F401) - // and <= 432MHz, min 50, max 432 - let plln = if pll48clk { - // try the different valid pllq according to the valid - // main scaller values, and take the best - let pllq = unwrap!((4..=9).min_by_key(|pllq| { - let plln = 48_000_000 * pllq / vco_in; - let pll48_diff = 48_000_000 - vco_in * plln / pllq; - let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs(); - (pll48_diff, sysclk_diff) - })); - 48_000_000 * pllq / vco_in - } else { - sysclk * sysclk_div / vco_in - }; - - let pllp = (sysclk_div / 2) - 1; - - let pllq = (vco_in * plln + 47_999_999) / 48_000_000; - let real_pll48clk = vco_in * plln / pllq; - - unsafe { - RCC.pllcfgr().modify(|w| { - w.set_pllm(pllm as u8); - w.set_plln(plln as u16); - w.set_pllp(Pllp(pllp as u8)); - w.set_pllq(pllq as u8); - w.set_pllsrc(Pllsrc(use_hse as u8)); - }); - } - - let real_pllsysclk = vco_in * plln / sysclk_div; - - PllResults { - use_pll: true, - pllsysclk: Some(real_pllsysclk), - pll48clk: if pll48clk { Some(real_pll48clk) } else { None }, - } - } - - fn flash_setup(sysclk: u32) { - use crate::pac::flash::vals::Latency; - - // Be conservative with voltage ranges - const FLASH_LATENCY_STEP: u32 = 30_000_000; - - critical_section::with(|_| unsafe { - FLASH - .acr() - .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); - }); - } + critical_section::with(|_| { + FLASH + .acr() + .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); + }); } pub(crate) unsafe fn init(config: Config) { - let r = ::steal(); - let clocks = Rcc::new(r, config).freeze(); - set_freqs(clocks); + crate::peripherals::PWR::enable(); + + if let Some(hse) = config.hse { + if config.bypass_hse { + assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0)); + } else { + assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0)); + } + } + + let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI); + let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); + let sysclk_on_pll = sysclk != pllsrcclk; + + assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk)); + + let plls = setup_pll( + pllsrcclk, + config.hse.is_some(), + if sysclk_on_pll { Some(sysclk) } else { None }, + config.pll48, + ); + + if config.pll48 { + let freq = unwrap!(plls.pll48clk); + + assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32); + } + + let sysclk = if sysclk_on_pll { + unwrap!(plls.pllsysclk) + } else { + sysclk + }; + + // AHB prescaler + let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk); + let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk { + 0 => unreachable!(), + 1 => (Hpre::DIV1, 1), + 2 => (Hpre::DIV2, 2), + 3..=5 => (Hpre::DIV4, 4), + 6..=11 => (Hpre::DIV8, 8), + 12..=39 => (Hpre::DIV16, 16), + 40..=95 => (Hpre::DIV64, 64), + 96..=191 => (Hpre::DIV128, 128), + 192..=383 => (Hpre::DIV256, 256), + _ => (Hpre::DIV512, 512), + }; + + // Calculate real AHB clock + let hclk = sysclk / hpre_div; + + assert!(hclk < max::HCLK_MAX); + + let pclk1 = config + .pclk1 + .map(|p| p.0) + .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk)); + + let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 { + 0 => unreachable!(), + 1 => (0b000, 1), + 2 => (0b100, 2), + 3..=5 => (0b101, 4), + 6..=11 => (0b110, 8), + _ => (0b111, 16), + }; + let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; + + // Calculate real APB1 clock + let pclk1 = hclk / ppre1; + assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1)); + + let pclk2 = config + .pclk2 + .map(|p| p.0) + .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk)); + let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 { + 0 => unreachable!(), + 1 => (0b000, 1), + 2 => (0b100, 2), + 3..=5 => (0b101, 4), + 6..=11 => (0b110, 8), + _ => (0b111, 16), + }; + let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; + + // Calculate real APB2 clock + let pclk2 = hclk / ppre2; + assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2)); + + flash_setup(sysclk); + + if config.hse.is_some() { + RCC.cr().modify(|w| { + w.set_hsebyp(Hsebyp(config.bypass_hse as u8)); + w.set_hseon(true); + }); + while !RCC.cr().read().hserdy() {} + } + + if plls.use_pll { + RCC.cr().modify(|w| w.set_pllon(false)); + + // enable PWR and setup VOSScale + + RCC.apb1enr().modify(|w| w.set_pwren(true)); + + let vos_scale = if sysclk <= 144_000_000 { + 3 + } else if sysclk <= 168_000_000 { + 2 + } else { + 1 + }; + PWR.cr1().modify(|w| { + w.set_vos(match vos_scale { + 3 => Vos::SCALE3, + 2 => Vos::SCALE2, + 1 => Vos::SCALE1, + _ => panic!("Invalid VOS Scale."), + }) + }); + + RCC.cr().modify(|w| w.set_pllon(true)); + + if hclk > max::HCLK_OVERDRIVE_FREQUENCY { + PWR.cr1().modify(|w| w.set_oden(true)); + while !PWR.csr1().read().odrdy() {} + + PWR.cr1().modify(|w| w.set_odswen(true)); + while !PWR.csr1().read().odswrdy() {} + } + + while !RCC.cr().read().pllrdy() {} + } + + RCC.cfgr().modify(|w| { + w.set_ppre2(Ppre(ppre2_bits)); + w.set_ppre1(Ppre(ppre1_bits)); + w.set_hpre(hpre_bits); + }); + + // Wait for the new prescalers to kick in + // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write" + cortex_m::asm::delay(16); + + RCC.cfgr().modify(|w| { + w.set_sw(if sysclk_on_pll { + Sw::PLL + } else if config.hse.is_some() { + Sw::HSE + } else { + Sw::HSI + }) + }); + + set_freqs(Clocks { + sys: Hertz(sysclk), + apb1: Hertz(pclk1), + apb2: Hertz(pclk2), + + apb1_tim: Hertz(pclk1 * timer_mul1), + apb2_tim: Hertz(pclk2 * timer_mul2), + + ahb1: Hertz(hclk), + ahb2: Hertz(hclk), + ahb3: Hertz(hclk), + + pll48: plls.pll48clk.map(Hertz), + }); } struct PllResults { diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index df11ff36..a3a4c197 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -1,11 +1,7 @@ -use crate::pac; -use crate::peripherals::{self, RCC}; -use crate::rcc::{get_freqs, set_freqs, Clocks}; +use crate::pac::{PWR, RCC}; +use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; use crate::time::U32Ext; -use core::marker::PhantomData; -use embassy::util::Unborrow; -use embassy_hal_common::unborrow; /// HSI speed pub const HSI_FREQ: u32 = 16_000_000; @@ -120,115 +116,68 @@ impl Default for Config { } } -/// RCC peripheral -pub struct Rcc<'d> { - _rb: peripherals::RCC, - phantom: PhantomData<&'d mut peripherals::RCC>, -} - -impl<'d> Rcc<'d> { - pub fn new(rcc: impl Unborrow + 'd) -> Self { - unborrow!(rcc); - Self { - _rb: rcc, - phantom: PhantomData, - } - } - - // Safety: RCC init must have been called - pub fn clocks(&self) -> &'static Clocks { - unsafe { get_freqs() } - } -} - -/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration -pub trait RccExt { - fn freeze(self, config: Config) -> Clocks; -} - -impl RccExt for RCC { - #[inline] - fn freeze(self, cfgr: Config) -> Clocks { - let rcc = pac::RCC; - let (sys_clk, sw) = match cfgr.mux { - ClockSrc::HSI16(div) => { - // Enable HSI16 - let div: u8 = div.into(); - unsafe { - rcc.cr().write(|w| { - w.set_hsidiv(div); - w.set_hsion(true) - }); - while !rcc.cr().read().hsirdy() {} - } - - (HSI_FREQ >> div, 0x00) - } - ClockSrc::HSE(freq) => { - // Enable HSE - unsafe { - rcc.cr().write(|w| w.set_hseon(true)); - while !rcc.cr().read().hserdy() {} - } - - (freq.0, 0x01) - } - ClockSrc::LSI => { - // Enable LSI - unsafe { - rcc.csr().write(|w| w.set_lsion(true)); - while !rcc.csr().read().lsirdy() {} - } - (LSI_FREQ, 0x03) - } - }; - - unsafe { - rcc.cfgr().modify(|w| { - w.set_sw(sw.into()); - w.set_hpre(cfgr.ahb_pre.into()); - w.set_ppre(cfgr.apb_pre.into()); - }); - } - - let ahb_freq: u32 = match cfgr.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, - pre => { - let pre: u8 = pre.into(); - let pre = 1 << (pre as u32 - 7); - sys_clk / pre - } - }; - - let (apb_freq, apb_tim_freq) = match cfgr.apb_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) - } - }; - - let pwr = pac::PWR; - if cfgr.low_power_run { - assert!(sys_clk.hz() <= 2_000_000.hz()); - unsafe { - pwr.cr1().modify(|w| w.set_lpr(true)); - } - } - - Clocks { - sys: sys_clk.hz(), - ahb: ahb_freq.hz(), - apb: apb_freq.hz(), - apb_tim: apb_tim_freq.hz(), - } - } -} - pub(crate) unsafe fn init(config: Config) { - let r = ::steal(); - let clocks = r.freeze(config); - set_freqs(clocks); + let (sys_clk, sw) = match config.mux { + ClockSrc::HSI16(div) => { + // Enable HSI16 + let div: u8 = div.into(); + RCC.cr().write(|w| { + w.set_hsidiv(div); + w.set_hsion(true) + }); + while !RCC.cr().read().hsirdy() {} + + (HSI_FREQ >> div, 0x00) + } + ClockSrc::HSE(freq) => { + // Enable HSE + RCC.cr().write(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + + (freq.0, 0x01) + } + ClockSrc::LSI => { + // Enable LSI + RCC.csr().write(|w| w.set_lsion(true)); + while !RCC.csr().read().lsirdy() {} + (LSI_FREQ, 0x03) + } + }; + + RCC.cfgr().modify(|w| { + w.set_sw(sw.into()); + w.set_hpre(config.ahb_pre.into()); + w.set_ppre(config.apb_pre.into()); + }); + + let ahb_freq: u32 = match config.ahb_pre { + AHBPrescaler::NotDivided => sys_clk, + pre => { + let pre: u8 = pre.into(); + let pre = 1 << (pre as u32 - 7); + sys_clk / pre + } + }; + + let (apb_freq, apb_tim_freq) = match config.apb_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: u8 = pre.into(); + let pre: u8 = 1 << (pre - 3); + let freq = ahb_freq / pre as u32; + (freq, freq * 2) + } + }; + + if config.low_power_run { + assert!(sys_clk.hz() <= 2_000_000.hz()); + PWR.cr1().modify(|w| w.set_lpr(true)); + } + + set_freqs(Clocks { + sys: sys_clk.hz(), + ahb: ahb_freq.hz(), + apb: apb_freq.hz(), + apb_tim: apb_tim_freq.hz(), + }); } diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index ee49e2ec..ce8cca45 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -1,11 +1,7 @@ -use crate::pac; -use crate::peripherals::{self, RCC}; -use crate::rcc::{get_freqs, set_freqs, Clocks}; +use crate::pac::{PWR, RCC}; +use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; use crate::time::U32Ext; -use core::marker::PhantomData; -use embassy::util::Unborrow; -use embassy_hal_common::unborrow; /// HSI speed pub const HSI_FREQ: u32 = 16_000_000; @@ -94,117 +90,72 @@ impl Default for Config { } } -/// RCC peripheral -pub struct Rcc<'d> { - _rb: peripherals::RCC, - phantom: PhantomData<&'d mut peripherals::RCC>, -} - -impl<'d> Rcc<'d> { - pub fn new(rcc: impl Unborrow + 'd) -> Self { - unborrow!(rcc); - Self { - _rb: rcc, - phantom: PhantomData, - } - } - - // Safety: RCC init must have been called - pub fn clocks(&self) -> &'static Clocks { - unsafe { get_freqs() } - } -} - -/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration -pub trait RccExt { - fn freeze(self, config: Config) -> Clocks; -} - -impl RccExt for RCC { - #[inline] - fn freeze(self, cfgr: Config) -> Clocks { - let rcc = pac::RCC; - let (sys_clk, sw) = match cfgr.mux { - ClockSrc::HSI16 => { - // Enable HSI16 - unsafe { - rcc.cr().write(|w| w.set_hsion(true)); - while !rcc.cr().read().hsirdy() {} - } - - (HSI_FREQ, 0x01) - } - ClockSrc::HSE(freq) => { - // Enable HSE - unsafe { - rcc.cr().write(|w| w.set_hseon(true)); - while !rcc.cr().read().hserdy() {} - } - - (freq.0, 0x02) - } - }; - - unsafe { - rcc.cfgr().modify(|w| { - w.set_sw(sw.into()); - w.set_hpre(cfgr.ahb_pre.into()); - w.set_ppre1(cfgr.apb1_pre.into()); - w.set_ppre2(cfgr.apb2_pre.into()); - }); - } - - let ahb_freq: u32 = match cfgr.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, - pre => { - let pre: u8 = pre.into(); - let pre = 1 << (pre as u32 - 7); - sys_clk / pre - } - }; - - let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) - } - }; - - let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) - } - }; - - let pwr = pac::PWR; - if cfgr.low_power_run { - assert!(sys_clk.hz() <= 2_000_000.hz()); - unsafe { - pwr.cr1().modify(|w| w.set_lpr(true)); - } - } - - Clocks { - sys: sys_clk.hz(), - ahb1: ahb_freq.hz(), - ahb2: ahb_freq.hz(), - apb1: apb1_freq.hz(), - apb1_tim: apb1_tim_freq.hz(), - apb2: apb2_freq.hz(), - apb2_tim: apb2_tim_freq.hz(), - } - } -} - pub(crate) unsafe fn init(config: Config) { - let r = ::steal(); - let clocks = r.freeze(config); - set_freqs(clocks); + let (sys_clk, sw) = match config.mux { + ClockSrc::HSI16 => { + // Enable HSI16 + RCC.cr().write(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + + (HSI_FREQ, 0x01) + } + ClockSrc::HSE(freq) => { + // Enable HSE + RCC.cr().write(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + + (freq.0, 0x02) + } + }; + + RCC.cfgr().modify(|w| { + w.set_sw(sw.into()); + w.set_hpre(config.ahb_pre.into()); + w.set_ppre1(config.apb1_pre.into()); + w.set_ppre2(config.apb2_pre.into()); + }); + + let ahb_freq: u32 = match config.ahb_pre { + AHBPrescaler::NotDivided => sys_clk, + pre => { + let pre: u8 = pre.into(); + let pre = 1 << (pre as u32 - 7); + sys_clk / pre + } + }; + + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: u8 = pre.into(); + let pre: u8 = 1 << (pre - 3); + let freq = ahb_freq / pre as u32; + (freq, freq * 2) + } + }; + + let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: u8 = pre.into(); + let pre: u8 = 1 << (pre - 3); + let freq = ahb_freq / pre as u32; + (freq, freq * 2) + } + }; + + if config.low_power_run { + assert!(sys_clk.hz() <= 2_000_000.hz()); + PWR.cr1().modify(|w| w.set_lpr(true)); + } + + set_freqs(Clocks { + sys: sys_clk.hz(), + ahb1: ahb_freq.hz(), + ahb2: ahb_freq.hz(), + apb1: apb1_freq.hz(), + apb1_tim: apb1_tim_freq.hz(), + apb2: apb2_freq.hz(), + apb2_tim: apb2_tim_freq.hz(), + }); } diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index ac4d033b..55ddf073 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs @@ -7,9 +7,9 @@ use stm32_metapac::rcc::vals::{Mco1, Mco2}; use crate::gpio::sealed::Pin as __GpioPin; use crate::gpio::Pin; use crate::pac::rcc::vals::Timpre; -use crate::pac::{RCC, SYSCFG}; +use crate::pac::rcc::vals::{Ckpersel, Dppre, Hpre, Hsebyp, Hsidiv, Pllsrc, Sw}; +use crate::pac::{PWR, RCC, SYSCFG}; use crate::peripherals; -use crate::pwr::{Power, VoltageScale}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -20,6 +20,22 @@ const CSI: Hertz = Hertz(4_000_000); const HSI48: Hertz = Hertz(48_000_000); const LSI: Hertz = Hertz(32_000); +/// Voltage Scale +/// +/// Represents the voltage range feeding the CPU core. The maximum core +/// clock frequency depends on this value. +#[derive(Copy, Clone, PartialEq)] +pub enum VoltageScale { + /// VOS 0 range VCORE 1.26V - 1.40V + Scale0, + /// VOS 1 range VCORE 1.15V - 1.26V + Scale1, + /// VOS 2 range VCORE 1.05V - 1.15V + Scale2, + /// VOS 3 range VCORE 0.95V - 1.05V + Scale3, +} + /// Core clock frequencies #[derive(Clone, Copy)] pub struct CoreClocks { @@ -72,439 +88,151 @@ pub struct Config { pub pll3: PllConfig, } -pub struct Rcc<'d> { - inner: PhantomData<&'d ()>, - config: Config, +/// Setup traceclk +/// Returns a pll1_r_ck +fn traceclk_setup(config: &mut Config, sys_use_pll1_p: bool) { + let pll1_r_ck = match (sys_use_pll1_p, config.pll1.r_ck) { + // pll1_p_ck selected as system clock but pll1_r_ck not + // set. The traceclk mux is synchronous with the system + // clock mux, but has pll1_r_ck as an input. In order to + // keep traceclk running, we force a pll1_r_ck. + (true, None) => Some(Hertz(unwrap!(config.pll1.p_ck).0 / 2)), + + // Either pll1 not selected as system clock, free choice + // of pll1_r_ck. Or pll1 is selected, assume user has set + // a suitable pll1_r_ck frequency. + _ => config.pll1.r_ck, + }; + config.pll1.r_ck = pll1_r_ck; } -impl<'d> Rcc<'d> { - pub fn new(_rcc: impl Unborrow + 'd, config: Config) -> Self { - Self { - inner: PhantomData, - config, - } - } +/// Divider calculator for pclk 1 - 4 +/// +/// Returns real pclk, bits, ppre and the timer kernel clock +fn ppre_calculate( + requested_pclk: u32, + hclk: u32, + max_pclk: u32, + tim_pre: Option, +) -> (u32, u8, u8, Option) { + let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk { + 0 => panic!(), + 1 => (0b000, 1), + 2 => (0b100, 2), + 3..=5 => (0b101, 4), + 6..=11 => (0b110, 8), + _ => (0b111, 16), + }; + let real_pclk = hclk / u32::from(ppre); + assert!(real_pclk <= max_pclk); - /// Freeze the core clocks, returning a Core Clocks Distribution - /// and Reset (CCDR) structure. The actual frequency of the clocks - /// configured is returned in the `clocks` member of the CCDR - /// structure. - /// - /// Note that `freeze` will never result in a clock _faster_ than - /// that specified. It may result in a clock that is a factor of [1, - /// 2) slower. - /// - /// `syscfg` is required to enable the I/O compensation cell. - /// - /// # Panics - /// - /// If a clock specification cannot be achieved within the - /// hardware specification then this function will panic. This - /// function may also panic if a clock specification can be - /// achieved, but the mechanism for doing so is not yet - /// implemented here. - pub fn freeze(mut self, pwr: &Power) -> CoreClocks { - use crate::pac::rcc::vals::{Ckpersel, Dppre, Hpre, Hsebyp, Hsidiv, Pllsrc, Sw}; - - let srcclk = self.config.hse.unwrap_or(HSI); // Available clocks - let (sys_ck, sys_use_pll1_p) = self.sys_ck_setup(srcclk); - - // Configure traceclk from PLL if needed - self.traceclk_setup(sys_use_pll1_p); - - // NOTE(unsafe) We have exclusive access to the RCC - let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = - unsafe { pll::pll_setup(srcclk.0, &self.config.pll1, 0) }; - let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = - unsafe { pll::pll_setup(srcclk.0, &self.config.pll2, 1) }; - let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = - 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 - } else { - sys_ck + let tim_ker_clk = if let Some(tim_pre) = tim_pre { + let clk = match (bits, tim_pre) { + (0b101, Timpre::DEFAULTX2) => hclk / 2, + (0b110, Timpre::DEFAULTX4) => hclk / 2, + (0b110, Timpre::DEFAULTX2) => hclk / 4, + (0b111, Timpre::DEFAULTX4) => hclk / 4, + (0b111, Timpre::DEFAULTX2) => hclk / 8, + _ => hclk, }; + Some(clk) + } else { + None + }; + (real_pclk, bits, ppre, tim_ker_clk) +} - // NOTE(unsafe) We own the regblock - unsafe { - // This routine does not support HSIDIV != 1. To - // do so it would need to ensure all PLLxON bits are clear - // before changing the value of HSIDIV - let cr = RCC.cr().read(); - assert!(cr.hsion()); - assert!(cr.hsidiv() == Hsidiv::DIV1); +/// Setup sys_ck +/// Returns sys_ck frequency, and a pll1_p_ck +fn sys_ck_setup(config: &mut Config, srcclk: Hertz) -> (Hertz, bool) { + // Compare available with wanted clocks + let sys_ck = config.sys_ck.unwrap_or(srcclk); - RCC.csr().modify(|w| w.set_lsion(true)); - while !RCC.csr().read().lsirdy() {} - } - - // per_ck from HSI by default - let (per_ck, ckpersel) = match (self.config.per_ck == self.config.hse, self.config.per_ck) { - (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE - (_, Some(CSI)) => (CSI, Ckpersel::CSI), // CSI - _ => (HSI, Ckpersel::HSI), // HSI - }; - - // D1 Core Prescaler - // Set to 1 - let d1cpre_bits = 0; - let d1cpre_div = 1; - let sys_d1cpre_ck = sys_ck.0 / d1cpre_div; - - // Refer to part datasheet "General operating conditions" - // table for (rev V). We do not assert checks for earlier - // revisions which may have lower limits. - let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr.vos { - VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000), - VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000), - VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000), - _ => (200_000_000, 100_000_000, 50_000_000), - }; - assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max); - - let rcc_hclk = self - .config - .rcc_hclk - .map(|v| v.0) - .unwrap_or(sys_d1cpre_ck / 2); - assert!(rcc_hclk <= rcc_hclk_max); - - // Estimate divisor - let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk { - 0 => panic!(), - 1 => (Hpre::DIV1, 1), - 2 => (Hpre::DIV2, 2), - 3..=5 => (Hpre::DIV4, 4), - 6..=11 => (Hpre::DIV8, 8), - 12..=39 => (Hpre::DIV16, 16), - 40..=95 => (Hpre::DIV64, 64), - 96..=191 => (Hpre::DIV128, 128), - 192..=383 => (Hpre::DIV256, 256), - _ => (Hpre::DIV512, 512), - }; - // Calculate real AXI and AHB clock - let rcc_hclk = sys_d1cpre_ck / hpre_div; - assert!(rcc_hclk <= rcc_hclk_max); - let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7 - // Timer prescaler selection - let timpre = Timpre::DEFAULTX2; - - let requested_pclk1 = self - .config - .pclk1 - .map(|v| v.0) - .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); - let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) = - Self::ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre)); - - let requested_pclk2 = self - .config - .pclk2 - .map(|v| v.0) - .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); - let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) = - Self::ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre)); - - let requested_pclk3 = self - .config - .pclk3 - .map(|v| v.0) - .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); - let (rcc_pclk3, ppre3_bits, ppre3, _) = - Self::ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None); - - let requested_pclk4 = self - .config - .pclk4 - .map(|v| v.0) - .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); - let (rcc_pclk4, ppre4_bits, ppre4, _) = - Self::ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None); - - Self::flash_setup(rcc_aclk, pwr.vos); - - // Start switching clocks ------------------- - // NOTE(unsafe) We have the RCC singleton - unsafe { - // Ensure CSI is on and stable - RCC.cr().modify(|w| w.set_csion(true)); - while !RCC.cr().read().csirdy() {} - - // Ensure HSI48 is on and stable - RCC.cr().modify(|w| w.set_hsi48on(true)); - while !RCC.cr().read().hsi48on() {} - - // XXX: support MCO ? - - let hse_ck = match self.config.hse { - Some(hse) => { - // Ensure HSE is on and stable - RCC.cr().modify(|w| { - w.set_hseon(true); - w.set_hsebyp(if self.config.bypass_hse { - Hsebyp::BYPASSED - } else { - Hsebyp::NOTBYPASSED - }); - }); - while !RCC.cr().read().hserdy() {} - Some(hse) - } - None => None, - }; - - let pllsrc = if self.config.hse.is_some() { - Pllsrc::HSE - } else { - Pllsrc::HSI - }; - RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc)); - - let enable_pll = |pll| { - RCC.cr().modify(|w| w.set_pllon(pll, true)); - while !RCC.cr().read().pllrdy(pll) {} - }; - - if pll1_p_ck.is_some() { - enable_pll(0); - } - - if pll2_p_ck.is_some() { - enable_pll(1); - } - - if pll3_p_ck.is_some() { - enable_pll(2); - } - - // Core Prescaler / AHB Prescaler / APB3 Prescaler - RCC.d1cfgr().modify(|w| { - w.set_d1cpre(Hpre(d1cpre_bits)); - w.set_d1ppre(Dppre(ppre3_bits)); - w.set_hpre(hpre_bits) - }); - // Ensure core prescaler value is valid before future lower - // core voltage - while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {} - - // APB1 / APB2 Prescaler - RCC.d2cfgr().modify(|w| { - w.set_d2ppre1(Dppre(ppre1_bits)); - w.set_d2ppre2(Dppre(ppre2_bits)); - }); - - // APB4 Prescaler - RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits))); - - // Peripheral Clock (per_ck) - RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); - - // Set timer clocks prescaler setting - RCC.cfgr().modify(|w| w.set_timpre(timpre)); - - // Select system clock source - let sw = match (sys_use_pll1_p, self.config.hse.is_some()) { - (true, _) => Sw::PLL1, - (false, true) => Sw::HSE, - _ => Sw::HSI, - }; - RCC.cfgr().modify(|w| w.set_sw(sw)); - while RCC.cfgr().read().sws() != sw.0 {} - - // IO compensation cell - Requires CSI clock and SYSCFG - assert!(RCC.cr().read().csirdy()); - RCC.apb4enr().modify(|w| w.set_syscfgen(true)); - - // Enable the compensation cell, using back-bias voltage code - // provide by the cell. - critical_section::with(|_| { - SYSCFG.cccsr().modify(|w| { - w.set_en(true); - w.set_cs(false); - w.set_hslv(false); - }) - }); - while !SYSCFG.cccsr().read().ready() {} - - CoreClocks { - hclk: Hertz(rcc_hclk), - pclk1: Hertz(rcc_pclk1), - pclk2: Hertz(rcc_pclk2), - pclk3: Hertz(rcc_pclk3), - pclk4: Hertz(rcc_pclk4), - ppre1, - ppre2, - ppre3, - ppre4, - csi_ck: Some(CSI), - hsi_ck: Some(HSI), - hsi48_ck: Some(HSI48), - lsi_ck: Some(LSI), - per_ck: Some(per_ck), - hse_ck, - pll1_p_ck: pll1_p_ck.map(Hertz), - pll1_q_ck: pll1_q_ck.map(Hertz), - pll1_r_ck: pll1_r_ck.map(Hertz), - pll2_p_ck: pll2_p_ck.map(Hertz), - pll2_q_ck: pll2_q_ck.map(Hertz), - pll2_r_ck: pll2_r_ck.map(Hertz), - pll3_p_ck: pll3_p_ck.map(Hertz), - pll3_q_ck: pll3_q_ck.map(Hertz), - pll3_r_ck: pll3_r_ck.map(Hertz), - timx_ker_ck: rcc_timerx_ker_ck.map(Hertz), - timy_ker_ck: rcc_timery_ker_ck.map(Hertz), - sys_ck, - c_ck: Hertz(sys_d1cpre_ck), - } - } - } - - /// Setup traceclk - /// Returns a pll1_r_ck - fn traceclk_setup(&mut self, sys_use_pll1_p: bool) { - let pll1_r_ck = match (sys_use_pll1_p, self.config.pll1.r_ck) { - // pll1_p_ck selected as system clock but pll1_r_ck not - // set. The traceclk mux is synchronous with the system - // clock mux, but has pll1_r_ck as an input. In order to - // keep traceclk running, we force a pll1_r_ck. - (true, None) => Some(Hertz(unwrap!(self.config.pll1.p_ck).0 / 2)), - - // Either pll1 not selected as system clock, free choice - // of pll1_r_ck. Or pll1 is selected, assume user has set - // a suitable pll1_r_ck frequency. - _ => self.config.pll1.r_ck, - }; - self.config.pll1.r_ck = pll1_r_ck; - } - - /// Divider calculator for pclk 1 - 4 - /// - /// Returns real pclk, bits, ppre and the timer kernel clock - fn ppre_calculate( - requested_pclk: u32, - hclk: u32, - max_pclk: u32, - tim_pre: Option, - ) -> (u32, u8, u8, Option) { - let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk { - 0 => panic!(), - 1 => (0b000, 1), - 2 => (0b100, 2), - 3..=5 => (0b101, 4), - 6..=11 => (0b110, 8), - _ => (0b111, 16), - }; - let real_pclk = hclk / u32::from(ppre); - assert!(real_pclk <= max_pclk); - - let tim_ker_clk = if let Some(tim_pre) = tim_pre { - let clk = match (bits, tim_pre) { - (0b101, Timpre::DEFAULTX2) => hclk / 2, - (0b110, Timpre::DEFAULTX4) => hclk / 2, - (0b110, Timpre::DEFAULTX2) => hclk / 4, - (0b111, Timpre::DEFAULTX4) => hclk / 4, - (0b111, Timpre::DEFAULTX2) => hclk / 8, - _ => hclk, - }; - Some(clk) - } else { - None - }; - (real_pclk, bits, ppre, tim_ker_clk) - } - - /// Setup sys_ck - /// Returns sys_ck frequency, and a pll1_p_ck - fn sys_ck_setup(&mut self, srcclk: Hertz) -> (Hertz, bool) { - // Compare available with wanted clocks - let sys_ck = self.config.sys_ck.unwrap_or(srcclk); - - if sys_ck != srcclk { - // The requested system clock is not the immediately available - // HSE/HSI clock. Perhaps there are other ways of obtaining - // the requested system clock (such as `HSIDIV`) but we will - // ignore those for now. - // - // Therefore we must use pll1_p_ck - let pll1_p_ck = match self.config.pll1.p_ck { - Some(p_ck) => { - assert!(p_ck == sys_ck, + if sys_ck != srcclk { + // The requested system clock is not the immediately available + // HSE/HSI clock. Perhaps there are other ways of obtaining + // the requested system clock (such as `HSIDIV`) but we will + // ignore those for now. + // + // Therefore we must use pll1_p_ck + let pll1_p_ck = match config.pll1.p_ck { + Some(p_ck) => { + assert!(p_ck == sys_ck, "Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck"); - Some(p_ck) - } - None => Some(sys_ck), - }; - self.config.pll1.p_ck = pll1_p_ck; - - (sys_ck, true) - } else { - // sys_ck is derived directly from a source clock - // (HSE/HSI). pll1_p_ck can be as requested - (sys_ck, false) - } - } - - fn flash_setup(rcc_aclk: u32, vos: VoltageScale) { - use crate::pac::FLASH; - - // ACLK in MHz, round down and subtract 1 from integers. eg. - // 61_999_999 -> 61MHz - // 62_000_000 -> 61MHz - // 62_000_001 -> 62MHz - let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000; - - // See RM0433 Rev 7 Table 17. FLASH recommended number of wait - // states and programming delay - let (wait_states, progr_delay) = match vos { - // VOS 0 range VCORE 1.26V - 1.40V - VoltageScale::Scale0 => match rcc_aclk_mhz { - 0..=69 => (0, 0), - 70..=139 => (1, 1), - 140..=184 => (2, 1), - 185..=209 => (2, 2), - 210..=224 => (3, 2), - 225..=239 => (4, 2), - _ => (7, 3), - }, - // VOS 1 range VCORE 1.15V - 1.26V - VoltageScale::Scale1 => match rcc_aclk_mhz { - 0..=69 => (0, 0), - 70..=139 => (1, 1), - 140..=184 => (2, 1), - 185..=209 => (2, 2), - 210..=224 => (3, 2), - _ => (7, 3), - }, - // VOS 2 range VCORE 1.05V - 1.15V - VoltageScale::Scale2 => match rcc_aclk_mhz { - 0..=54 => (0, 0), - 55..=109 => (1, 1), - 110..=164 => (2, 1), - 165..=224 => (3, 2), - _ => (7, 3), - }, - // VOS 3 range VCORE 0.95V - 1.05V - VoltageScale::Scale3 => match rcc_aclk_mhz { - 0..=44 => (0, 0), - 45..=89 => (1, 1), - 90..=134 => (2, 1), - 135..=179 => (3, 2), - 180..=224 => (4, 2), - _ => (7, 3), - }, + Some(p_ck) + } + None => Some(sys_ck), }; + config.pll1.p_ck = pll1_p_ck; - // NOTE(unsafe) Atomic write - unsafe { - FLASH.acr().write(|w| { - w.set_wrhighfreq(progr_delay); - w.set_latency(wait_states) - }); - while FLASH.acr().read().latency() != wait_states {} - } + (sys_ck, true) + } else { + // sys_ck is derived directly from a source clock + // (HSE/HSI). pll1_p_ck can be as requested + (sys_ck, false) } } + +fn flash_setup(rcc_aclk: u32, vos: VoltageScale) { + use crate::pac::FLASH; + + // ACLK in MHz, round down and subtract 1 from integers. eg. + // 61_999_999 -> 61MHz + // 62_000_000 -> 61MHz + // 62_000_001 -> 62MHz + let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000; + + // See RM0433 Rev 7 Table 17. FLASH recommended number of wait + // states and programming delay + let (wait_states, progr_delay) = match vos { + // VOS 0 range VCORE 1.26V - 1.40V + VoltageScale::Scale0 => match rcc_aclk_mhz { + 0..=69 => (0, 0), + 70..=139 => (1, 1), + 140..=184 => (2, 1), + 185..=209 => (2, 2), + 210..=224 => (3, 2), + 225..=239 => (4, 2), + _ => (7, 3), + }, + // VOS 1 range VCORE 1.15V - 1.26V + VoltageScale::Scale1 => match rcc_aclk_mhz { + 0..=69 => (0, 0), + 70..=139 => (1, 1), + 140..=184 => (2, 1), + 185..=209 => (2, 2), + 210..=224 => (3, 2), + _ => (7, 3), + }, + // VOS 2 range VCORE 1.05V - 1.15V + VoltageScale::Scale2 => match rcc_aclk_mhz { + 0..=54 => (0, 0), + 55..=109 => (1, 1), + 110..=164 => (2, 1), + 165..=224 => (3, 2), + _ => (7, 3), + }, + // VOS 3 range VCORE 0.95V - 1.05V + VoltageScale::Scale3 => match rcc_aclk_mhz { + 0..=44 => (0, 0), + 45..=89 => (1, 1), + 90..=134 => (2, 1), + 135..=179 => (3, 2), + 180..=224 => (4, 2), + _ => (7, 3), + }, + }; + + // NOTE(unsafe) Atomic write + unsafe { + FLASH.acr().write(|w| { + w.set_wrhighfreq(progr_delay); + w.set_latency(wait_states) + }); + while FLASH.acr().read().latency() != wait_states {} + } +} + pub enum McoClock { Disabled, Bypassed, @@ -681,10 +409,309 @@ impl<'d, T: McoInstance> Mco<'d, T> { } } -pub(crate) unsafe fn init(config: Config) { - let mut power = Power::new(::steal(), false); - let rcc = Rcc::new(::steal(), config); - let core_clocks = rcc.freeze(&mut power); +pub(crate) unsafe fn init(mut config: Config) { + // TODO make configurable? + let enable_overdrive = false; + + // NB. The lower bytes of CR3 can only be written once after + // POR, and must be written with a valid combination. Refer to + // RM0433 Rev 7 6.8.4. This is partially enforced by dropping + // `self` at the end of this method, but of course we cannot + // know what happened between the previous POR and here. + #[cfg(pwr_h7)] + PWR.cr3().modify(|w| { + w.set_scuen(true); + w.set_ldoen(true); + w.set_bypass(false); + }); + + #[cfg(pwr_h7smps)] + PWR.cr3().modify(|w| { + // hardcode "Direct SPMS" for now, this is what works on nucleos with the + // default solderbridge configuration. + w.set_sden(true); + w.set_ldoen(false); + }); + + // Validate the supply configuration. If you are stuck here, it is + // because the voltages on your board do not match those specified + // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset + // VOS = Scale 3, so check that the voltage on the VCAP pins = + // 1.0V. + while !PWR.csr1().read().actvosrdy() {} + + // Go to Scale 1 + PWR.d3cr().modify(|w| w.set_vos(0b11)); + while !PWR.d3cr().read().vosrdy() {} + + let pwr_vos = if !enable_overdrive { + VoltageScale::Scale1 + } else { + critical_section::with(|_| { + RCC.apb4enr().modify(|w| w.set_syscfgen(true)); + + SYSCFG.pwrcr().modify(|w| w.set_oden(1)); + }); + while !PWR.d3cr().read().vosrdy() {} + VoltageScale::Scale0 + }; + + // Freeze the core clocks, returning a Core Clocks Distribution + // and Reset (CCDR) structure. The actual frequency of the clocks + // configured is returned in the `clocks` member of the CCDR + // structure. + // + // Note that `freeze` will never result in a clock _faster_ than + // that specified. It may result in a clock that is a factor of [1, + // 2) slower. + // + // `syscfg` is required to enable the I/O compensation cell. + // + // # Panics + // + // If a clock specification cannot be achieved within the + // hardware specification then this function will panic. This + // function may also panic if a clock specification can be + // achieved, but the mechanism for doing so is not yet + // implemented here. + + let srcclk = config.hse.unwrap_or(HSI); // Available clocks + let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk); + + // Configure traceclk from PLL if needed + traceclk_setup(&mut config, sys_use_pll1_p); + + // NOTE(unsafe) We have exclusive access to the RCC + let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0); + let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1); + let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2); + + let sys_ck = if sys_use_pll1_p { + Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup + } else { + sys_ck + }; + + // This routine does not support HSIDIV != 1. To + // do so it would need to ensure all PLLxON bits are clear + // before changing the value of HSIDIV + let cr = RCC.cr().read(); + assert!(cr.hsion()); + assert!(cr.hsidiv() == Hsidiv::DIV1); + + RCC.csr().modify(|w| w.set_lsion(true)); + while !RCC.csr().read().lsirdy() {} + + // per_ck from HSI by default + let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) { + (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE + (_, Some(CSI)) => (CSI, Ckpersel::CSI), // CSI + _ => (HSI, Ckpersel::HSI), // HSI + }; + + // D1 Core Prescaler + // Set to 1 + let d1cpre_bits = 0; + let d1cpre_div = 1; + let sys_d1cpre_ck = sys_ck.0 / d1cpre_div; + + // Refer to part datasheet "General operating conditions" + // table for (rev V). We do not assert checks for earlier + // revisions which may have lower limits. + let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr_vos { + VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000), + VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000), + VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000), + _ => (200_000_000, 100_000_000, 50_000_000), + }; + assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max); + + let rcc_hclk = config.rcc_hclk.map(|v| v.0).unwrap_or(sys_d1cpre_ck / 2); + assert!(rcc_hclk <= rcc_hclk_max); + + // Estimate divisor + let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk { + 0 => panic!(), + 1 => (Hpre::DIV1, 1), + 2 => (Hpre::DIV2, 2), + 3..=5 => (Hpre::DIV4, 4), + 6..=11 => (Hpre::DIV8, 8), + 12..=39 => (Hpre::DIV16, 16), + 40..=95 => (Hpre::DIV64, 64), + 96..=191 => (Hpre::DIV128, 128), + 192..=383 => (Hpre::DIV256, 256), + _ => (Hpre::DIV512, 512), + }; + // Calculate real AXI and AHB clock + let rcc_hclk = sys_d1cpre_ck / hpre_div; + assert!(rcc_hclk <= rcc_hclk_max); + let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7 + // Timer prescaler selection + let timpre = Timpre::DEFAULTX2; + + let requested_pclk1 = config + .pclk1 + .map(|v| v.0) + .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); + let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) = + ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre)); + + let requested_pclk2 = config + .pclk2 + .map(|v| v.0) + .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); + let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) = + ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre)); + + let requested_pclk3 = config + .pclk3 + .map(|v| v.0) + .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); + let (rcc_pclk3, ppre3_bits, ppre3, _) = + ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None); + + let requested_pclk4 = config + .pclk4 + .map(|v| v.0) + .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); + let (rcc_pclk4, ppre4_bits, ppre4, _) = + ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None); + + flash_setup(rcc_aclk, pwr_vos); + + // Start switching clocks ------------------- + + // Ensure CSI is on and stable + RCC.cr().modify(|w| w.set_csion(true)); + while !RCC.cr().read().csirdy() {} + + // Ensure HSI48 is on and stable + RCC.cr().modify(|w| w.set_hsi48on(true)); + while !RCC.cr().read().hsi48on() {} + + // XXX: support MCO ? + + let hse_ck = match config.hse { + Some(hse) => { + // Ensure HSE is on and stable + RCC.cr().modify(|w| { + w.set_hseon(true); + w.set_hsebyp(if config.bypass_hse { + Hsebyp::BYPASSED + } else { + Hsebyp::NOTBYPASSED + }); + }); + while !RCC.cr().read().hserdy() {} + Some(hse) + } + None => None, + }; + + let pllsrc = if config.hse.is_some() { + Pllsrc::HSE + } else { + Pllsrc::HSI + }; + RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc)); + + let enable_pll = |pll| { + RCC.cr().modify(|w| w.set_pllon(pll, true)); + while !RCC.cr().read().pllrdy(pll) {} + }; + + if pll1_p_ck.is_some() { + enable_pll(0); + } + + if pll2_p_ck.is_some() { + enable_pll(1); + } + + if pll3_p_ck.is_some() { + enable_pll(2); + } + + // Core Prescaler / AHB Prescaler / APB3 Prescaler + RCC.d1cfgr().modify(|w| { + w.set_d1cpre(Hpre(d1cpre_bits)); + w.set_d1ppre(Dppre(ppre3_bits)); + w.set_hpre(hpre_bits) + }); + // Ensure core prescaler value is valid before future lower + // core voltage + while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {} + + // APB1 / APB2 Prescaler + RCC.d2cfgr().modify(|w| { + w.set_d2ppre1(Dppre(ppre1_bits)); + w.set_d2ppre2(Dppre(ppre2_bits)); + }); + + // APB4 Prescaler + RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits))); + + // Peripheral Clock (per_ck) + RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); + + // Set timer clocks prescaler setting + RCC.cfgr().modify(|w| w.set_timpre(timpre)); + + // Select system clock source + let sw = match (sys_use_pll1_p, config.hse.is_some()) { + (true, _) => Sw::PLL1, + (false, true) => Sw::HSE, + _ => Sw::HSI, + }; + RCC.cfgr().modify(|w| w.set_sw(sw)); + while RCC.cfgr().read().sws() != sw.0 {} + + // IO compensation cell - Requires CSI clock and SYSCFG + assert!(RCC.cr().read().csirdy()); + RCC.apb4enr().modify(|w| w.set_syscfgen(true)); + + // Enable the compensation cell, using back-bias voltage code + // provide by the cell. + critical_section::with(|_| { + SYSCFG.cccsr().modify(|w| { + w.set_en(true); + w.set_cs(false); + w.set_hslv(false); + }) + }); + while !SYSCFG.cccsr().read().ready() {} + + let core_clocks = CoreClocks { + hclk: Hertz(rcc_hclk), + pclk1: Hertz(rcc_pclk1), + pclk2: Hertz(rcc_pclk2), + pclk3: Hertz(rcc_pclk3), + pclk4: Hertz(rcc_pclk4), + ppre1, + ppre2, + ppre3, + ppre4, + csi_ck: Some(CSI), + hsi_ck: Some(HSI), + hsi48_ck: Some(HSI48), + lsi_ck: Some(LSI), + per_ck: Some(per_ck), + hse_ck, + pll1_p_ck: pll1_p_ck.map(Hertz), + pll1_q_ck: pll1_q_ck.map(Hertz), + pll1_r_ck: pll1_r_ck.map(Hertz), + pll2_p_ck: pll2_p_ck.map(Hertz), + pll2_q_ck: pll2_q_ck.map(Hertz), + pll2_r_ck: pll2_r_ck.map(Hertz), + pll3_p_ck: pll3_p_ck.map(Hertz), + pll3_q_ck: pll3_q_ck.map(Hertz), + pll3_r_ck: pll3_r_ck.map(Hertz), + timx_ker_ck: rcc_timerx_ker_ck.map(Hertz), + timy_ker_ck: rcc_timery_ker_ck.map(Hertz), + sys_ck, + c_ck: Hertz(sys_d1cpre_ck), + }; + set_freqs(Clocks { sys: core_clocks.c_ck, ahb1: core_clocks.hclk, diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index fc70ef0a..25daeedf 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -1,18 +1,11 @@ -use crate::pac; -use crate::peripherals::{self, CRS, RCC, SYSCFG}; -use crate::rcc::{get_freqs, set_freqs, Clocks}; +use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; +use crate::pac::{CRS, RCC, SYSCFG}; +use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; use crate::time::U32Ext; -use core::marker::PhantomData; -use embassy::util::Unborrow; -use embassy_hal_common::unborrow; -use pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; -/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, -/// and with the addition of the init function to configure a system clock. - -/// HSI speed -pub const HSI_FREQ: u32 = 16_000_000; +/// HSI16 speed +pub const HSI16_FREQ: u32 = 16_000_000; /// System clock mux source #[derive(Clone, Copy)] @@ -104,9 +97,9 @@ pub enum PLLSource { HSE(Hertz), } -impl Into for PLLMul { - fn into(self) -> Pllmul { - match self { +impl From for Pllmul { + fn from(val: PLLMul) -> Pllmul { + match val { PLLMul::Mul3 => Pllmul::MUL3, PLLMul::Mul4 => Pllmul::MUL4, PLLMul::Mul6 => Pllmul::MUL6, @@ -120,9 +113,9 @@ impl Into for PLLMul { } } -impl Into for PLLDiv { - fn into(self) -> Plldiv { - match self { +impl From for Plldiv { + fn from(val: PLLDiv) -> Plldiv { + match val { PLLDiv::Div2 => Plldiv::DIV2, PLLDiv::Div3 => Plldiv::DIV3, PLLDiv::Div4 => Plldiv::DIV4, @@ -130,18 +123,18 @@ impl Into for PLLDiv { } } -impl Into for PLLSource { - fn into(self) -> Pllsrc { - match self { +impl From for Pllsrc { + fn from(val: PLLSource) -> Pllsrc { + match val { PLLSource::HSI16 => Pllsrc::HSI16, PLLSource::HSE(_) => Pllsrc::HSE, } } } -impl Into for APBPrescaler { - fn into(self) -> Ppre { - match self { +impl From for Ppre { + fn from(val: APBPrescaler) -> Ppre { + match val { APBPrescaler::NotDivided => Ppre::DIV1, APBPrescaler::Div2 => Ppre::DIV2, APBPrescaler::Div4 => Ppre::DIV4, @@ -151,9 +144,9 @@ impl Into for APBPrescaler { } } -impl Into for AHBPrescaler { - fn into(self) -> Hpre { - match self { +impl From for Hpre { + fn from(val: AHBPrescaler) -> Hpre { + match val { AHBPrescaler::NotDivided => Hpre::DIV1, AHBPrescaler::Div2 => Hpre::DIV2, AHBPrescaler::Div4 => Hpre::DIV4, @@ -167,9 +160,9 @@ impl Into for AHBPrescaler { } } -impl Into for MSIRange { - fn into(self) -> Msirange { - match self { +impl From for Msirange { + fn from(val: MSIRange) -> Msirange { + match val { MSIRange::Range0 => Msirange::RANGE0, MSIRange::Range1 => Msirange::RANGE1, MSIRange::Range2 => Msirange::RANGE2, @@ -187,6 +180,7 @@ pub struct Config { pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, + pub enable_hsi48: bool, } impl Default for Config { @@ -197,241 +191,172 @@ impl Default for Config { ahb_pre: AHBPrescaler::NotDivided, apb1_pre: APBPrescaler::NotDivided, apb2_pre: APBPrescaler::NotDivided, + enable_hsi48: false, } } } -/// RCC peripheral -pub struct Rcc<'d> { - _rb: peripherals::RCC, - phantom: PhantomData<&'d mut peripherals::RCC>, -} - -impl<'d> Rcc<'d> { - pub fn new(rcc: impl Unborrow + 'd) -> Self { - unborrow!(rcc); - Self { - _rb: rcc, - phantom: PhantomData, - } - } - - // Safety: RCC init must have been called - pub fn clocks(&self) -> &'static Clocks { - unsafe { get_freqs() } - } - - pub fn enable_hsi48(&mut self, _syscfg: &mut SYSCFG, _crs: CRS) -> HSI48 { - let rcc = pac::RCC; - unsafe { - // Reset SYSCFG peripheral - rcc.apb2rstr().modify(|w| w.set_syscfgrst(true)); - rcc.apb2rstr().modify(|w| w.set_syscfgrst(false)); - - // Enable SYSCFG peripheral - rcc.apb2enr().modify(|w| w.set_syscfgen(true)); - - // Reset CRS peripheral - rcc.apb1rstr().modify(|w| w.set_crsrst(true)); - rcc.apb1rstr().modify(|w| w.set_crsrst(false)); - - // Enable CRS peripheral - rcc.apb1enr().modify(|w| w.set_crsen(true)); - - // Initialize CRS - let crs = pac::CRS; - crs.cfgr().write(|w| - - // Select LSE as synchronization source - w.set_syncsrc(0b01)); - crs.cr().modify(|w| { - w.set_autotrimen(true); - w.set_cen(true); - }); - - // Enable VREFINT reference for HSI48 oscillator - let syscfg = pac::SYSCFG; - syscfg.cfgr3().modify(|w| { - w.set_enref_hsi48(true); - w.set_en_vrefint(true); - }); - - // Select HSI48 as USB clock - rcc.ccipr().modify(|w| w.set_hsi48msel(true)); - - // Enable dedicated USB clock - rcc.crrcr().modify(|w| w.set_hsi48on(true)); - while !rcc.crrcr().read().hsi48rdy() {} - } - - HSI48(()) - } -} - -/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration -pub trait RccExt { - fn freeze(self, config: Config) -> Clocks; -} - -impl RccExt for RCC { - // `cfgr` is almost always a constant, so make sure it can be constant-propagated properly by - // marking this function and all `Config` constructors and setters as `#[inline]`. - // This saves ~900 Bytes for the `pwr.rs` example. - #[inline] - fn freeze(self, cfgr: Config) -> Clocks { - let rcc = pac::RCC; - let (sys_clk, sw) = match cfgr.mux { - ClockSrc::MSI(range) => { - // Set MSI range - unsafe { - rcc.icscr().write(|w| w.set_msirange(range.into())); - } - - // Enable MSI - unsafe { - rcc.cr().write(|w| w.set_msion(true)); - while !rcc.cr().read().msirdy() {} - } - - let freq = 32_768 * (1 << (range as u8 + 1)); - (freq, Sw::MSI) - } - ClockSrc::HSI16 => { - // Enable HSI16 - unsafe { - rcc.cr().write(|w| w.set_hsi16on(true)); - while !rcc.cr().read().hsi16rdyf() {} - } - - (HSI_FREQ, Sw::HSI16) - } - ClockSrc::HSE(freq) => { - // Enable HSE - unsafe { - rcc.cr().write(|w| w.set_hseon(true)); - while !rcc.cr().read().hserdy() {} - } - - (freq.0, Sw::HSE) - } - ClockSrc::PLL(src, mul, div) => { - let freq = match src { - PLLSource::HSE(freq) => { - // Enable HSE - unsafe { - rcc.cr().write(|w| w.set_hseon(true)); - while !rcc.cr().read().hserdy() {} - } - freq.0 - } - PLLSource::HSI16 => { - // Enable HSI - unsafe { - rcc.cr().write(|w| w.set_hsi16on(true)); - while !rcc.cr().read().hsi16rdyf() {} - } - HSI_FREQ - } - }; - - // Disable PLL - unsafe { - rcc.cr().modify(|w| w.set_pllon(false)); - while rcc.cr().read().pllrdy() {} - } - - 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_u32.mhz().0); - - unsafe { - rcc.cfgr().write(move |w| { - w.set_pllmul(mul.into()); - w.set_plldiv(div.into()); - w.set_pllsrc(src.into()); - }); - - // Enable PLL - rcc.cr().modify(|w| w.set_pllon(true)); - while !rcc.cr().read().pllrdy() {} - } - - (freq, Sw::PLL) - } - }; - - unsafe { - rcc.cfgr().modify(|w| { - w.set_sw(sw.into()); - w.set_hpre(cfgr.ahb_pre.into()); - w.set_ppre1(cfgr.apb1_pre.into()); - w.set_ppre2(cfgr.apb2_pre.into()); - }); - } - - let ahb_freq: u32 = match cfgr.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, - pre => { - let pre: Hpre = pre.into(); - let pre = 1 << (pre.0 as u32 - 7); - sys_clk / pre - } - }; - - let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.0 - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) - } - }; - - let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.0 - 3); - let freq = ahb_freq / (1 << (pre as u8 - 3)); - (freq, freq * 2) - } - }; - - Clocks { - sys: sys_clk.hz(), - ahb: ahb_freq.hz(), - apb1: apb1_freq.hz(), - apb2: apb2_freq.hz(), - apb1_tim: apb1_tim_freq.hz(), - apb2_tim: apb2_tim_freq.hz(), - } - } -} - -/// Token that exists only, if the HSI48 clock has been enabled -/// -/// You can get an instance of this struct by calling [`Rcc::enable_hsi48`]. -#[derive(Clone, Copy)] -pub struct HSI48(()); - pub(crate) unsafe fn init(config: Config) { - let r = ::steal(); - let clocks = r.freeze(config); - set_freqs(clocks); + let (sys_clk, sw) = match config.mux { + ClockSrc::MSI(range) => { + // Set MSI range + RCC.icscr().write(|w| w.set_msirange(range.into())); + + // Enable MSI + RCC.cr().write(|w| w.set_msion(true)); + while !RCC.cr().read().msirdy() {} + + let freq = 32_768 * (1 << (range as u8 + 1)); + (freq, Sw::MSI) + } + ClockSrc::HSI16 => { + // Enable HSI16 + RCC.cr().write(|w| w.set_hsi16on(true)); + while !RCC.cr().read().hsi16rdyf() {} + + (HSI16_FREQ, Sw::HSI16) + } + ClockSrc::HSE(freq) => { + // Enable HSE + RCC.cr().write(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + + (freq.0, Sw::HSE) + } + ClockSrc::PLL(src, mul, div) => { + let freq = match src { + PLLSource::HSE(freq) => { + // Enable HSE + RCC.cr().write(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + freq.0 + } + PLLSource::HSI16 => { + // Enable HSI + RCC.cr().write(|w| w.set_hsi16on(true)); + while !RCC.cr().read().hsi16rdyf() {} + HSI16_FREQ + } + }; + + // Disable PLL + RCC.cr().modify(|w| w.set_pllon(false)); + while RCC.cr().read().pllrdy() {} + + 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_u32.mhz().0); + + RCC.cfgr().write(move |w| { + w.set_pllmul(mul.into()); + w.set_plldiv(div.into()); + w.set_pllsrc(src.into()); + }); + + // Enable PLL + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} + + (freq, Sw::PLL) + } + }; + + RCC.cfgr().modify(|w| { + w.set_sw(sw); + w.set_hpre(config.ahb_pre.into()); + w.set_ppre1(config.apb1_pre.into()); + w.set_ppre2(config.apb2_pre.into()); + }); + + let ahb_freq: u32 = match config.ahb_pre { + AHBPrescaler::NotDivided => sys_clk, + pre => { + let pre: Hpre = pre.into(); + let pre = 1 << (pre.0 as u32 - 7); + sys_clk / pre + } + }; + + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: Ppre = pre.into(); + let pre: u8 = 1 << (pre.0 - 3); + let freq = ahb_freq / pre as u32; + (freq, freq * 2) + } + }; + + let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: Ppre = pre.into(); + let pre: u8 = 1 << (pre.0 - 3); + let freq = ahb_freq / (1 << (pre as u8 - 3)); + (freq, freq * 2) + } + }; + + if config.enable_hsi48 { + // Reset SYSCFG peripheral + RCC.apb2rstr().modify(|w| w.set_syscfgrst(true)); + RCC.apb2rstr().modify(|w| w.set_syscfgrst(false)); + + // Enable SYSCFG peripheral + RCC.apb2enr().modify(|w| w.set_syscfgen(true)); + + // Reset CRS peripheral + RCC.apb1rstr().modify(|w| w.set_crsrst(true)); + RCC.apb1rstr().modify(|w| w.set_crsrst(false)); + + // Enable CRS peripheral + RCC.apb1enr().modify(|w| w.set_crsen(true)); + + // Initialize CRS + CRS.cfgr().write(|w| + + // Select LSE as synchronization source + w.set_syncsrc(0b01)); + CRS.cr().modify(|w| { + w.set_autotrimen(true); + w.set_cen(true); + }); + + // Enable VREFINT reference for HSI48 oscillator + SYSCFG.cfgr3().modify(|w| { + w.set_enref_hsi48(true); + w.set_en_vrefint(true); + }); + + // Select HSI48 as USB clock + RCC.ccipr().modify(|w| w.set_hsi48msel(true)); + + // Enable dedicated USB clock + RCC.crrcr().modify(|w| w.set_hsi48on(true)); + while !RCC.crrcr().read().hsi48rdy() {} + } + + set_freqs(Clocks { + sys: sys_clk.hz(), + ahb: ahb_freq.hz(), + apb1: apb1_freq.hz(), + apb2: apb2_freq.hz(), + apb1_tim: apb1_tim_freq.hz(), + apb2_tim: apb2_tim_freq.hz(), + }); } diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs index 746433c1..517869ca 100644 --- a/embassy-stm32/src/rcc/l1.rs +++ b/embassy-stm32/src/rcc/l1.rs @@ -1,13 +1,8 @@ -use crate::pac; -use crate::peripherals::{self, RCC}; -use crate::rcc::{get_freqs, set_freqs, Clocks}; +use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; +use crate::pac::RCC; +use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; use crate::time::U32Ext; -use core::marker::PhantomData; -use embassy::util::Unborrow; -use embassy_hal_common::unborrow; - -/// Most of clock setup is copied from rcc/l0 /// HSI speed pub const HSI_FREQ: u32 = 16_000_000; @@ -16,6 +11,7 @@ pub const HSI_FREQ: u32 = 16_000_000; #[derive(Clone, Copy)] pub enum ClockSrc { MSI(MSIRange), + PLL(PLLSource, PLLMul, PLLDiv), HSE(Hertz), HSI, } @@ -48,6 +44,28 @@ impl Default for MSIRange { } } +/// PLL divider +#[derive(Clone, Copy)] +pub enum PLLDiv { + Div2, + Div3, + Div4, +} + +/// PLL multiplier +#[derive(Clone, Copy)] +pub enum PLLMul { + Mul3, + Mul4, + Mul6, + Mul8, + Mul12, + Mul16, + Mul24, + Mul32, + Mul48, +} + /// AHB prescaler #[derive(Clone, Copy, PartialEq)] pub enum AHBPrescaler { @@ -72,46 +90,86 @@ pub enum APBPrescaler { Div16, } -type Ppre = u8; -impl Into for APBPrescaler { - fn into(self) -> Ppre { - match self { - APBPrescaler::NotDivided => 0b000, - APBPrescaler::Div2 => 0b100, - APBPrescaler::Div4 => 0b101, - APBPrescaler::Div8 => 0b110, - APBPrescaler::Div16 => 0b111, +/// PLL clock input source +#[derive(Clone, Copy)] +pub enum PLLSource { + HSI, + HSE(Hertz), +} + +impl From for Pllmul { + fn from(val: PLLMul) -> Pllmul { + match val { + PLLMul::Mul3 => Pllmul::MUL3, + PLLMul::Mul4 => Pllmul::MUL4, + PLLMul::Mul6 => Pllmul::MUL6, + PLLMul::Mul8 => Pllmul::MUL8, + PLLMul::Mul12 => Pllmul::MUL12, + PLLMul::Mul16 => Pllmul::MUL16, + PLLMul::Mul24 => Pllmul::MUL24, + PLLMul::Mul32 => Pllmul::MUL32, + PLLMul::Mul48 => Pllmul::MUL48, } } } -type Hpre = u8; -impl Into for AHBPrescaler { - fn into(self) -> Hpre { - match self { - AHBPrescaler::NotDivided => 0b0000, - AHBPrescaler::Div2 => 0b1000, - AHBPrescaler::Div4 => 0b1001, - AHBPrescaler::Div8 => 0b1010, - AHBPrescaler::Div16 => 0b1011, - AHBPrescaler::Div64 => 0b1100, - AHBPrescaler::Div128 => 0b1101, - AHBPrescaler::Div256 => 0b1110, - AHBPrescaler::Div512 => 0b1111, +impl From for Plldiv { + fn from(val: PLLDiv) -> Plldiv { + match val { + PLLDiv::Div2 => Plldiv::DIV2, + PLLDiv::Div3 => Plldiv::DIV3, + PLLDiv::Div4 => Plldiv::DIV4, } } } -impl Into for MSIRange { - fn into(self) -> u8 { - match self { - MSIRange::Range0 => 0b000, - MSIRange::Range1 => 0b001, - MSIRange::Range2 => 0b010, - MSIRange::Range3 => 0b011, - MSIRange::Range4 => 0b100, - MSIRange::Range5 => 0b101, - MSIRange::Range6 => 0b110, +impl From for Pllsrc { + fn from(val: PLLSource) -> Pllsrc { + match val { + PLLSource::HSI => Pllsrc::HSI, + PLLSource::HSE(_) => Pllsrc::HSE, + } + } +} + +impl From for Ppre { + fn from(val: APBPrescaler) -> Ppre { + match val { + APBPrescaler::NotDivided => Ppre::DIV1, + APBPrescaler::Div2 => Ppre::DIV2, + APBPrescaler::Div4 => Ppre::DIV4, + APBPrescaler::Div8 => Ppre::DIV8, + APBPrescaler::Div16 => Ppre::DIV16, + } + } +} + +impl From for Hpre { + fn from(val: AHBPrescaler) -> Hpre { + match val { + AHBPrescaler::NotDivided => Hpre::DIV1, + AHBPrescaler::Div2 => Hpre::DIV2, + AHBPrescaler::Div4 => Hpre::DIV4, + AHBPrescaler::Div8 => Hpre::DIV8, + AHBPrescaler::Div16 => Hpre::DIV16, + AHBPrescaler::Div64 => Hpre::DIV64, + AHBPrescaler::Div128 => Hpre::DIV128, + AHBPrescaler::Div256 => Hpre::DIV256, + AHBPrescaler::Div512 => Hpre::DIV512, + } + } +} + +impl From for Msirange { + fn from(val: MSIRange) -> Msirange { + match val { + MSIRange::Range0 => Msirange::RANGE0, + MSIRange::Range1 => Msirange::RANGE1, + MSIRange::Range2 => Msirange::RANGE2, + MSIRange::Range3 => Msirange::RANGE3, + MSIRange::Range4 => Msirange::RANGE4, + MSIRange::Range5 => Msirange::RANGE5, + MSIRange::Range6 => Msirange::RANGE6, } } } @@ -136,126 +194,128 @@ impl Default for Config { } } -/// RCC peripheral -pub struct Rcc<'d> { - _rb: peripherals::RCC, - phantom: PhantomData<&'d mut peripherals::RCC>, -} - -impl<'d> Rcc<'d> { - pub fn new(rcc: impl Unborrow + 'd) -> Self { - unborrow!(rcc); - Self { - _rb: rcc, - phantom: PhantomData, - } - } - - // Safety: RCC init must have been called - pub fn clocks(&self) -> &'static Clocks { - unsafe { get_freqs() } - } -} - -/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration -pub trait RccExt { - fn freeze(self, config: Config) -> Clocks; -} - -impl RccExt for RCC { - // `cfgr` is almost always a constant, so make sure it can be constant-propagated properly by - // marking this function and all `Config` constructors and setters as `#[inline]`. - // This saves ~900 Bytes for the `pwr.rs` example. - #[inline] - fn freeze(self, cfgr: Config) -> Clocks { - let rcc = pac::RCC; - let (sys_clk, sw) = match cfgr.mux { - ClockSrc::MSI(range) => { - // Set MSI range - unsafe { - rcc.icscr().write(|w| w.set_msirange(range.into())); - } - - // Enable MSI - unsafe { - rcc.cr().write(|w| w.set_msion(true)); - while !rcc.cr().read().msirdy() {} - } - - let freq = 32_768 * (1 << (range as u8 + 1)); - (freq, 0b00) - } - ClockSrc::HSI => { - // Enable HSI - unsafe { - rcc.cr().write(|w| w.set_hsion(true)); - while !rcc.cr().read().hsirdy() {} - } - - (HSI_FREQ, 0b01) - } - ClockSrc::HSE(freq) => { - // Enable HSE - unsafe { - rcc.cr().write(|w| w.set_hseon(true)); - while !rcc.cr().read().hserdy() {} - } - - (freq.0, 0b10) - } - }; - - unsafe { - rcc.cfgr().modify(|w| { - w.set_sw(sw.into()); - w.set_hpre(cfgr.ahb_pre.into()); - w.set_ppre1(cfgr.apb1_pre.into()); - w.set_ppre2(cfgr.apb2_pre.into()); - }); - } - - let ahb_freq: u32 = match cfgr.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, - pre => { - let pre: Hpre = pre.into(); - let pre = 1 << (pre as u32 - 7); - sys_clk / pre - } - }; - - let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) - } - }; - - let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / (1 << (pre as u8 - 3)); - (freq, freq * 2) - } - }; - - Clocks { - sys: sys_clk.hz(), - ahb: ahb_freq.hz(), - apb1: apb1_freq.hz(), - apb2: apb2_freq.hz(), - apb1_tim: apb1_tim_freq.hz(), - apb2_tim: apb2_tim_freq.hz(), - } - } -} - pub(crate) unsafe fn init(config: Config) { - let r = ::steal(); - let clocks = r.freeze(config); - set_freqs(clocks); + let (sys_clk, sw) = match config.mux { + ClockSrc::MSI(range) => { + // Set MSI range + RCC.icscr().write(|w| w.set_msirange(range.into())); + + // Enable MSI + RCC.cr().write(|w| w.set_msion(true)); + while !RCC.cr().read().msirdy() {} + + let freq = 32_768 * (1 << (range as u8 + 1)); + (freq, Sw::MSI) + } + ClockSrc::HSI => { + // Enable HSI + RCC.cr().write(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + + (HSI_FREQ, Sw::HSI) + } + ClockSrc::HSE(freq) => { + // Enable HSE + RCC.cr().write(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + + (freq.0, Sw::HSE) + } + ClockSrc::PLL(src, mul, div) => { + let freq = match src { + PLLSource::HSE(freq) => { + // Enable HSE + RCC.cr().write(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + freq.0 + } + PLLSource::HSI => { + // Enable HSI + RCC.cr().write(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + HSI_FREQ + } + }; + + // Disable PLL + RCC.cr().modify(|w| w.set_pllon(false)); + while RCC.cr().read().pllrdy() {} + + 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_u32.mhz().0); + + RCC.cfgr().write(move |w| { + w.set_pllmul(mul.into()); + w.set_plldiv(div.into()); + w.set_pllsrc(src.into()); + }); + + // Enable PLL + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} + + (freq, Sw::PLL) + } + }; + + RCC.cfgr().modify(|w| { + w.set_sw(sw); + w.set_hpre(config.ahb_pre.into()); + w.set_ppre1(config.apb1_pre.into()); + w.set_ppre2(config.apb2_pre.into()); + }); + + let ahb_freq: u32 = match config.ahb_pre { + AHBPrescaler::NotDivided => sys_clk, + pre => { + let pre: Hpre = pre.into(); + let pre = 1 << (pre.0 as u32 - 7); + sys_clk / pre + } + }; + + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: Ppre = pre.into(); + let pre: u8 = 1 << (pre.0 - 3); + let freq = ahb_freq / pre as u32; + (freq, freq * 2) + } + }; + + let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: Ppre = pre.into(); + let pre: u8 = 1 << (pre.0 - 3); + let freq = ahb_freq / (1 << (pre as u8 - 3)); + (freq, freq * 2) + } + }; + + set_freqs(Clocks { + sys: sys_clk.hz(), + ahb: ahb_freq.hz(), + apb1: apb1_freq.hz(), + apb2: apb2_freq.hz(), + apb1_tim: apb1_tim_freq.hz(), + apb2_tim: apb2_tim_freq.hz(), + }); } diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 510cbddf..68b960d7 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -1,17 +1,8 @@ -use crate::pac; -use crate::peripherals::{self, RCC}; -use crate::rcc::{get_freqs, set_freqs, Clocks}; +use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; +use crate::pac::{FLASH, RCC}; +use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; use crate::time::U32Ext; -use core::marker::PhantomData; -use embassy::util::Unborrow; -use embassy_hal_common::unborrow; -use stm32_metapac::rcc::vals::Msirange; - -/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, -/// and with the addition of the init function to configure a system clock. - -/// Only the basic setup using the HSE and HSI clocks are supported as of now. /// HSI16 speed pub const HSI16_FREQ: u32 = 16_000_000; @@ -19,8 +10,8 @@ pub const HSI16_FREQ: u32 = 16_000_000; /// System clock mux source #[derive(Clone, Copy)] pub enum ClockSrc { - PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option), MSI(MSIRange), + PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option), HSE(Hertz), HSI16, } @@ -57,25 +48,6 @@ pub enum MSIRange { Range11, } -impl Into for MSIRange { - fn into(self) -> u32 { - match self { - MSIRange::Range0 => 100_000, - MSIRange::Range1 => 200_000, - MSIRange::Range2 => 400_000, - MSIRange::Range3 => 800_000, - MSIRange::Range4 => 1_000_000, - MSIRange::Range5 => 2_000_000, - MSIRange::Range6 => 4_000_000, - MSIRange::Range7 => 8_000_000, - MSIRange::Range8 => 16_000_000, - MSIRange::Range9 => 24_000_000, - MSIRange::Range10 => 32_000_000, - MSIRange::Range11 => 48_000_000, - } - } -} - impl Default for MSIRange { fn default() -> MSIRange { MSIRange::Range6 @@ -131,9 +103,9 @@ seq_macro::seq!(N in 8..=86 { )* } - impl Into for PLLMul { - fn into(self) -> u8 { - match self { + impl From for u8 { + fn from(val: PLLMul) -> u8 { + match val { #( PLLMul::Mul#N => N, )* @@ -163,13 +135,13 @@ pub enum PLLClkDiv { impl PLLClkDiv { pub fn to_div(self) -> u32 { let val: u8 = self.into(); - val as u32 + 1 * 2 + (val as u32 + 1) * 2 } } -impl Into for PLLClkDiv { - fn into(self) -> u8 { - match self { +impl From for u8 { + fn from(val: PLLClkDiv) -> u8 { + match val { PLLClkDiv::Div2 => 0b00, PLLClkDiv::Div4 => 0b01, PLLClkDiv::Div6 => 0b10, @@ -197,9 +169,9 @@ impl PLLSrcDiv { } } -impl Into for PLLSrcDiv { - fn into(self) -> u8 { - match self { +impl From for u8 { + fn from(val: PLLSrcDiv) -> u8 { + match val { PLLSrcDiv::Div1 => 0b000, PLLSrcDiv::Div2 => 0b001, PLLSrcDiv::Div3 => 0b010, @@ -212,18 +184,46 @@ impl Into for PLLSrcDiv { } } -impl Into for PLLSource { - fn into(self) -> u8 { - match self { - PLLSource::HSI16 => 0b10, - PLLSource::HSE(_) => 0b11, +impl From for Pllsrc { + fn from(val: PLLSource) -> Pllsrc { + match val { + PLLSource::HSI16 => Pllsrc::HSI16, + PLLSource::HSE(_) => Pllsrc::HSE, } } } -impl Into for MSIRange { - fn into(self) -> Msirange { - match self { +impl From for Ppre { + fn from(val: APBPrescaler) -> Ppre { + match val { + APBPrescaler::NotDivided => Ppre::DIV1, + APBPrescaler::Div2 => Ppre::DIV2, + APBPrescaler::Div4 => Ppre::DIV4, + APBPrescaler::Div8 => Ppre::DIV8, + APBPrescaler::Div16 => Ppre::DIV16, + } + } +} + +impl From for Hpre { + fn from(val: AHBPrescaler) -> Hpre { + match val { + AHBPrescaler::NotDivided => Hpre::DIV1, + AHBPrescaler::Div2 => Hpre::DIV2, + AHBPrescaler::Div4 => Hpre::DIV4, + AHBPrescaler::Div8 => Hpre::DIV8, + AHBPrescaler::Div16 => Hpre::DIV16, + AHBPrescaler::Div64 => Hpre::DIV64, + AHBPrescaler::Div128 => Hpre::DIV128, + AHBPrescaler::Div256 => Hpre::DIV256, + AHBPrescaler::Div512 => Hpre::DIV512, + } + } +} + +impl From for Msirange { + fn from(val: MSIRange) -> Msirange { + match val { MSIRange::Range0 => Msirange::RANGE100K, MSIRange::Range1 => Msirange::RANGE200K, MSIRange::Range2 => Msirange::RANGE400K, @@ -239,30 +239,22 @@ impl Into for MSIRange { } } } -impl Into for APBPrescaler { - fn into(self) -> u8 { - match self { - APBPrescaler::NotDivided => 1, - APBPrescaler::Div2 => 0x04, - APBPrescaler::Div4 => 0x05, - APBPrescaler::Div8 => 0x06, - APBPrescaler::Div16 => 0x07, - } - } -} -impl Into for AHBPrescaler { - fn into(self) -> u8 { - match self { - AHBPrescaler::NotDivided => 1, - AHBPrescaler::Div2 => 0x08, - AHBPrescaler::Div4 => 0x09, - AHBPrescaler::Div8 => 0x0a, - AHBPrescaler::Div16 => 0x0b, - AHBPrescaler::Div64 => 0x0c, - AHBPrescaler::Div128 => 0x0d, - AHBPrescaler::Div256 => 0x0e, - AHBPrescaler::Div512 => 0x0f, +impl From for u32 { + fn from(val: MSIRange) -> u32 { + match val { + MSIRange::Range0 => 100_000, + MSIRange::Range1 => 200_000, + MSIRange::Range2 => 400_000, + MSIRange::Range3 => 800_000, + MSIRange::Range4 => 1_000_000, + MSIRange::Range5 => 2_000_000, + MSIRange::Range6 => 4_000_000, + MSIRange::Range7 => 8_000_000, + MSIRange::Range8 => 16_000_000, + MSIRange::Range9 => 24_000_000, + MSIRange::Range10 => 32_000_000, + MSIRange::Range11 => 48_000_000, } } } @@ -287,203 +279,151 @@ impl Default for Config { } } -/// RCC peripheral -pub struct Rcc<'d> { - _rb: peripherals::RCC, - phantom: PhantomData<&'d mut peripherals::RCC>, -} - -impl<'d> Rcc<'d> { - pub fn new(rcc: impl Unborrow + 'd) -> Self { - unborrow!(rcc); - Self { - _rb: rcc, - phantom: PhantomData, - } - } - - // Safety: RCC init must have been called - pub fn clocks(&self) -> &'static Clocks { - unsafe { get_freqs() } - } -} - -/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration -pub trait RccExt { - fn freeze(self, config: Config) -> Clocks; -} - -impl RccExt for RCC { - #[inline] - fn freeze(self, cfgr: Config) -> Clocks { - let rcc = pac::RCC; - let (sys_clk, sw) = match cfgr.mux { - ClockSrc::HSI16 => { - // Enable HSI16 - unsafe { - rcc.cr().write(|w| w.set_hsion(true)); - while !rcc.cr().read().hsirdy() {} - } - - (HSI16_FREQ, 0b01) - } - ClockSrc::HSE(freq) => { - // Enable HSE - unsafe { - rcc.cr().write(|w| w.set_hseon(true)); - while !rcc.cr().read().hserdy() {} - } - - (freq.0, 0b10) - } - ClockSrc::MSI(range) => { - // Enable MSI - unsafe { - rcc.cr().write(|w| { - let bits: Msirange = range.into(); - w.set_msirange(bits); - w.set_msipllen(false); - w.set_msirgsel(true); - w.set_msion(true); - }); - while !rcc.cr().read().msirdy() {} - - // Enable as clock source for USB, RNG if running at 48 MHz - if let MSIRange::Range11 = range { - rcc.ccipr().modify(|w| { - w.set_clk48sel(0b11); - }); - } - } - (range.into(), 0b00) - } - ClockSrc::PLL(src, div, prediv, mul, pll48div) => { - let freq = match src { - PLLSource::HSE(freq) => { - // Enable HSE - unsafe { - rcc.cr().write(|w| w.set_hseon(true)); - while !rcc.cr().read().hserdy() {} - } - freq.0 - } - PLLSource::HSI16 => { - // Enable HSI - unsafe { - rcc.cr().write(|w| w.set_hsion(true)); - while !rcc.cr().read().hsirdy() {} - } - HSI16_FREQ - } - }; - - // Disable PLL - unsafe { - rcc.cr().modify(|w| w.set_pllon(false)); - while rcc.cr().read().pllrdy() {} - } - - let freq = (freq / prediv.to_div() * mul.to_mul()) / div.to_div(); - - assert!(freq <= 80_000_000); - - unsafe { - rcc.pllcfgr().write(move |w| { - w.set_plln(mul.into()); - w.set_pllm(prediv.into()); - w.set_pllr(div.into()); - if let Some(pll48div) = pll48div { - w.set_pllq(pll48div.into()); - w.set_pllqen(true); - } - w.set_pllsrc(src.into()); - }); - - // Enable as clock source for USB, RNG if PLL48 divisor is provided - if pll48div.is_some() { - rcc.ccipr().modify(|w| { - w.set_clk48sel(0b10); - }); - } - - // Enable PLL - rcc.cr().modify(|w| w.set_pllon(true)); - while !rcc.cr().read().pllrdy() {} - rcc.pllcfgr().modify(|w| w.set_pllren(true)); - } - (freq, 0b11) - } - }; - - unsafe { - // Set flash wait states - pac::FLASH.acr().modify(|w| { - w.set_latency(if sys_clk <= 16_000_000 { - 0b000 - } else if sys_clk <= 32_000_000 { - 0b001 - } else if sys_clk <= 48_000_000 { - 0b010 - } else if sys_clk <= 64_000_000 { - 0b011 - } else { - 0b100 - }); - }); - - // Switch active clocks to new clock source - rcc.cfgr().modify(|w| { - w.set_sw(sw.into()); - w.set_hpre(cfgr.ahb_pre.into()); - w.set_ppre1(cfgr.apb1_pre.into()); - w.set_ppre2(cfgr.apb2_pre.into()); - }); - } - - let ahb_freq: u32 = match cfgr.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, - pre => { - let pre: u8 = pre.into(); - let pre = 1 << (pre as u32 - 7); - sys_clk / pre - } - }; - - let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) - } - }; - - let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / (1 << (pre as u8 - 3)); - (freq, freq * 2) - } - }; - - Clocks { - sys: sys_clk.hz(), - ahb1: ahb_freq.hz(), - ahb2: ahb_freq.hz(), - ahb3: ahb_freq.hz(), - apb1: apb1_freq.hz(), - apb2: apb2_freq.hz(), - apb1_tim: apb1_tim_freq.hz(), - apb2_tim: apb2_tim_freq.hz(), - } - } -} - pub(crate) unsafe fn init(config: Config) { - let r = ::steal(); - let clocks = r.freeze(config); - set_freqs(clocks); + let (sys_clk, sw) = match config.mux { + ClockSrc::MSI(range) => { + // Enable MSI + RCC.cr().write(|w| { + let bits: Msirange = range.into(); + w.set_msirange(bits); + w.set_msipllen(false); + w.set_msirgsel(true); + w.set_msion(true); + }); + while !RCC.cr().read().msirdy() {} + + // Enable as clock source for USB, RNG if running at 48 MHz + if let MSIRange::Range11 = range { + RCC.ccipr().modify(|w| { + w.set_clk48sel(0b11); + }); + } + (range.into(), Sw::MSI) + } + ClockSrc::HSI16 => { + // Enable HSI16 + RCC.cr().write(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + + (HSI16_FREQ, Sw::HSI16) + } + ClockSrc::HSE(freq) => { + // Enable HSE + RCC.cr().write(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + + (freq.0, Sw::HSE) + } + ClockSrc::PLL(src, div, prediv, mul, pll48div) => { + let freq = match src { + PLLSource::HSE(freq) => { + // Enable HSE + RCC.cr().write(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + freq.0 + } + PLLSource::HSI16 => { + // Enable HSI + RCC.cr().write(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + HSI16_FREQ + } + }; + + // Disable PLL + RCC.cr().modify(|w| w.set_pllon(false)); + while RCC.cr().read().pllrdy() {} + + let freq = (freq / prediv.to_div() * mul.to_mul()) / div.to_div(); + + assert!(freq <= 80_000_000); + + RCC.pllcfgr().write(move |w| { + w.set_plln(mul.into()); + w.set_pllm(prediv.into()); + w.set_pllr(div.into()); + if let Some(pll48div) = pll48div { + w.set_pllq(pll48div.into()); + w.set_pllqen(true); + } + w.set_pllsrc(src.into()); + }); + + // Enable as clock source for USB, RNG if PLL48 divisor is provided + if pll48div.is_some() { + RCC.ccipr().modify(|w| { + w.set_clk48sel(0b10); + }); + } + + // Enable PLL + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} + RCC.pllcfgr().modify(|w| w.set_pllren(true)); + + (freq, Sw::PLL) + } + }; + + // Set flash wait states + FLASH.acr().modify(|w| { + w.set_latency(if sys_clk <= 16_000_000 { + 0b000 + } else if sys_clk <= 32_000_000 { + 0b001 + } else if sys_clk <= 48_000_000 { + 0b010 + } else if sys_clk <= 64_000_000 { + 0b011 + } else { + 0b100 + }); + }); + + RCC.cfgr().modify(|w| { + w.set_sw(sw); + w.set_hpre(config.ahb_pre.into()); + w.set_ppre1(config.apb1_pre.into()); + w.set_ppre2(config.apb2_pre.into()); + }); + + let ahb_freq: u32 = match config.ahb_pre { + AHBPrescaler::NotDivided => sys_clk, + pre => { + let pre: Hpre = pre.into(); + let pre = 1 << (pre.0 as u32 - 7); + sys_clk / pre + } + }; + + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: Ppre = pre.into(); + let pre: u8 = 1 << (pre.0 - 3); + let freq = ahb_freq / pre as u32; + (freq, freq * 2) + } + }; + + let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: Ppre = pre.into(); + let pre: u8 = 1 << (pre.0 - 3); + let freq = ahb_freq / (1 << (pre as u8 - 3)); + (freq, freq * 2) + } + }; + + set_freqs(Clocks { + sys: sys_clk.hz(), + ahb1: ahb_freq.hz(), + ahb2: ahb_freq.hz(), + ahb3: ahb_freq.hz(), + apb1: apb1_freq.hz(), + apb2: apb2_freq.hz(), + apb1_tim: apb1_tim_freq.hz(), + apb2_tim: apb2_tim_freq.hz(), + }); } diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index e8bd8271..ac1cd06c 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -1,6 +1,4 @@ -use crate::pac; -use crate::peripherals::{self, RCC}; -use crate::pwr::{Power, VoltageScale}; +use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::{Hertz, U32Ext}; use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw}; @@ -8,6 +6,20 @@ use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw} /// HSI16 speed pub const HSI16_FREQ: u32 = 16_000_000; +/// Voltage Scale +/// +/// Represents the voltage range feeding the CPU core. The maximum core +/// clock frequency depends on this value. +#[derive(Copy, Clone, PartialEq)] +pub enum VoltageScale { + // Highest frequency + Range1, + Range2, + Range3, + // Lowest power + Range4, +} + #[derive(Copy, Clone)] pub enum ClockSrc { MSI(MSIRange), @@ -293,218 +305,188 @@ impl Default for Config { } } -/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration -pub trait RccExt { - fn freeze(self, config: Config, power: &Power) -> Clocks; -} - -impl RccExt for RCC { - #[inline] - fn freeze(self, cfgr: Config, power: &Power) -> Clocks { - let rcc = pac::RCC; - - let sys_clk = match cfgr.mux { - ClockSrc::MSI(range) => { - unsafe { - rcc.icscr1().modify(|w| { - let bits: Msirange = range.into(); - w.set_msisrange(bits); - w.set_msirgsel(Msirgsel::RCC_ICSCR1); - }); - rcc.cr().write(|w| { - w.set_msipllen(false); - w.set_msison(true); - w.set_msison(true); - }); - while !rcc.cr().read().msisrdy() {} - } - - range.into() - } - ClockSrc::HSE(freq) => { - unsafe { - rcc.cr().write(|w| w.set_hseon(true)); - while !rcc.cr().read().hserdy() {} - } - - freq.0 - } - ClockSrc::HSI16 => { - unsafe { - rcc.cr().write(|w| w.set_hsion(true)); - while !rcc.cr().read().hsirdy() {} - } - - HSI16_FREQ - } - ClockSrc::PLL1R(src, m, n, div) => { - let freq = match src { - PllSrc::MSI(_) => MSIRange::default().into(), - PllSrc::HSE(hertz) => hertz.0, - PllSrc::HSI16 => HSI16_FREQ, - }; - - // disable - unsafe { - rcc.cr().modify(|w| w.set_pllon(0, false)); - while rcc.cr().read().pllrdy(0) {} - } - - let vco = freq * n as u8 as u32; - let pll_ck = vco / (div as u8 as u32 + 1); - - unsafe { - rcc.pll1cfgr().write(|w| { - w.set_pllm(m.into()); - w.set_pllsrc(src.into()); - }); - - rcc.pll1divr().modify(|w| { - w.set_pllr(div.to_div()); - w.set_plln(n.to_mul()); - }); - - // Enable PLL - rcc.cr().modify(|w| w.set_pllon(0, true)); - while !rcc.cr().read().pllrdy(0) {} - rcc.pll1cfgr().modify(|w| w.set_pllren(true)); - } - - unsafe { - rcc.cr().write(|w| w.set_pllon(0, true)); - while !rcc.cr().read().pllrdy(0) {} - } - - pll_ck - } - }; - - // states and programming delay - let wait_states = match power.vos { - // VOS 0 range VCORE 1.26V - 1.40V - VoltageScale::Range1 => { - if sys_clk < 32_000_000 { - 0 - } else if sys_clk < 64_000_000 { - 1 - } else if sys_clk < 96_000_000 { - 2 - } else if sys_clk < 128_000_000 { - 3 - } else { - 4 - } - } - // VOS 1 range VCORE 1.15V - 1.26V - VoltageScale::Range2 => { - if sys_clk < 30_000_000 { - 0 - } else if sys_clk < 60_000_000 { - 1 - } else if sys_clk < 90_000_000 { - 2 - } else { - 3 - } - } - // VOS 2 range VCORE 1.05V - 1.15V - VoltageScale::Range3 => { - if sys_clk < 24_000_000 { - 0 - } else if sys_clk < 48_000_000 { - 1 - } else { - 2 - } - } - // VOS 3 range VCORE 0.95V - 1.05V - VoltageScale::Range4 => { - if sys_clk < 12_000_000 { - 0 - } else { - 1 - } - } - }; - - unsafe { - pac::FLASH.acr().modify(|w| { - w.set_latency(wait_states); - }) - } - - unsafe { - rcc.cfgr1().modify(|w| { - w.set_sw(cfgr.mux.into()); - }); - - rcc.cfgr2().modify(|w| { - w.set_hpre(cfgr.ahb_pre.into()); - w.set_ppre1(cfgr.apb1_pre.into()); - w.set_ppre2(cfgr.apb2_pre.into()); - }); - - rcc.cfgr3().modify(|w| { - w.set_ppre3(cfgr.apb3_pre.into()); - }); - } - - let ahb_freq: u32 = match cfgr.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, - pre => { - let pre: u8 = pre.into(); - let pre = 1 << (pre as u32 - 7); - sys_clk / pre - } - }; - - let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) - } - }; - - let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / (1 << (pre as u8 - 3)); - (freq, freq * 2) - } - }; - - let (apb3_freq, _apb3_tim_freq) = match cfgr.apb3_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / (1 << (pre as u8 - 3)); - (freq, freq * 2) - } - }; - - Clocks { - sys: sys_clk.hz(), - ahb1: ahb_freq.hz(), - ahb2: ahb_freq.hz(), - ahb3: ahb_freq.hz(), - apb1: apb1_freq.hz(), - apb2: apb2_freq.hz(), - apb3: apb3_freq.hz(), - apb1_tim: apb1_tim_freq.hz(), - apb2_tim: apb2_tim_freq.hz(), - } - } -} - pub(crate) unsafe fn init(config: Config) { - let r = ::steal(); - let power = Power::new(::steal()); - let clocks = r.freeze(config, &power); - set_freqs(clocks); + let sys_clk = match config.mux { + ClockSrc::MSI(range) => { + RCC.icscr1().modify(|w| { + let bits: Msirange = range.into(); + w.set_msisrange(bits); + w.set_msirgsel(Msirgsel::RCC_ICSCR1); + }); + RCC.cr().write(|w| { + w.set_msipllen(false); + w.set_msison(true); + w.set_msison(true); + }); + while !RCC.cr().read().msisrdy() {} + + range.into() + } + ClockSrc::HSE(freq) => { + RCC.cr().write(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + + freq.0 + } + ClockSrc::HSI16 => { + RCC.cr().write(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + + HSI16_FREQ + } + ClockSrc::PLL1R(src, m, n, div) => { + let freq = match src { + PllSrc::MSI(_) => MSIRange::default().into(), + PllSrc::HSE(hertz) => hertz.0, + PllSrc::HSI16 => HSI16_FREQ, + }; + + // disable + RCC.cr().modify(|w| w.set_pllon(0, false)); + while RCC.cr().read().pllrdy(0) {} + + let vco = freq * n as u8 as u32; + let pll_ck = vco / (div as u8 as u32 + 1); + + RCC.pll1cfgr().write(|w| { + w.set_pllm(m.into()); + w.set_pllsrc(src.into()); + }); + + RCC.pll1divr().modify(|w| { + w.set_pllr(div.to_div()); + w.set_plln(n.to_mul()); + }); + + // Enable PLL + RCC.cr().modify(|w| w.set_pllon(0, true)); + while !RCC.cr().read().pllrdy(0) {} + RCC.pll1cfgr().modify(|w| w.set_pllren(true)); + + RCC.cr().write(|w| w.set_pllon(0, true)); + while !RCC.cr().read().pllrdy(0) {} + + pll_ck + } + }; + + // TODO make configurable + let power_vos = VoltageScale::Range4; + + // states and programming delay + let wait_states = match power_vos { + // VOS 0 range VCORE 1.26V - 1.40V + VoltageScale::Range1 => { + if sys_clk < 32_000_000 { + 0 + } else if sys_clk < 64_000_000 { + 1 + } else if sys_clk < 96_000_000 { + 2 + } else if sys_clk < 128_000_000 { + 3 + } else { + 4 + } + } + // VOS 1 range VCORE 1.15V - 1.26V + VoltageScale::Range2 => { + if sys_clk < 30_000_000 { + 0 + } else if sys_clk < 60_000_000 { + 1 + } else if sys_clk < 90_000_000 { + 2 + } else { + 3 + } + } + // VOS 2 range VCORE 1.05V - 1.15V + VoltageScale::Range3 => { + if sys_clk < 24_000_000 { + 0 + } else if sys_clk < 48_000_000 { + 1 + } else { + 2 + } + } + // VOS 3 range VCORE 0.95V - 1.05V + VoltageScale::Range4 => { + if sys_clk < 12_000_000 { + 0 + } else { + 1 + } + } + }; + + FLASH.acr().modify(|w| { + w.set_latency(wait_states); + }); + + RCC.cfgr1().modify(|w| { + w.set_sw(config.mux.into()); + }); + + RCC.cfgr2().modify(|w| { + w.set_hpre(config.ahb_pre.into()); + w.set_ppre1(config.apb1_pre.into()); + w.set_ppre2(config.apb2_pre.into()); + }); + + RCC.cfgr3().modify(|w| { + w.set_ppre3(config.apb3_pre.into()); + }); + + let ahb_freq: u32 = match config.ahb_pre { + AHBPrescaler::NotDivided => sys_clk, + pre => { + let pre: u8 = pre.into(); + let pre = 1 << (pre as u32 - 7); + sys_clk / pre + } + }; + + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: u8 = pre.into(); + let pre: u8 = 1 << (pre - 3); + let freq = ahb_freq / pre as u32; + (freq, freq * 2) + } + }; + + let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: u8 = pre.into(); + let pre: u8 = 1 << (pre - 3); + let freq = ahb_freq / (1 << (pre as u8 - 3)); + (freq, freq * 2) + } + }; + + let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: u8 = pre.into(); + let pre: u8 = 1 << (pre - 3); + let freq = ahb_freq / (1 << (pre as u8 - 3)); + (freq, freq * 2) + } + }; + + set_freqs(Clocks { + sys: sys_clk.hz(), + ahb1: ahb_freq.hz(), + ahb2: ahb_freq.hz(), + ahb3: ahb_freq.hz(), + apb1: apb1_freq.hz(), + apb2: apb2_freq.hz(), + apb3: apb3_freq.hz(), + apb1_tim: apb1_tim_freq.hz(), + apb2_tim: apb2_tim_freq.hz(), + }); } diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index 58146d4b..eae7c946 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -1,11 +1,7 @@ -use crate::pac; -use crate::peripherals::{self, RCC}; -use crate::rcc::{get_freqs, set_freqs, Clocks}; +use crate::pac::RCC; +use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; use crate::time::U32Ext; -use core::marker::PhantomData; -use embassy::util::Unborrow; -use embassy_hal_common::unborrow; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, /// and with the addition of the init function to configure a system clock. @@ -104,110 +100,68 @@ impl Default for Config { } } -/// RCC peripheral -pub struct Rcc<'d> { - _rb: peripherals::RCC, - phantom: PhantomData<&'d mut peripherals::RCC>, -} - -impl<'d> Rcc<'d> { - pub fn new(rcc: impl Unborrow + 'd) -> Self { - unborrow!(rcc); - Self { - _rb: rcc, - phantom: PhantomData, - } - } - - // Safety: RCC init must have been called - pub fn clocks(&self) -> &'static Clocks { - unsafe { get_freqs() } - } -} - -/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration -pub trait RccExt { - fn freeze(self, config: Config) -> Clocks; -} - -impl RccExt for RCC { - #[inline] - fn freeze(self, cfgr: Config) -> Clocks { - let rcc = pac::RCC; - let (sys_clk, sw) = match cfgr.mux { - ClockSrc::HSI16 => { - // Enable HSI16 - unsafe { - rcc.cr().write(|w| w.set_hsion(true)); - while !rcc.cr().read().hsirdy() {} - } - - (HSI_FREQ, 0x01) - } - ClockSrc::HSE(freq) => { - // Enable HSE - unsafe { - rcc.cr().write(|w| w.set_hseon(true)); - while !rcc.cr().read().hserdy() {} - } - - (freq.0, 0x02) - } - }; - - unsafe { - rcc.cfgr().modify(|w| { - w.set_sw(sw.into()); - w.set_hpre(cfgr.ahb_pre.into()); - w.set_ppre1(cfgr.apb1_pre.into()); - w.set_ppre2(cfgr.apb2_pre.into()); - }); - } - - let ahb_freq: u32 = match cfgr.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, - pre => { - let pre: u8 = pre.into(); - let pre = 1 << (pre as u32 - 7); - sys_clk / pre - } - }; - - let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) - } - }; - - let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / (1 << (pre as u8 - 3)); - (freq, freq * 2) - } - }; - - Clocks { - sys: sys_clk.hz(), - ahb1: ahb_freq.hz(), - ahb2: ahb_freq.hz(), - ahb3: ahb_freq.hz(), - apb1: apb1_freq.hz(), - apb2: apb2_freq.hz(), - apb1_tim: apb1_tim_freq.hz(), - apb2_tim: apb2_tim_freq.hz(), - } - } -} - pub(crate) unsafe fn init(config: Config) { - let r = ::steal(); - let clocks = r.freeze(config); - set_freqs(clocks); + let (sys_clk, sw) = match config.mux { + ClockSrc::HSI16 => { + // Enable HSI16 + RCC.cr().write(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + + (HSI_FREQ, 0x01) + } + ClockSrc::HSE(freq) => { + // Enable HSE + RCC.cr().write(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + + (freq.0, 0x02) + } + }; + + RCC.cfgr().modify(|w| { + w.set_sw(sw.into()); + w.set_hpre(config.ahb_pre.into()); + w.set_ppre1(config.apb1_pre.into()); + w.set_ppre2(config.apb2_pre.into()); + }); + + let ahb_freq: u32 = match config.ahb_pre { + AHBPrescaler::NotDivided => sys_clk, + pre => { + let pre: u8 = pre.into(); + let pre = 1 << (pre as u32 - 7); + sys_clk / pre + } + }; + + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: u8 = pre.into(); + let pre: u8 = 1 << (pre - 3); + let freq = ahb_freq / pre as u32; + (freq, freq * 2) + } + }; + + let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: u8 = pre.into(); + let pre: u8 = 1 << (pre - 3); + let freq = ahb_freq / (1 << (pre as u8 - 3)); + (freq, freq * 2) + } + }; + + set_freqs(Clocks { + sys: sys_clk.hz(), + ahb1: ahb_freq.hz(), + ahb2: ahb_freq.hz(), + ahb3: ahb_freq.hz(), + apb1: apb1_freq.hz(), + apb2: apb2_freq.hz(), + apb1_tim: apb1_tim_freq.hz(), + apb2_tim: apb2_tim_freq.hz(), + }); } diff --git a/embassy-stm32/src/rcc/wl5.rs b/embassy-stm32/src/rcc/wl5.rs index 00b91dfe..fb2dd998 100644 --- a/embassy-stm32/src/rcc/wl5.rs +++ b/embassy-stm32/src/rcc/wl5.rs @@ -1,10 +1,6 @@ -use crate::pac; -use crate::peripherals::{self, RCC}; -use crate::rcc::{get_freqs, set_freqs, Clocks}; +use crate::pac::RCC; +use crate::rcc::{set_freqs, Clocks}; use crate::time::U32Ext; -use core::marker::PhantomData; -use embassy::util::Unborrow; -use embassy_hal_common::unborrow; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, /// and with the addition of the init function to configure a system clock. @@ -91,6 +87,7 @@ pub struct Config { pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, + pub enable_lsi: bool, } impl Default for Config { @@ -101,136 +98,92 @@ impl Default for Config { ahb_pre: AHBPrescaler::NotDivided, apb1_pre: APBPrescaler::NotDivided, apb2_pre: APBPrescaler::NotDivided, - } - } -} - -/// RCC peripheral -pub struct Rcc<'d> { - _rb: peripherals::RCC, - phantom: PhantomData<&'d mut peripherals::RCC>, -} - -impl<'d> Rcc<'d> { - pub fn new(rcc: impl Unborrow + 'd) -> Self { - unborrow!(rcc); - Self { - _rb: rcc, - phantom: PhantomData, - } - } - - pub fn enable_lsi(&mut self) { - let rcc = pac::RCC; - unsafe { - let csr = rcc.csr().read(); - if !csr.lsion() { - rcc.csr().modify(|w| w.set_lsion(true)); - while !rcc.csr().read().lsirdy() {} - } - } - } - - // Safety: RCC init must have been called - pub fn clocks(&self) -> &'static Clocks { - unsafe { get_freqs() } - } -} - -/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration -pub trait RccExt { - fn freeze(self, config: Config) -> Clocks; -} - -impl RccExt for RCC { - #[inline] - fn freeze(self, cfgr: Config) -> Clocks { - let rcc = pac::RCC; - let (sys_clk, sw) = match cfgr.mux { - ClockSrc::HSI16 => { - // Enable HSI16 - unsafe { - rcc.cr().write(|w| w.set_hsion(true)); - while !rcc.cr().read().hsirdy() {} - } - - (HSI_FREQ, 0x01) - } - ClockSrc::HSE32 => { - // Enable HSE32 - unsafe { - rcc.cr().write(|w| { - w.set_hsebyppwr(true); - w.set_hseon(true); - }); - while !rcc.cr().read().hserdy() {} - } - - (HSE32_FREQ, 0x02) - } - }; - - unsafe { - rcc.cfgr().modify(|w| { - w.set_sw(sw.into()); - if cfgr.ahb_pre == AHBPrescaler::NotDivided { - w.set_hpre(0); - } else { - w.set_hpre(cfgr.ahb_pre.into()); - } - w.set_ppre1(cfgr.apb1_pre.into()); - w.set_ppre2(cfgr.apb2_pre.into()); - }); - } - - let ahb_freq: u32 = match cfgr.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, - pre => { - let pre: u8 = pre.into(); - let pre = 1 << (pre as u32 - 7); - sys_clk / pre - } - }; - - let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) - } - }; - - let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), - pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / (1 << (pre as u8 - 3)); - (freq, freq * 2) - } - }; - - // TODO: completely untested - let apb3_freq = ahb_freq; - - Clocks { - sys: sys_clk.hz(), - ahb1: ahb_freq.hz(), - ahb2: ahb_freq.hz(), - ahb3: ahb_freq.hz(), - apb1: apb1_freq.hz(), - apb2: apb2_freq.hz(), - apb3: apb3_freq.hz(), - apb1_tim: apb1_tim_freq.hz(), - apb2_tim: apb2_tim_freq.hz(), + enable_lsi: false, } } } pub(crate) unsafe fn init(config: Config) { - let r = ::steal(); - let clocks = r.freeze(config); - set_freqs(clocks); + let (sys_clk, sw) = match config.mux { + ClockSrc::HSI16 => { + // Enable HSI16 + RCC.cr().write(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + + (HSI_FREQ, 0x01) + } + ClockSrc::HSE32 => { + // Enable HSE32 + RCC.cr().write(|w| { + w.set_hsebyppwr(true); + w.set_hseon(true); + }); + while !RCC.cr().read().hserdy() {} + + (HSE32_FREQ, 0x02) + } + }; + + RCC.cfgr().modify(|w| { + w.set_sw(sw.into()); + if config.ahb_pre == AHBPrescaler::NotDivided { + w.set_hpre(0); + } else { + w.set_hpre(config.ahb_pre.into()); + } + w.set_ppre1(config.apb1_pre.into()); + w.set_ppre2(config.apb2_pre.into()); + }); + + let ahb_freq: u32 = match config.ahb_pre { + AHBPrescaler::NotDivided => sys_clk, + pre => { + let pre: u8 = pre.into(); + let pre = 1 << (pre as u32 - 7); + sys_clk / pre + } + }; + + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: u8 = pre.into(); + let pre: u8 = 1 << (pre - 3); + let freq = ahb_freq / pre as u32; + (freq, freq * 2) + } + }; + + let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: u8 = pre.into(); + let pre: u8 = 1 << (pre - 3); + let freq = ahb_freq / (1 << (pre as u8 - 3)); + (freq, freq * 2) + } + }; + + // TODO: completely untested + let apb3_freq = ahb_freq; + + if config.enable_lsi { + let csr = RCC.csr().read(); + if !csr.lsion() { + RCC.csr().modify(|w| w.set_lsion(true)); + while !RCC.csr().read().lsirdy() {} + } + } + + set_freqs(Clocks { + sys: sys_clk.hz(), + ahb1: ahb_freq.hz(), + ahb2: ahb_freq.hz(), + ahb3: ahb_freq.hz(), + apb1: apb1_freq.hz(), + apb2: apb2_freq.hz(), + apb3: apb3_freq.hz(), + apb1_tim: apb1_tim_freq.hz(), + apb2_tim: apb2_tim_freq.hz(), + }); } diff --git a/examples/stm32l0/src/bin/button_exti.rs b/examples/stm32l0/src/bin/button_exti.rs index 20d6f555..88c75ce6 100644 --- a/examples/stm32l0/src/bin/button_exti.rs +++ b/examples/stm32l0/src/bin/button_exti.rs @@ -8,16 +8,18 @@ mod example_common; use embassy::executor::Spawner; use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::{Input, Pull}; -use embassy_stm32::{rcc, Peripherals}; +use embassy_stm32::Peripherals; use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge}; use example_common::*; -#[embassy::main] -async fn main(_spawner: Spawner, mut p: Peripherals) { - let mut rcc = rcc::Rcc::new(p.RCC); - // Enables SYSCFG - let _ = rcc.enable_hsi48(&mut p.SYSCFG, p.CRS); +fn config() -> embassy_stm32::Config { + let mut config = embassy_stm32::Config::default(); + config.rcc.enable_hsi48 = true; + config +} +#[embassy::main(config = "config()")] +async fn main(_spawner: Spawner, p: Peripherals) { let button = Input::new(p.PB2, Pull::Up); let mut button = ExtiInput::new(button, p.EXTI2); diff --git a/examples/stm32l0/src/bin/lorawan.rs b/examples/stm32l0/src/bin/lorawan.rs index 7ce859a8..df08ba18 100644 --- a/examples/stm32l0/src/bin/lorawan.rs +++ b/examples/stm32l0/src/bin/lorawan.rs @@ -11,10 +11,8 @@ mod example_common; use embassy_lora::{sx127x::*, LoraTimer}; use embassy_stm32::{ - dbgmcu::Dbgmcu, exti::ExtiInput, gpio::{Input, Level, Output, Pull, Speed}, - rcc, rng::Rng, spi, time::U32Ext, @@ -26,18 +24,12 @@ use lorawan_encoding::default_crypto::DefaultFactory as Crypto; fn config() -> embassy_stm32::Config { let mut config = embassy_stm32::Config::default(); config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16; + config.rcc.enable_hsi48 = true; config } #[embassy::main(config = "config()")] -async fn main(_spawner: embassy::executor::Spawner, mut p: Peripherals) { - unsafe { - Dbgmcu::enable_all(); - } - - let mut rcc = rcc::Rcc::new(p.RCC); - let _ = rcc.enable_hsi48(&mut p.SYSCFG, p.CRS); - +async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { // SPI for sx127x let spi = spi::Spi::new( p.SPI1, diff --git a/examples/stm32wl55/src/bin/lorawan.rs b/examples/stm32wl55/src/bin/lorawan.rs index 7048a581..5d26dead 100644 --- a/examples/stm32wl55/src/bin/lorawan.rs +++ b/examples/stm32wl55/src/bin/lorawan.rs @@ -10,10 +10,9 @@ mod example_common; use embassy_lora::{stm32wl::*, LoraTimer}; use embassy_stm32::{ - dbgmcu::Dbgmcu, dma::NoDma, gpio::{Level, Output, Pin, Speed}, - interrupt, pac, rcc, + interrupt, pac, rng::Rng, subghz::*, Peripherals, @@ -24,19 +23,13 @@ use lorawan_encoding::default_crypto::DefaultFactory as Crypto; fn config() -> embassy_stm32::Config { let mut config = embassy_stm32::Config::default(); config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16; + config.rcc.enable_lsi = true; config } #[embassy::main(config = "config()")] async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { - unsafe { - Dbgmcu::enable_all(); - let mut rcc = rcc::Rcc::new(p.RCC); - rcc.enable_lsi(); - pac::RCC.ccipr().modify(|w| { - w.set_rngsel(0b01); - }); - } + unsafe { pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)) } let ctrl1 = Output::new(p.PC3.degrade(), Level::High, Speed::High); let ctrl2 = Output::new(p.PC4.degrade(), Level::High, Speed::High); diff --git a/examples/stm32wl55/src/bin/subghz.rs b/examples/stm32wl55/src/bin/subghz.rs index a73c361c..52fe6e9f 100644 --- a/examples/stm32wl55/src/bin/subghz.rs +++ b/examples/stm32wl55/src/bin/subghz.rs @@ -11,7 +11,6 @@ mod example_common; use embassy::channel::signal::Signal; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::traits::gpio::WaitForRisingEdge; -use embassy_stm32::dbgmcu::Dbgmcu; use embassy_stm32::dma::NoDma; use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; @@ -72,10 +71,6 @@ fn config() -> embassy_stm32::Config { #[embassy::main(config = "config()")] async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { - unsafe { - Dbgmcu::enable_all(); - } - let mut led1 = Output::new(p.PB15, Level::High, Speed::Low); let mut led2 = Output::new(p.PB9, Level::Low, Speed::Low); let mut led3 = Output::new(p.PB11, Level::Low, Speed::Low); diff --git a/stm32-data b/stm32-data index 8530a19f..3fa97966 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 8530a19ffdcdcbc608a97b40895827d09e670eb7 +Subproject commit 3fa97966f07d43a28c0031175591e1c2ff5d0831