aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-10-18 03:23:47 +0000
committerGitHub <[email protected]>2023-10-18 03:23:47 +0000
commit4f7b8316769d4b0ca59e8501cecfaed0de5a3000 (patch)
tree6a61685dc05bb97e2345c68ccc93969e4ec317ef
parent51708c8ed1962618ac7bc244a3f5e7ceced28182 (diff)
parentf20f170b1fa97a86e9d9258ac5cea248203580fb (diff)
Merge pull request #2088 from embassy-rs/rcc-no-spaghetti
stm32: rcc no spaghetti
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/rcc/f4.rs400
-rw-r--r--embassy-stm32/src/rcc/f4f7.rs379
-rw-r--r--embassy-stm32/src/rcc/f7.rs305
-rw-r--r--embassy-stm32/src/rcc/h.rs9
-rw-r--r--embassy-stm32/src/rcc/l4l5.rs1
-rw-r--r--embassy-stm32/src/rcc/mod.rs3
-rw-r--r--examples/stm32f4/src/bin/eth.rs22
-rw-r--r--examples/stm32f4/src/bin/hello.rs4
-rw-r--r--examples/stm32f4/src/bin/sdmmc.rs23
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs24
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs24
-rw-r--r--examples/stm32f7/src/bin/eth.rs22
-rw-r--r--examples/stm32f7/src/bin/hello.rs4
-rw-r--r--examples/stm32f7/src/bin/sdmmc.rs23
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs25
-rw-r--r--tests/stm32/src/common.rs40
17 files changed, 559 insertions, 753 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index ab7b92219..3b9220bc7 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-6f7449303bf8af60a63704d35df9af46006c6148" } 61stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5b04234fbe61ea875f1a904cd5f68795daaeb526" }
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-6f7449303bf8af60a63704d35df9af46006c6148", default-features = false, features = ["metadata"]} 79stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5b04234fbe61ea875f1a904cd5f68795daaeb526", default-features = false, features = ["metadata"]}
80 80
81 81
82[features] 82[features]
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs
deleted file mode 100644
index eb51dc89a..000000000
--- a/embassy-stm32/src/rcc/f4.rs
+++ /dev/null
@@ -1,400 +0,0 @@
1use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllq, Pllr, Ppre, Sw};
2use crate::pac::{FLASH, PWR, RCC};
3use crate::rcc::{set_freqs, Clocks};
4use crate::time::Hertz;
5
6/// HSI speed
7pub const HSI_FREQ: Hertz = Hertz(16_000_000);
8
9/// Clocks configuration
10#[non_exhaustive]
11#[derive(Default)]
12pub struct Config {
13 pub hse: Option<Hertz>,
14 pub bypass_hse: bool,
15 pub hclk: Option<Hertz>,
16 pub sys_ck: Option<Hertz>,
17 pub pclk1: Option<Hertz>,
18 pub pclk2: Option<Hertz>,
19
20 #[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
21 pub plli2s: Option<Hertz>,
22
23 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
24 pub pllsai: Option<Hertz>,
25
26 pub pll48: bool,
27 pub ls: super::LsConfig,
28}
29
30#[cfg(stm32f410)]
31fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
32 None
33}
34
35// Not currently implemented, but will be in the future
36#[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
37fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
38 None
39}
40
41#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423)))]
42fn calculate_sai_i2s_pll_values(vco_in: u32, max_div: u32, target: Option<u32>) -> Option<(u32, u32, u32)> {
43 let min_div = 2;
44 let target = match target {
45 Some(target) => target,
46 None => return None,
47 };
48
49 // We loop through the possible divider values to find the best configuration. Looping
50 // through all possible "N" values would result in more iterations.
51 let (n, outdiv, output, _error) = (min_div..=max_div)
52 .filter_map(|outdiv| {
53 let target_vco_out = match target.checked_mul(outdiv) {
54 Some(x) => x,
55 None => return None,
56 };
57 let n = (target_vco_out + (vco_in >> 1)) / vco_in;
58 let vco_out = vco_in * n;
59 if !(100_000_000..=432_000_000).contains(&vco_out) {
60 return None;
61 }
62 let output = vco_out / outdiv;
63 let error = (output as i32 - target as i32).unsigned_abs();
64 Some((n, outdiv, output, error))
65 })
66 .min_by_key(|(_, _, _, error)| *error)?;
67
68 Some((n, outdiv, output))
69}
70
71#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
72fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
73 let (n, outdiv, output) = calculate_sai_i2s_pll_values(vco_in, 7, plli2s)?;
74
75 RCC.plli2scfgr().modify(|w| {
76 w.set_plli2sn(n as u16);
77 w.set_plli2sr(outdiv as u8);
78 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
79 w.set_plli2sq(outdiv as u8); //set sai divider same as i2s
80 });
81
82 Some(output)
83}
84
85#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479)))]
86fn setup_sai_pll(_vco_in: u32, _pllsai: Option<u32>) -> Option<u32> {
87 None
88}
89
90#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
91fn setup_sai_pll(vco_in: u32, pllsai: Option<u32>) -> Option<u32> {
92 let (n, outdiv, output) = calculate_sai_i2s_pll_values(vco_in, 15, pllsai)?;
93
94 RCC.pllsaicfgr().modify(|w| {
95 w.set_pllsain(n as u16);
96 w.set_pllsaiq(outdiv as u8);
97 });
98
99 Some(output)
100}
101
102fn setup_pll(
103 pllsrcclk: u32,
104 use_hse: bool,
105 pllsysclk: Option<u32>,
106 plli2s: Option<u32>,
107 pllsai: Option<u32>,
108 pll48clk: bool,
109) -> PllResults {
110 use crate::pac::rcc::vals::{Pllp, Pllsrc};
111
112 let sysclk = pllsysclk.unwrap_or(pllsrcclk);
113 if pllsysclk.is_none() && !pll48clk {
114 RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)));
115
116 return PllResults {
117 use_pll: false,
118 pllsysclk: None,
119 pll48clk: None,
120 plli2sclk: None,
121 pllsaiclk: None,
122 };
123 }
124 // Input divisor from PLL source clock, must result to frequency in
125 // the range from 1 to 2 MHz
126 let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
127 let pllm_max = pllsrcclk / 1_000_000;
128
129 // Sysclk output divisor must be one of 2, 4, 6 or 8
130 let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
131
132 let target_freq = if pll48clk { 48_000_000 } else { sysclk * sysclk_div };
133
134 // Find the lowest pllm value that minimize the difference between
135 // target frequency and the real vco_out frequency.
136 let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
137 let vco_in = pllsrcclk / pllm;
138 let plln = target_freq / vco_in;
139 target_freq - vco_in * plln
140 }));
141
142 let vco_in = pllsrcclk / pllm;
143 assert!((1_000_000..=2_000_000).contains(&vco_in));
144
145 // Main scaler, must result in >= 100MHz (>= 192MHz for F401)
146 // and <= 432MHz, min 50, max 432
147 let plln = if pll48clk {
148 // try the different valid pllq according to the valid
149 // main scaller values, and take the best
150 let pllq = unwrap!((4..=9).min_by_key(|pllq| {
151 let plln = 48_000_000 * pllq / vco_in;
152 let pll48_diff = 48_000_000 - vco_in * plln / pllq;
153 let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
154 (pll48_diff, sysclk_diff)
155 }));
156 48_000_000 * pllq / vco_in
157 } else {
158 sysclk * sysclk_div / vco_in
159 };
160
161 let pllp = (sysclk_div / 2) - 1;
162
163 let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
164 let real_pll48clk = vco_in * plln / pllq;
165
166 RCC.pllcfgr().modify(|w| {
167 w.set_pllm(Pllm::from_bits(pllm as u8));
168 w.set_plln(Plln::from_bits(plln as u16));
169 w.set_pllp(Pllp::from_bits(pllp as u8));
170 w.set_pllq(Pllq::from_bits(pllq as u8));
171 w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
172 w.set_pllr(Pllr::from_bits(0));
173 });
174
175 let real_pllsysclk = vco_in * plln / sysclk_div;
176
177 PllResults {
178 use_pll: true,
179 pllsysclk: Some(real_pllsysclk),
180 pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
181 plli2sclk: setup_i2s_pll(vco_in, plli2s),
182 pllsaiclk: setup_sai_pll(vco_in, pllsai),
183 }
184}
185
186fn flash_setup(sysclk: u32) {
187 use crate::pac::flash::vals::Latency;
188
189 // Be conservative with voltage ranges
190 const FLASH_LATENCY_STEP: u32 = 30_000_000;
191
192 critical_section::with(|_| {
193 FLASH
194 .acr()
195 .modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
196 });
197}
198
199pub(crate) unsafe fn init(config: Config) {
200 let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0);
201 let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
202 let sysclk_on_pll = sysclk != pllsrcclk;
203
204 let plls = setup_pll(
205 pllsrcclk,
206 config.hse.is_some(),
207 if sysclk_on_pll { Some(sysclk) } else { None },
208 #[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
209 config.plli2s.map(|i2s| i2s.0),
210 #[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
211 None,
212 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
213 config.pllsai.map(|sai| sai.0),
214 #[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479)))]
215 None,
216 config.pll48,
217 );
218
219 if config.pll48 {
220 let freq = unwrap!(plls.pll48clk);
221
222 assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
223 }
224
225 let sysclk = if sysclk_on_pll { unwrap!(plls.pllsysclk) } else { sysclk };
226
227 // AHB prescaler
228 let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
229 let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
230 0 => unreachable!(),
231 1 => (Hpre::DIV1, 1),
232 2 => (Hpre::DIV2, 2),
233 3..=5 => (Hpre::DIV4, 4),
234 6..=11 => (Hpre::DIV8, 8),
235 12..=39 => (Hpre::DIV16, 16),
236 40..=95 => (Hpre::DIV64, 64),
237 96..=191 => (Hpre::DIV128, 128),
238 192..=383 => (Hpre::DIV256, 256),
239 _ => (Hpre::DIV512, 512),
240 };
241
242 // Calculate real AHB clock
243 let hclk = sysclk / hpre_div;
244
245 let pclk1 = config
246 .pclk1
247 .map(|p| p.0)
248 .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
249
250 let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
251 0 => unreachable!(),
252 1 => (0b000, 1),
253 2 => (0b100, 2),
254 3..=5 => (0b101, 4),
255 6..=11 => (0b110, 8),
256 _ => (0b111, 16),
257 };
258 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
259
260 // Calculate real APB1 clock
261 let pclk1 = hclk / ppre1;
262 assert!(pclk1 <= max::PCLK1_MAX);
263
264 let pclk2 = config
265 .pclk2
266 .map(|p| p.0)
267 .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
268 let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
269 0 => unreachable!(),
270 1 => (0b000, 1),
271 2 => (0b100, 2),
272 3..=5 => (0b101, 4),
273 6..=11 => (0b110, 8),
274 _ => (0b111, 16),
275 };
276 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
277
278 // Calculate real APB2 clock
279 let pclk2 = hclk / ppre2;
280 assert!(pclk2 <= max::PCLK2_MAX);
281
282 flash_setup(sysclk);
283
284 if config.hse.is_some() {
285 RCC.cr().modify(|w| {
286 w.set_hsebyp(config.bypass_hse);
287 w.set_hseon(true);
288 });
289 while !RCC.cr().read().hserdy() {}
290 }
291
292 if plls.use_pll {
293 RCC.cr().modify(|w| w.set_pllon(true));
294
295 if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
296 PWR.cr1().modify(|w| w.set_oden(true));
297 while !PWR.csr1().read().odrdy() {}
298
299 PWR.cr1().modify(|w| w.set_odswen(true));
300 while !PWR.csr1().read().odswrdy() {}
301 }
302
303 while !RCC.cr().read().pllrdy() {}
304 }
305
306 #[cfg(not(stm32f410))]
307 if plls.plli2sclk.is_some() {
308 RCC.cr().modify(|w| w.set_plli2son(true));
309
310 while !RCC.cr().read().plli2srdy() {}
311 }
312
313 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
314 if plls.pllsaiclk.is_some() {
315 RCC.cr().modify(|w| w.set_pllsaion(true));
316 while !RCC.cr().read().pllsairdy() {}
317 }
318
319 RCC.cfgr().modify(|w| {
320 w.set_ppre2(Ppre::from_bits(ppre2_bits));
321 w.set_ppre1(Ppre::from_bits(ppre1_bits));
322 w.set_hpre(hpre_bits);
323 });
324
325 // Wait for the new prescalers to kick in
326 // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
327 cortex_m::asm::delay(16);
328
329 RCC.cfgr().modify(|w| {
330 w.set_sw(if sysclk_on_pll {
331 Sw::PLL1_P
332 } else if config.hse.is_some() {
333 Sw::HSE
334 } else {
335 Sw::HSI
336 })
337 });
338
339 let rtc = config.ls.init();
340
341 set_freqs(Clocks {
342 sys: Hertz(sysclk),
343 pclk1: Hertz(pclk1),
344 pclk2: Hertz(pclk2),
345
346 pclk1_tim: Hertz(pclk1 * timer_mul1),
347 pclk2_tim: Hertz(pclk2 * timer_mul2),
348
349 hclk1: Hertz(hclk),
350 hclk2: Hertz(hclk),
351 hclk3: Hertz(hclk),
352
353 pll1_q: plls.pll48clk.map(Hertz),
354
355 #[cfg(not(stm32f410))]
356 plli2s1_q: plls.plli2sclk.map(Hertz),
357 #[cfg(not(stm32f410))]
358 plli2s1_r: None,
359
360 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
361 pllsai1_q: plls.pllsaiclk.map(Hertz),
362 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
363 pllsai1_r: None,
364
365 rtc,
366 });
367}
368
369struct PllResults {
370 use_pll: bool,
371 pllsysclk: Option<u32>,
372 pll48clk: Option<u32>,
373 #[allow(dead_code)]
374 plli2sclk: Option<u32>,
375 #[allow(dead_code)]
376 pllsaiclk: Option<u32>,
377}
378
379mod max {
380 #[cfg(stm32f401)]
381 pub(crate) const SYSCLK_MAX: u32 = 84_000_000;
382 #[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
383 pub(crate) const SYSCLK_MAX: u32 = 168_000_000;
384 #[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
385 pub(crate) const SYSCLK_MAX: u32 = 100_000_000;
386 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,))]
387 pub(crate) const SYSCLK_MAX: u32 = 180_000_000;
388
389 pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 168_000_000;
390
391 pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2;
392
393 #[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
394 pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX;
395 #[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
396 pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
397
398 pub(crate) const PLL_48_CLK: u32 = 48_000_000;
399 pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
400}
diff --git a/embassy-stm32/src/rcc/f4f7.rs b/embassy-stm32/src/rcc/f4f7.rs
new file mode 100644
index 000000000..de37eab72
--- /dev/null
+++ b/embassy-stm32/src/rcc/f4f7.rs
@@ -0,0 +1,379 @@
1pub use crate::pac::rcc::vals::{
2 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp, Pllq, Pllr, Pllsrc as PllSource,
3 Ppre as APBPrescaler, Sw as Sysclk,
4};
5use crate::pac::{FLASH, PWR, RCC};
6use crate::rcc::{set_freqs, Clocks};
7use crate::time::Hertz;
8
9// TODO: on some F4s, PLLM is shared between all PLLs. Enforce that.
10// TODO: on some F4s, add support for plli2s_src
11//
12// plli2s plli2s_m plli2s_src pllsai pllsai_m
13// f401 y shared
14// f410
15// f411 y individual
16// f412 y individual y
17// f4[12]3 y individual y
18// f446 y individual y individual
19// f4[67]9 y shared y shared
20// f4[23][79] y shared y shared
21// f4[01][57] y shared
22
23/// HSI speed
24pub const HSI_FREQ: Hertz = Hertz(16_000_000);
25
26#[derive(Clone, Copy, Eq, PartialEq)]
27pub enum HseMode {
28 /// crystal/ceramic oscillator (HSEBYP=0)
29 Oscillator,
30 /// external analog clock (low swing) (HSEBYP=1)
31 Bypass,
32}
33
34#[derive(Clone, Copy, Eq, PartialEq)]
35pub struct Hse {
36 /// HSE frequency.
37 pub freq: Hertz,
38 /// HSE mode.
39 pub mode: HseMode,
40}
41
42#[derive(Clone, Copy)]
43pub struct Pll {
44 /// PLL pre-divider (DIVM).
45 pub prediv: PllPreDiv,
46
47 /// PLL multiplication factor.
48 pub mul: PllMul,
49
50 /// PLL P division factor. If None, PLL P output is disabled.
51 pub divp: Option<Pllp>,
52 /// PLL Q division factor. If None, PLL Q output is disabled.
53 pub divq: Option<Pllq>,
54 /// PLL R division factor. If None, PLL R output is disabled.
55 pub divr: Option<Pllr>,
56}
57
58/// Configuration of the core clocks
59#[non_exhaustive]
60pub struct Config {
61 pub hsi: bool,
62 pub hse: Option<Hse>,
63 pub sys: Sysclk,
64
65 pub pll_src: PllSource,
66
67 pub pll: Option<Pll>,
68 #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
69 pub plli2s: Option<Pll>,
70 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
71 pub pllsai: Option<Pll>,
72
73 pub ahb_pre: AHBPrescaler,
74 pub apb1_pre: APBPrescaler,
75 pub apb2_pre: APBPrescaler,
76
77 pub ls: super::LsConfig,
78}
79
80impl Default for Config {
81 fn default() -> Self {
82 Self {
83 hsi: true,
84 hse: None,
85 sys: Sysclk::HSI,
86 pll_src: PllSource::HSI,
87 pll: None,
88 #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
89 plli2s: None,
90 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
91 pllsai: None,
92
93 ahb_pre: AHBPrescaler::DIV1,
94 apb1_pre: APBPrescaler::DIV1,
95 apb2_pre: APBPrescaler::DIV1,
96
97 ls: Default::default(),
98 }
99 }
100}
101
102pub(crate) unsafe fn init(config: Config) {
103 // always enable overdrive for now. Make it configurable in the future.
104 PWR.cr1().modify(|w| w.set_oden(true));
105 while !PWR.csr1().read().odrdy() {}
106
107 PWR.cr1().modify(|w| w.set_odswen(true));
108 while !PWR.csr1().read().odswrdy() {}
109
110 // Configure HSI
111 let hsi = match config.hsi {
112 false => {
113 RCC.cr().modify(|w| w.set_hsion(false));
114 None
115 }
116 true => {
117 RCC.cr().modify(|w| w.set_hsion(true));
118 while !RCC.cr().read().hsirdy() {}
119 Some(HSI_FREQ)
120 }
121 };
122
123 // Configure HSE
124 let hse = match config.hse {
125 None => {
126 RCC.cr().modify(|w| w.set_hseon(false));
127 None
128 }
129 Some(hse) => {
130 match hse.mode {
131 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)),
132 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)),
133 }
134
135 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
136 RCC.cr().modify(|w| w.set_hseon(true));
137 while !RCC.cr().read().hserdy() {}
138 Some(hse.freq)
139 }
140 };
141
142 // Configure PLLs.
143 let pll_input = PllInput {
144 hse,
145 hsi,
146 source: config.pll_src,
147 };
148 let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
149 #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
150 let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input);
151 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
152 let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input);
153
154 // Configure sysclk
155 let sys = match config.sys {
156 Sysclk::HSI => unwrap!(hsi),
157 Sysclk::HSE => unwrap!(hse),
158 Sysclk::PLL1_P => unwrap!(pll.p),
159 _ => unreachable!(),
160 };
161
162 let hclk = sys / config.ahb_pre;
163 let (pclk1, pclk1_tim) = calc_pclk(hclk, config.apb1_pre);
164 let (pclk2, pclk2_tim) = calc_pclk(hclk, config.apb2_pre);
165
166 assert!(max::SYSCLK.contains(&sys));
167 assert!(max::HCLK.contains(&hclk));
168 assert!(max::PCLK1.contains(&pclk1));
169 assert!(max::PCLK2.contains(&pclk2));
170
171 let rtc = config.ls.init();
172
173 flash_setup(hclk);
174
175 RCC.cfgr().modify(|w| {
176 w.set_sw(config.sys);
177 w.set_hpre(config.ahb_pre);
178 w.set_ppre1(config.apb1_pre);
179 w.set_ppre2(config.apb2_pre);
180 });
181 while RCC.cfgr().read().sws() != config.sys {}
182
183 set_freqs(Clocks {
184 sys,
185 hclk1: hclk,
186 hclk2: hclk,
187 hclk3: hclk,
188 pclk1,
189 pclk2,
190 pclk1_tim,
191 pclk2_tim,
192 rtc,
193 pll1_q: pll.q,
194 #[cfg(all(rcc_f4, not(stm32f410)))]
195 plli2s1_q: _plli2s.q,
196 #[cfg(all(rcc_f4, not(stm32f410)))]
197 plli2s1_r: _plli2s.r,
198
199 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
200 pllsai1_q: _pllsai.q,
201 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
202 pllsai1_r: _pllsai.r,
203 });
204}
205
206struct PllInput {
207 source: PllSource,
208 hsi: Option<Hertz>,
209 hse: Option<Hertz>,
210}
211
212#[derive(Default)]
213#[allow(unused)]
214struct PllOutput {
215 p: Option<Hertz>,
216 q: Option<Hertz>,
217 r: Option<Hertz>,
218}
219
220#[derive(PartialEq, Eq, Clone, Copy)]
221enum PllInstance {
222 Pll,
223 #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
224 Plli2s,
225 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
226 Pllsai,
227}
228
229fn pll_enable(instance: PllInstance, enabled: bool) {
230 match instance {
231 PllInstance::Pll => {
232 RCC.cr().modify(|w| w.set_pllon(enabled));
233 while RCC.cr().read().pllrdy() != enabled {}
234 }
235 #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
236 PllInstance::Plli2s => {
237 RCC.cr().modify(|w| w.set_plli2son(enabled));
238 while RCC.cr().read().plli2srdy() != enabled {}
239 }
240 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
241 PllInstance::Pllsai => {
242 RCC.cr().modify(|w| w.set_pllsaion(enabled));
243 while RCC.cr().read().pllsairdy() != enabled {}
244 }
245 }
246}
247
248fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput {
249 // Disable PLL
250 pll_enable(instance, false);
251
252 let Some(pll) = config else { return PllOutput::default() };
253
254 let pll_src = match input.source {
255 PllSource::HSE => input.hse,
256 PllSource::HSI => input.hsi,
257 };
258
259 let pll_src = pll_src.unwrap();
260
261 let in_freq = pll_src / pll.prediv;
262 assert!(max::PLL_IN.contains(&in_freq));
263 let vco_freq = in_freq * pll.mul;
264 assert!(max::PLL_VCO.contains(&vco_freq));
265
266 let p = pll.divp.map(|div| vco_freq / div);
267 let q = pll.divq.map(|div| vco_freq / div);
268 let r = pll.divr.map(|div| vco_freq / div);
269
270 macro_rules! write_fields {
271 ($w:ident) => {
272 $w.set_plln(pll.mul);
273 if let Some(divp) = pll.divp {
274 $w.set_pllp(divp);
275 }
276 if let Some(divq) = pll.divq {
277 $w.set_pllq(divq);
278 }
279 if let Some(divr) = pll.divr {
280 $w.set_pllr(divr);
281 }
282 };
283 }
284
285 match instance {
286 PllInstance::Pll => RCC.pllcfgr().write(|w| {
287 w.set_pllm(pll.prediv);
288 w.set_pllsrc(input.source);
289 write_fields!(w);
290 }),
291 #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
292 PllInstance::Plli2s => RCC.plli2scfgr().write(|w| {
293 write_fields!(w);
294 }),
295 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
296 PllInstance::Pllsai => RCC.pllsaicfgr().write(|w| {
297 write_fields!(w);
298 }),
299 }
300
301 // Enable PLL
302 pll_enable(instance, true);
303
304 PllOutput { p, q, r }
305}
306
307fn flash_setup(clk: Hertz) {
308 use crate::pac::flash::vals::Latency;
309
310 // Be conservative with voltage ranges
311 const FLASH_LATENCY_STEP: u32 = 30_000_000;
312
313 let latency = (clk.0 - 1) / FLASH_LATENCY_STEP;
314 debug!("flash: latency={}", latency);
315
316 let latency = Latency::from_bits(latency as u8);
317 FLASH.acr().write(|w| {
318 w.set_latency(latency);
319 });
320 while FLASH.acr().read().latency() != latency {}
321}
322
323fn calc_pclk<D>(hclk: Hertz, ppre: D) -> (Hertz, Hertz)
324where
325 Hertz: core::ops::Div<D, Output = Hertz>,
326{
327 let pclk = hclk / ppre;
328 let pclk_tim = if hclk == pclk { pclk } else { pclk * 2u32 };
329 (pclk, pclk_tim)
330}
331
332#[cfg(stm32f7)]
333mod max {
334 use core::ops::RangeInclusive;
335
336 use crate::time::Hertz;
337
338 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(26_000_000);
339 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(50_000_000);
340
341 pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(12_500_000)..=Hertz(216_000_000);
342 pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(12_500_000)..=Hertz(216_000_000);
343 pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(12_500_000)..=Hertz(216_000_000 / 4);
344 pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(12_500_000)..=Hertz(216_000_000 / 2);
345
346 pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(2_100_000);
347 pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(100_000_000)..=Hertz(432_000_000);
348}
349
350#[cfg(stm32f4)]
351mod max {
352 use core::ops::RangeInclusive;
353
354 use crate::time::Hertz;
355
356 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(26_000_000);
357 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(50_000_000);
358
359 #[cfg(stm32f401)]
360 pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(84_000_000);
361 #[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
362 pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(168_000_000);
363 #[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
364 pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(100_000_000);
365 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,))]
366 pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(180_000_000);
367
368 pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(SYSCLK.end().0);
369
370 pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(0)..=Hertz(PCLK2.end().0 / 2);
371
372 #[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
373 pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(0)..=Hertz(HCLK.end().0);
374 #[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
375 pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(0)..=Hertz(HCLK.end().0 / 2);
376
377 pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(2_100_000);
378 pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(100_000_000)..=Hertz(432_000_000);
379}
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs
deleted file mode 100644
index 7c6c150d9..000000000
--- a/embassy-stm32/src/rcc/f7.rs
+++ /dev/null
@@ -1,305 +0,0 @@
1use crate::pac::pwr::vals::Vos;
2use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllp, Pllq, Pllsrc, Ppre, Sw};
3use crate::pac::{FLASH, PWR, RCC};
4use crate::rcc::{set_freqs, Clocks};
5use crate::time::Hertz;
6
7/// HSI speed
8pub const HSI_FREQ: Hertz = Hertz(16_000_000);
9
10/// Clocks configuration
11#[non_exhaustive]
12#[derive(Default)]
13pub struct Config {
14 pub hse: Option<Hertz>,
15 pub bypass_hse: bool,
16 pub hclk: Option<Hertz>,
17 pub sys_ck: Option<Hertz>,
18 pub pclk1: Option<Hertz>,
19 pub pclk2: Option<Hertz>,
20
21 pub pll48: bool,
22 pub ls: super::LsConfig,
23}
24
25fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
26 let sysclk = pllsysclk.unwrap_or(pllsrcclk);
27 if pllsysclk.is_none() && !pll48clk {
28 RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)));
29
30 return PllResults {
31 use_pll: false,
32 pllsysclk: None,
33 pll48clk: None,
34 };
35 }
36 // Input divisor from PLL source clock, must result to frequency in
37 // the range from 1 to 2 MHz
38 let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
39 let pllm_max = pllsrcclk / 1_000_000;
40
41 // Sysclk output divisor must be one of 2, 4, 6 or 8
42 let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
43
44 let target_freq = if pll48clk { 48_000_000 } else { sysclk * sysclk_div };
45
46 // Find the lowest pllm value that minimize the difference between
47 // target frequency and the real vco_out frequency.
48 let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
49 let vco_in = pllsrcclk / pllm;
50 let plln = target_freq / vco_in;
51 target_freq - vco_in * plln
52 }));
53
54 let vco_in = pllsrcclk / pllm;
55 assert!((1_000_000..=2_000_000).contains(&vco_in));
56
57 // Main scaler, must result in >= 100MHz (>= 192MHz for F401)
58 // and <= 432MHz, min 50, max 432
59 let plln = if pll48clk {
60 // try the different valid pllq according to the valid
61 // main scaller values, and take the best
62 let pllq = unwrap!((4..=9).min_by_key(|pllq| {
63 let plln = 48_000_000 * pllq / vco_in;
64 let pll48_diff = 48_000_000 - vco_in * plln / pllq;
65 let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
66 (pll48_diff, sysclk_diff)
67 }));
68 48_000_000 * pllq / vco_in
69 } else {
70 sysclk * sysclk_div / vco_in
71 };
72
73 let pllp = (sysclk_div / 2) - 1;
74
75 let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
76 let real_pll48clk = vco_in * plln / pllq;
77
78 RCC.pllcfgr().modify(|w| {
79 w.set_pllm(Pllm::from_bits(pllm as u8));
80 w.set_plln(Plln::from_bits(plln as u16));
81 w.set_pllp(Pllp::from_bits(pllp as u8));
82 w.set_pllq(Pllq::from_bits(pllq as u8));
83 w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
84 });
85
86 let real_pllsysclk = vco_in * plln / sysclk_div;
87
88 PllResults {
89 use_pll: true,
90 pllsysclk: Some(real_pllsysclk),
91 pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
92 }
93}
94
95fn flash_setup(sysclk: u32) {
96 use crate::pac::flash::vals::Latency;
97
98 // Be conservative with voltage ranges
99 const FLASH_LATENCY_STEP: u32 = 30_000_000;
100
101 critical_section::with(|_| {
102 FLASH
103 .acr()
104 .modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
105 });
106}
107
108pub(crate) unsafe fn init(config: Config) {
109 if let Some(hse) = config.hse {
110 if config.bypass_hse {
111 assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0));
112 } else {
113 assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0));
114 }
115 }
116
117 let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0);
118 let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
119 let sysclk_on_pll = sysclk != pllsrcclk;
120
121 assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk));
122
123 let plls = setup_pll(
124 pllsrcclk,
125 config.hse.is_some(),
126 if sysclk_on_pll { Some(sysclk) } else { None },
127 config.pll48,
128 );
129
130 if config.pll48 {
131 let freq = unwrap!(plls.pll48clk);
132
133 assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
134 }
135
136 let sysclk = if sysclk_on_pll { unwrap!(plls.pllsysclk) } else { sysclk };
137
138 // AHB prescaler
139 let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
140 let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
141 0 => unreachable!(),
142 1 => (Hpre::DIV1, 1),
143 2 => (Hpre::DIV2, 2),
144 3..=5 => (Hpre::DIV4, 4),
145 6..=11 => (Hpre::DIV8, 8),
146 12..=39 => (Hpre::DIV16, 16),
147 40..=95 => (Hpre::DIV64, 64),
148 96..=191 => (Hpre::DIV128, 128),
149 192..=383 => (Hpre::DIV256, 256),
150 _ => (Hpre::DIV512, 512),
151 };
152
153 // Calculate real AHB clock
154 let hclk = sysclk / hpre_div;
155
156 assert!(hclk <= max::HCLK_MAX);
157
158 let pclk1 = config
159 .pclk1
160 .map(|p| p.0)
161 .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
162
163 let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
164 0 => unreachable!(),
165 1 => (0b000, 1),
166 2 => (0b100, 2),
167 3..=5 => (0b101, 4),
168 6..=11 => (0b110, 8),
169 _ => (0b111, 16),
170 };
171 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
172
173 // Calculate real APB1 clock
174 let pclk1 = hclk / ppre1;
175 assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1));
176
177 let pclk2 = config
178 .pclk2
179 .map(|p| p.0)
180 .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
181 let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
182 0 => unreachable!(),
183 1 => (0b000, 1),
184 2 => (0b100, 2),
185 3..=5 => (0b101, 4),
186 6..=11 => (0b110, 8),
187 _ => (0b111, 16),
188 };
189 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
190
191 // Calculate real APB2 clock
192 let pclk2 = hclk / ppre2;
193 assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2));
194
195 flash_setup(sysclk);
196
197 if config.hse.is_some() {
198 RCC.cr().modify(|w| {
199 w.set_hsebyp(config.bypass_hse);
200 w.set_hseon(true);
201 });
202 while !RCC.cr().read().hserdy() {}
203 }
204
205 if plls.use_pll {
206 RCC.cr().modify(|w| w.set_pllon(false));
207
208 // setup VOSScale
209 let vos_scale = if sysclk <= 144_000_000 {
210 3
211 } else if sysclk <= 168_000_000 {
212 2
213 } else {
214 1
215 };
216 PWR.cr1().modify(|w| {
217 w.set_vos(match vos_scale {
218 3 => Vos::SCALE3,
219 2 => Vos::SCALE2,
220 1 => Vos::SCALE1,
221 _ => panic!("Invalid VOS Scale."),
222 })
223 });
224
225 RCC.cr().modify(|w| w.set_pllon(true));
226
227 if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
228 PWR.cr1().modify(|w| w.set_oden(true));
229 while !PWR.csr1().read().odrdy() {}
230
231 PWR.cr1().modify(|w| w.set_odswen(true));
232 while !PWR.csr1().read().odswrdy() {}
233 }
234
235 while !RCC.cr().read().pllrdy() {}
236 }
237
238 RCC.cfgr().modify(|w| {
239 w.set_ppre2(Ppre::from_bits(ppre2_bits));
240 w.set_ppre1(Ppre::from_bits(ppre1_bits));
241 w.set_hpre(hpre_bits);
242 });
243
244 // Wait for the new prescalers to kick in
245 // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
246 cortex_m::asm::delay(16);
247
248 RCC.cfgr().modify(|w| {
249 w.set_sw(if sysclk_on_pll {
250 Sw::PLL1_P
251 } else if config.hse.is_some() {
252 Sw::HSE
253 } else {
254 Sw::HSI
255 })
256 });
257
258 let rtc = config.ls.init();
259
260 set_freqs(Clocks {
261 sys: Hertz(sysclk),
262 pclk1: Hertz(pclk1),
263 pclk2: Hertz(pclk2),
264
265 pclk1_tim: Hertz(pclk1 * timer_mul1),
266 pclk2_tim: Hertz(pclk2 * timer_mul2),
267
268 hclk1: Hertz(hclk),
269 hclk2: Hertz(hclk),
270 hclk3: Hertz(hclk),
271
272 pll1_q: plls.pll48clk.map(Hertz),
273
274 rtc,
275 });
276}
277
278struct PllResults {
279 use_pll: bool,
280 pllsysclk: Option<u32>,
281 pll48clk: Option<u32>,
282}
283
284mod max {
285 pub(crate) const HSE_OSC_MIN: u32 = 4_000_000;
286 pub(crate) const HSE_OSC_MAX: u32 = 26_000_000;
287 pub(crate) const HSE_BYPASS_MIN: u32 = 1_000_000;
288 pub(crate) const HSE_BYPASS_MAX: u32 = 50_000_000;
289
290 pub(crate) const HCLK_MAX: u32 = 216_000_000;
291 pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 180_000_000;
292
293 pub(crate) const SYSCLK_MIN: u32 = 12_500_000;
294 pub(crate) const SYSCLK_MAX: u32 = 216_000_000;
295
296 pub(crate) const PCLK1_MIN: u32 = SYSCLK_MIN;
297 pub(crate) const PCLK1_MAX: u32 = SYSCLK_MAX / 4;
298
299 pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN;
300 pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
301
302 // USB specification allows +-0.25%
303 pub(crate) const PLL_48_CLK: u32 = 48_000_000;
304 pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
305}
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 86136d438..5dbcfea90 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -58,15 +58,6 @@ pub struct Hse {
58 pub mode: HseMode, 58 pub mode: HseMode,
59} 59}
60 60
61#[cfg(stm32h7)]
62#[derive(Clone, Copy, Eq, PartialEq)]
63pub enum Lse {
64 /// 32.768 kHz crystal/ceramic oscillator (LSEBYP=0)
65 Oscillator,
66 /// external clock input up to 1MHz (LSEBYP=1)
67 Bypass(Hertz),
68}
69
70#[derive(Clone, Copy, Eq, PartialEq)] 61#[derive(Clone, Copy, Eq, PartialEq)]
71pub enum Hsi { 62pub enum Hsi {
72 /// 64Mhz 63 /// 64Mhz
diff --git a/embassy-stm32/src/rcc/l4l5.rs b/embassy-stm32/src/rcc/l4l5.rs
index a10169d6c..683b47c05 100644
--- a/embassy-stm32/src/rcc/l4l5.rs
+++ b/embassy-stm32/src/rcc/l4l5.rs
@@ -241,6 +241,7 @@ pub(crate) unsafe fn init(config: Config) {
241 w.set_ppre1(config.apb1_pre); 241 w.set_ppre1(config.apb1_pre);
242 w.set_ppre2(config.apb2_pre); 242 w.set_ppre2(config.apb2_pre);
243 }); 243 });
244 while RCC.cfgr().read().sws() != config.mux {}
244 245
245 let ahb_freq = sys_clk / config.ahb_pre; 246 let ahb_freq = sys_clk / config.ahb_pre;
246 247
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index d587a1988..49174b27f 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -13,8 +13,7 @@ pub use mco::*;
13#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] 13#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")]
14#[cfg_attr(rcc_f2, path = "f2.rs")] 14#[cfg_attr(rcc_f2, path = "f2.rs")]
15#[cfg_attr(any(rcc_f3, rcc_f3_v2), path = "f3.rs")] 15#[cfg_attr(any(rcc_f3, rcc_f3_v2), path = "f3.rs")]
16#[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")] 16#[cfg_attr(any(rcc_f4, rcc_f410, rcc_f7), path = "f4f7.rs")]
17#[cfg_attr(rcc_f7, path = "f7.rs")]
18#[cfg_attr(rcc_c0, path = "c0.rs")] 17#[cfg_attr(rcc_c0, path = "c0.rs")]
19#[cfg_attr(rcc_g0, path = "g0.rs")] 18#[cfg_attr(rcc_g0, path = "g0.rs")]
20#[cfg_attr(rcc_g4, path = "g4.rs")] 19#[cfg_attr(rcc_g4, path = "g4.rs")]
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs
index ddf8596ae..1747bbf4b 100644
--- a/examples/stm32f4/src/bin/eth.rs
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -10,7 +10,7 @@ use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, PacketQueue}; 10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH; 11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng; 12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz; 13use embassy_stm32::time::Hertz;
14use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 14use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
15use embassy_time::Timer; 15use embassy_time::Timer;
16use embedded_io_async::Write; 16use embedded_io_async::Write;
@@ -32,7 +32,25 @@ async fn net_task(stack: &'static Stack<Device>) -> ! {
32#[embassy_executor::main] 32#[embassy_executor::main]
33async fn main(spawner: Spawner) -> ! { 33async fn main(spawner: Spawner) -> ! {
34 let mut config = Config::default(); 34 let mut config = Config::default();
35 config.rcc.sys_ck = Some(mhz(200)); 35 {
36 use embassy_stm32::rcc::*;
37 config.rcc.hse = Some(Hse {
38 freq: Hertz(8_000_000),
39 mode: HseMode::Bypass,
40 });
41 config.rcc.pll_src = PllSource::HSE;
42 config.rcc.pll = Some(Pll {
43 prediv: PllPreDiv::DIV4,
44 mul: PllMul::MUL180,
45 divp: Some(Pllp::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz.
46 divq: None,
47 divr: None,
48 });
49 config.rcc.ahb_pre = AHBPrescaler::DIV1;
50 config.rcc.apb1_pre = APBPrescaler::DIV4;
51 config.rcc.apb2_pre = APBPrescaler::DIV2;
52 config.rcc.sys = Sysclk::PLL1_P;
53 }
36 let p = embassy_stm32::init(config); 54 let p = embassy_stm32::init(config);
37 55
38 info!("Hello World!"); 56 info!("Hello World!");
diff --git a/examples/stm32f4/src/bin/hello.rs b/examples/stm32f4/src/bin/hello.rs
index 27ee83aa5..a2a287110 100644
--- a/examples/stm32f4/src/bin/hello.rs
+++ b/examples/stm32f4/src/bin/hello.rs
@@ -4,15 +4,13 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::time::Hertz;
8use embassy_stm32::Config; 7use embassy_stm32::Config;
9use embassy_time::Timer; 8use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
11 10
12#[embassy_executor::main] 11#[embassy_executor::main]
13async fn main(_spawner: Spawner) -> ! { 12async fn main(_spawner: Spawner) -> ! {
14 let mut config = Config::default(); 13 let config = Config::default();
15 config.rcc.sys_ck = Some(Hertz(84_000_000));
16 let _p = embassy_stm32::init(config); 14 let _p = embassy_stm32::init(config);
17 15
18 loop { 16 loop {
diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs
index 6ec7d0fec..37e42384b 100644
--- a/examples/stm32f4/src/bin/sdmmc.rs
+++ b/examples/stm32f4/src/bin/sdmmc.rs
@@ -5,7 +5,7 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::sdmmc::{DataBlock, Sdmmc}; 7use embassy_stm32::sdmmc::{DataBlock, Sdmmc};
8use embassy_stm32::time::mhz; 8use embassy_stm32::time::{mhz, Hertz};
9use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
@@ -20,8 +20,25 @@ 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.sys_ck = Some(mhz(48)); 23 {
24 config.rcc.pll48 = true; 24 use embassy_stm32::rcc::*;
25 config.rcc.hse = Some(Hse {
26 freq: Hertz(8_000_000),
27 mode: HseMode::Bypass,
28 });
29 config.rcc.pll_src = PllSource::HSE;
30 config.rcc.pll = Some(Pll {
31 prediv: PllPreDiv::DIV4,
32 mul: PllMul::MUL168,
33 divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz.
34 divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz.
35 divr: None,
36 });
37 config.rcc.ahb_pre = AHBPrescaler::DIV1;
38 config.rcc.apb1_pre = APBPrescaler::DIV4;
39 config.rcc.apb2_pre = APBPrescaler::DIV2;
40 config.rcc.sys = Sysclk::PLL1_P;
41 }
25 let p = embassy_stm32::init(config); 42 let p = embassy_stm32::init(config);
26 info!("Hello World!"); 43 info!("Hello World!");
27 44
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index 763e3a9e7..7c0644aeb 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -7,7 +7,7 @@ use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket; 7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Stack, StackResources}; 8use embassy_net::{Stack, StackResources};
9use embassy_stm32::rng::{self, Rng}; 9use embassy_stm32::rng::{self, Rng};
10use embassy_stm32::time::mhz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::usb_otg::Driver; 11use embassy_stm32::usb_otg::Driver;
12use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 12use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
13use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; 13use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
@@ -46,9 +46,25 @@ async fn main(spawner: Spawner) {
46 info!("Hello World!"); 46 info!("Hello World!");
47 47
48 let mut config = Config::default(); 48 let mut config = Config::default();
49 config.rcc.pll48 = true; 49 {
50 config.rcc.sys_ck = Some(mhz(48)); 50 use embassy_stm32::rcc::*;
51 51 config.rcc.hse = Some(Hse {
52 freq: Hertz(8_000_000),
53 mode: HseMode::Bypass,
54 });
55 config.rcc.pll_src = PllSource::HSE;
56 config.rcc.pll = Some(Pll {
57 prediv: PllPreDiv::DIV4,
58 mul: PllMul::MUL168,
59 divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz.
60 divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz.
61 divr: None,
62 });
63 config.rcc.ahb_pre = AHBPrescaler::DIV1;
64 config.rcc.apb1_pre = APBPrescaler::DIV4;
65 config.rcc.apb2_pre = APBPrescaler::DIV2;
66 config.rcc.sys = Sysclk::PLL1_P;
67 }
52 let p = embassy_stm32::init(config); 68 let p = embassy_stm32::init(config);
53 69
54 // Create the driver, from the HAL. 70 // Create the driver, from the HAL.
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index 4ff6452ef..004ff038d 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -4,7 +4,7 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::time::mhz; 7use embassy_stm32::time::Hertz;
8use embassy_stm32::usb_otg::{Driver, Instance}; 8use embassy_stm32::usb_otg::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -22,9 +22,25 @@ async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 22 info!("Hello World!");
23 23
24 let mut config = Config::default(); 24 let mut config = Config::default();
25 config.rcc.pll48 = true; 25 {
26 config.rcc.sys_ck = Some(mhz(48)); 26 use embassy_stm32::rcc::*;
27 27 config.rcc.hse = Some(Hse {
28 freq: Hertz(8_000_000),
29 mode: HseMode::Bypass,
30 });
31 config.rcc.pll_src = PllSource::HSE;
32 config.rcc.pll = Some(Pll {
33 prediv: PllPreDiv::DIV4,
34 mul: PllMul::MUL168,
35 divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz.
36 divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz.
37 divr: None,
38 });
39 config.rcc.ahb_pre = AHBPrescaler::DIV1;
40 config.rcc.apb1_pre = APBPrescaler::DIV4;
41 config.rcc.apb2_pre = APBPrescaler::DIV2;
42 config.rcc.sys = Sysclk::PLL1_P;
43 }
28 let p = embassy_stm32::init(config); 44 let p = embassy_stm32::init(config);
29 45
30 // Create the driver, from the HAL. 46 // Create the driver, from the HAL.
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index d50473b9d..7c6c419a6 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -10,7 +10,7 @@ use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, PacketQueue}; 10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH; 11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng; 12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz; 13use embassy_stm32::time::Hertz;
14use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 14use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
15use embassy_time::Timer; 15use embassy_time::Timer;
16use embedded_io_async::Write; 16use embedded_io_async::Write;
@@ -33,7 +33,25 @@ async fn net_task(stack: &'static Stack<Device>) -> ! {
33#[embassy_executor::main] 33#[embassy_executor::main]
34async fn main(spawner: Spawner) -> ! { 34async fn main(spawner: Spawner) -> ! {
35 let mut config = Config::default(); 35 let mut config = Config::default();
36 config.rcc.sys_ck = Some(mhz(200)); 36 {
37 use embassy_stm32::rcc::*;
38 config.rcc.hse = Some(Hse {
39 freq: Hertz(8_000_000),
40 mode: HseMode::Bypass,
41 });
42 config.rcc.pll_src = PllSource::HSE;
43 config.rcc.pll = Some(Pll {
44 prediv: PllPreDiv::DIV4,
45 mul: PllMul::MUL216,
46 divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz
47 divq: None,
48 divr: None,
49 });
50 config.rcc.ahb_pre = AHBPrescaler::DIV1;
51 config.rcc.apb1_pre = APBPrescaler::DIV4;
52 config.rcc.apb2_pre = APBPrescaler::DIV2;
53 config.rcc.sys = Sysclk::PLL1_P;
54 }
37 let p = embassy_stm32::init(config); 55 let p = embassy_stm32::init(config);
38 56
39 info!("Hello World!"); 57 info!("Hello World!");
diff --git a/examples/stm32f7/src/bin/hello.rs b/examples/stm32f7/src/bin/hello.rs
index 27ee83aa5..a2a287110 100644
--- a/examples/stm32f7/src/bin/hello.rs
+++ b/examples/stm32f7/src/bin/hello.rs
@@ -4,15 +4,13 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::time::Hertz;
8use embassy_stm32::Config; 7use embassy_stm32::Config;
9use embassy_time::Timer; 8use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
11 10
12#[embassy_executor::main] 11#[embassy_executor::main]
13async fn main(_spawner: Spawner) -> ! { 12async fn main(_spawner: Spawner) -> ! {
14 let mut config = Config::default(); 13 let config = Config::default();
15 config.rcc.sys_ck = Some(Hertz(84_000_000));
16 let _p = embassy_stm32::init(config); 14 let _p = embassy_stm32::init(config);
17 15
18 loop { 16 loop {
diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs
index 9d43892a0..430aa781f 100644
--- a/examples/stm32f7/src/bin/sdmmc.rs
+++ b/examples/stm32f7/src/bin/sdmmc.rs
@@ -5,7 +5,7 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::sdmmc::Sdmmc; 7use embassy_stm32::sdmmc::Sdmmc;
8use embassy_stm32::time::mhz; 8use embassy_stm32::time::{mhz, Hertz};
9use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
@@ -16,8 +16,25 @@ 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.sys_ck = Some(mhz(200)); 19 {
20 config.rcc.pll48 = true; 20 use embassy_stm32::rcc::*;
21 config.rcc.hse = Some(Hse {
22 freq: Hertz(8_000_000),
23 mode: HseMode::Bypass,
24 });
25 config.rcc.pll_src = PllSource::HSE;
26 config.rcc.pll = Some(Pll {
27 prediv: PllPreDiv::DIV4,
28 mul: PllMul::MUL216,
29 divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz
30 divq: Some(Pllq::DIV9), // 8mhz / 4 * 216 / 9 = 48Mhz
31 divr: None,
32 });
33 config.rcc.ahb_pre = AHBPrescaler::DIV1;
34 config.rcc.apb1_pre = APBPrescaler::DIV4;
35 config.rcc.apb2_pre = APBPrescaler::DIV2;
36 config.rcc.sys = Sysclk::PLL1_P;
37 }
21 let p = embassy_stm32::init(config); 38 let p = embassy_stm32::init(config);
22 39
23 info!("Hello World!"); 40 info!("Hello World!");
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index a2c76178b..2f832c234 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -4,7 +4,7 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::time::mhz; 7use embassy_stm32::time::Hertz;
8use embassy_stm32::usb_otg::{Driver, Instance}; 8use embassy_stm32::usb_otg::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -22,10 +22,25 @@ async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 22 info!("Hello World!");
23 23
24 let mut config = Config::default(); 24 let mut config = Config::default();
25 config.rcc.hse = Some(mhz(8)); 25 {
26 config.rcc.pll48 = true; 26 use embassy_stm32::rcc::*;
27 config.rcc.sys_ck = Some(mhz(200)); 27 config.rcc.hse = Some(Hse {
28 28 freq: Hertz(8_000_000),
29 mode: HseMode::Bypass,
30 });
31 config.rcc.pll_src = PllSource::HSE;
32 config.rcc.pll = Some(Pll {
33 prediv: PllPreDiv::DIV4,
34 mul: PllMul::MUL216,
35 divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz
36 divq: Some(Pllq::DIV9), // 8mhz / 4 * 216 / 9 = 48Mhz
37 divr: None,
38 });
39 config.rcc.ahb_pre = AHBPrescaler::DIV1;
40 config.rcc.apb1_pre = APBPrescaler::DIV4;
41 config.rcc.apb2_pre = APBPrescaler::DIV2;
42 config.rcc.sys = Sysclk::PLL1_P;
43 }
29 let p = embassy_stm32::init(config); 44 let p = embassy_stm32::init(config);
30 45
31 // Create the driver, from the HAL. 46 // Create the driver, from the HAL.
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 9f1307ce5..8dde71fb3 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -224,16 +224,44 @@ pub fn config() -> Config {
224 224
225 #[cfg(feature = "stm32f429zi")] 225 #[cfg(feature = "stm32f429zi")]
226 { 226 {
227 // TODO: stm32f429zi can do up to 180mhz, but that makes tests fail. 227 use embassy_stm32::rcc::*;
228 // perhaps we have some bug w.r.t overdrive. 228 config.rcc.hse = Some(Hse {
229 config.rcc.sys_ck = Some(Hertz(168_000_000)); 229 freq: Hertz(8_000_000),
230 config.rcc.pclk1 = Some(Hertz(42_000_000)); 230 mode: HseMode::Bypass,
231 config.rcc.pclk2 = Some(Hertz(84_000_000)); 231 });
232 config.rcc.pll_src = PllSource::HSE;
233 config.rcc.pll = Some(Pll {
234 prediv: PllPreDiv::DIV4,
235 mul: PllMul::MUL180,
236 divp: Some(Pllp::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz.
237 divq: None,
238 divr: None,
239 });
240 config.rcc.ahb_pre = AHBPrescaler::DIV1;
241 config.rcc.apb1_pre = APBPrescaler::DIV4;
242 config.rcc.apb2_pre = APBPrescaler::DIV2;
243 config.rcc.sys = Sysclk::PLL1_P;
232 } 244 }
233 245
234 #[cfg(feature = "stm32f767zi")] 246 #[cfg(feature = "stm32f767zi")]
235 { 247 {
236 config.rcc.sys_ck = Some(Hertz(200_000_000)); 248 use embassy_stm32::rcc::*;
249 config.rcc.hse = Some(Hse {
250 freq: Hertz(8_000_000),
251 mode: HseMode::Bypass,
252 });
253 config.rcc.pll_src = PllSource::HSE;
254 config.rcc.pll = Some(Pll {
255 prediv: PllPreDiv::DIV4,
256 mul: PllMul::MUL216,
257 divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz.
258 divq: None,
259 divr: None,
260 });
261 config.rcc.ahb_pre = AHBPrescaler::DIV1;
262 config.rcc.apb1_pre = APBPrescaler::DIV4;
263 config.rcc.apb2_pre = APBPrescaler::DIV2;
264 config.rcc.sys = Sysclk::PLL1_P;
237 } 265 }
238 266
239 #[cfg(feature = "stm32h563zi")] 267 #[cfg(feature = "stm32h563zi")]