From 2376b3bdfa573027c1ee4d66f8fdd6ca422a0fdd Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 13 Nov 2023 01:53:27 +0100 Subject: [PATCH 1/2] stm32/rcc: fix pll enum naming on f4, f7. --- embassy-stm32/src/rcc/f4f7.rs | 10 +++++----- examples/stm32f4/src/bin/eth.rs | 2 +- examples/stm32f4/src/bin/sdmmc.rs | 4 ++-- examples/stm32f4/src/bin/usb_ethernet.rs | 4 ++-- examples/stm32f4/src/bin/usb_raw.rs | 4 ++-- examples/stm32f4/src/bin/usb_serial.rs | 4 ++-- examples/stm32f7/src/bin/eth.rs | 2 +- examples/stm32f7/src/bin/sdmmc.rs | 4 ++-- examples/stm32f7/src/bin/usb_serial.rs | 4 ++-- tests/stm32/src/common.rs | 4 ++-- 10 files changed, 21 insertions(+), 21 deletions(-) diff --git a/embassy-stm32/src/rcc/f4f7.rs b/embassy-stm32/src/rcc/f4f7.rs index 9e8c639d0..718ba9b7c 100644 --- a/embassy-stm32/src/rcc/f4f7.rs +++ b/embassy-stm32/src/rcc/f4f7.rs @@ -1,7 +1,7 @@ use crate::pac::pwr::vals::Vos; pub use crate::pac::rcc::vals::{ - Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp, Pllq, Pllr, Pllsrc as PllSource, - Ppre as APBPrescaler, Sw as Sysclk, + Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, + Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::{set_freqs, Clocks}; @@ -49,11 +49,11 @@ pub struct Pll { pub mul: PllMul, /// PLL P division factor. If None, PLL P output is disabled. - pub divp: Option, + pub divp: Option, /// PLL Q division factor. If None, PLL Q output is disabled. - pub divq: Option, + pub divq: Option, /// PLL R division factor. If None, PLL R output is disabled. - pub divr: Option, + pub divr: Option, } /// Configuration of the core clocks diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 1747bbf4b..088d83c06 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -42,7 +42,7 @@ async fn main(spawner: Spawner) -> ! { config.rcc.pll = Some(Pll { prediv: PllPreDiv::DIV4, mul: PllMul::MUL180, - divp: Some(Pllp::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. divq: None, divr: None, }); diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index 37e42384b..91747b2d5 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs @@ -30,8 +30,8 @@ async fn main(_spawner: Spawner) { config.rcc.pll = Some(Pll { prediv: PllPreDiv::DIV4, mul: PllMul::MUL168, - divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. - divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. + divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. divr: None, }); config.rcc.ahb_pre = AHBPrescaler::DIV1; diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 34407b95a..6bf5b1cba 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -56,8 +56,8 @@ async fn main(spawner: Spawner) { config.rcc.pll = Some(Pll { prediv: PllPreDiv::DIV4, mul: PllMul::MUL168, - divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. - divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. + divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. divr: None, }); config.rcc.ahb_pre = AHBPrescaler::DIV1; diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index 689aea4fc..719b22bb9 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs @@ -85,8 +85,8 @@ async fn main(_spawner: Spawner) { config.rcc.pll = Some(Pll { prediv: PllPreDiv::DIV4, mul: PllMul::MUL168, - divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. - divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. + divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. divr: None, }); config.rcc.ahb_pre = AHBPrescaler::DIV1; diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index 3e05b0ef2..e2ccc9142 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -32,8 +32,8 @@ async fn main(_spawner: Spawner) { config.rcc.pll = Some(Pll { prediv: PllPreDiv::DIV4, mul: PllMul::MUL168, - divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. - divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. + divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. divr: None, }); config.rcc.ahb_pre = AHBPrescaler::DIV1; diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 7c6c419a6..dd0069447 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -43,7 +43,7 @@ async fn main(spawner: Spawner) -> ! { config.rcc.pll = Some(Pll { prediv: PllPreDiv::DIV4, mul: PllMul::MUL216, - divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz divq: None, divr: None, }); diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs index 430aa781f..990de0ab1 100644 --- a/examples/stm32f7/src/bin/sdmmc.rs +++ b/examples/stm32f7/src/bin/sdmmc.rs @@ -26,8 +26,8 @@ async fn main(_spawner: Spawner) { config.rcc.pll = Some(Pll { prediv: PllPreDiv::DIV4, mul: PllMul::MUL216, - divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz - divq: Some(Pllq::DIV9), // 8mhz / 4 * 216 / 9 = 48Mhz + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz + divq: Some(PllQDiv::DIV9), // 8mhz / 4 * 216 / 9 = 48Mhz divr: None, }); config.rcc.ahb_pre = AHBPrescaler::DIV1; diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 6aca732b4..4991edbf0 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -32,8 +32,8 @@ async fn main(_spawner: Spawner) { config.rcc.pll = Some(Pll { prediv: PllPreDiv::DIV4, mul: PllMul::MUL216, - divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz - divq: Some(Pllq::DIV9), // 8mhz / 4 * 216 / 9 = 48Mhz + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz + divq: Some(PllQDiv::DIV9), // 8mhz / 4 * 216 / 9 = 48Mhz divr: None, }); config.rcc.ahb_pre = AHBPrescaler::DIV1; diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index e7367d5ed..fe694cbef 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -271,7 +271,7 @@ pub fn config() -> Config { config.rcc.pll = Some(Pll { prediv: PllPreDiv::DIV4, mul: PllMul::MUL180, - divp: Some(Pllp::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. divq: None, divr: None, }); @@ -292,7 +292,7 @@ pub fn config() -> Config { config.rcc.pll = Some(Pll { prediv: PllPreDiv::DIV4, mul: PllMul::MUL216, - divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz. + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz. divq: None, divr: None, }); From ace52210802a18a551f506bc3ad163703e3f9efa Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 13 Nov 2023 01:56:28 +0100 Subject: [PATCH 2/2] stm32/rcc: unify f2 into f4/f7. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/rcc/{f4f7.rs => f.rs} | 143 ++++++++--- embassy-stm32/src/rcc/f2.rs | 320 ------------------------ embassy-stm32/src/rcc/mod.rs | 9 +- examples/stm32f2/src/bin/pll.rs | 55 ++-- tests/stm32/src/common.rs | 21 +- 6 files changed, 161 insertions(+), 391 deletions(-) rename embassy-stm32/src/rcc/{f4f7.rs => f.rs} (71%) delete mode 100644 embassy-stm32/src/rcc/f2.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 373172760..4b650cc88 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -58,7 +58,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c551c07bf12513dd8346a9fe0bc70cf79f2ea02f" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c551c07bf12513dd8346a9fe0bc70cf79f2ea02f", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/rcc/f4f7.rs b/embassy-stm32/src/rcc/f.rs similarity index 71% rename from embassy-stm32/src/rcc/f4f7.rs rename to embassy-stm32/src/rcc/f.rs index 718ba9b7c..36d9f178f 100644 --- a/embassy-stm32/src/rcc/f4f7.rs +++ b/embassy-stm32/src/rcc/f.rs @@ -1,9 +1,12 @@ -use crate::pac::pwr::vals::Vos; +use stm32_metapac::flash::vals::Latency; + pub use crate::pac::rcc::vals::{ Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; -use crate::pac::{FLASH, PWR, RCC}; +#[cfg(any(stm32f4, stm32f7))] +use crate::pac::PWR; +use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -56,6 +59,22 @@ pub struct Pll { pub divr: Option, } +/// Voltage range of the power supply used. +/// +/// Used to calculate flash waitstates. See +/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency +#[cfg(stm32f2)] +pub enum VoltageScale { + /// 2.7 to 3.6 V + Range0, + /// 2.4 to 2.7 V + Range1, + /// 2.1 to 2.4 V + Range2, + /// 1.8 to 2.1 V + Range3, +} + /// Configuration of the core clocks #[non_exhaustive] pub struct Config { @@ -66,7 +85,7 @@ pub struct Config { pub pll_src: PllSource, pub pll: Option, - #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] + #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] pub plli2s: Option, #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] pub pllsai: Option, @@ -76,6 +95,9 @@ pub struct Config { pub apb2_pre: APBPrescaler, pub ls: super::LsConfig, + + #[cfg(stm32f2)] + pub voltage: VoltageScale, } impl Default for Config { @@ -86,7 +108,7 @@ impl Default for Config { sys: Sysclk::HSI, pll_src: PllSource::HSI, pll: None, - #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] + #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] plli2s: None, #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] pllsai: None, @@ -96,6 +118,9 @@ impl Default for Config { apb2_pre: APBPrescaler::DIV1, ls: Default::default(), + + #[cfg(stm32f2)] + voltage: VoltageScale::Range3, } } } @@ -103,14 +128,13 @@ impl Default for Config { pub(crate) unsafe fn init(config: Config) { // set VOS to SCALE1, if use PLL // TODO: check real clock speed before set VOS + #[cfg(any(stm32f4, stm32f7))] if config.pll.is_some() { - PWR.cr1().modify(|w| w.set_vos(Vos::SCALE1)); + PWR.cr1().modify(|w| w.set_vos(crate::pac::pwr::vals::Vos::SCALE1)); } // always enable overdrive for now. Make it configurable in the future. - #[cfg(not(any( - stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f405, stm32f407, stm32f415, stm32f417 - )))] + #[cfg(any(stm32f446, stm32f4x9, stm32f427, stm32f437, stm32f7))] { PWR.cr1().modify(|w| w.set_oden(true)); while !PWR.csr1().read().odrdy() {} @@ -158,7 +182,7 @@ pub(crate) unsafe fn init(config: Config) { source: config.pll_src, }; let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); - #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] + #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input); #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input); @@ -182,7 +206,48 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); - flash_setup(hclk); + #[cfg(stm32f2)] + let latency = match (config.voltage, hclk.0) { + (VoltageScale::Range3, ..=16_000_000) => Latency::WS0, + (VoltageScale::Range3, ..=32_000_000) => Latency::WS1, + (VoltageScale::Range3, ..=48_000_000) => Latency::WS2, + (VoltageScale::Range3, ..=64_000_000) => Latency::WS3, + (VoltageScale::Range3, ..=80_000_000) => Latency::WS4, + (VoltageScale::Range3, ..=96_000_000) => Latency::WS5, + (VoltageScale::Range3, ..=112_000_000) => Latency::WS6, + (VoltageScale::Range3, ..=120_000_000) => Latency::WS7, + (VoltageScale::Range2, ..=18_000_000) => Latency::WS0, + (VoltageScale::Range2, ..=36_000_000) => Latency::WS1, + (VoltageScale::Range2, ..=54_000_000) => Latency::WS2, + (VoltageScale::Range2, ..=72_000_000) => Latency::WS3, + (VoltageScale::Range2, ..=90_000_000) => Latency::WS4, + (VoltageScale::Range2, ..=108_000_000) => Latency::WS5, + (VoltageScale::Range2, ..=120_000_000) => Latency::WS6, + (VoltageScale::Range1, ..=24_000_000) => Latency::WS0, + (VoltageScale::Range1, ..=48_000_000) => Latency::WS1, + (VoltageScale::Range1, ..=72_000_000) => Latency::WS2, + (VoltageScale::Range1, ..=96_000_000) => Latency::WS3, + (VoltageScale::Range1, ..=120_000_000) => Latency::WS4, + (VoltageScale::Range0, ..=30_000_000) => Latency::WS0, + (VoltageScale::Range0, ..=60_000_000) => Latency::WS1, + (VoltageScale::Range0, ..=90_000_000) => Latency::WS2, + (VoltageScale::Range0, ..=120_000_000) => Latency::WS3, + _ => unreachable!(), + }; + + #[cfg(any(stm32f4, stm32f7))] + let latency = { + // Be conservative with voltage ranges + const FLASH_LATENCY_STEP: u32 = 30_000_000; + + let latency = (hclk.0 - 1) / FLASH_LATENCY_STEP; + debug!("flash: latency={}", latency); + + Latency::from_bits(latency as u8) + }; + + FLASH.acr().write(|w| w.set_latency(latency)); + while FLASH.acr().read().latency() != latency {} RCC.cfgr().modify(|w| { w.set_sw(config.sys); @@ -232,7 +297,7 @@ struct PllOutput { #[derive(PartialEq, Eq, Clone, Copy)] enum PllInstance { Pll, - #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] + #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] Plli2s, #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] Pllsai, @@ -244,7 +309,7 @@ fn pll_enable(instance: PllInstance, enabled: bool) { RCC.cr().modify(|w| w.set_pllon(enabled)); while RCC.cr().read().pllrdy() != enabled {} } - #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] + #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] PllInstance::Plli2s => { RCC.cr().modify(|w| w.set_plli2son(enabled)); while RCC.cr().read().plli2srdy() != enabled {} @@ -275,6 +340,18 @@ fn init_pll(instance: PllInstance, config: Option, input: &PllInput) -> Pll let vco_freq = in_freq * pll.mul; assert!(max::PLL_VCO.contains(&vco_freq)); + // stm32f2 plls are like swiss cheese + #[cfg(stm32f2)] + match instance { + PllInstance::Pll => { + assert!(pll.divr.is_none()); + } + PllInstance::Plli2s => { + assert!(pll.divp.is_none()); + assert!(pll.divq.is_none()); + } + } + let p = pll.divp.map(|div| vco_freq / div); let q = pll.divq.map(|div| vco_freq / div); let r = pll.divr.map(|div| vco_freq / div); @@ -288,6 +365,7 @@ fn init_pll(instance: PllInstance, config: Option, input: &PllInput) -> Pll if let Some(divq) = pll.divq { $w.set_pllq(divq); } + #[cfg(any(stm32f4, stm32f7))] if let Some(divr) = pll.divr { $w.set_pllr(divr); } @@ -304,6 +382,12 @@ fn init_pll(instance: PllInstance, config: Option, input: &PllInput) -> Pll PllInstance::Plli2s => RCC.plli2scfgr().write(|w| { write_fields!(w); }), + #[cfg(stm32f2)] + PllInstance::Plli2s => RCC.plli2scfgr().write(|w| { + if let Some(divr) = pll.divr { + w.set_pllr(divr); + } + }), #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] PllInstance::Pllsai => RCC.pllsaicfgr().write(|w| { write_fields!(w); @@ -316,22 +400,6 @@ fn init_pll(instance: PllInstance, config: Option, input: &PllInput) -> Pll PllOutput { p, q, r } } -fn flash_setup(clk: Hertz) { - use crate::pac::flash::vals::Latency; - - // Be conservative with voltage ranges - const FLASH_LATENCY_STEP: u32 = 30_000_000; - - let latency = (clk.0 - 1) / FLASH_LATENCY_STEP; - debug!("flash: latency={}", latency); - - let latency = Latency::from_bits(latency as u8); - FLASH.acr().write(|w| { - w.set_latency(latency); - }); - while FLASH.acr().read().latency() != latency {} -} - #[cfg(stm32f7)] mod max { use core::ops::RangeInclusive; @@ -380,3 +448,22 @@ mod max { pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(2_100_000); pub(crate) const PLL_VCO: RangeInclusive = Hertz(100_000_000)..=Hertz(432_000_000); } + +#[cfg(stm32f2)] +mod max { + use core::ops::RangeInclusive; + + use crate::time::Hertz; + + pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(26_000_000); + pub(crate) const HSE_BYP: RangeInclusive = Hertz(1_000_000)..=Hertz(26_000_000); + + pub(crate) const SYSCLK: RangeInclusive = Hertz(0)..=Hertz(120_000_000); + + pub(crate) const HCLK: RangeInclusive = Hertz(0)..=Hertz(SYSCLK.end().0); + pub(crate) const PCLK1: RangeInclusive = Hertz(0)..=Hertz(SYSCLK.end().0 / 4); + pub(crate) const PCLK2: RangeInclusive = Hertz(0)..=Hertz(SYSCLK.end().0 / 2); + + pub(crate) const PLL_IN: RangeInclusive = Hertz(0_950_000)..=Hertz(2_100_000); + pub(crate) const PLL_VCO: RangeInclusive = Hertz(192_000_000)..=Hertz(432_000_000); +} diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs deleted file mode 100644 index 00480222a..000000000 --- a/embassy-stm32/src/rcc/f2.rs +++ /dev/null @@ -1,320 +0,0 @@ -use crate::pac::flash::vals::Latency; -use crate::pac::rcc::vals::Sw; -pub use crate::pac::rcc::vals::{ - Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllsrc as PllSource, - Ppre as APBPrescaler, -}; -use crate::pac::{FLASH, RCC}; -use crate::rcc::{set_freqs, Clocks}; -use crate::time::Hertz; - -/// HSI speed -pub const HSI_FREQ: Hertz = Hertz(16_000_000); - -#[derive(Clone, Copy)] -pub struct HSEConfig { - pub frequency: Hertz, - pub source: HSESrc, -} - -/// System clock mux source -#[derive(Clone, Copy)] -pub enum ClockSrc { - HSE, - HSI, - PLL, -} - -/// HSE clock source -#[derive(Clone, Copy)] -pub enum HSESrc { - /// Crystal/ceramic resonator - Crystal, - /// External clock source, HSE bypassed - Bypass, -} - -#[derive(Clone, Copy)] -pub struct Pll { - pub pre_div: PllPreDiv, - pub mul: PllMul, - pub divp: PllPDiv, - pub divq: PllQDiv, -} - -impl Default for Pll { - fn default() -> Self { - Pll { - pre_div: PllPreDiv::DIV16, - mul: PllMul::MUL192, - divp: PllPDiv::DIV2, - divq: PllQDiv::DIV4, - } - } -} - -impl Pll { - pub fn clocks(&self, src_freq: Hertz) -> PLLClocks { - let in_freq = src_freq / self.pre_div; - let vco_freq = src_freq / self.pre_div * self.mul; - let main_freq = vco_freq / self.divp; - let pll48_freq = vco_freq / self.divq; - PLLClocks { - in_freq, - vco_freq, - main_freq, - pll48_freq, - } - } -} -#[derive(Clone, Copy, PartialEq)] -pub struct PLLClocks { - pub in_freq: Hertz, - pub vco_freq: Hertz, - pub main_freq: Hertz, - pub pll48_freq: Hertz, -} - -/// Voltage range of the power supply used. -/// -/// Used to calculate flash waitstates. See -/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency -pub enum VoltageScale { - /// 2.7 to 3.6 V - Range0, - /// 2.4 to 2.7 V - Range1, - /// 2.1 to 2.4 V - Range2, - /// 1.8 to 2.1 V - Range3, -} - -impl VoltageScale { - const fn wait_states(&self, ahb_freq: Hertz) -> Option { - let ahb_freq = ahb_freq.0; - // Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock - // frequency - match self { - VoltageScale::Range3 => { - if ahb_freq <= 16_000_000 { - Some(Latency::WS0) - } else if ahb_freq <= 32_000_000 { - Some(Latency::WS1) - } else if ahb_freq <= 48_000_000 { - Some(Latency::WS2) - } else if ahb_freq <= 64_000_000 { - Some(Latency::WS3) - } else if ahb_freq <= 80_000_000 { - Some(Latency::WS4) - } else if ahb_freq <= 96_000_000 { - Some(Latency::WS5) - } else if ahb_freq <= 112_000_000 { - Some(Latency::WS6) - } else if ahb_freq <= 120_000_000 { - Some(Latency::WS7) - } else { - None - } - } - VoltageScale::Range2 => { - if ahb_freq <= 18_000_000 { - Some(Latency::WS0) - } else if ahb_freq <= 36_000_000 { - Some(Latency::WS1) - } else if ahb_freq <= 54_000_000 { - Some(Latency::WS2) - } else if ahb_freq <= 72_000_000 { - Some(Latency::WS3) - } else if ahb_freq <= 90_000_000 { - Some(Latency::WS4) - } else if ahb_freq <= 108_000_000 { - Some(Latency::WS5) - } else if ahb_freq <= 120_000_000 { - Some(Latency::WS6) - } else { - None - } - } - VoltageScale::Range1 => { - if ahb_freq <= 24_000_000 { - Some(Latency::WS0) - } else if ahb_freq <= 48_000_000 { - Some(Latency::WS1) - } else if ahb_freq <= 72_000_000 { - Some(Latency::WS2) - } else if ahb_freq <= 96_000_000 { - Some(Latency::WS3) - } else if ahb_freq <= 120_000_000 { - Some(Latency::WS4) - } else { - None - } - } - VoltageScale::Range0 => { - if ahb_freq <= 30_000_000 { - Some(Latency::WS0) - } else if ahb_freq <= 60_000_000 { - Some(Latency::WS1) - } else if ahb_freq <= 90_000_000 { - Some(Latency::WS2) - } else if ahb_freq <= 120_000_000 { - Some(Latency::WS3) - } else { - None - } - } - } - } -} - -/// Clocks configuration -pub struct Config { - pub hse: Option, - pub hsi: bool, - pub pll_mux: PllSource, - pub pll: Pll, - pub mux: ClockSrc, - pub voltage: VoltageScale, - pub ahb_pre: AHBPrescaler, - pub apb1_pre: APBPrescaler, - pub apb2_pre: APBPrescaler, - pub ls: super::LsConfig, -} - -impl Default for Config { - #[inline] - fn default() -> Config { - Config { - hse: None, - hsi: true, - pll_mux: PllSource::HSI, - pll: Pll::default(), - voltage: VoltageScale::Range3, - mux: ClockSrc::HSI, - ahb_pre: AHBPrescaler::DIV1, - apb1_pre: APBPrescaler::DIV1, - apb2_pre: APBPrescaler::DIV1, - ls: Default::default(), - } - } -} - -pub(crate) unsafe fn init(config: Config) { - // Make sure HSI is enabled - RCC.cr().write(|w| w.set_hsion(true)); - while !RCC.cr().read().hsirdy() {} - - if let Some(hse_config) = config.hse { - RCC.cr().modify(|w| { - w.set_hsebyp(match hse_config.source { - HSESrc::Bypass => true, - HSESrc::Crystal => false, - }); - w.set_hseon(true) - }); - while !RCC.cr().read().hserdy() {} - } - - let pll_src_freq = match config.pll_mux { - PllSource::HSE => { - let hse_config = config - .hse - .unwrap_or_else(|| panic!("HSE must be configured to be used as PLL input")); - hse_config.frequency - } - PllSource::HSI => HSI_FREQ, - }; - - // Reference: STM32F215xx/217xx datasheet Table 33. Main PLL characteristics - let pll_clocks = config.pll.clocks(pll_src_freq); - assert!(Hertz(950_000) <= pll_clocks.in_freq && pll_clocks.in_freq <= Hertz(2_100_000)); - assert!(Hertz(192_000_000) <= pll_clocks.vco_freq && pll_clocks.vco_freq <= Hertz(432_000_000)); - assert!(Hertz(24_000_000) <= pll_clocks.main_freq && pll_clocks.main_freq <= Hertz(120_000_000)); - // USB actually requires == 48 MHz, but other PLL48 peripherals are fine with <= 48MHz - assert!(pll_clocks.pll48_freq <= Hertz(48_000_000)); - - RCC.pllcfgr().write(|w| { - w.set_pllsrc(config.pll_mux); - w.set_pllm(config.pll.pre_div); - w.set_plln(config.pll.mul); - w.set_pllp(config.pll.divp); - w.set_pllq(config.pll.divq); - }); - - let (sys_clk, sw) = match config.mux { - ClockSrc::HSI => { - assert!(config.hsi, "HSI must be enabled to be used as system clock"); - (HSI_FREQ, Sw::HSI) - } - ClockSrc::HSE => { - let hse_config = config - .hse - .unwrap_or_else(|| panic!("HSE must be configured to be used as PLL input")); - (hse_config.frequency, Sw::HSE) - } - ClockSrc::PLL => { - RCC.cr().modify(|w| w.set_pllon(true)); - while !RCC.cr().read().pllrdy() {} - (pll_clocks.main_freq, Sw::PLL1_P) - } - }; - // RM0033 Figure 9. Clock tree suggests max SYSCLK/HCLK is 168 MHz, but datasheet specifies PLL - // max output to be 120 MHz, so there's no way to get higher frequencies - assert!(sys_clk <= Hertz(120_000_000)); - - let ahb_freq = sys_clk / config.ahb_pre; - // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions - assert!(ahb_freq <= Hertz(120_000_000)); - - let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::DIV1 => (ahb_freq, ahb_freq), - pre => { - let freq = ahb_freq / pre; - (freq, Hertz(freq.0 * 2)) - } - }; - // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions - assert!(apb1_freq <= Hertz(30_000_000)); - - let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::DIV1 => (ahb_freq, ahb_freq), - pre => { - let freq = ahb_freq / pre; - (freq, Hertz(freq.0 * 2)) - } - }; - // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions - assert!(apb2_freq <= Hertz(60_000_000)); - - let flash_ws = unwrap!(config.voltage.wait_states(ahb_freq)); - FLASH.acr().modify(|w| w.set_latency(flash_ws)); - - RCC.cfgr().modify(|w| { - w.set_sw(sw.into()); - w.set_hpre(config.ahb_pre); - w.set_ppre1(config.apb1_pre); - w.set_ppre2(config.apb2_pre); - }); - while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} - - // Turn off HSI to save power if we don't need it - if !config.hsi { - RCC.cr().modify(|w| w.set_hsion(false)); - } - - let rtc = config.ls.init(); - - set_freqs(Clocks { - sys: sys_clk, - hclk1: ahb_freq, - hclk2: ahb_freq, - hclk3: ahb_freq, - pclk1: apb1_freq, - pclk1_tim: apb1_tim_freq, - pclk2: apb2_freq, - pclk2_tim: apb2_tim_freq, - pll1_q: Some(pll_clocks.pll48_freq), - rtc, - }); -} diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index debd16ca1..2e144dc77 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -15,14 +15,13 @@ mod hsi48; pub use hsi48::*; #[cfg_attr(rcc_f0, path = "f0.rs")] -#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] -#[cfg_attr(rcc_f2, path = "f2.rs")] -#[cfg_attr(any(rcc_f3, rcc_f3_v2), path = "f3.rs")] -#[cfg_attr(any(rcc_f4, rcc_f410, rcc_f7), path = "f4f7.rs")] +#[cfg_attr(any(stm32f1), path = "f1.rs")] +#[cfg_attr(any(stm32f3), path = "f3.rs")] +#[cfg_attr(any(stm32f2, stm32f4, stm32f7), path = "f.rs")] #[cfg_attr(rcc_c0, path = "c0.rs")] #[cfg_attr(rcc_g0, path = "g0.rs")] #[cfg_attr(rcc_g4, path = "g4.rs")] -#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")] +#[cfg_attr(any(stm32h5, stm32h7), path = "h.rs")] #[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl), path = "l.rs")] #[cfg_attr(rcc_u5, path = "u5.rs")] #[cfg_attr(rcc_wba, path = "wba.rs")] diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs index feec90016..aae7637dc 100644 --- a/examples/stm32f2/src/bin/pll.rs +++ b/examples/stm32f2/src/bin/pll.rs @@ -6,9 +6,6 @@ use core::convert::TryFrom; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rcc::{ - APBPrescaler, ClockSrc, HSEConfig, HSESrc, Pll, PllMul, PllPDiv, PllPreDiv, PllQDiv, PllSource, -}; use embassy_stm32::time::Hertz; use embassy_stm32::Config; use embassy_time::Timer; @@ -19,29 +16,35 @@ async fn main(_spawner: Spawner) { // Example config for maximum performance on a NUCLEO-F207ZG board let mut config = Config::default(); - // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) - config.rcc.hse = Some(HSEConfig { - frequency: Hertz(8_000_000), - source: HSESrc::Bypass, - }); - // PLL uses HSE as the clock source - config.rcc.pll_mux = PllSource::HSE; - config.rcc.pll = Pll { - // 8 MHz clock source / 8 = 1 MHz PLL input - pre_div: unwrap!(PllPreDiv::try_from(8)), - // 1 MHz PLL input * 240 = 240 MHz PLL VCO - mul: unwrap!(PllMul::try_from(240)), - // 240 MHz PLL VCO / 2 = 120 MHz main PLL output - divp: PllPDiv::DIV2, - // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output - divq: PllQDiv::DIV5, - }; - // System clock comes from PLL (= the 120 MHz main PLL output) - config.rcc.mux = ClockSrc::PLL; - // 120 MHz / 4 = 30 MHz APB1 frequency - config.rcc.apb1_pre = APBPrescaler::DIV4; - // 120 MHz / 2 = 60 MHz APB2 frequency - config.rcc.apb2_pre = APBPrescaler::DIV2; + + { + use embassy_stm32::rcc::*; + + // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Bypass, + }); + // PLL uses HSE as the clock source + config.rcc.pll_src = PllSource::HSE; + config.rcc.pll = Some(Pll { + // 8 MHz clock source / 8 = 1 MHz PLL input + prediv: unwrap!(PllPreDiv::try_from(8)), + // 1 MHz PLL input * 240 = 240 MHz PLL VCO + mul: unwrap!(PllMul::try_from(240)), + // 240 MHz PLL VCO / 2 = 120 MHz main PLL output + divp: Some(PllPDiv::DIV2), + // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output + divq: Some(PllQDiv::DIV5), + divr: None, + }); + // System clock comes from PLL (= the 120 MHz main PLL output) + config.rcc.sys = Sysclk::PLL1_P; + // 120 MHz / 4 = 30 MHz APB1 frequency + config.rcc.apb1_pre = APBPrescaler::DIV4; + // 120 MHz / 2 = 60 MHz APB2 frequency + config.rcc.apb2_pre = APBPrescaler::DIV2; + } let _p = embassy_stm32::init(config); diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index fe694cbef..a44e8230f 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -236,24 +236,25 @@ pub fn config() -> Config { { use embassy_stm32::rcc::*; // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) - config.rcc.hse = Some(HSEConfig { - frequency: Hertz(8_000_000), - source: HSESrc::Bypass, + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Bypass, }); // PLL uses HSE as the clock source - config.rcc.pll_mux = PllSource::HSE; - config.rcc.pll = Pll { + config.rcc.pll_src = PllSource::HSE; + config.rcc.pll = Some(Pll { // 8 MHz clock source / 8 = 1 MHz PLL input - pre_div: unwrap!(PllPreDiv::try_from(8)), + prediv: unwrap!(PllPreDiv::try_from(8)), // 1 MHz PLL input * 240 = 240 MHz PLL VCO mul: unwrap!(PllMul::try_from(240)), // 240 MHz PLL VCO / 2 = 120 MHz main PLL output - divp: PllPDiv::DIV2, + divp: Some(PllPDiv::DIV2), // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output - divq: PllQDiv::DIV5, - }; + divq: Some(PllQDiv::DIV5), + divr: None, + }); // System clock comes from PLL (= the 120 MHz main PLL output) - config.rcc.mux = ClockSrc::PLL; + config.rcc.sys = Sysclk::PLL1_P; // 120 MHz / 4 = 30 MHz APB1 frequency config.rcc.apb1_pre = APBPrescaler::DIV4; // 120 MHz / 2 = 60 MHz APB2 frequency