diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-10-16 03:47:54 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-10-16 04:00:51 +0200 |
| commit | 18e96898eab47840951305481cc669b8b221bdda (patch) | |
| tree | 2a7629edc797c850a69d66728f8a9e7d168c2d8d | |
| parent | 870dcc5970cbd043049e0ce2c9cde208c11a7d32 (diff) | |
stm32/rcc: unify L4 and L5.
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l4l5.rs (renamed from embassy-stm32/src/rcc/l4.rs) | 69 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l5.rs | 291 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 3 | ||||
| -rw-r--r-- | examples/stm32l5/src/bin/rng.rs | 20 | ||||
| -rw-r--r-- | examples/stm32l5/src/bin/usb_ethernet.rs | 13 | ||||
| -rw-r--r-- | examples/stm32l5/src/bin/usb_hid_mouse.rs | 13 | ||||
| -rw-r--r-- | examples/stm32l5/src/bin/usb_serial.rs | 13 | ||||
| -rw-r--r-- | tests/stm32/src/common.rs | 17 |
9 files changed, 97 insertions, 346 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 50ccd7934..1eff10707 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-73e3f8a965a01fd5a168c3543b93ce49d475e130" } | 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ecc410f93477d3d9314723ec26e637aa0c63b8f" } |
| 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-73e3f8a965a01fd5a168c3543b93ce49d475e130", default-features = false, features = ["metadata"]} | 79 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ecc410f93477d3d9314723ec26e637aa0c63b8f", default-features = false, features = ["metadata"]} |
| 80 | 80 | ||
| 81 | 81 | ||
| 82 | [features] | 82 | [features] |
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4l5.rs index aceafc490..1a8974ff6 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4l5.rs | |||
| @@ -42,9 +42,7 @@ pub struct Config { | |||
| 42 | // pll | 42 | // pll |
| 43 | pub pll: Option<Pll>, | 43 | pub pll: Option<Pll>, |
| 44 | pub pllsai1: Option<Pll>, | 44 | pub pllsai1: Option<Pll>, |
| 45 | #[cfg(any( | 45 | #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] |
| 46 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 47 | ))] | ||
| 48 | pub pllsai2: Option<Pll>, | 46 | pub pllsai2: Option<Pll>, |
| 49 | 47 | ||
| 50 | // sysclk, buses. | 48 | // sysclk, buses. |
| @@ -73,9 +71,7 @@ impl Default for Config { | |||
| 73 | apb2_pre: APBPrescaler::DIV1, | 71 | apb2_pre: APBPrescaler::DIV1, |
| 74 | pll: None, | 72 | pll: None, |
| 75 | pllsai1: None, | 73 | pllsai1: None, |
| 76 | #[cfg(any( | 74 | #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] |
| 77 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 78 | ))] | ||
| 79 | pllsai2: None, | 75 | pllsai2: None, |
| 80 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | 76 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] |
| 81 | hsi48: true, | 77 | hsi48: true, |
| @@ -106,6 +102,11 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 106 | while RCC.cfgr().read().sws() != ClockSrc::MSI {} | 102 | while RCC.cfgr().read().sws() != ClockSrc::MSI {} |
| 107 | } | 103 | } |
| 108 | 104 | ||
| 105 | #[cfg(stm32l5)] | ||
| 106 | crate::pac::PWR.cr1().modify(|w| { | ||
| 107 | w.set_vos(crate::pac::pwr::vals::Vos::RANGE0); | ||
| 108 | }); | ||
| 109 | |||
| 109 | let rtc = config.ls.init(); | 110 | let rtc = config.ls.init(); |
| 110 | 111 | ||
| 111 | let msi = config.msi.map(|range| { | 112 | let msi = config.msi.map(|range| { |
| @@ -153,14 +154,12 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 153 | let _plls = [ | 154 | let _plls = [ |
| 154 | &config.pll, | 155 | &config.pll, |
| 155 | &config.pllsai1, | 156 | &config.pllsai1, |
| 156 | #[cfg(any( | 157 | #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] |
| 157 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 158 | ))] | ||
| 159 | &config.pllsai2, | 158 | &config.pllsai2, |
| 160 | ]; | 159 | ]; |
| 161 | 160 | ||
| 162 | // L4 has shared PLLSRC, PLLM, check it's equal in all PLLs. | 161 | // L4 has shared PLLSRC, PLLM, check it's equal in all PLLs. |
| 163 | #[cfg(all(stm32l4, not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))))] | 162 | #[cfg(all(stm32l4, not(rcc_l4plus)))] |
| 164 | match get_equal(_plls.into_iter().flatten().map(|p| (p.source, p.prediv))) { | 163 | match get_equal(_plls.into_iter().flatten().map(|p| (p.source, p.prediv))) { |
| 165 | Err(()) => panic!("Source must be equal across all enabled PLLs."), | 164 | Err(()) => panic!("Source must be equal across all enabled PLLs."), |
| 166 | Ok(None) => {} | 165 | Ok(None) => {} |
| @@ -171,7 +170,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 171 | }; | 170 | }; |
| 172 | 171 | ||
| 173 | // L4+ has shared PLLSRC, check it's equal in all PLLs. | 172 | // L4+ has shared PLLSRC, check it's equal in all PLLs. |
| 174 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] | 173 | #[cfg(any(rcc_l4plus))] |
| 175 | match get_equal(_plls.into_iter().flatten().map(|p| p.source)) { | 174 | match get_equal(_plls.into_iter().flatten().map(|p| p.source)) { |
| 176 | Err(()) => panic!("Source must be equal across all enabled PLLs."), | 175 | Err(()) => panic!("Source must be equal across all enabled PLLs."), |
| 177 | Ok(None) => {} | 176 | Ok(None) => {} |
| @@ -183,9 +182,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 183 | let pll_input = PllInput { hse, hsi16, msi }; | 182 | let pll_input = PllInput { hse, hsi16, msi }; |
| 184 | let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); | 183 | let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); |
| 185 | let pllsai1 = init_pll(PllInstance::Pllsai1, config.pllsai1, &pll_input); | 184 | let pllsai1 = init_pll(PllInstance::Pllsai1, config.pllsai1, &pll_input); |
| 186 | #[cfg(any( | 185 | #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] |
| 187 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 188 | ))] | ||
| 189 | let _pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input); | 186 | let _pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input); |
| 190 | 187 | ||
| 191 | let sys_clk = match config.mux { | 188 | let sys_clk = match config.mux { |
| @@ -202,12 +199,13 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 202 | Clk48Src::PLL_Q => pll._q, | 199 | Clk48Src::PLL_Q => pll._q, |
| 203 | }; | 200 | }; |
| 204 | 201 | ||
| 205 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] | 202 | #[cfg(rcc_l4plus)] |
| 206 | assert!(sys_clk.0 <= 120_000_000); | 203 | assert!(sys_clk.0 <= 120_000_000); |
| 207 | #[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))] | 204 | #[cfg(all(stm32l4, not(rcc_l4plus)))] |
| 208 | assert!(sys_clk.0 <= 80_000_000); | 205 | assert!(sys_clk.0 <= 80_000_000); |
| 209 | 206 | ||
| 210 | // Set flash wait states | 207 | // Set flash wait states |
| 208 | #[cfg(stm32l4)] | ||
| 211 | FLASH.acr().modify(|w| { | 209 | FLASH.acr().modify(|w| { |
| 212 | w.set_latency(match sys_clk.0 { | 210 | w.set_latency(match sys_clk.0 { |
| 213 | 0..=16_000_000 => 0, | 211 | 0..=16_000_000 => 0, |
| @@ -217,6 +215,18 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 217 | _ => 4, | 215 | _ => 4, |
| 218 | }) | 216 | }) |
| 219 | }); | 217 | }); |
| 218 | // VCORE Range 0 (performance), others TODO | ||
| 219 | #[cfg(stm32l5)] | ||
| 220 | FLASH.acr().modify(|w| { | ||
| 221 | w.set_latency(match sys_clk.0 { | ||
| 222 | 0..=20_000_000 => 0, | ||
| 223 | 0..=40_000_000 => 1, | ||
| 224 | 0..=60_000_000 => 2, | ||
| 225 | 0..=80_000_000 => 3, | ||
| 226 | 0..=100_000_000 => 4, | ||
| 227 | _ => 5, | ||
| 228 | }) | ||
| 229 | }); | ||
| 220 | 230 | ||
| 221 | RCC.cfgr().modify(|w| { | 231 | RCC.cfgr().modify(|w| { |
| 222 | w.set_sw(config.mux); | 232 | w.set_sw(config.mux); |
| @@ -274,6 +284,7 @@ fn msirange_to_hertz(range: MSIRange) -> Hertz { | |||
| 274 | } | 284 | } |
| 275 | } | 285 | } |
| 276 | 286 | ||
| 287 | #[allow(unused)] | ||
| 277 | fn get_equal<T: Eq>(mut iter: impl Iterator<Item = T>) -> Result<Option<T>, ()> { | 288 | fn get_equal<T: Eq>(mut iter: impl Iterator<Item = T>) -> Result<Option<T>, ()> { |
| 278 | let Some(x) = iter.next() else { return Ok(None) }; | 289 | let Some(x) = iter.next() else { return Ok(None) }; |
| 279 | if !iter.all(|y| y == x) { | 290 | if !iter.all(|y| y == x) { |
| @@ -299,9 +310,7 @@ struct PllOutput { | |||
| 299 | enum PllInstance { | 310 | enum PllInstance { |
| 300 | Pll, | 311 | Pll, |
| 301 | Pllsai1, | 312 | Pllsai1, |
| 302 | #[cfg(any( | 313 | #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] |
| 303 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 304 | ))] | ||
| 305 | Pllsai2, | 314 | Pllsai2, |
| 306 | } | 315 | } |
| 307 | 316 | ||
| @@ -316,9 +325,7 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll | |||
| 316 | RCC.cr().modify(|w| w.set_pllsai1on(false)); | 325 | RCC.cr().modify(|w| w.set_pllsai1on(false)); |
| 317 | while RCC.cr().read().pllsai1rdy() {} | 326 | while RCC.cr().read().pllsai1rdy() {} |
| 318 | } | 327 | } |
| 319 | #[cfg(any( | 328 | #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] |
| 320 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 321 | ))] | ||
| 322 | PllInstance::Pllsai2 => { | 329 | PllInstance::Pllsai2 => { |
| 323 | RCC.cr().modify(|w| w.set_pllsai2on(false)); | 330 | RCC.cr().modify(|w| w.set_pllsai2on(false)); |
| 324 | while RCC.cr().read().pllsai2rdy() {} | 331 | while RCC.cr().read().pllsai2rdy() {} |
| @@ -342,6 +349,12 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll | |||
| 342 | let q = pll.divq.map(|div| vco_freq / div); | 349 | let q = pll.divq.map(|div| vco_freq / div); |
| 343 | let r = pll.divr.map(|div| vco_freq / div); | 350 | let r = pll.divr.map(|div| vco_freq / div); |
| 344 | 351 | ||
| 352 | #[cfg(stm32l5)] | ||
| 353 | if instance == PllInstance::Pllsai2 { | ||
| 354 | assert!(q.is_none(), "PLLSAI2_Q is not available on L5"); | ||
| 355 | assert!(r.is_none(), "PLLSAI2_R is not available on L5"); | ||
| 356 | } | ||
| 357 | |||
| 345 | macro_rules! write_fields { | 358 | macro_rules! write_fields { |
| 346 | ($w:ident) => { | 359 | ($w:ident) => { |
| 347 | $w.set_plln(pll.mul); | 360 | $w.set_plln(pll.mul); |
| @@ -367,17 +380,15 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll | |||
| 367 | write_fields!(w); | 380 | write_fields!(w); |
| 368 | }), | 381 | }), |
| 369 | PllInstance::Pllsai1 => RCC.pllsai1cfgr().write(|w| { | 382 | PllInstance::Pllsai1 => RCC.pllsai1cfgr().write(|w| { |
| 370 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx, stm32l5))] | 383 | #[cfg(any(rcc_l4plus, stm32l5))] |
| 371 | w.set_pllm(pll.prediv); | 384 | w.set_pllm(pll.prediv); |
| 372 | #[cfg(stm32l5)] | 385 | #[cfg(stm32l5)] |
| 373 | w.set_pllsrc(pll.source); | 386 | w.set_pllsrc(pll.source); |
| 374 | write_fields!(w); | 387 | write_fields!(w); |
| 375 | }), | 388 | }), |
| 376 | #[cfg(any( | 389 | #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] |
| 377 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 378 | ))] | ||
| 379 | PllInstance::Pllsai2 => RCC.pllsai2cfgr().write(|w| { | 390 | PllInstance::Pllsai2 => RCC.pllsai2cfgr().write(|w| { |
| 380 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx, stm32l5))] | 391 | #[cfg(any(rcc_l4plus, stm32l5))] |
| 381 | w.set_pllm(pll.prediv); | 392 | w.set_pllm(pll.prediv); |
| 382 | #[cfg(stm32l5)] | 393 | #[cfg(stm32l5)] |
| 383 | w.set_pllsrc(pll.source); | 394 | w.set_pllsrc(pll.source); |
| @@ -395,9 +406,7 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll | |||
| 395 | RCC.cr().modify(|w| w.set_pllsai1on(true)); | 406 | RCC.cr().modify(|w| w.set_pllsai1on(true)); |
| 396 | while !RCC.cr().read().pllsai1rdy() {} | 407 | while !RCC.cr().read().pllsai1rdy() {} |
| 397 | } | 408 | } |
| 398 | #[cfg(any( | 409 | #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] |
| 399 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 400 | ))] | ||
| 401 | PllInstance::Pllsai2 => { | 410 | PllInstance::Pllsai2 => { |
| 402 | RCC.cr().modify(|w| w.set_pllsai2on(true)); | 411 | RCC.cr().modify(|w| w.set_pllsai2on(true)); |
| 403 | while !RCC.cr().read().pllsai2rdy() {} | 412 | while !RCC.cr().read().pllsai2rdy() {} |
diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs deleted file mode 100644 index 7e095a6b2..000000000 --- a/embassy-stm32/src/rcc/l5.rs +++ /dev/null | |||
| @@ -1,291 +0,0 @@ | |||
| 1 | use crate::pac::rcc::regs::Cfgr; | ||
| 2 | pub use crate::pac::rcc::vals::{ | ||
| 3 | Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, | ||
| 4 | Pllr as PllRDiv, Ppre as APBPrescaler, | ||
| 5 | }; | ||
| 6 | use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw}; | ||
| 7 | use crate::pac::{FLASH, PWR, 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 | /// System clock mux source | ||
| 15 | #[derive(Clone, Copy)] | ||
| 16 | pub enum ClockSrc { | ||
| 17 | MSI(MSIRange), | ||
| 18 | PLL(PLLSource, PllRDiv, PllPreDiv, PllMul, Option<PllQDiv>), | ||
| 19 | HSE(Hertz), | ||
| 20 | HSI16, | ||
| 21 | } | ||
| 22 | |||
| 23 | /// PLL clock input source | ||
| 24 | #[derive(Clone, Copy)] | ||
| 25 | pub enum PLLSource { | ||
| 26 | HSI16, | ||
| 27 | HSE(Hertz), | ||
| 28 | MSI(MSIRange), | ||
| 29 | } | ||
| 30 | |||
| 31 | impl From<PLLSource> for Pllsrc { | ||
| 32 | fn from(val: PLLSource) -> Pllsrc { | ||
| 33 | match val { | ||
| 34 | PLLSource::HSI16 => Pllsrc::HSI16, | ||
| 35 | PLLSource::HSE(_) => Pllsrc::HSE, | ||
| 36 | PLLSource::MSI(_) => Pllsrc::MSI, | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | /// Clocks configutation | ||
| 42 | pub struct Config { | ||
| 43 | pub mux: ClockSrc, | ||
| 44 | pub ahb_pre: AHBPrescaler, | ||
| 45 | pub apb1_pre: APBPrescaler, | ||
| 46 | pub apb2_pre: APBPrescaler, | ||
| 47 | pub pllsai1: Option<(PllMul, PllPreDiv, Option<PllRDiv>, Option<PllQDiv>, Option<PllPDiv>)>, | ||
| 48 | pub hsi48: bool, | ||
| 49 | pub ls: super::LsConfig, | ||
| 50 | } | ||
| 51 | |||
| 52 | impl Default for Config { | ||
| 53 | #[inline] | ||
| 54 | fn default() -> Config { | ||
| 55 | Config { | ||
| 56 | mux: ClockSrc::MSI(MSIRange::RANGE4M), | ||
| 57 | ahb_pre: AHBPrescaler::DIV1, | ||
| 58 | apb1_pre: APBPrescaler::DIV1, | ||
| 59 | apb2_pre: APBPrescaler::DIV1, | ||
| 60 | pllsai1: None, | ||
| 61 | hsi48: false, | ||
| 62 | ls: Default::default(), | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | pub(crate) unsafe fn init(config: Config) { | ||
| 68 | // Switch to MSI to prevent problems with PLL configuration. | ||
| 69 | if !RCC.cr().read().msion() { | ||
| 70 | // Turn on MSI and configure it to 4MHz. | ||
| 71 | RCC.cr().modify(|w| { | ||
| 72 | w.set_msirgsel(true); // MSI Range is provided by MSIRANGE[3:0]. | ||
| 73 | w.set_msirange(MSIRange::RANGE4M); | ||
| 74 | w.set_msipllen(false); | ||
| 75 | w.set_msion(true) | ||
| 76 | }); | ||
| 77 | |||
| 78 | // Wait until MSI is running | ||
| 79 | while !RCC.cr().read().msirdy() {} | ||
| 80 | } | ||
| 81 | if RCC.cfgr().read().sws() != Sw::MSI { | ||
| 82 | // Set MSI as a clock source, reset prescalers. | ||
| 83 | RCC.cfgr().write_value(Cfgr::default()); | ||
| 84 | // Wait for clock switch status bits to change. | ||
| 85 | while RCC.cfgr().read().sws() != Sw::MSI {} | ||
| 86 | } | ||
| 87 | |||
| 88 | let rtc = config.ls.init(); | ||
| 89 | |||
| 90 | PWR.cr1().modify(|w| w.set_vos(stm32_metapac::pwr::vals::Vos::RANGE0)); | ||
| 91 | let (sys_clk, sw) = match config.mux { | ||
| 92 | ClockSrc::MSI(range) => { | ||
| 93 | // Enable MSI | ||
| 94 | RCC.cr().write(|w| { | ||
| 95 | w.set_msirange(range); | ||
| 96 | w.set_msirgsel(true); | ||
| 97 | w.set_msion(true); | ||
| 98 | |||
| 99 | // If LSE is enabled, enable calibration of MSI | ||
| 100 | w.set_msipllen(config.ls.lse.is_some()); | ||
| 101 | }); | ||
| 102 | while !RCC.cr().read().msirdy() {} | ||
| 103 | |||
| 104 | // Enable as clock source for USB, RNG if running at 48 MHz | ||
| 105 | if range == MSIRange::RANGE48M { | ||
| 106 | RCC.ccipr1().modify(|w| { | ||
| 107 | w.set_clk48sel(0b11); | ||
| 108 | }); | ||
| 109 | } | ||
| 110 | (msirange_to_hertz(range), Sw::MSI) | ||
| 111 | } | ||
| 112 | ClockSrc::HSI16 => { | ||
| 113 | // Enable HSI16 | ||
| 114 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 115 | while !RCC.cr().read().hsirdy() {} | ||
| 116 | |||
| 117 | (HSI_FREQ, Sw::HSI16) | ||
| 118 | } | ||
| 119 | ClockSrc::HSE(freq) => { | ||
| 120 | // Enable HSE | ||
| 121 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 122 | while !RCC.cr().read().hserdy() {} | ||
| 123 | |||
| 124 | (freq, Sw::HSE) | ||
| 125 | } | ||
| 126 | ClockSrc::PLL(src, divr, prediv, mul, divq) => { | ||
| 127 | let src_freq = match src { | ||
| 128 | PLLSource::HSE(freq) => { | ||
| 129 | // Enable HSE | ||
| 130 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 131 | while !RCC.cr().read().hserdy() {} | ||
| 132 | freq | ||
| 133 | } | ||
| 134 | PLLSource::HSI16 => { | ||
| 135 | // Enable HSI | ||
| 136 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 137 | while !RCC.cr().read().hsirdy() {} | ||
| 138 | HSI_FREQ | ||
| 139 | } | ||
| 140 | PLLSource::MSI(range) => { | ||
| 141 | // Enable MSI | ||
| 142 | RCC.cr().write(|w| { | ||
| 143 | w.set_msirange(range); | ||
| 144 | w.set_msipllen(false); // should be turned on if LSE is started | ||
| 145 | w.set_msirgsel(true); | ||
| 146 | w.set_msion(true); | ||
| 147 | }); | ||
| 148 | while !RCC.cr().read().msirdy() {} | ||
| 149 | |||
| 150 | msirange_to_hertz(range) | ||
| 151 | } | ||
| 152 | }; | ||
| 153 | |||
| 154 | // Disable PLL | ||
| 155 | RCC.cr().modify(|w| w.set_pllon(false)); | ||
| 156 | while RCC.cr().read().pllrdy() {} | ||
| 157 | |||
| 158 | let freq = src_freq / prediv * mul / divr; | ||
| 159 | |||
| 160 | RCC.pllcfgr().write(move |w| { | ||
| 161 | w.set_plln(mul); | ||
| 162 | w.set_pllm(prediv); | ||
| 163 | w.set_pllr(divr); | ||
| 164 | if let Some(divq) = divq { | ||
| 165 | w.set_pllq(divq); | ||
| 166 | w.set_pllqen(true); | ||
| 167 | } | ||
| 168 | w.set_pllsrc(src.into()); | ||
| 169 | }); | ||
| 170 | |||
| 171 | // Enable as clock source for USB, RNG if PLL48 divisor is provided | ||
| 172 | if let Some(divq) = divq { | ||
| 173 | let freq = src_freq / prediv * mul / divq; | ||
| 174 | assert!(freq.0 == 48_000_000); | ||
| 175 | RCC.ccipr1().modify(|w| { | ||
| 176 | w.set_clk48sel(0b10); | ||
| 177 | }); | ||
| 178 | } | ||
| 179 | |||
| 180 | if let Some((mul, prediv, r_div, q_div, p_div)) = config.pllsai1 { | ||
| 181 | RCC.pllsai1cfgr().write(move |w| { | ||
| 182 | w.set_plln(mul); | ||
| 183 | w.set_pllm(prediv); | ||
| 184 | if let Some(r_div) = r_div { | ||
| 185 | w.set_pllr(r_div); | ||
| 186 | w.set_pllren(true); | ||
| 187 | } | ||
| 188 | if let Some(q_div) = q_div { | ||
| 189 | w.set_pllq(q_div); | ||
| 190 | w.set_pllqen(true); | ||
| 191 | let freq = src_freq / prediv * mul / q_div; | ||
| 192 | if freq.0 == 48_000_000 { | ||
| 193 | RCC.ccipr1().modify(|w| { | ||
| 194 | w.set_clk48sel(0b1); | ||
| 195 | }); | ||
| 196 | } | ||
| 197 | } | ||
| 198 | if let Some(p_div) = p_div { | ||
| 199 | w.set_pllp(p_div); | ||
| 200 | w.set_pllpen(true); | ||
| 201 | } | ||
| 202 | }); | ||
| 203 | |||
| 204 | RCC.cr().modify(|w| w.set_pllsai1on(true)); | ||
| 205 | } | ||
| 206 | |||
| 207 | // Enable PLL | ||
| 208 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 209 | while !RCC.cr().read().pllrdy() {} | ||
| 210 | RCC.pllcfgr().modify(|w| w.set_pllren(true)); | ||
| 211 | |||
| 212 | (freq, Sw::PLL) | ||
| 213 | } | ||
| 214 | }; | ||
| 215 | |||
| 216 | if config.hsi48 { | ||
| 217 | RCC.crrcr().modify(|w| w.set_hsi48on(true)); | ||
| 218 | while !RCC.crrcr().read().hsi48rdy() {} | ||
| 219 | |||
| 220 | // Enable as clock source for USB, RNG and SDMMC | ||
| 221 | RCC.ccipr1().modify(|w| w.set_clk48sel(0)); | ||
| 222 | } | ||
| 223 | |||
| 224 | // Set flash wait states | ||
| 225 | // VCORE Range 0 (performance), others TODO | ||
| 226 | FLASH.acr().modify(|w| { | ||
| 227 | w.set_latency(match sys_clk.0 { | ||
| 228 | 0..=20_000_000 => 0, | ||
| 229 | 0..=40_000_000 => 1, | ||
| 230 | 0..=60_000_000 => 2, | ||
| 231 | 0..=80_000_000 => 3, | ||
| 232 | 0..=100_000_000 => 4, | ||
| 233 | _ => 5, | ||
| 234 | }) | ||
| 235 | }); | ||
| 236 | |||
| 237 | RCC.cfgr().modify(|w| { | ||
| 238 | w.set_sw(sw); | ||
| 239 | w.set_hpre(config.ahb_pre); | ||
| 240 | w.set_ppre1(config.apb1_pre); | ||
| 241 | w.set_ppre2(config.apb2_pre); | ||
| 242 | }); | ||
| 243 | |||
| 244 | let ahb_freq = sys_clk / config.ahb_pre; | ||
| 245 | |||
| 246 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | ||
| 247 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 248 | pre => { | ||
| 249 | let freq = ahb_freq / pre; | ||
| 250 | (freq, freq * 2u32) | ||
| 251 | } | ||
| 252 | }; | ||
| 253 | |||
| 254 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 255 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 256 | pre => { | ||
| 257 | let freq = ahb_freq / pre; | ||
| 258 | (freq, freq * 2u32) | ||
| 259 | } | ||
| 260 | }; | ||
| 261 | |||
| 262 | set_freqs(Clocks { | ||
| 263 | sys: sys_clk, | ||
| 264 | hclk1: ahb_freq, | ||
| 265 | hclk2: ahb_freq, | ||
| 266 | hclk3: ahb_freq, | ||
| 267 | pclk1: apb1_freq, | ||
| 268 | pclk2: apb2_freq, | ||
| 269 | pclk1_tim: apb1_tim_freq, | ||
| 270 | pclk2_tim: apb2_tim_freq, | ||
| 271 | rtc, | ||
| 272 | }); | ||
| 273 | } | ||
| 274 | |||
| 275 | fn msirange_to_hertz(range: Msirange) -> Hertz { | ||
| 276 | match range { | ||
| 277 | MSIRange::RANGE100K => Hertz(100_000), | ||
| 278 | MSIRange::RANGE200K => Hertz(200_000), | ||
| 279 | MSIRange::RANGE400K => Hertz(400_000), | ||
| 280 | MSIRange::RANGE800K => Hertz(800_000), | ||
| 281 | MSIRange::RANGE1M => Hertz(1_000_000), | ||
| 282 | MSIRange::RANGE2M => Hertz(2_000_000), | ||
| 283 | MSIRange::RANGE4M => Hertz(4_000_000), | ||
| 284 | MSIRange::RANGE8M => Hertz(8_000_000), | ||
| 285 | MSIRange::RANGE16M => Hertz(16_000_000), | ||
| 286 | MSIRange::RANGE24M => Hertz(24_000_000), | ||
| 287 | MSIRange::RANGE32M => Hertz(32_000_000), | ||
| 288 | MSIRange::RANGE48M => Hertz(48_000_000), | ||
| 289 | _ => unreachable!(), | ||
| 290 | } | ||
| 291 | } | ||
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 76c9f34b0..8df6deaae 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -20,8 +20,7 @@ pub use mco::*; | |||
| 20 | #[cfg_attr(rcc_g4, path = "g4.rs")] | 20 | #[cfg_attr(rcc_g4, path = "g4.rs")] |
| 21 | #[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")] | 21 | #[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")] |
| 22 | #[cfg_attr(any(rcc_l0, rcc_l0_v2, rcc_l1), path = "l0l1.rs")] | 22 | #[cfg_attr(any(rcc_l0, rcc_l0_v2, rcc_l1), path = "l0l1.rs")] |
| 23 | #[cfg_attr(any(rcc_l4, rcc_l4plus), path = "l4.rs")] | 23 | #[cfg_attr(any(rcc_l4, rcc_l4plus, rcc_l5), path = "l4l5.rs")] |
| 24 | #[cfg_attr(rcc_l5, path = "l5.rs")] | ||
| 25 | #[cfg_attr(rcc_u5, path = "u5.rs")] | 24 | #[cfg_attr(rcc_u5, path = "u5.rs")] |
| 26 | #[cfg_attr(rcc_wb, path = "wb.rs")] | 25 | #[cfg_attr(rcc_wb, path = "wb.rs")] |
| 27 | #[cfg_attr(rcc_wba, path = "wba.rs")] | 26 | #[cfg_attr(rcc_wba, path = "wba.rs")] |
diff --git a/examples/stm32l5/src/bin/rng.rs b/examples/stm32l5/src/bin/rng.rs index cc3c99b57..e6233dbe6 100644 --- a/examples/stm32l5/src/bin/rng.rs +++ b/examples/stm32l5/src/bin/rng.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::rcc::{ClockSrc, PLLSource, PllMul, PllPreDiv, PllQDiv, PllRDiv}; | 7 | use embassy_stm32::rcc::{ClockSrc, PLLSource, Pll, PllMul, PllPreDiv, PllRDiv}; |
| 8 | use embassy_stm32::rng::Rng; | 8 | use embassy_stm32::rng::Rng; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -16,13 +16,17 @@ bind_interrupts!(struct Irqs { | |||
| 16 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 17 | async fn main(_spawner: Spawner) { | 17 | async fn main(_spawner: Spawner) { |
| 18 | let mut config = Config::default(); | 18 | let mut config = Config::default(); |
| 19 | config.rcc.mux = ClockSrc::PLL( | 19 | config.rcc.hsi16 = true; |
| 20 | PLLSource::HSI16, | 20 | config.rcc.mux = ClockSrc::PLL; |
| 21 | PllRDiv::DIV2, | 21 | config.rcc.pll = Some(Pll { |
| 22 | PllPreDiv::DIV1, | 22 | // 64Mhz clock (16 / 1 * 8 / 2) |
| 23 | PllMul::MUL8, | 23 | source: PLLSource::HSI16, |
| 24 | Some(PllQDiv::DIV2), | 24 | prediv: PllPreDiv::DIV1, |
| 25 | ); | 25 | mul: PllMul::MUL8, |
| 26 | divp: None, | ||
| 27 | divq: None, | ||
| 28 | divr: Some(PllRDiv::DIV2), | ||
| 29 | }); | ||
| 26 | let p = embassy_stm32::init(config); | 30 | let p = embassy_stm32::init(config); |
| 27 | 31 | ||
| 28 | info!("Hello World!"); | 32 | info!("Hello World!"); |
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 498147f9d..baa86640e 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs | |||
| @@ -45,8 +45,17 @@ async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | |||
| 45 | #[embassy_executor::main] | 45 | #[embassy_executor::main] |
| 46 | async fn main(spawner: Spawner) { | 46 | async fn main(spawner: Spawner) { |
| 47 | let mut config = Config::default(); | 47 | let mut config = Config::default(); |
| 48 | config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PllRDiv::DIV2, PllPreDiv::DIV1, PllMul::MUL10, None); | 48 | config.rcc.hsi16 = true; |
| 49 | config.rcc.hsi48 = true; | 49 | config.rcc.mux = ClockSrc::PLL; |
| 50 | config.rcc.pll = Some(Pll { | ||
| 51 | // 80Mhz clock (16 / 1 * 10 / 2) | ||
| 52 | source: PLLSource::HSI16, | ||
| 53 | prediv: PllPreDiv::DIV1, | ||
| 54 | mul: PllMul::MUL10, | ||
| 55 | divp: None, | ||
| 56 | divq: None, | ||
| 57 | divr: Some(PllRDiv::DIV2), | ||
| 58 | }); | ||
| 50 | let p = embassy_stm32::init(config); | 59 | let p = embassy_stm32::init(config); |
| 51 | 60 | ||
| 52 | // Create the driver, from the HAL. | 61 | // Create the driver, from the HAL. |
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index 0d06c94a2..1ce7e3e49 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs | |||
| @@ -22,8 +22,17 @@ bind_interrupts!(struct Irqs { | |||
| 22 | #[embassy_executor::main] | 22 | #[embassy_executor::main] |
| 23 | async fn main(_spawner: Spawner) { | 23 | async fn main(_spawner: Spawner) { |
| 24 | let mut config = Config::default(); | 24 | let mut config = Config::default(); |
| 25 | config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PllRDiv::DIV2, PllPreDiv::DIV1, PllMul::MUL10, None); | 25 | config.rcc.hsi16 = true; |
| 26 | config.rcc.hsi48 = true; | 26 | config.rcc.mux = ClockSrc::PLL; |
| 27 | config.rcc.pll = Some(Pll { | ||
| 28 | // 80Mhz clock (16 / 1 * 10 / 2) | ||
| 29 | source: PLLSource::HSI16, | ||
| 30 | prediv: PllPreDiv::DIV1, | ||
| 31 | mul: PllMul::MUL10, | ||
| 32 | divp: None, | ||
| 33 | divq: None, | ||
| 34 | divr: Some(PllRDiv::DIV2), | ||
| 35 | }); | ||
| 27 | let p = embassy_stm32::init(config); | 36 | let p = embassy_stm32::init(config); |
| 28 | 37 | ||
| 29 | // Create the driver, from the HAL. | 38 | // Create the driver, from the HAL. |
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index e19ecbf08..03d277a22 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs | |||
| @@ -20,8 +20,17 @@ bind_interrupts!(struct Irqs { | |||
| 20 | #[embassy_executor::main] | 20 | #[embassy_executor::main] |
| 21 | async fn main(_spawner: Spawner) { | 21 | async fn main(_spawner: Spawner) { |
| 22 | let mut config = Config::default(); | 22 | let mut config = Config::default(); |
| 23 | config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PllRDiv::DIV2, PllPreDiv::DIV1, PllMul::MUL10, None); | 23 | config.rcc.hsi16 = true; |
| 24 | config.rcc.hsi48 = true; | 24 | config.rcc.mux = ClockSrc::PLL; |
| 25 | config.rcc.pll = Some(Pll { | ||
| 26 | // 80Mhz clock (16 / 1 * 10 / 2) | ||
| 27 | source: PLLSource::HSI16, | ||
| 28 | prediv: PllPreDiv::DIV1, | ||
| 29 | mul: PllMul::MUL10, | ||
| 30 | divp: None, | ||
| 31 | divq: None, | ||
| 32 | divr: Some(PllRDiv::DIV2), | ||
| 33 | }); | ||
| 25 | let p = embassy_stm32::init(config); | 34 | let p = embassy_stm32::init(config); |
| 26 | 35 | ||
| 27 | info!("Hello World!"); | 36 | info!("Hello World!"); |
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index c5a24044a..6dc1b3002 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs | |||
| @@ -302,14 +302,17 @@ pub fn config() -> Config { | |||
| 302 | #[cfg(any(feature = "stm32l552ze"))] | 302 | #[cfg(any(feature = "stm32l552ze"))] |
| 303 | { | 303 | { |
| 304 | use embassy_stm32::rcc::*; | 304 | use embassy_stm32::rcc::*; |
| 305 | config.rcc.mux = ClockSrc::PLL( | 305 | config.rcc.hsi16 = true; |
| 306 | config.rcc.mux = ClockSrc::PLL; | ||
| 307 | config.rcc.pll = Some(Pll { | ||
| 306 | // 110Mhz clock (16 / 4 * 55 / 2) | 308 | // 110Mhz clock (16 / 4 * 55 / 2) |
| 307 | PLLSource::HSI16, | 309 | source: PLLSource::HSI16, |
| 308 | PllRDiv::DIV2, | 310 | prediv: PllPreDiv::DIV4, |
| 309 | PllPreDiv::DIV4, | 311 | mul: PllMul::MUL55, |
| 310 | PllMul::MUL55, | 312 | divp: None, |
| 311 | None, | 313 | divq: None, |
| 312 | ); | 314 | divr: Some(PllRDiv::DIV2), |
| 315 | }); | ||
| 313 | } | 316 | } |
| 314 | 317 | ||
| 315 | #[cfg(feature = "stm32u585ai")] | 318 | #[cfg(feature = "stm32u585ai")] |
