diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-11-13 01:08:27 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-13 01:08:27 +0000 |
| commit | ac7134ed0d304282d2b10b1efff316426757fdab (patch) | |
| tree | 69cd68e35968cf0a5da5000308e338bdbad3724a | |
| parent | f00e97a5f14b25d261eafba7cbc63b035c938996 (diff) | |
| parent | ace52210802a18a551f506bc3ad163703e3f9efa (diff) | |
Merge pull request #2178 from embassy-rs/rcc-no-spaghetti
stm32/rcc: unify f2 into f4/f7.
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/f.rs (renamed from embassy-stm32/src/rcc/f4f7.rs) | 153 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/f2.rs | 320 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 9 | ||||
| -rw-r--r-- | examples/stm32f2/src/bin/pll.rs | 55 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/eth.rs | 2 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/sdmmc.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usb_ethernet.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usb_raw.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usb_serial.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f7/src/bin/eth.rs | 2 | ||||
| -rw-r--r-- | examples/stm32f7/src/bin/sdmmc.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f7/src/bin/usb_serial.rs | 4 | ||||
| -rw-r--r-- | tests/stm32/src/common.rs | 25 |
14 files changed, 182 insertions, 412 deletions
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" | |||
| 58 | sdio-host = "0.5.0" | 58 | sdio-host = "0.5.0" |
| 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } |
| 60 | critical-section = "1.1" | 60 | critical-section = "1.1" |
| 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c551c07bf12513dd8346a9fe0bc70cf79f2ea02f" } | 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b" } |
| 62 | vcell = "0.1.3" | 62 | vcell = "0.1.3" |
| 63 | bxcan = "0.7.0" | 63 | bxcan = "0.7.0" |
| 64 | nb = "1.0.0" | 64 | nb = "1.0.0" |
| @@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 76 | [build-dependencies] | 76 | [build-dependencies] |
| 77 | proc-macro2 = "1.0.36" | 77 | proc-macro2 = "1.0.36" |
| 78 | quote = "1.0.15" | 78 | quote = "1.0.15" |
| 79 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c551c07bf12513dd8346a9fe0bc70cf79f2ea02f", default-features = false, features = ["metadata"]} | 79 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b", default-features = false, features = ["metadata"]} |
| 80 | 80 | ||
| 81 | 81 | ||
| 82 | [features] | 82 | [features] |
diff --git a/embassy-stm32/src/rcc/f4f7.rs b/embassy-stm32/src/rcc/f.rs index 9e8c639d0..36d9f178f 100644 --- a/embassy-stm32/src/rcc/f4f7.rs +++ b/embassy-stm32/src/rcc/f.rs | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | use crate::pac::pwr::vals::Vos; | 1 | use stm32_metapac::flash::vals::Latency; |
| 2 | |||
| 2 | pub use crate::pac::rcc::vals::{ | 3 | pub use crate::pac::rcc::vals::{ |
| 3 | Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp, Pllq, Pllr, Pllsrc as PllSource, | 4 | Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, |
| 4 | Ppre as APBPrescaler, Sw as Sysclk, | 5 | Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, |
| 5 | }; | 6 | }; |
| 6 | use crate::pac::{FLASH, PWR, RCC}; | 7 | #[cfg(any(stm32f4, stm32f7))] |
| 8 | use crate::pac::PWR; | ||
| 9 | use crate::pac::{FLASH, RCC}; | ||
| 7 | use crate::rcc::{set_freqs, Clocks}; | 10 | use crate::rcc::{set_freqs, Clocks}; |
| 8 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 9 | 12 | ||
| @@ -49,11 +52,27 @@ pub struct Pll { | |||
| 49 | pub mul: PllMul, | 52 | pub mul: PllMul, |
| 50 | 53 | ||
| 51 | /// PLL P division factor. If None, PLL P output is disabled. | 54 | /// PLL P division factor. If None, PLL P output is disabled. |
| 52 | pub divp: Option<Pllp>, | 55 | pub divp: Option<PllPDiv>, |
| 53 | /// PLL Q division factor. If None, PLL Q output is disabled. | 56 | /// PLL Q division factor. If None, PLL Q output is disabled. |
| 54 | pub divq: Option<Pllq>, | 57 | pub divq: Option<PllQDiv>, |
| 55 | /// PLL R division factor. If None, PLL R output is disabled. | 58 | /// PLL R division factor. If None, PLL R output is disabled. |
| 56 | pub divr: Option<Pllr>, | 59 | pub divr: Option<PllRDiv>, |
| 60 | } | ||
| 61 | |||
| 62 | /// Voltage range of the power supply used. | ||
| 63 | /// | ||
| 64 | /// Used to calculate flash waitstates. See | ||
| 65 | /// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency | ||
| 66 | #[cfg(stm32f2)] | ||
| 67 | pub enum VoltageScale { | ||
| 68 | /// 2.7 to 3.6 V | ||
| 69 | Range0, | ||
| 70 | /// 2.4 to 2.7 V | ||
| 71 | Range1, | ||
| 72 | /// 2.1 to 2.4 V | ||
| 73 | Range2, | ||
| 74 | /// 1.8 to 2.1 V | ||
| 75 | Range3, | ||
| 57 | } | 76 | } |
| 58 | 77 | ||
| 59 | /// Configuration of the core clocks | 78 | /// Configuration of the core clocks |
| @@ -66,7 +85,7 @@ pub struct Config { | |||
| 66 | pub pll_src: PllSource, | 85 | pub pll_src: PllSource, |
| 67 | 86 | ||
| 68 | pub pll: Option<Pll>, | 87 | pub pll: Option<Pll>, |
| 69 | #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] | 88 | #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] |
| 70 | pub plli2s: Option<Pll>, | 89 | pub plli2s: Option<Pll>, |
| 71 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] | 90 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] |
| 72 | pub pllsai: Option<Pll>, | 91 | pub pllsai: Option<Pll>, |
| @@ -76,6 +95,9 @@ pub struct Config { | |||
| 76 | pub apb2_pre: APBPrescaler, | 95 | pub apb2_pre: APBPrescaler, |
| 77 | 96 | ||
| 78 | pub ls: super::LsConfig, | 97 | pub ls: super::LsConfig, |
| 98 | |||
| 99 | #[cfg(stm32f2)] | ||
| 100 | pub voltage: VoltageScale, | ||
| 79 | } | 101 | } |
| 80 | 102 | ||
| 81 | impl Default for Config { | 103 | impl Default for Config { |
| @@ -86,7 +108,7 @@ impl Default for Config { | |||
| 86 | sys: Sysclk::HSI, | 108 | sys: Sysclk::HSI, |
| 87 | pll_src: PllSource::HSI, | 109 | pll_src: PllSource::HSI, |
| 88 | pll: None, | 110 | pll: None, |
| 89 | #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] | 111 | #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] |
| 90 | plli2s: None, | 112 | plli2s: None, |
| 91 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] | 113 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] |
| 92 | pllsai: None, | 114 | pllsai: None, |
| @@ -96,6 +118,9 @@ impl Default for Config { | |||
| 96 | apb2_pre: APBPrescaler::DIV1, | 118 | apb2_pre: APBPrescaler::DIV1, |
| 97 | 119 | ||
| 98 | ls: Default::default(), | 120 | ls: Default::default(), |
| 121 | |||
| 122 | #[cfg(stm32f2)] | ||
| 123 | voltage: VoltageScale::Range3, | ||
| 99 | } | 124 | } |
| 100 | } | 125 | } |
| 101 | } | 126 | } |
| @@ -103,14 +128,13 @@ impl Default for Config { | |||
| 103 | pub(crate) unsafe fn init(config: Config) { | 128 | pub(crate) unsafe fn init(config: Config) { |
| 104 | // set VOS to SCALE1, if use PLL | 129 | // set VOS to SCALE1, if use PLL |
| 105 | // TODO: check real clock speed before set VOS | 130 | // TODO: check real clock speed before set VOS |
| 131 | #[cfg(any(stm32f4, stm32f7))] | ||
| 106 | if config.pll.is_some() { | 132 | if config.pll.is_some() { |
| 107 | PWR.cr1().modify(|w| w.set_vos(Vos::SCALE1)); | 133 | PWR.cr1().modify(|w| w.set_vos(crate::pac::pwr::vals::Vos::SCALE1)); |
| 108 | } | 134 | } |
| 109 | 135 | ||
| 110 | // always enable overdrive for now. Make it configurable in the future. | 136 | // always enable overdrive for now. Make it configurable in the future. |
| 111 | #[cfg(not(any( | 137 | #[cfg(any(stm32f446, stm32f4x9, stm32f427, stm32f437, stm32f7))] |
| 112 | stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f405, stm32f407, stm32f415, stm32f417 | ||
| 113 | )))] | ||
| 114 | { | 138 | { |
| 115 | PWR.cr1().modify(|w| w.set_oden(true)); | 139 | PWR.cr1().modify(|w| w.set_oden(true)); |
| 116 | while !PWR.csr1().read().odrdy() {} | 140 | while !PWR.csr1().read().odrdy() {} |
| @@ -158,7 +182,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 158 | source: config.pll_src, | 182 | source: config.pll_src, |
| 159 | }; | 183 | }; |
| 160 | let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); | 184 | let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); |
| 161 | #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] | 185 | #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] |
| 162 | let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input); | 186 | let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input); |
| 163 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] | 187 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] |
| 164 | let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input); | 188 | let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input); |
| @@ -182,7 +206,48 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 182 | 206 | ||
| 183 | let rtc = config.ls.init(); | 207 | let rtc = config.ls.init(); |
| 184 | 208 | ||
| 185 | flash_setup(hclk); | 209 | #[cfg(stm32f2)] |
| 210 | let latency = match (config.voltage, hclk.0) { | ||
| 211 | (VoltageScale::Range3, ..=16_000_000) => Latency::WS0, | ||
| 212 | (VoltageScale::Range3, ..=32_000_000) => Latency::WS1, | ||
| 213 | (VoltageScale::Range3, ..=48_000_000) => Latency::WS2, | ||
| 214 | (VoltageScale::Range3, ..=64_000_000) => Latency::WS3, | ||
| 215 | (VoltageScale::Range3, ..=80_000_000) => Latency::WS4, | ||
| 216 | (VoltageScale::Range3, ..=96_000_000) => Latency::WS5, | ||
| 217 | (VoltageScale::Range3, ..=112_000_000) => Latency::WS6, | ||
| 218 | (VoltageScale::Range3, ..=120_000_000) => Latency::WS7, | ||
| 219 | (VoltageScale::Range2, ..=18_000_000) => Latency::WS0, | ||
| 220 | (VoltageScale::Range2, ..=36_000_000) => Latency::WS1, | ||
| 221 | (VoltageScale::Range2, ..=54_000_000) => Latency::WS2, | ||
| 222 | (VoltageScale::Range2, ..=72_000_000) => Latency::WS3, | ||
| 223 | (VoltageScale::Range2, ..=90_000_000) => Latency::WS4, | ||
| 224 | (VoltageScale::Range2, ..=108_000_000) => Latency::WS5, | ||
| 225 | (VoltageScale::Range2, ..=120_000_000) => Latency::WS6, | ||
| 226 | (VoltageScale::Range1, ..=24_000_000) => Latency::WS0, | ||
| 227 | (VoltageScale::Range1, ..=48_000_000) => Latency::WS1, | ||
| 228 | (VoltageScale::Range1, ..=72_000_000) => Latency::WS2, | ||
| 229 | (VoltageScale::Range1, ..=96_000_000) => Latency::WS3, | ||
| 230 | (VoltageScale::Range1, ..=120_000_000) => Latency::WS4, | ||
| 231 | (VoltageScale::Range0, ..=30_000_000) => Latency::WS0, | ||
| 232 | (VoltageScale::Range0, ..=60_000_000) => Latency::WS1, | ||
| 233 | (VoltageScale::Range0, ..=90_000_000) => Latency::WS2, | ||
| 234 | (VoltageScale::Range0, ..=120_000_000) => Latency::WS3, | ||
| 235 | _ => unreachable!(), | ||
| 236 | }; | ||
| 237 | |||
| 238 | #[cfg(any(stm32f4, stm32f7))] | ||
| 239 | let latency = { | ||
| 240 | // Be conservative with voltage ranges | ||
| 241 | const FLASH_LATENCY_STEP: u32 = 30_000_000; | ||
| 242 | |||
| 243 | let latency = (hclk.0 - 1) / FLASH_LATENCY_STEP; | ||
| 244 | debug!("flash: latency={}", latency); | ||
| 245 | |||
| 246 | Latency::from_bits(latency as u8) | ||
| 247 | }; | ||
| 248 | |||
| 249 | FLASH.acr().write(|w| w.set_latency(latency)); | ||
| 250 | while FLASH.acr().read().latency() != latency {} | ||
| 186 | 251 | ||
| 187 | RCC.cfgr().modify(|w| { | 252 | RCC.cfgr().modify(|w| { |
| 188 | w.set_sw(config.sys); | 253 | w.set_sw(config.sys); |
| @@ -232,7 +297,7 @@ struct PllOutput { | |||
| 232 | #[derive(PartialEq, Eq, Clone, Copy)] | 297 | #[derive(PartialEq, Eq, Clone, Copy)] |
| 233 | enum PllInstance { | 298 | enum PllInstance { |
| 234 | Pll, | 299 | Pll, |
| 235 | #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] | 300 | #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] |
| 236 | Plli2s, | 301 | Plli2s, |
| 237 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] | 302 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] |
| 238 | Pllsai, | 303 | Pllsai, |
| @@ -244,7 +309,7 @@ fn pll_enable(instance: PllInstance, enabled: bool) { | |||
| 244 | RCC.cr().modify(|w| w.set_pllon(enabled)); | 309 | RCC.cr().modify(|w| w.set_pllon(enabled)); |
| 245 | while RCC.cr().read().pllrdy() != enabled {} | 310 | while RCC.cr().read().pllrdy() != enabled {} |
| 246 | } | 311 | } |
| 247 | #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] | 312 | #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] |
| 248 | PllInstance::Plli2s => { | 313 | PllInstance::Plli2s => { |
| 249 | RCC.cr().modify(|w| w.set_plli2son(enabled)); | 314 | RCC.cr().modify(|w| w.set_plli2son(enabled)); |
| 250 | while RCC.cr().read().plli2srdy() != enabled {} | 315 | while RCC.cr().read().plli2srdy() != enabled {} |
| @@ -275,6 +340,18 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll | |||
| 275 | let vco_freq = in_freq * pll.mul; | 340 | let vco_freq = in_freq * pll.mul; |
| 276 | assert!(max::PLL_VCO.contains(&vco_freq)); | 341 | assert!(max::PLL_VCO.contains(&vco_freq)); |
| 277 | 342 | ||
| 343 | // stm32f2 plls are like swiss cheese | ||
| 344 | #[cfg(stm32f2)] | ||
| 345 | match instance { | ||
| 346 | PllInstance::Pll => { | ||
| 347 | assert!(pll.divr.is_none()); | ||
| 348 | } | ||
| 349 | PllInstance::Plli2s => { | ||
| 350 | assert!(pll.divp.is_none()); | ||
| 351 | assert!(pll.divq.is_none()); | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 278 | let p = pll.divp.map(|div| vco_freq / div); | 355 | let p = pll.divp.map(|div| vco_freq / div); |
| 279 | let q = pll.divq.map(|div| vco_freq / div); | 356 | let q = pll.divq.map(|div| vco_freq / div); |
| 280 | let r = pll.divr.map(|div| vco_freq / div); | 357 | let r = pll.divr.map(|div| vco_freq / div); |
| @@ -288,6 +365,7 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll | |||
| 288 | if let Some(divq) = pll.divq { | 365 | if let Some(divq) = pll.divq { |
| 289 | $w.set_pllq(divq); | 366 | $w.set_pllq(divq); |
| 290 | } | 367 | } |
| 368 | #[cfg(any(stm32f4, stm32f7))] | ||
| 291 | if let Some(divr) = pll.divr { | 369 | if let Some(divr) = pll.divr { |
| 292 | $w.set_pllr(divr); | 370 | $w.set_pllr(divr); |
| 293 | } | 371 | } |
| @@ -304,6 +382,12 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll | |||
| 304 | PllInstance::Plli2s => RCC.plli2scfgr().write(|w| { | 382 | PllInstance::Plli2s => RCC.plli2scfgr().write(|w| { |
| 305 | write_fields!(w); | 383 | write_fields!(w); |
| 306 | }), | 384 | }), |
| 385 | #[cfg(stm32f2)] | ||
| 386 | PllInstance::Plli2s => RCC.plli2scfgr().write(|w| { | ||
| 387 | if let Some(divr) = pll.divr { | ||
| 388 | w.set_pllr(divr); | ||
| 389 | } | ||
| 390 | }), | ||
| 307 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] | 391 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] |
| 308 | PllInstance::Pllsai => RCC.pllsaicfgr().write(|w| { | 392 | PllInstance::Pllsai => RCC.pllsaicfgr().write(|w| { |
| 309 | write_fields!(w); | 393 | write_fields!(w); |
| @@ -316,22 +400,6 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll | |||
| 316 | PllOutput { p, q, r } | 400 | PllOutput { p, q, r } |
| 317 | } | 401 | } |
| 318 | 402 | ||
| 319 | fn flash_setup(clk: Hertz) { | ||
| 320 | use crate::pac::flash::vals::Latency; | ||
| 321 | |||
| 322 | // Be conservative with voltage ranges | ||
| 323 | const FLASH_LATENCY_STEP: u32 = 30_000_000; | ||
| 324 | |||
| 325 | let latency = (clk.0 - 1) / FLASH_LATENCY_STEP; | ||
| 326 | debug!("flash: latency={}", latency); | ||
| 327 | |||
| 328 | let latency = Latency::from_bits(latency as u8); | ||
| 329 | FLASH.acr().write(|w| { | ||
| 330 | w.set_latency(latency); | ||
| 331 | }); | ||
| 332 | while FLASH.acr().read().latency() != latency {} | ||
| 333 | } | ||
| 334 | |||
| 335 | #[cfg(stm32f7)] | 403 | #[cfg(stm32f7)] |
| 336 | mod max { | 404 | mod max { |
| 337 | use core::ops::RangeInclusive; | 405 | use core::ops::RangeInclusive; |
| @@ -380,3 +448,22 @@ mod max { | |||
| 380 | pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(2_100_000); | 448 | pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(2_100_000); |
| 381 | pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(100_000_000)..=Hertz(432_000_000); | 449 | pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(100_000_000)..=Hertz(432_000_000); |
| 382 | } | 450 | } |
| 451 | |||
| 452 | #[cfg(stm32f2)] | ||
| 453 | mod max { | ||
| 454 | use core::ops::RangeInclusive; | ||
| 455 | |||
| 456 | use crate::time::Hertz; | ||
| 457 | |||
| 458 | pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(26_000_000); | ||
| 459 | pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(26_000_000); | ||
| 460 | |||
| 461 | pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(120_000_000); | ||
| 462 | |||
| 463 | pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(SYSCLK.end().0); | ||
| 464 | pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(0)..=Hertz(SYSCLK.end().0 / 4); | ||
| 465 | pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(0)..=Hertz(SYSCLK.end().0 / 2); | ||
| 466 | |||
| 467 | pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(0_950_000)..=Hertz(2_100_000); | ||
| 468 | pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(192_000_000)..=Hertz(432_000_000); | ||
| 469 | } | ||
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 @@ | |||
| 1 | use crate::pac::flash::vals::Latency; | ||
| 2 | use crate::pac::rcc::vals::Sw; | ||
| 3 | pub use crate::pac::rcc::vals::{ | ||
| 4 | Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllsrc as PllSource, | ||
| 5 | Ppre as APBPrescaler, | ||
| 6 | }; | ||
| 7 | use crate::pac::{FLASH, RCC}; | ||
| 8 | use crate::rcc::{set_freqs, Clocks}; | ||
| 9 | use crate::time::Hertz; | ||
| 10 | |||
| 11 | /// HSI speed | ||
| 12 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); | ||
| 13 | |||
| 14 | #[derive(Clone, Copy)] | ||
| 15 | pub struct HSEConfig { | ||
| 16 | pub frequency: Hertz, | ||
| 17 | pub source: HSESrc, | ||
| 18 | } | ||
| 19 | |||
| 20 | /// System clock mux source | ||
| 21 | #[derive(Clone, Copy)] | ||
| 22 | pub enum ClockSrc { | ||
| 23 | HSE, | ||
| 24 | HSI, | ||
| 25 | PLL, | ||
| 26 | } | ||
| 27 | |||
| 28 | /// HSE clock source | ||
| 29 | #[derive(Clone, Copy)] | ||
| 30 | pub enum HSESrc { | ||
| 31 | /// Crystal/ceramic resonator | ||
| 32 | Crystal, | ||
| 33 | /// External clock source, HSE bypassed | ||
| 34 | Bypass, | ||
| 35 | } | ||
| 36 | |||
| 37 | #[derive(Clone, Copy)] | ||
| 38 | pub struct Pll { | ||
| 39 | pub pre_div: PllPreDiv, | ||
| 40 | pub mul: PllMul, | ||
| 41 | pub divp: PllPDiv, | ||
| 42 | pub divq: PllQDiv, | ||
| 43 | } | ||
| 44 | |||
| 45 | impl Default for Pll { | ||
| 46 | fn default() -> Self { | ||
| 47 | Pll { | ||
| 48 | pre_div: PllPreDiv::DIV16, | ||
| 49 | mul: PllMul::MUL192, | ||
| 50 | divp: PllPDiv::DIV2, | ||
| 51 | divq: PllQDiv::DIV4, | ||
| 52 | } | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | impl Pll { | ||
| 57 | pub fn clocks(&self, src_freq: Hertz) -> PLLClocks { | ||
| 58 | let in_freq = src_freq / self.pre_div; | ||
| 59 | let vco_freq = src_freq / self.pre_div * self.mul; | ||
| 60 | let main_freq = vco_freq / self.divp; | ||
| 61 | let pll48_freq = vco_freq / self.divq; | ||
| 62 | PLLClocks { | ||
| 63 | in_freq, | ||
| 64 | vco_freq, | ||
| 65 | main_freq, | ||
| 66 | pll48_freq, | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | #[derive(Clone, Copy, PartialEq)] | ||
| 71 | pub struct PLLClocks { | ||
| 72 | pub in_freq: Hertz, | ||
| 73 | pub vco_freq: Hertz, | ||
| 74 | pub main_freq: Hertz, | ||
| 75 | pub pll48_freq: Hertz, | ||
| 76 | } | ||
| 77 | |||
| 78 | /// Voltage range of the power supply used. | ||
| 79 | /// | ||
| 80 | /// Used to calculate flash waitstates. See | ||
| 81 | /// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency | ||
| 82 | pub enum VoltageScale { | ||
| 83 | /// 2.7 to 3.6 V | ||
| 84 | Range0, | ||
| 85 | /// 2.4 to 2.7 V | ||
| 86 | Range1, | ||
| 87 | /// 2.1 to 2.4 V | ||
| 88 | Range2, | ||
| 89 | /// 1.8 to 2.1 V | ||
| 90 | Range3, | ||
| 91 | } | ||
| 92 | |||
| 93 | impl VoltageScale { | ||
| 94 | const fn wait_states(&self, ahb_freq: Hertz) -> Option<Latency> { | ||
| 95 | let ahb_freq = ahb_freq.0; | ||
| 96 | // Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock | ||
| 97 | // frequency | ||
| 98 | match self { | ||
| 99 | VoltageScale::Range3 => { | ||
| 100 | if ahb_freq <= 16_000_000 { | ||
| 101 | Some(Latency::WS0) | ||
| 102 | } else if ahb_freq <= 32_000_000 { | ||
| 103 | Some(Latency::WS1) | ||
| 104 | } else if ahb_freq <= 48_000_000 { | ||
| 105 | Some(Latency::WS2) | ||
| 106 | } else if ahb_freq <= 64_000_000 { | ||
| 107 | Some(Latency::WS3) | ||
| 108 | } else if ahb_freq <= 80_000_000 { | ||
| 109 | Some(Latency::WS4) | ||
| 110 | } else if ahb_freq <= 96_000_000 { | ||
| 111 | Some(Latency::WS5) | ||
| 112 | } else if ahb_freq <= 112_000_000 { | ||
| 113 | Some(Latency::WS6) | ||
| 114 | } else if ahb_freq <= 120_000_000 { | ||
| 115 | Some(Latency::WS7) | ||
| 116 | } else { | ||
| 117 | None | ||
| 118 | } | ||
| 119 | } | ||
| 120 | VoltageScale::Range2 => { | ||
| 121 | if ahb_freq <= 18_000_000 { | ||
| 122 | Some(Latency::WS0) | ||
| 123 | } else if ahb_freq <= 36_000_000 { | ||
| 124 | Some(Latency::WS1) | ||
| 125 | } else if ahb_freq <= 54_000_000 { | ||
| 126 | Some(Latency::WS2) | ||
| 127 | } else if ahb_freq <= 72_000_000 { | ||
| 128 | Some(Latency::WS3) | ||
| 129 | } else if ahb_freq <= 90_000_000 { | ||
| 130 | Some(Latency::WS4) | ||
| 131 | } else if ahb_freq <= 108_000_000 { | ||
| 132 | Some(Latency::WS5) | ||
| 133 | } else if ahb_freq <= 120_000_000 { | ||
| 134 | Some(Latency::WS6) | ||
| 135 | } else { | ||
| 136 | None | ||
| 137 | } | ||
| 138 | } | ||
| 139 | VoltageScale::Range1 => { | ||
| 140 | if ahb_freq <= 24_000_000 { | ||
| 141 | Some(Latency::WS0) | ||
| 142 | } else if ahb_freq <= 48_000_000 { | ||
| 143 | Some(Latency::WS1) | ||
| 144 | } else if ahb_freq <= 72_000_000 { | ||
| 145 | Some(Latency::WS2) | ||
| 146 | } else if ahb_freq <= 96_000_000 { | ||
| 147 | Some(Latency::WS3) | ||
| 148 | } else if ahb_freq <= 120_000_000 { | ||
| 149 | Some(Latency::WS4) | ||
| 150 | } else { | ||
| 151 | None | ||
| 152 | } | ||
| 153 | } | ||
| 154 | VoltageScale::Range0 => { | ||
| 155 | if ahb_freq <= 30_000_000 { | ||
| 156 | Some(Latency::WS0) | ||
| 157 | } else if ahb_freq <= 60_000_000 { | ||
| 158 | Some(Latency::WS1) | ||
| 159 | } else if ahb_freq <= 90_000_000 { | ||
| 160 | Some(Latency::WS2) | ||
| 161 | } else if ahb_freq <= 120_000_000 { | ||
| 162 | Some(Latency::WS3) | ||
| 163 | } else { | ||
| 164 | None | ||
| 165 | } | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | /// Clocks configuration | ||
| 172 | pub struct Config { | ||
| 173 | pub hse: Option<HSEConfig>, | ||
| 174 | pub hsi: bool, | ||
| 175 | pub pll_mux: PllSource, | ||
| 176 | pub pll: Pll, | ||
| 177 | pub mux: ClockSrc, | ||
| 178 | pub voltage: VoltageScale, | ||
| 179 | pub ahb_pre: AHBPrescaler, | ||
| 180 | pub apb1_pre: APBPrescaler, | ||
| 181 | pub apb2_pre: APBPrescaler, | ||
| 182 | pub ls: super::LsConfig, | ||
| 183 | } | ||
| 184 | |||
| 185 | impl Default for Config { | ||
| 186 | #[inline] | ||
| 187 | fn default() -> Config { | ||
| 188 | Config { | ||
| 189 | hse: None, | ||
| 190 | hsi: true, | ||
| 191 | pll_mux: PllSource::HSI, | ||
| 192 | pll: Pll::default(), | ||
| 193 | voltage: VoltageScale::Range3, | ||
| 194 | mux: ClockSrc::HSI, | ||
| 195 | ahb_pre: AHBPrescaler::DIV1, | ||
| 196 | apb1_pre: APBPrescaler::DIV1, | ||
| 197 | apb2_pre: APBPrescaler::DIV1, | ||
| 198 | ls: Default::default(), | ||
| 199 | } | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | pub(crate) unsafe fn init(config: Config) { | ||
| 204 | // Make sure HSI is enabled | ||
| 205 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 206 | while !RCC.cr().read().hsirdy() {} | ||
| 207 | |||
| 208 | if let Some(hse_config) = config.hse { | ||
| 209 | RCC.cr().modify(|w| { | ||
| 210 | w.set_hsebyp(match hse_config.source { | ||
| 211 | HSESrc::Bypass => true, | ||
| 212 | HSESrc::Crystal => false, | ||
| 213 | }); | ||
| 214 | w.set_hseon(true) | ||
| 215 | }); | ||
| 216 | while !RCC.cr().read().hserdy() {} | ||
| 217 | } | ||
| 218 | |||
| 219 | let pll_src_freq = match config.pll_mux { | ||
| 220 | PllSource::HSE => { | ||
| 221 | let hse_config = config | ||
| 222 | .hse | ||
| 223 | .unwrap_or_else(|| panic!("HSE must be configured to be used as PLL input")); | ||
| 224 | hse_config.frequency | ||
| 225 | } | ||
| 226 | PllSource::HSI => HSI_FREQ, | ||
| 227 | }; | ||
| 228 | |||
| 229 | // Reference: STM32F215xx/217xx datasheet Table 33. Main PLL characteristics | ||
| 230 | let pll_clocks = config.pll.clocks(pll_src_freq); | ||
| 231 | assert!(Hertz(950_000) <= pll_clocks.in_freq && pll_clocks.in_freq <= Hertz(2_100_000)); | ||
| 232 | assert!(Hertz(192_000_000) <= pll_clocks.vco_freq && pll_clocks.vco_freq <= Hertz(432_000_000)); | ||
| 233 | assert!(Hertz(24_000_000) <= pll_clocks.main_freq && pll_clocks.main_freq <= Hertz(120_000_000)); | ||
| 234 | // USB actually requires == 48 MHz, but other PLL48 peripherals are fine with <= 48MHz | ||
| 235 | assert!(pll_clocks.pll48_freq <= Hertz(48_000_000)); | ||
| 236 | |||
| 237 | RCC.pllcfgr().write(|w| { | ||
| 238 | w.set_pllsrc(config.pll_mux); | ||
| 239 | w.set_pllm(config.pll.pre_div); | ||
| 240 | w.set_plln(config.pll.mul); | ||
| 241 | w.set_pllp(config.pll.divp); | ||
| 242 | w.set_pllq(config.pll.divq); | ||
| 243 | }); | ||
| 244 | |||
| 245 | let (sys_clk, sw) = match config.mux { | ||
| 246 | ClockSrc::HSI => { | ||
| 247 | assert!(config.hsi, "HSI must be enabled to be used as system clock"); | ||
| 248 | (HSI_FREQ, Sw::HSI) | ||
| 249 | } | ||
| 250 | ClockSrc::HSE => { | ||
| 251 | let hse_config = config | ||
| 252 | .hse | ||
| 253 | .unwrap_or_else(|| panic!("HSE must be configured to be used as PLL input")); | ||
| 254 | (hse_config.frequency, Sw::HSE) | ||
| 255 | } | ||
| 256 | ClockSrc::PLL => { | ||
| 257 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 258 | while !RCC.cr().read().pllrdy() {} | ||
| 259 | (pll_clocks.main_freq, Sw::PLL1_P) | ||
| 260 | } | ||
| 261 | }; | ||
| 262 | // RM0033 Figure 9. Clock tree suggests max SYSCLK/HCLK is 168 MHz, but datasheet specifies PLL | ||
| 263 | // max output to be 120 MHz, so there's no way to get higher frequencies | ||
| 264 | assert!(sys_clk <= Hertz(120_000_000)); | ||
| 265 | |||
| 266 | let ahb_freq = sys_clk / config.ahb_pre; | ||
| 267 | // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions | ||
| 268 | assert!(ahb_freq <= Hertz(120_000_000)); | ||
| 269 | |||
| 270 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | ||
| 271 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 272 | pre => { | ||
| 273 | let freq = ahb_freq / pre; | ||
| 274 | (freq, Hertz(freq.0 * 2)) | ||
| 275 | } | ||
| 276 | }; | ||
| 277 | // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions | ||
| 278 | assert!(apb1_freq <= Hertz(30_000_000)); | ||
| 279 | |||
| 280 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 281 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 282 | pre => { | ||
| 283 | let freq = ahb_freq / pre; | ||
| 284 | (freq, Hertz(freq.0 * 2)) | ||
| 285 | } | ||
| 286 | }; | ||
| 287 | // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions | ||
| 288 | assert!(apb2_freq <= Hertz(60_000_000)); | ||
| 289 | |||
| 290 | let flash_ws = unwrap!(config.voltage.wait_states(ahb_freq)); | ||
| 291 | FLASH.acr().modify(|w| w.set_latency(flash_ws)); | ||
| 292 | |||
| 293 | RCC.cfgr().modify(|w| { | ||
| 294 | w.set_sw(sw.into()); | ||
| 295 | w.set_hpre(config.ahb_pre); | ||
| 296 | w.set_ppre1(config.apb1_pre); | ||
| 297 | w.set_ppre2(config.apb2_pre); | ||
| 298 | }); | ||
| 299 | while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} | ||
| 300 | |||
| 301 | // Turn off HSI to save power if we don't need it | ||
| 302 | if !config.hsi { | ||
| 303 | RCC.cr().modify(|w| w.set_hsion(false)); | ||
| 304 | } | ||
| 305 | |||
| 306 | let rtc = config.ls.init(); | ||
| 307 | |||
| 308 | set_freqs(Clocks { | ||
| 309 | sys: sys_clk, | ||
| 310 | hclk1: ahb_freq, | ||
| 311 | hclk2: ahb_freq, | ||
| 312 | hclk3: ahb_freq, | ||
| 313 | pclk1: apb1_freq, | ||
| 314 | pclk1_tim: apb1_tim_freq, | ||
| 315 | pclk2: apb2_freq, | ||
| 316 | pclk2_tim: apb2_tim_freq, | ||
| 317 | pll1_q: Some(pll_clocks.pll48_freq), | ||
| 318 | rtc, | ||
| 319 | }); | ||
| 320 | } | ||
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; | |||
| 15 | pub use hsi48::*; | 15 | pub use hsi48::*; |
| 16 | 16 | ||
| 17 | #[cfg_attr(rcc_f0, path = "f0.rs")] | 17 | #[cfg_attr(rcc_f0, path = "f0.rs")] |
| 18 | #[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] | 18 | #[cfg_attr(any(stm32f1), path = "f1.rs")] |
| 19 | #[cfg_attr(rcc_f2, path = "f2.rs")] | 19 | #[cfg_attr(any(stm32f3), path = "f3.rs")] |
| 20 | #[cfg_attr(any(rcc_f3, rcc_f3_v2), path = "f3.rs")] | 20 | #[cfg_attr(any(stm32f2, stm32f4, stm32f7), path = "f.rs")] |
| 21 | #[cfg_attr(any(rcc_f4, rcc_f410, rcc_f7), path = "f4f7.rs")] | ||
| 22 | #[cfg_attr(rcc_c0, path = "c0.rs")] | 21 | #[cfg_attr(rcc_c0, path = "c0.rs")] |
| 23 | #[cfg_attr(rcc_g0, path = "g0.rs")] | 22 | #[cfg_attr(rcc_g0, path = "g0.rs")] |
| 24 | #[cfg_attr(rcc_g4, path = "g4.rs")] | 23 | #[cfg_attr(rcc_g4, path = "g4.rs")] |
| 25 | #[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")] | 24 | #[cfg_attr(any(stm32h5, stm32h7), path = "h.rs")] |
| 26 | #[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl), path = "l.rs")] | 25 | #[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl), path = "l.rs")] |
| 27 | #[cfg_attr(rcc_u5, path = "u5.rs")] | 26 | #[cfg_attr(rcc_u5, path = "u5.rs")] |
| 28 | #[cfg_attr(rcc_wba, path = "wba.rs")] | 27 | #[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; | |||
| 6 | 6 | ||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::rcc::{ | ||
| 10 | APBPrescaler, ClockSrc, HSEConfig, HSESrc, Pll, PllMul, PllPDiv, PllPreDiv, PllQDiv, PllSource, | ||
| 11 | }; | ||
| 12 | use embassy_stm32::time::Hertz; | 9 | use embassy_stm32::time::Hertz; |
| 13 | use embassy_stm32::Config; | 10 | use embassy_stm32::Config; |
| 14 | use embassy_time::Timer; | 11 | use embassy_time::Timer; |
| @@ -19,29 +16,35 @@ async fn main(_spawner: Spawner) { | |||
| 19 | // Example config for maximum performance on a NUCLEO-F207ZG board | 16 | // Example config for maximum performance on a NUCLEO-F207ZG board |
| 20 | 17 | ||
| 21 | let mut config = Config::default(); | 18 | let mut config = Config::default(); |
| 22 | // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) | 19 | |
| 23 | config.rcc.hse = Some(HSEConfig { | 20 | { |
| 24 | frequency: Hertz(8_000_000), | 21 | use embassy_stm32::rcc::*; |
| 25 | source: HSESrc::Bypass, | 22 | |
| 26 | }); | 23 | // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) |
| 27 | // PLL uses HSE as the clock source | 24 | config.rcc.hse = Some(Hse { |
| 28 | config.rcc.pll_mux = PllSource::HSE; | 25 | freq: Hertz(8_000_000), |
| 29 | config.rcc.pll = Pll { | 26 | mode: HseMode::Bypass, |
| 30 | // 8 MHz clock source / 8 = 1 MHz PLL input | 27 | }); |
| 31 | pre_div: unwrap!(PllPreDiv::try_from(8)), | 28 | // PLL uses HSE as the clock source |
| 32 | // 1 MHz PLL input * 240 = 240 MHz PLL VCO | 29 | config.rcc.pll_src = PllSource::HSE; |
| 33 | mul: unwrap!(PllMul::try_from(240)), | 30 | config.rcc.pll = Some(Pll { |
| 34 | // 240 MHz PLL VCO / 2 = 120 MHz main PLL output | 31 | // 8 MHz clock source / 8 = 1 MHz PLL input |
| 35 | divp: PllPDiv::DIV2, | 32 | prediv: unwrap!(PllPreDiv::try_from(8)), |
| 36 | // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output | 33 | // 1 MHz PLL input * 240 = 240 MHz PLL VCO |
| 37 | divq: PllQDiv::DIV5, | 34 | mul: unwrap!(PllMul::try_from(240)), |
| 38 | }; | 35 | // 240 MHz PLL VCO / 2 = 120 MHz main PLL output |
| 39 | // System clock comes from PLL (= the 120 MHz main PLL output) | 36 | divp: Some(PllPDiv::DIV2), |
| 40 | config.rcc.mux = ClockSrc::PLL; | 37 | // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output |
| 41 | // 120 MHz / 4 = 30 MHz APB1 frequency | 38 | divq: Some(PllQDiv::DIV5), |
| 42 | config.rcc.apb1_pre = APBPrescaler::DIV4; | 39 | divr: None, |
| 43 | // 120 MHz / 2 = 60 MHz APB2 frequency | 40 | }); |
| 44 | config.rcc.apb2_pre = APBPrescaler::DIV2; | 41 | // System clock comes from PLL (= the 120 MHz main PLL output) |
| 42 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 43 | // 120 MHz / 4 = 30 MHz APB1 frequency | ||
| 44 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 45 | // 120 MHz / 2 = 60 MHz APB2 frequency | ||
| 46 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 47 | } | ||
| 45 | 48 | ||
| 46 | let _p = embassy_stm32::init(config); | 49 | let _p = embassy_stm32::init(config); |
| 47 | 50 | ||
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) -> ! { | |||
| 42 | config.rcc.pll = Some(Pll { | 42 | config.rcc.pll = Some(Pll { |
| 43 | prediv: PllPreDiv::DIV4, | 43 | prediv: PllPreDiv::DIV4, |
| 44 | mul: PllMul::MUL180, | 44 | mul: PllMul::MUL180, |
| 45 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. | 45 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. |
| 46 | divq: None, | 46 | divq: None, |
| 47 | divr: None, | 47 | divr: None, |
| 48 | }); | 48 | }); |
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) { | |||
| 30 | config.rcc.pll = Some(Pll { | 30 | config.rcc.pll = Some(Pll { |
| 31 | prediv: PllPreDiv::DIV4, | 31 | prediv: PllPreDiv::DIV4, |
| 32 | mul: PllMul::MUL168, | 32 | mul: PllMul::MUL168, |
| 33 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. | 33 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. |
| 34 | divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. | 34 | divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. |
| 35 | divr: None, | 35 | divr: None, |
| 36 | }); | 36 | }); |
| 37 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | 37 | 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) { | |||
| 56 | config.rcc.pll = Some(Pll { | 56 | config.rcc.pll = Some(Pll { |
| 57 | prediv: PllPreDiv::DIV4, | 57 | prediv: PllPreDiv::DIV4, |
| 58 | mul: PllMul::MUL168, | 58 | mul: PllMul::MUL168, |
| 59 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. | 59 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. |
| 60 | divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. | 60 | divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. |
| 61 | divr: None, | 61 | divr: None, |
| 62 | }); | 62 | }); |
| 63 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | 63 | 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) { | |||
| 85 | config.rcc.pll = Some(Pll { | 85 | config.rcc.pll = Some(Pll { |
| 86 | prediv: PllPreDiv::DIV4, | 86 | prediv: PllPreDiv::DIV4, |
| 87 | mul: PllMul::MUL168, | 87 | mul: PllMul::MUL168, |
| 88 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. | 88 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. |
| 89 | divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. | 89 | divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. |
| 90 | divr: None, | 90 | divr: None, |
| 91 | }); | 91 | }); |
| 92 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | 92 | 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) { | |||
| 32 | config.rcc.pll = Some(Pll { | 32 | config.rcc.pll = Some(Pll { |
| 33 | prediv: PllPreDiv::DIV4, | 33 | prediv: PllPreDiv::DIV4, |
| 34 | mul: PllMul::MUL168, | 34 | mul: PllMul::MUL168, |
| 35 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. | 35 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. |
| 36 | divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. | 36 | divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. |
| 37 | divr: None, | 37 | divr: None, |
| 38 | }); | 38 | }); |
| 39 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | 39 | 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) -> ! { | |||
| 43 | config.rcc.pll = Some(Pll { | 43 | config.rcc.pll = Some(Pll { |
| 44 | prediv: PllPreDiv::DIV4, | 44 | prediv: PllPreDiv::DIV4, |
| 45 | mul: PllMul::MUL216, | 45 | mul: PllMul::MUL216, |
| 46 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz | 46 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz |
| 47 | divq: None, | 47 | divq: None, |
| 48 | divr: None, | 48 | divr: None, |
| 49 | }); | 49 | }); |
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) { | |||
| 26 | config.rcc.pll = Some(Pll { | 26 | config.rcc.pll = Some(Pll { |
| 27 | prediv: PllPreDiv::DIV4, | 27 | prediv: PllPreDiv::DIV4, |
| 28 | mul: PllMul::MUL216, | 28 | mul: PllMul::MUL216, |
| 29 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz | 29 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz |
| 30 | divq: Some(Pllq::DIV9), // 8mhz / 4 * 216 / 9 = 48Mhz | 30 | divq: Some(PllQDiv::DIV9), // 8mhz / 4 * 216 / 9 = 48Mhz |
| 31 | divr: None, | 31 | divr: None, |
| 32 | }); | 32 | }); |
| 33 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | 33 | 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) { | |||
| 32 | config.rcc.pll = Some(Pll { | 32 | config.rcc.pll = Some(Pll { |
| 33 | prediv: PllPreDiv::DIV4, | 33 | prediv: PllPreDiv::DIV4, |
| 34 | mul: PllMul::MUL216, | 34 | mul: PllMul::MUL216, |
| 35 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz | 35 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz |
| 36 | divq: Some(Pllq::DIV9), // 8mhz / 4 * 216 / 9 = 48Mhz | 36 | divq: Some(PllQDiv::DIV9), // 8mhz / 4 * 216 / 9 = 48Mhz |
| 37 | divr: None, | 37 | divr: None, |
| 38 | }); | 38 | }); |
| 39 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | 39 | config.rcc.ahb_pre = AHBPrescaler::DIV1; |
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index e7367d5ed..a44e8230f 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs | |||
| @@ -236,24 +236,25 @@ pub fn config() -> Config { | |||
| 236 | { | 236 | { |
| 237 | use embassy_stm32::rcc::*; | 237 | use embassy_stm32::rcc::*; |
| 238 | // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) | 238 | // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) |
| 239 | config.rcc.hse = Some(HSEConfig { | 239 | config.rcc.hse = Some(Hse { |
| 240 | frequency: Hertz(8_000_000), | 240 | freq: Hertz(8_000_000), |
| 241 | source: HSESrc::Bypass, | 241 | mode: HseMode::Bypass, |
| 242 | }); | 242 | }); |
| 243 | // PLL uses HSE as the clock source | 243 | // PLL uses HSE as the clock source |
| 244 | config.rcc.pll_mux = PllSource::HSE; | 244 | config.rcc.pll_src = PllSource::HSE; |
| 245 | config.rcc.pll = Pll { | 245 | config.rcc.pll = Some(Pll { |
| 246 | // 8 MHz clock source / 8 = 1 MHz PLL input | 246 | // 8 MHz clock source / 8 = 1 MHz PLL input |
| 247 | pre_div: unwrap!(PllPreDiv::try_from(8)), | 247 | prediv: unwrap!(PllPreDiv::try_from(8)), |
| 248 | // 1 MHz PLL input * 240 = 240 MHz PLL VCO | 248 | // 1 MHz PLL input * 240 = 240 MHz PLL VCO |
| 249 | mul: unwrap!(PllMul::try_from(240)), | 249 | mul: unwrap!(PllMul::try_from(240)), |
| 250 | // 240 MHz PLL VCO / 2 = 120 MHz main PLL output | 250 | // 240 MHz PLL VCO / 2 = 120 MHz main PLL output |
| 251 | divp: PllPDiv::DIV2, | 251 | divp: Some(PllPDiv::DIV2), |
| 252 | // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output | 252 | // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output |
| 253 | divq: PllQDiv::DIV5, | 253 | divq: Some(PllQDiv::DIV5), |
| 254 | }; | 254 | divr: None, |
| 255 | }); | ||
| 255 | // System clock comes from PLL (= the 120 MHz main PLL output) | 256 | // System clock comes from PLL (= the 120 MHz main PLL output) |
| 256 | config.rcc.mux = ClockSrc::PLL; | 257 | config.rcc.sys = Sysclk::PLL1_P; |
| 257 | // 120 MHz / 4 = 30 MHz APB1 frequency | 258 | // 120 MHz / 4 = 30 MHz APB1 frequency |
| 258 | config.rcc.apb1_pre = APBPrescaler::DIV4; | 259 | config.rcc.apb1_pre = APBPrescaler::DIV4; |
| 259 | // 120 MHz / 2 = 60 MHz APB2 frequency | 260 | // 120 MHz / 2 = 60 MHz APB2 frequency |
| @@ -271,7 +272,7 @@ pub fn config() -> Config { | |||
| 271 | config.rcc.pll = Some(Pll { | 272 | config.rcc.pll = Some(Pll { |
| 272 | prediv: PllPreDiv::DIV4, | 273 | prediv: PllPreDiv::DIV4, |
| 273 | mul: PllMul::MUL180, | 274 | mul: PllMul::MUL180, |
| 274 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. | 275 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. |
| 275 | divq: None, | 276 | divq: None, |
| 276 | divr: None, | 277 | divr: None, |
| 277 | }); | 278 | }); |
| @@ -292,7 +293,7 @@ pub fn config() -> Config { | |||
| 292 | config.rcc.pll = Some(Pll { | 293 | config.rcc.pll = Some(Pll { |
| 293 | prediv: PllPreDiv::DIV4, | 294 | prediv: PllPreDiv::DIV4, |
| 294 | mul: PllMul::MUL216, | 295 | mul: PllMul::MUL216, |
| 295 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz. | 296 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz. |
| 296 | divq: None, | 297 | divq: None, |
| 297 | divr: None, | 298 | divr: None, |
| 298 | }); | 299 | }); |
