aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-10-16 03:47:54 +0200
committerDario Nieuwenhuis <[email protected]>2023-10-16 04:00:51 +0200
commit18e96898eab47840951305481cc669b8b221bdda (patch)
tree2a7629edc797c850a69d66728f8a9e7d168c2d8d
parent870dcc5970cbd043049e0ce2c9cde208c11a7d32 (diff)
stm32/rcc: unify L4 and L5.
-rw-r--r--embassy-stm32/Cargo.toml4
-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.rs291
-rw-r--r--embassy-stm32/src/rcc/mod.rs3
-rw-r--r--examples/stm32l5/src/bin/rng.rs20
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs13
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs13
-rw-r--r--examples/stm32l5/src/bin/usb_serial.rs13
-rw-r--r--tests/stm32/src/common.rs17
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"
58sdio-host = "0.5.0" 58sdio-host = "0.5.0"
59embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } 59embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
60critical-section = "1.1" 60critical-section = "1.1"
61stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-73e3f8a965a01fd5a168c3543b93ce49d475e130" } 61stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ecc410f93477d3d9314723ec26e637aa0c63b8f" }
62vcell = "0.1.3" 62vcell = "0.1.3"
63bxcan = "0.7.0" 63bxcan = "0.7.0"
64nb = "1.0.0" 64nb = "1.0.0"
@@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
76[build-dependencies] 76[build-dependencies]
77proc-macro2 = "1.0.36" 77proc-macro2 = "1.0.36"
78quote = "1.0.15" 78quote = "1.0.15"
79stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-73e3f8a965a01fd5a168c3543b93ce49d475e130", default-features = false, features = ["metadata"]} 79stm32-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)]
277fn get_equal<T: Eq>(mut iter: impl Iterator<Item = T>) -> Result<Option<T>, ()> { 288fn 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 {
299enum PllInstance { 310enum 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 @@
1use crate::pac::rcc::regs::Cfgr;
2pub 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};
6use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw};
7use crate::pac::{FLASH, PWR, RCC};
8use crate::rcc::{set_freqs, Clocks};
9use crate::time::Hertz;
10
11/// HSI speed
12pub const HSI_FREQ: Hertz = Hertz(16_000_000);
13
14/// System clock mux source
15#[derive(Clone, Copy)]
16pub 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)]
25pub enum PLLSource {
26 HSI16,
27 HSE(Hertz),
28 MSI(MSIRange),
29}
30
31impl 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
42pub 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
52impl 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
67pub(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
275fn 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
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::rcc::{ClockSrc, PLLSource, PllMul, PllPreDiv, PllQDiv, PllRDiv}; 7use embassy_stm32::rcc::{ClockSrc, PLLSource, Pll, PllMul, PllPreDiv, PllRDiv};
8use embassy_stm32::rng::Rng; 8use embassy_stm32::rng::Rng;
9use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, rng, Config};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
@@ -16,13 +16,17 @@ bind_interrupts!(struct Irqs {
16#[embassy_executor::main] 16#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 17async 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]
46async fn main(spawner: Spawner) { 46async 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]
23async fn main(_spawner: Spawner) { 23async 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]
21async fn main(_spawner: Spawner) { 21async 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")]