aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-09-19 04:22:57 +0200
committerDario Nieuwenhuis <[email protected]>2023-09-21 23:47:56 +0200
commit83b4c0127337c55c6a445abee6ab5eac4c993f9c (patch)
treedaa4050b6dd0bf7ecfae113c51ad2b21fe74e914
parente313ca4ae8bb4b7ab5dc4c348a471ccc5745b599 (diff)
stm32/rcc: unify h5 and h7.
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/rcc/h.rs777
-rw-r--r--embassy-stm32/src/rcc/h5.rs511
-rw-r--r--embassy-stm32/src/rcc/h7.rs934
-rw-r--r--embassy-stm32/src/rcc/mco.rs71
-rw-r--r--embassy-stm32/src/rcc/mod.rs14
-rw-r--r--examples/stm32f4/src/bin/eth.rs3
-rw-r--r--examples/stm32f7/src/bin/eth.rs3
-rw-r--r--examples/stm32h5/src/bin/eth.rs4
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32h7/src/bin/adc.rs34
-rw-r--r--examples/stm32h7/src/bin/camera.rs33
-rw-r--r--examples/stm32h7/src/bin/dac.rs32
-rw-r--r--examples/stm32h7/src/bin/dac_dma.rs33
-rw-r--r--examples/stm32h7/src/bin/eth.rs28
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs27
-rw-r--r--examples/stm32h7/src/bin/fmc.rs24
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs30
-rw-r--r--examples/stm32h7/src/bin/mco.rs4
-rw-r--r--examples/stm32h7/src/bin/pwm.rs29
-rw-r--r--examples/stm32h7/src/bin/rng.rs6
-rw-r--r--examples/stm32h7/src/bin/sdmmc.rs21
-rw-r--r--examples/stm32h7/src/bin/spi.rs23
-rw-r--r--examples/stm32h7/src/bin/spi_dma.rs23
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs25
-rw-r--r--tests/stm32/src/common.rs29
26 files changed, 1195 insertions, 1529 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 1a024e9a9..67f3f526b 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -59,7 +59,7 @@ sdio-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"
61atomic-polyfill = "1.0.1" 61atomic-polyfill = "1.0.1"
62stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2dba1f1ddee697e616aff2a4db57a6ffaf1b29b7" } 62stm32-metapac = { git = "https://ci.embassy.dev/jobs/7d2e0e63527f/artifacts/generated.git" }
63vcell = "0.1.3" 63vcell = "0.1.3"
64bxcan = "0.7.0" 64bxcan = "0.7.0"
65nb = "1.0.0" 65nb = "1.0.0"
@@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] }
78[build-dependencies] 78[build-dependencies]
79proc-macro2 = "1.0.36" 79proc-macro2 = "1.0.36"
80quote = "1.0.15" 80quote = "1.0.15"
81stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2dba1f1ddee697e616aff2a4db57a6ffaf1b29b7", default-features = false, features = ["metadata"]} 81stm32-metapac = { git = "https://ci.embassy.dev/jobs/7d2e0e63527f/artifacts/generated.git", default-features = false, features = ["metadata"]}
82 82
83[features] 83[features]
84default = ["rt"] 84default = ["rt"]
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
new file mode 100644
index 000000000..a4730ed49
--- /dev/null
+++ b/embassy-stm32/src/rcc/h.rs
@@ -0,0 +1,777 @@
1use core::ops::RangeInclusive;
2
3use crate::pac;
4use crate::pac::pwr::vals::Vos;
5#[cfg(stm32h5)]
6pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
7#[cfg(stm32h7)]
8pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
9pub use crate::pac::rcc::vals::Ckpersel as PerClockSource;
10use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre};
11use crate::pac::{FLASH, PWR, RCC};
12use crate::rcc::{set_freqs, Clocks};
13use crate::time::Hertz;
14
15/// HSI speed
16pub const HSI_FREQ: Hertz = Hertz(64_000_000);
17
18/// CSI speed
19pub const CSI_FREQ: Hertz = Hertz(4_000_000);
20
21/// HSI48 speed
22pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
23
24/// LSI speed
25pub const LSI_FREQ: Hertz = Hertz(32_000);
26
27const VCO_RANGE: RangeInclusive<u32> = 150_000_000..=420_000_000;
28#[cfg(any(stm32h5, pwr_h7rm0455))]
29const VCO_WIDE_RANGE: RangeInclusive<u32> = 128_000_000..=560_000_000;
30#[cfg(pwr_h7rm0468)]
31const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=836_000_000;
32#[cfg(any(pwr_h7rm0399, pwr_h7rm0433))]
33const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=960_000_000;
34
35pub use super::bus::{AHBPrescaler, APBPrescaler};
36
37#[derive(Clone, Copy, Eq, PartialEq)]
38pub enum VoltageScale {
39 Scale0,
40 Scale1,
41 Scale2,
42 Scale3,
43}
44
45#[derive(Clone, Copy, Eq, PartialEq)]
46pub enum HseMode {
47 /// crystal/ceramic oscillator (HSEBYP=0)
48 Oscillator,
49 /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
50 Bypass,
51 /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
52 #[cfg(any(rcc_h5, rcc_h50))]
53 BypassDigital,
54}
55
56#[derive(Clone, Copy, Eq, PartialEq)]
57pub struct Hse {
58 /// HSE frequency.
59 pub freq: Hertz,
60 /// HSE mode.
61 pub mode: HseMode,
62}
63
64#[derive(Clone, Copy, Eq, PartialEq)]
65pub enum Hsi {
66 /// 64Mhz
67 Mhz64,
68 /// 32Mhz (divided by 2)
69 Mhz32,
70 /// 16Mhz (divided by 4)
71 Mhz16,
72 /// 8Mhz (divided by 8)
73 Mhz8,
74}
75
76#[derive(Clone, Copy, Eq, PartialEq)]
77pub enum Sysclk {
78 /// HSI selected as sysclk
79 HSI,
80 /// HSE selected as sysclk
81 HSE,
82 /// CSI selected as sysclk
83 CSI,
84 /// PLL1_P selected as sysclk
85 Pll1P,
86}
87
88#[derive(Clone, Copy, Eq, PartialEq)]
89pub enum PllSource {
90 Hsi,
91 Csi,
92 Hse,
93}
94
95#[derive(Clone, Copy)]
96pub struct Pll {
97 /// Source clock selection.
98 #[cfg(stm32h5)]
99 pub source: PllSource,
100
101 /// PLL pre-divider (DIVM). Must be between 1 and 63.
102 pub prediv: u8,
103
104 /// PLL multiplication factor. Must be between 4 and 512.
105 pub mul: u16,
106
107 /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
108 /// On PLL1, it must be even (in particular, it cannot be 1.)
109 pub divp: Option<u16>,
110 /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
111 pub divq: Option<u16>,
112 /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
113 pub divr: Option<u16>,
114}
115
116fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz {
117 match (tim, apb) {
118 (TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk,
119 (TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk,
120 (TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32,
121 (TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32,
122 (TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32,
123
124 (TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk,
125 (TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk,
126 (TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk,
127 (TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32,
128 (TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32,
129
130 _ => unreachable!(),
131 }
132}
133
134/// Timer prescaler
135#[derive(Clone, Copy, Eq, PartialEq)]
136pub enum TimerPrescaler {
137 /// The timers kernel clock is equal to hclk if PPREx corresponds to a
138 /// division by 1 or 2, else it is equal to 2*pclk
139 DefaultX2,
140
141 /// The timers kernel clock is equal to hclk if PPREx corresponds to a
142 /// division by 1, 2 or 4, else it is equal to 4*pclk
143 DefaultX4,
144}
145
146impl From<TimerPrescaler> for Timpre {
147 fn from(value: TimerPrescaler) -> Self {
148 match value {
149 TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2,
150 TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4,
151 }
152 }
153}
154
155/// Configuration of the core clocks
156#[non_exhaustive]
157pub struct Config {
158 pub hsi: Option<Hsi>,
159 pub hse: Option<Hse>,
160 pub csi: bool,
161 pub hsi48: bool,
162 pub sys: Sysclk,
163
164 #[cfg(stm32h7)]
165 pub pll_src: PllSource,
166
167 pub pll1: Option<Pll>,
168 pub pll2: Option<Pll>,
169 #[cfg(any(rcc_h5, stm32h7))]
170 pub pll3: Option<Pll>,
171
172 pub d1c_pre: AHBPrescaler,
173 pub ahb_pre: AHBPrescaler,
174 pub apb1_pre: APBPrescaler,
175 pub apb2_pre: APBPrescaler,
176 pub apb3_pre: APBPrescaler,
177 #[cfg(stm32h7)]
178 pub apb4_pre: APBPrescaler,
179
180 pub per_clock_source: PerClockSource,
181 pub adc_clock_source: AdcClockSource,
182 pub timer_prescaler: TimerPrescaler,
183 pub voltage_scale: VoltageScale,
184}
185
186impl Default for Config {
187 fn default() -> Self {
188 Self {
189 hsi: Some(Hsi::Mhz64),
190 hse: None,
191 csi: false,
192 hsi48: false,
193 sys: Sysclk::HSI,
194 #[cfg(stm32h7)]
195 pll_src: PllSource::Hsi,
196 pll1: None,
197 pll2: None,
198 #[cfg(any(rcc_h5, stm32h7))]
199 pll3: None,
200
201 d1c_pre: AHBPrescaler::DIV1,
202 ahb_pre: AHBPrescaler::DIV1,
203 apb1_pre: APBPrescaler::DIV1,
204 apb2_pre: APBPrescaler::DIV1,
205 apb3_pre: APBPrescaler::DIV1,
206 #[cfg(stm32h7)]
207 apb4_pre: APBPrescaler::DIV1,
208
209 per_clock_source: PerClockSource::HSI,
210 adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5
211 timer_prescaler: TimerPrescaler::DefaultX2,
212 voltage_scale: VoltageScale::Scale0,
213 }
214 }
215}
216
217pub(crate) unsafe fn init(config: Config) {
218 #[cfg(stm32h7)]
219 RCC.apb4enr().modify(|w| w.set_syscfgen(true));
220 #[cfg(stm32h5)]
221 RCC.apb3enr().modify(|w| w.set_sbsen(true));
222
223 // NB. The lower bytes of CR3 can only be written once after
224 // POR, and must be written with a valid combination. Refer to
225 // RM0433 Rev 7 6.8.4. This is partially enforced by dropping
226 // `self` at the end of this method, but of course we cannot
227 // know what happened between the previous POR and here.
228 #[cfg(pwr_h7rm0433)]
229 PWR.cr3().modify(|w| {
230 w.set_scuen(true);
231 w.set_ldoen(true);
232 w.set_bypass(false);
233 });
234
235 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
236 PWR.cr3().modify(|w| {
237 // hardcode "Direct SPMS" for now, this is what works on nucleos with the
238 // default solderbridge configuration.
239 w.set_sden(true);
240 w.set_ldoen(false);
241 });
242
243 // Validate the supply configuration. If you are stuck here, it is
244 // because the voltages on your board do not match those specified
245 // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
246 // VOS = Scale 3, so check that the voltage on the VCAP pins =
247 // 1.0V.
248 #[cfg(any(pwr_h7rm0433, pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
249 while !PWR.csr1().read().actvosrdy() {}
250
251 // Configure voltage scale.
252 #[cfg(any(pwr_h5, pwr_h50))]
253 {
254 PWR.voscr().modify(|w| {
255 w.set_vos(match config.voltage_scale {
256 VoltageScale::Scale0 => Vos::SCALE0,
257 VoltageScale::Scale1 => Vos::SCALE1,
258 VoltageScale::Scale2 => Vos::SCALE2,
259 VoltageScale::Scale3 => Vos::SCALE3,
260 })
261 });
262 while !PWR.vossr().read().vosrdy() {}
263 }
264
265 #[cfg(syscfg_h7)]
266 {
267 // in chips without the overdrive bit, we can go from any scale to any scale directly.
268 PWR.d3cr().modify(|w| {
269 w.set_vos(match config.voltage_scale {
270 VoltageScale::Scale0 => Vos::SCALE0,
271 VoltageScale::Scale1 => Vos::SCALE1,
272 VoltageScale::Scale2 => Vos::SCALE2,
273 VoltageScale::Scale3 => Vos::SCALE3,
274 })
275 });
276 while !PWR.d3cr().read().vosrdy() {}
277 }
278
279 #[cfg(syscfg_h7od)]
280 {
281 match config.voltage_scale {
282 VoltageScale::Scale0 => {
283 // to go to scale0, we must go to Scale1 first...
284 PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1));
285 while !PWR.d3cr().read().vosrdy() {}
286
287 // Then enable overdrive.
288 critical_section::with(|_| pac::SYSCFG.pwrcr().modify(|w| w.set_oden(1)));
289 while !PWR.d3cr().read().vosrdy() {}
290 }
291 _ => {
292 // for all other scales, we can go directly.
293 PWR.d3cr().modify(|w| {
294 w.set_vos(match config.voltage_scale {
295 VoltageScale::Scale0 => unreachable!(),
296 VoltageScale::Scale1 => Vos::SCALE1,
297 VoltageScale::Scale2 => Vos::SCALE2,
298 VoltageScale::Scale3 => Vos::SCALE3,
299 })
300 });
301 while !PWR.d3cr().read().vosrdy() {}
302 }
303 }
304 }
305
306 // Configure HSI
307 let hsi = match config.hsi {
308 None => {
309 RCC.cr().modify(|w| w.set_hsion(false));
310 None
311 }
312 Some(hsi) => {
313 let (freq, hsidiv) = match hsi {
314 Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1),
315 Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2),
316 Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4),
317 Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8),
318 };
319 RCC.cr().modify(|w| {
320 w.set_hsidiv(hsidiv);
321 w.set_hsion(true);
322 });
323 while !RCC.cr().read().hsirdy() {}
324 Some(freq)
325 }
326 };
327
328 // Configure HSE
329 let hse = match config.hse {
330 None => {
331 RCC.cr().modify(|w| w.set_hseon(false));
332 None
333 }
334 Some(hse) => {
335 RCC.cr().modify(|w| {
336 w.set_hsebyp(hse.mode != HseMode::Oscillator);
337 #[cfg(any(rcc_h5, rcc_h50))]
338 w.set_hseext(match hse.mode {
339 HseMode::Oscillator | HseMode::Bypass => pac::rcc::vals::Hseext::ANALOG,
340 HseMode::BypassDigital => pac::rcc::vals::Hseext::DIGITAL,
341 });
342 });
343 RCC.cr().modify(|w| w.set_hseon(true));
344 while !RCC.cr().read().hserdy() {}
345 Some(hse.freq)
346 }
347 };
348
349 // Configure HSI48.
350 RCC.cr().modify(|w| w.set_hsi48on(config.hsi48));
351 let _hsi48 = match config.hsi48 {
352 false => None,
353 true => {
354 while !RCC.cr().read().hsi48rdy() {}
355 Some(CSI_FREQ)
356 }
357 };
358
359 // Configure CSI.
360 RCC.cr().modify(|w| w.set_csion(config.csi));
361 let csi = match config.csi {
362 false => None,
363 true => {
364 while !RCC.cr().read().csirdy() {}
365 Some(CSI_FREQ)
366 }
367 };
368
369 // Configure PLLs.
370 let pll_input = PllInput {
371 csi,
372 hse,
373 hsi,
374 #[cfg(stm32h7)]
375 source: config.pll_src,
376 };
377 let pll1 = init_pll(0, config.pll1, &pll_input);
378 let pll2 = init_pll(1, config.pll2, &pll_input);
379 #[cfg(any(rcc_h5, stm32h7))]
380 let _pll3 = init_pll(2, config.pll3, &pll_input);
381
382 // Configure sysclk
383 let (sys, sw) = match config.sys {
384 Sysclk::HSI => (unwrap!(hsi), Sw::HSI),
385 Sysclk::HSE => (unwrap!(hse), Sw::HSE),
386 Sysclk::CSI => (unwrap!(csi), Sw::CSI),
387 Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1),
388 };
389
390 // Check limits.
391 #[cfg(stm32h5)]
392 let (hclk_max, pclk_max) = match config.voltage_scale {
393 VoltageScale::Scale0 => (Hertz(250_000_000), Hertz(250_000_000)),
394 VoltageScale::Scale1 => (Hertz(200_000_000), Hertz(200_000_000)),
395 VoltageScale::Scale2 => (Hertz(150_000_000), Hertz(150_000_000)),
396 VoltageScale::Scale3 => (Hertz(100_000_000), Hertz(100_000_000)),
397 };
398 #[cfg(stm32h7)]
399 let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
400 VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)),
401 VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)),
402 VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)),
403 VoltageScale::Scale3 => (Hertz(200_000_000), Hertz(100_000_000), Hertz(50_000_000)),
404 };
405
406 #[cfg(stm32h7)]
407 let hclk = {
408 let d1cpre_clk = sys / config.d1c_pre;
409 assert!(d1cpre_clk <= d1cpre_clk_max);
410 sys / config.ahb_pre
411 };
412 #[cfg(stm32h5)]
413 let hclk = sys / config.ahb_pre;
414 assert!(hclk <= hclk_max);
415
416 let apb1 = hclk / config.apb1_pre;
417 let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler);
418 assert!(apb1 <= pclk_max);
419 let apb2 = hclk / config.apb2_pre;
420 let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler);
421 assert!(apb2 <= pclk_max);
422 let apb3 = hclk / config.apb3_pre;
423 assert!(apb3 <= pclk_max);
424 #[cfg(stm32h7)]
425 let apb4 = hclk / config.apb4_pre;
426 #[cfg(stm32h7)]
427 assert!(apb4 <= pclk_max);
428
429 let _per_ck = match config.per_clock_source {
430 Ckpersel::HSI => hsi,
431 Ckpersel::CSI => csi,
432 Ckpersel::HSE => hse,
433 _ => unreachable!(),
434 };
435
436 #[cfg(stm32h7)]
437 let adc = match config.adc_clock_source {
438 AdcClockSource::PLL2_P => pll2.p,
439 AdcClockSource::PLL3_R => _pll3.r,
440 AdcClockSource::PER => _per_ck,
441 _ => unreachable!(),
442 };
443 #[cfg(stm32h5)]
444 let adc = match config.adc_clock_source {
445 AdcClockSource::HCLK => Some(hclk),
446 AdcClockSource::SYSCLK => Some(sys),
447 AdcClockSource::PLL2_R => pll2.r,
448 AdcClockSource::HSE => hse,
449 AdcClockSource::HSI_KER => hsi,
450 AdcClockSource::CSI_KER => csi,
451 _ => unreachable!(),
452 };
453
454 flash_setup(hclk, config.voltage_scale);
455
456 #[cfg(stm32h7)]
457 {
458 RCC.d1cfgr().modify(|w| {
459 w.set_d1cpre(config.d1c_pre);
460 w.set_d1ppre(config.apb3_pre);
461 w.set_hpre(config.ahb_pre);
462 });
463 // Ensure core prescaler value is valid before future lower core voltage
464 while RCC.d1cfgr().read().d1cpre() != config.d1c_pre {}
465
466 RCC.d2cfgr().modify(|w| {
467 w.set_d2ppre1(config.apb1_pre);
468 w.set_d2ppre2(config.apb2_pre);
469 });
470 RCC.d3cfgr().modify(|w| {
471 w.set_d3ppre(config.apb4_pre);
472 });
473
474 RCC.d1ccipr().modify(|w| {
475 w.set_ckpersel(config.per_clock_source);
476 });
477 RCC.d3ccipr().modify(|w| {
478 w.set_adcsel(config.adc_clock_source);
479 });
480 }
481 #[cfg(stm32h5)]
482 {
483 // Set hpre
484 RCC.cfgr2().modify(|w| w.set_hpre(config.ahb_pre));
485 while RCC.cfgr2().read().hpre() != config.ahb_pre {}
486
487 // set ppre
488 RCC.cfgr2().modify(|w| {
489 w.set_ppre1(config.apb1_pre);
490 w.set_ppre2(config.apb2_pre);
491 w.set_ppre3(config.apb3_pre);
492 });
493
494 RCC.ccipr5().modify(|w| {
495 w.set_ckpersel(config.per_clock_source);
496 w.set_adcdacsel(config.adc_clock_source)
497 });
498 }
499
500 RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
501
502 RCC.cfgr().modify(|w| w.set_sw(sw));
503 while RCC.cfgr().read().sws() != sw {}
504
505 // IO compensation cell - Requires CSI clock and SYSCFG
506 #[cfg(stm32h7)] // TODO h5
507 if csi.is_some() {
508 // Enable the compensation cell, using back-bias voltage code
509 // provide by the cell.
510 critical_section::with(|_| {
511 pac::SYSCFG.cccsr().modify(|w| {
512 w.set_en(true);
513 w.set_cs(false);
514 w.set_hslv(false);
515 })
516 });
517 while !pac::SYSCFG.cccsr().read().ready() {}
518 }
519
520 set_freqs(Clocks {
521 sys,
522 ahb1: hclk,
523 ahb2: hclk,
524 ahb3: hclk,
525 ahb4: hclk,
526 apb1,
527 apb2,
528 apb3,
529 #[cfg(stm32h7)]
530 apb4,
531 apb1_tim,
532 apb2_tim,
533 adc: adc,
534 });
535}
536
537struct PllInput {
538 hsi: Option<Hertz>,
539 hse: Option<Hertz>,
540 csi: Option<Hertz>,
541 #[cfg(stm32h7)]
542 source: PllSource,
543}
544
545struct PllOutput {
546 p: Option<Hertz>,
547 #[allow(dead_code)]
548 q: Option<Hertz>,
549 #[allow(dead_code)]
550 r: Option<Hertz>,
551}
552
553fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
554 let Some(config) = config else {
555 // Stop PLL
556 RCC.cr().modify(|w| w.set_pllon(num, false));
557 while RCC.cr().read().pllrdy(num) {}
558
559 // "To save power when PLL1 is not used, the value of PLL1M must be set to 0.""
560 #[cfg(stm32h7)]
561 RCC.pllckselr().write(|w| w.set_divm(num, 0));
562 #[cfg(stm32h5)]
563 RCC.pllcfgr(num).write(|w| w.set_divm(0));
564
565 return PllOutput {
566 p: None,
567 q: None,
568 r: None,
569 };
570 };
571
572 assert!(1 <= config.prediv && config.prediv <= 63);
573 assert!(4 <= config.mul && config.mul <= 512);
574
575 #[cfg(stm32h5)]
576 let source = config.source;
577 #[cfg(stm32h7)]
578 let source = input.source;
579
580 let (in_clk, src) = match source {
581 PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI),
582 PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE),
583 PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI),
584 };
585
586 let ref_clk = in_clk / config.prediv as u32;
587
588 let ref_range = match ref_clk.0 {
589 ..=1_999_999 => Pllrge::RANGE1,
590 ..=3_999_999 => Pllrge::RANGE2,
591 ..=7_999_999 => Pllrge::RANGE4,
592 ..=16_000_000 => Pllrge::RANGE8,
593 x => panic!("pll ref_clk out of range: {} mhz", x),
594 };
595
596 // The smaller range (150 to 420 MHz) must
597 // be chosen when the reference clock frequency is lower than 2 MHz.
598 let wide_allowed = ref_range != Pllrge::RANGE1;
599
600 let vco_clk = ref_clk * config.mul;
601 let vco_range = if VCO_RANGE.contains(&vco_clk.0) {
602 Pllvcosel::MEDIUMVCO
603 } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk.0) {
604 Pllvcosel::WIDEVCO
605 } else {
606 panic!("pll vco_clk out of range: {} mhz", vco_clk.0)
607 };
608
609 let p = config.divp.map(|div| {
610 assert!(1 <= div && div <= 128);
611 if num == 0 {
612 // on PLL1, DIVP must be even.
613 assert!(div % 2 == 0);
614 }
615
616 vco_clk / div
617 });
618 let q = config.divq.map(|div| {
619 assert!(1 <= div && div <= 128);
620 vco_clk / div
621 });
622 let r = config.divr.map(|div| {
623 assert!(1 <= div && div <= 128);
624 vco_clk / div
625 });
626
627 #[cfg(stm32h5)]
628 RCC.pllcfgr(num).write(|w| {
629 w.set_pllsrc(src);
630 w.set_divm(config.prediv);
631 w.set_pllvcosel(vco_range);
632 w.set_pllrge(ref_range);
633 w.set_pllfracen(false);
634 w.set_pllpen(p.is_some());
635 w.set_pllqen(q.is_some());
636 w.set_pllren(r.is_some());
637 });
638
639 #[cfg(stm32h7)]
640 {
641 RCC.pllckselr().modify(|w| {
642 w.set_divm(num, config.prediv);
643 w.set_pllsrc(src);
644 });
645 RCC.pllcfgr().modify(|w| {
646 w.set_pllvcosel(num, vco_range);
647 w.set_pllrge(num, ref_range);
648 w.set_pllfracen(num, false);
649 w.set_divpen(num, p.is_some());
650 w.set_divqen(num, q.is_some());
651 w.set_divren(num, r.is_some());
652 });
653 }
654
655 RCC.plldivr(num).write(|w| {
656 w.set_plln(config.mul - 1);
657 w.set_pllp((config.divp.unwrap_or(1) - 1) as u8);
658 w.set_pllq((config.divq.unwrap_or(1) - 1) as u8);
659 w.set_pllr((config.divr.unwrap_or(1) - 1) as u8);
660 });
661
662 RCC.cr().modify(|w| w.set_pllon(num, true));
663 while !RCC.cr().read().pllrdy(num) {}
664
665 PllOutput { p, q, r }
666}
667
668fn flash_setup(clk: Hertz, vos: VoltageScale) {
669 // RM0481 Rev 1, table 37
670 // LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0
671 // 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz
672 // 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz
673 // 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz
674 // 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz
675 // 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz
676 // 5 2 170 to 200 MHz 210 to 250 MHz
677 #[cfg(stm32h5)]
678 let (latency, wrhighfreq) = match (vos, clk.0) {
679 (VoltageScale::Scale0, ..=42_000_000) => (0, 0),
680 (VoltageScale::Scale0, ..=84_000_000) => (1, 0),
681 (VoltageScale::Scale0, ..=126_000_000) => (2, 1),
682 (VoltageScale::Scale0, ..=168_000_000) => (3, 1),
683 (VoltageScale::Scale0, ..=210_000_000) => (4, 2),
684 (VoltageScale::Scale0, ..=250_000_000) => (5, 2),
685
686 (VoltageScale::Scale1, ..=34_000_000) => (0, 0),
687 (VoltageScale::Scale1, ..=68_000_000) => (1, 0),
688 (VoltageScale::Scale1, ..=102_000_000) => (2, 1),
689 (VoltageScale::Scale1, ..=136_000_000) => (3, 1),
690 (VoltageScale::Scale1, ..=170_000_000) => (4, 2),
691 (VoltageScale::Scale1, ..=200_000_000) => (5, 2),
692
693 (VoltageScale::Scale2, ..=30_000_000) => (0, 0),
694 (VoltageScale::Scale2, ..=60_000_000) => (1, 0),
695 (VoltageScale::Scale2, ..=90_000_000) => (2, 1),
696 (VoltageScale::Scale2, ..=120_000_000) => (3, 1),
697 (VoltageScale::Scale2, ..=150_000_000) => (4, 2),
698
699 (VoltageScale::Scale3, ..=20_000_000) => (0, 0),
700 (VoltageScale::Scale3, ..=40_000_000) => (1, 0),
701 (VoltageScale::Scale3, ..=60_000_000) => (2, 1),
702 (VoltageScale::Scale3, ..=80_000_000) => (3, 1),
703 (VoltageScale::Scale3, ..=100_000_000) => (4, 2),
704
705 _ => unreachable!(),
706 };
707
708 #[cfg(flash_h7)]
709 let (latency, wrhighfreq) = match (vos, clk.0) {
710 // VOS 0 range VCORE 1.26V - 1.40V
711 (VoltageScale::Scale0, ..=70_000_000) => (0, 0),
712 (VoltageScale::Scale0, ..=140_000_000) => (1, 1),
713 (VoltageScale::Scale0, ..=185_000_000) => (2, 1),
714 (VoltageScale::Scale0, ..=210_000_000) => (2, 2),
715 (VoltageScale::Scale0, ..=225_000_000) => (3, 2),
716 (VoltageScale::Scale0, ..=240_000_000) => (4, 2),
717 // VOS 1 range VCORE 1.15V - 1.26V
718 (VoltageScale::Scale1, ..=70_000_000) => (0, 0),
719 (VoltageScale::Scale1, ..=140_000_000) => (1, 1),
720 (VoltageScale::Scale1, ..=185_000_000) => (2, 1),
721 (VoltageScale::Scale1, ..=210_000_000) => (2, 2),
722 (VoltageScale::Scale1, ..=225_000_000) => (3, 2),
723 // VOS 2 range VCORE 1.05V - 1.15V
724 (VoltageScale::Scale2, ..=55_000_000) => (0, 0),
725 (VoltageScale::Scale2, ..=110_000_000) => (1, 1),
726 (VoltageScale::Scale2, ..=165_000_000) => (2, 1),
727 (VoltageScale::Scale2, ..=224_000_000) => (3, 2),
728 // VOS 3 range VCORE 0.95V - 1.05V
729 (VoltageScale::Scale3, ..=45_000_000) => (0, 0),
730 (VoltageScale::Scale3, ..=90_000_000) => (1, 1),
731 (VoltageScale::Scale3, ..=135_000_000) => (2, 1),
732 (VoltageScale::Scale3, ..=180_000_000) => (3, 2),
733 (VoltageScale::Scale3, ..=224_000_000) => (4, 2),
734 _ => unreachable!(),
735 };
736
737 // See RM0455 Rev 10 Table 16. FLASH recommended number of wait
738 // states and programming delay
739 #[cfg(flash_h7ab)]
740 let (latency, wrhighfreq) = match (vos, clk.0) {
741 // VOS 0 range VCORE 1.25V - 1.35V
742 (VoltageScale::Scale0, ..=42_000_000) => (0, 0),
743 (VoltageScale::Scale0, ..=84_000_000) => (1, 0),
744 (VoltageScale::Scale0, ..=126_000_000) => (2, 1),
745 (VoltageScale::Scale0, ..=168_000_000) => (3, 1),
746 (VoltageScale::Scale0, ..=210_000_000) => (4, 2),
747 (VoltageScale::Scale0, ..=252_000_000) => (5, 2),
748 (VoltageScale::Scale0, ..=280_000_000) => (6, 3),
749 // VOS 1 range VCORE 1.15V - 1.25V
750 (VoltageScale::Scale1, ..=38_000_000) => (0, 0),
751 (VoltageScale::Scale1, ..=76_000_000) => (1, 0),
752 (VoltageScale::Scale1, ..=114_000_000) => (2, 1),
753 (VoltageScale::Scale1, ..=152_000_000) => (3, 1),
754 (VoltageScale::Scale1, ..=190_000_000) => (4, 2),
755 (VoltageScale::Scale1, ..=225_000_000) => (5, 2),
756 // VOS 2 range VCORE 1.05V - 1.15V
757 (VoltageScale::Scale2, ..=34) => (0, 0),
758 (VoltageScale::Scale2, ..=68) => (1, 0),
759 (VoltageScale::Scale2, ..=102) => (2, 1),
760 (VoltageScale::Scale2, ..=136) => (3, 1),
761 (VoltageScale::Scale2, ..=160) => (4, 2),
762 // VOS 3 range VCORE 0.95V - 1.05V
763 (VoltageScale::Scale3, ..=22) => (0, 0),
764 (VoltageScale::Scale3, ..=44) => (1, 0),
765 (VoltageScale::Scale3, ..=66) => (2, 1),
766 (VoltageScale::Scale3, ..=88) => (3, 1),
767 _ => unreachable!(),
768 };
769
770 debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
771
772 FLASH.acr().write(|w| {
773 w.set_wrhighfreq(wrhighfreq);
774 w.set_latency(latency);
775 });
776 while FLASH.acr().read().latency() != latency {}
777}
diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs
deleted file mode 100644
index 15f28c5dc..000000000
--- a/embassy-stm32/src/rcc/h5.rs
+++ /dev/null
@@ -1,511 +0,0 @@
1use core::marker::PhantomData;
2
3use stm32_metapac::rcc::vals::Timpre;
4
5use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw};
6use crate::pac::{FLASH, PWR, RCC};
7use crate::rcc::{set_freqs, Clocks};
8use crate::time::Hertz;
9use crate::{peripherals, Peripheral};
10
11/// HSI speed
12pub const HSI_FREQ: Hertz = Hertz(64_000_000);
13
14/// CSI speed
15pub const CSI_FREQ: Hertz = Hertz(4_000_000);
16
17/// HSI48 speed
18pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
19
20/// LSI speed
21pub const LSI_FREQ: Hertz = Hertz(32_000);
22
23const VCO_MIN: u32 = 150_000_000;
24const VCO_MAX: u32 = 420_000_000;
25const VCO_WIDE_MIN: u32 = 128_000_000;
26const VCO_WIDE_MAX: u32 = 560_000_000;
27
28pub use super::bus::{AHBPrescaler, APBPrescaler};
29pub use crate::pac::pwr::vals::Vos as VoltageScale;
30
31pub enum HseMode {
32 /// crystal/ceramic oscillator (HSEBYP=0)
33 Oscillator,
34 /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
35 BypassAnalog,
36 /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
37 BypassDigital,
38}
39
40pub struct Hse {
41 /// HSE frequency.
42 pub freq: Hertz,
43 /// HSE mode.
44 pub mode: HseMode,
45}
46
47pub enum Hsi {
48 /// 64Mhz
49 Mhz64,
50 /// 32Mhz (divided by 2)
51 Mhz32,
52 /// 16Mhz (divided by 4)
53 Mhz16,
54 /// 8Mhz (divided by 8)
55 Mhz8,
56}
57
58pub enum Sysclk {
59 /// HSI selected as sysclk
60 HSI,
61 /// HSE selected as sysclk
62 HSE,
63 /// CSI selected as sysclk
64 CSI,
65 /// PLL1_P selected as sysclk
66 Pll1P,
67}
68
69pub enum PllSource {
70 Hsi,
71 Csi,
72 Hse,
73}
74
75pub struct Pll {
76 /// Source clock selection.
77 pub source: PllSource,
78
79 /// PLL pre-divider (DIVM). Must be between 1 and 63.
80 pub prediv: u8,
81
82 /// PLL multiplication factor. Must be between 4 and 512.
83 pub mul: u16,
84
85 /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
86 /// On PLL1, it must be even (in particular, it cannot be 1.)
87 pub divp: Option<u16>,
88 /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
89 pub divq: Option<u16>,
90 /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
91 pub divr: Option<u16>,
92}
93
94fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz {
95 match (tim, apb) {
96 // The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a
97 // division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2
98 (TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk,
99 (TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk,
100 (TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32,
101 (TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32,
102 (TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32,
103 // The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2
104 // corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2
105 // this makes NO SENSE and is different than in the H7. Mistake in the RM??
106 (TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk * 2u32,
107 (TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk,
108 (TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk / 2u32,
109 (TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32,
110 (TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32,
111
112 _ => unreachable!(),
113 }
114}
115
116/// APB prescaler
117#[derive(Clone, Copy)]
118pub enum TimerPrescaler {
119 DefaultX2,
120 DefaultX4,
121}
122
123impl From<TimerPrescaler> for Timpre {
124 fn from(value: TimerPrescaler) -> Self {
125 match value {
126 TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2,
127 TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4,
128 }
129 }
130}
131
132/// Configuration of the core clocks
133#[non_exhaustive]
134pub struct Config {
135 pub hsi: Option<Hsi>,
136 pub hse: Option<Hse>,
137 pub csi: bool,
138 pub hsi48: bool,
139 pub sys: Sysclk,
140
141 pub pll1: Option<Pll>,
142 pub pll2: Option<Pll>,
143 #[cfg(rcc_h5)]
144 pub pll3: Option<Pll>,
145
146 pub ahb_pre: AHBPrescaler,
147 pub apb1_pre: APBPrescaler,
148 pub apb2_pre: APBPrescaler,
149 pub apb3_pre: APBPrescaler,
150 pub timer_prescaler: TimerPrescaler,
151
152 pub voltage_scale: VoltageScale,
153}
154
155impl Default for Config {
156 fn default() -> Self {
157 Self {
158 hsi: Some(Hsi::Mhz64),
159 hse: None,
160 csi: false,
161 hsi48: false,
162 sys: Sysclk::HSI,
163 pll1: None,
164 pll2: None,
165 #[cfg(rcc_h5)]
166 pll3: None,
167
168 ahb_pre: AHBPrescaler::DIV1,
169 apb1_pre: APBPrescaler::DIV1,
170 apb2_pre: APBPrescaler::DIV1,
171 apb3_pre: APBPrescaler::DIV1,
172 timer_prescaler: TimerPrescaler::DefaultX2,
173
174 voltage_scale: VoltageScale::SCALE3,
175 }
176 }
177}
178
179pub(crate) mod sealed {
180 pub trait McoInstance {
181 type Source;
182 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
183 }
184}
185
186pub trait McoInstance: sealed::McoInstance + 'static {}
187
188pin_trait!(McoPin, McoInstance);
189
190macro_rules! impl_peri {
191 ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
192 impl sealed::McoInstance for peripherals::$peri {
193 type Source = $source;
194
195 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
196 RCC.cfgr().modify(|w| {
197 w.$set_source(source);
198 w.$set_prescaler(prescaler);
199 });
200 }
201 }
202
203 impl McoInstance for peripherals::$peri {}
204 };
205}
206
207impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre);
208impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre);
209
210pub struct Mco<'d, T: McoInstance> {
211 phantom: PhantomData<&'d mut T>,
212}
213
214impl<'d, T: McoInstance> Mco<'d, T> {
215 pub fn new(
216 _peri: impl Peripheral<P = T> + 'd,
217 _pin: impl Peripheral<P = impl McoPin<T>> + 'd,
218 _source: T::Source,
219 ) -> Self {
220 todo!();
221 }
222}
223
224pub(crate) unsafe fn init(config: Config) {
225 let max_clk = match config.voltage_scale {
226 VoltageScale::SCALE0 => Hertz(250_000_000),
227 VoltageScale::SCALE1 => Hertz(200_000_000),
228 VoltageScale::SCALE2 => Hertz(150_000_000),
229 VoltageScale::SCALE3 => Hertz(100_000_000),
230 };
231
232 // Configure voltage scale.
233 PWR.voscr().modify(|w| w.set_vos(config.voltage_scale));
234 while !PWR.vossr().read().vosrdy() {}
235
236 // Configure HSI
237 let hsi = match config.hsi {
238 None => {
239 RCC.cr().modify(|w| w.set_hsion(false));
240 None
241 }
242 Some(hsi) => {
243 let (freq, hsidiv) = match hsi {
244 Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1),
245 Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2),
246 Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4),
247 Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8),
248 };
249 RCC.cr().modify(|w| {
250 w.set_hsidiv(hsidiv);
251 w.set_hsion(true);
252 });
253 while !RCC.cr().read().hsirdy() {}
254 Some(freq)
255 }
256 };
257
258 // Configure HSE
259 let hse = match config.hse {
260 None => {
261 RCC.cr().modify(|w| w.set_hseon(false));
262 None
263 }
264 Some(hse) => {
265 let (byp, ext) = match hse.mode {
266 HseMode::Oscillator => (false, Hseext::ANALOG),
267 HseMode::BypassAnalog => (true, Hseext::ANALOG),
268 HseMode::BypassDigital => (true, Hseext::DIGITAL),
269 };
270
271 RCC.cr().modify(|w| {
272 w.set_hsebyp(byp);
273 w.set_hseext(ext);
274 });
275 RCC.cr().modify(|w| w.set_hseon(true));
276 while !RCC.cr().read().hserdy() {}
277 Some(hse.freq)
278 }
279 };
280
281 // Configure HSI48.
282 RCC.cr().modify(|w| w.set_hsi48on(config.hsi48));
283 let _hsi48 = match config.hsi48 {
284 false => None,
285 true => {
286 while !RCC.cr().read().hsi48rdy() {}
287 Some(CSI_FREQ)
288 }
289 };
290
291 // Configure CSI.
292 RCC.cr().modify(|w| w.set_csion(config.csi));
293 let csi = match config.csi {
294 false => None,
295 true => {
296 while !RCC.cr().read().csirdy() {}
297 Some(CSI_FREQ)
298 }
299 };
300
301 // Configure PLLs.
302 let pll_input = PllInput { csi, hse, hsi };
303 let pll1 = init_pll(0, config.pll1, &pll_input);
304 let _pll2 = init_pll(1, config.pll2, &pll_input);
305 #[cfg(rcc_h5)]
306 let _pll3 = init_pll(2, config.pll3, &pll_input);
307
308 // Configure sysclk
309 let (sys, sw) = match config.sys {
310 Sysclk::HSI => (unwrap!(hsi), Sw::HSI),
311 Sysclk::HSE => (unwrap!(hse), Sw::HSE),
312 Sysclk::CSI => (unwrap!(csi), Sw::CSI),
313 Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1),
314 };
315 assert!(sys <= max_clk);
316
317 let hclk = sys / config.ahb_pre;
318
319 let apb1 = hclk / config.apb1_pre;
320 let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler);
321 let apb2 = hclk / config.apb2_pre;
322 let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler);
323 let apb3 = hclk / config.apb3_pre;
324
325 flash_setup(hclk, config.voltage_scale);
326
327 // Set hpre
328 let hpre = config.ahb_pre.into();
329 RCC.cfgr2().modify(|w| w.set_hpre(hpre));
330 while RCC.cfgr2().read().hpre() != hpre {}
331
332 // set ppre
333 RCC.cfgr2().modify(|w| {
334 w.set_ppre1(config.apb1_pre.into());
335 w.set_ppre2(config.apb2_pre.into());
336 w.set_ppre3(config.apb3_pre.into());
337 });
338
339 RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
340
341 RCC.cfgr().modify(|w| w.set_sw(sw));
342 while RCC.cfgr().read().sws() != sw {}
343
344 set_freqs(Clocks {
345 sys,
346 ahb1: hclk,
347 ahb2: hclk,
348 ahb3: hclk,
349 ahb4: hclk,
350 apb1,
351 apb2,
352 apb3,
353 apb1_tim,
354 apb2_tim,
355 adc: None,
356 });
357}
358
359struct PllInput {
360 hsi: Option<Hertz>,
361 hse: Option<Hertz>,
362 csi: Option<Hertz>,
363}
364
365struct PllOutput {
366 p: Option<Hertz>,
367 #[allow(dead_code)]
368 q: Option<Hertz>,
369 #[allow(dead_code)]
370 r: Option<Hertz>,
371}
372
373fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
374 let Some(config) = config else {
375 // Stop PLL
376 RCC.cr().modify(|w| w.set_pllon(num, false));
377 while RCC.cr().read().pllrdy(num) {}
378
379 // "To save power when PLL1 is not used, the value of PLL1M must be set to 0.""
380 RCC.pllcfgr(num).write(|w| {
381 w.set_divm(0);
382 });
383
384 return PllOutput {
385 p: None,
386 q: None,
387 r: None,
388 };
389 };
390
391 assert!(1 <= config.prediv && config.prediv <= 63);
392 assert!(4 <= config.mul && config.mul <= 512);
393
394 let (in_clk, src) = match config.source {
395 PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI),
396 PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE),
397 PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI),
398 };
399
400 let ref_clk = in_clk / config.prediv as u32;
401
402 let ref_range = match ref_clk.0 {
403 ..=1_999_999 => Pllrge::RANGE1,
404 ..=3_999_999 => Pllrge::RANGE2,
405 ..=7_999_999 => Pllrge::RANGE4,
406 ..=16_000_000 => Pllrge::RANGE8,
407 x => panic!("pll ref_clk out of range: {} mhz", x),
408 };
409
410 // The smaller range (150 to 420 MHz) must
411 // be chosen when the reference clock frequency is lower than 2 MHz.
412 let wide_allowed = ref_range != Pllrge::RANGE1;
413
414 let vco_clk = ref_clk * config.mul;
415 let vco_range = match vco_clk.0 {
416 VCO_MIN..=VCO_MAX => Pllvcosel::MEDIUMVCO,
417 VCO_WIDE_MIN..=VCO_WIDE_MAX if wide_allowed => Pllvcosel::WIDEVCO,
418 x => panic!("pll vco_clk out of range: {} mhz", x),
419 };
420
421 let p = config.divp.map(|div| {
422 assert!(1 <= div && div <= 128);
423 if num == 0 {
424 // on PLL1, DIVP must be even.
425 assert!(div % 2 == 0);
426 }
427
428 vco_clk / div
429 });
430 let q = config.divq.map(|div| {
431 assert!(1 <= div && div <= 128);
432 vco_clk / div
433 });
434 let r = config.divr.map(|div| {
435 assert!(1 <= div && div <= 128);
436 vco_clk / div
437 });
438
439 RCC.pllcfgr(num).write(|w| {
440 w.set_pllsrc(src);
441 w.set_divm(config.prediv);
442 w.set_pllvcosel(vco_range);
443 w.set_pllrge(ref_range);
444 w.set_pllfracen(false);
445 w.set_pllpen(p.is_some());
446 w.set_pllqen(q.is_some());
447 w.set_pllren(r.is_some());
448 });
449 RCC.plldivr(num).write(|w| {
450 w.set_plln(config.mul - 1);
451 w.set_pllp((config.divp.unwrap_or(1) - 1) as u8);
452 w.set_pllq((config.divq.unwrap_or(1) - 1) as u8);
453 w.set_pllr((config.divr.unwrap_or(1) - 1) as u8);
454 });
455
456 RCC.cr().modify(|w| w.set_pllon(num, true));
457 while !RCC.cr().read().pllrdy(num) {}
458
459 PllOutput { p, q, r }
460}
461
462fn flash_setup(clk: Hertz, vos: VoltageScale) {
463 // RM0481 Rev 1, table 37
464 // LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0
465 // 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz
466 // 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz
467 // 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz
468 // 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz
469 // 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz
470 // 5 2 170 to 200 MHz 210 to 250 MHz
471
472 // See RM0433 Rev 7 Table 17. FLASH recommended number of wait
473 // states and programming delay
474 let (latency, wrhighfreq) = match (vos, clk.0) {
475 (VoltageScale::SCALE0, ..=42_000_000) => (0, 0),
476 (VoltageScale::SCALE0, ..=84_000_000) => (1, 0),
477 (VoltageScale::SCALE0, ..=126_000_000) => (2, 1),
478 (VoltageScale::SCALE0, ..=168_000_000) => (3, 1),
479 (VoltageScale::SCALE0, ..=210_000_000) => (4, 2),
480 (VoltageScale::SCALE0, ..=250_000_000) => (5, 2),
481
482 (VoltageScale::SCALE1, ..=34_000_000) => (0, 0),
483 (VoltageScale::SCALE1, ..=68_000_000) => (1, 0),
484 (VoltageScale::SCALE1, ..=102_000_000) => (2, 1),
485 (VoltageScale::SCALE1, ..=136_000_000) => (3, 1),
486 (VoltageScale::SCALE1, ..=170_000_000) => (4, 2),
487 (VoltageScale::SCALE1, ..=200_000_000) => (5, 2),
488
489 (VoltageScale::SCALE2, ..=30_000_000) => (0, 0),
490 (VoltageScale::SCALE2, ..=60_000_000) => (1, 0),
491 (VoltageScale::SCALE2, ..=90_000_000) => (2, 1),
492 (VoltageScale::SCALE2, ..=120_000_000) => (3, 1),
493 (VoltageScale::SCALE2, ..=150_000_000) => (4, 2),
494
495 (VoltageScale::SCALE3, ..=20_000_000) => (0, 0),
496 (VoltageScale::SCALE3, ..=40_000_000) => (1, 0),
497 (VoltageScale::SCALE3, ..=60_000_000) => (2, 1),
498 (VoltageScale::SCALE3, ..=80_000_000) => (3, 1),
499 (VoltageScale::SCALE3, ..=100_000_000) => (4, 2),
500
501 _ => unreachable!(),
502 };
503
504 debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
505
506 FLASH.acr().write(|w| {
507 w.set_wrhighfreq(wrhighfreq);
508 w.set_latency(latency);
509 });
510 while FLASH.acr().read().latency() != latency {}
511}
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs
deleted file mode 100644
index ea26c26c1..000000000
--- a/embassy-stm32/src/rcc/h7.rs
+++ /dev/null
@@ -1,934 +0,0 @@
1use core::marker::PhantomData;
2
3use embassy_hal_internal::into_ref;
4use stm32_metapac::pwr::vals::Vos;
5use stm32_metapac::rcc::vals::{Mco1, Mco2};
6
7pub use self::pll::PllConfig;
8use crate::gpio::sealed::AFType;
9use crate::gpio::Speed;
10use crate::pac::rcc::vals::{Adcsel, Ckpersel, Hpre, Hsidiv, Pllsrc, Ppre, Sw, Timpre};
11use crate::pac::{PWR, RCC, SYSCFG};
12use crate::rcc::{set_freqs, Clocks};
13use crate::time::Hertz;
14use crate::{peripherals, Peripheral};
15
16/// HSI speed
17pub const HSI_FREQ: Hertz = Hertz(64_000_000);
18
19/// CSI speed
20pub const CSI_FREQ: Hertz = Hertz(4_000_000);
21
22/// HSI48 speed
23pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
24
25/// LSI speed
26pub const LSI_FREQ: Hertz = Hertz(32_000);
27
28#[derive(Clone, Copy)]
29pub enum VoltageScale {
30 Scale0,
31 Scale1,
32 Scale2,
33 Scale3,
34}
35
36#[derive(Clone, Copy)]
37pub enum AdcClockSource {
38 Pll2PCk,
39 Pll3RCk,
40 PerCk,
41}
42
43impl AdcClockSource {
44 pub fn adcsel(&self) -> Adcsel {
45 match self {
46 AdcClockSource::Pll2PCk => Adcsel::PLL2_P,
47 AdcClockSource::Pll3RCk => Adcsel::PLL3_R,
48 AdcClockSource::PerCk => Adcsel::PER,
49 }
50 }
51}
52
53impl Default for AdcClockSource {
54 fn default() -> Self {
55 Self::Pll2PCk
56 }
57}
58
59/// Core clock frequencies
60#[derive(Clone, Copy)]
61pub struct CoreClocks {
62 pub hclk: Hertz,
63 pub pclk1: Hertz,
64 pub pclk2: Hertz,
65 pub pclk3: Hertz,
66 pub pclk4: Hertz,
67 pub ppre1: u8,
68 pub ppre2: u8,
69 pub ppre3: u8,
70 pub ppre4: u8,
71 pub csi_ck: Option<Hertz>,
72 pub hsi_ck: Option<Hertz>,
73 pub hsi48_ck: Option<Hertz>,
74 pub lsi_ck: Option<Hertz>,
75 pub per_ck: Option<Hertz>,
76 pub hse_ck: Option<Hertz>,
77 pub pll1_p_ck: Option<Hertz>,
78 pub pll1_q_ck: Option<Hertz>,
79 pub pll1_r_ck: Option<Hertz>,
80 pub pll2_p_ck: Option<Hertz>,
81 pub pll2_q_ck: Option<Hertz>,
82 pub pll2_r_ck: Option<Hertz>,
83 pub pll3_p_ck: Option<Hertz>,
84 pub pll3_q_ck: Option<Hertz>,
85 pub pll3_r_ck: Option<Hertz>,
86 pub timx_ker_ck: Option<Hertz>,
87 pub timy_ker_ck: Option<Hertz>,
88 pub adc_ker_ck: Option<Hertz>,
89 pub sys_ck: Hertz,
90 pub c_ck: Hertz,
91}
92
93/// Configuration of the core clocks
94#[non_exhaustive]
95pub struct Config {
96 pub hse: Option<Hertz>,
97 pub bypass_hse: bool,
98 pub sys_ck: Option<Hertz>,
99 pub per_ck: Option<Hertz>,
100 pub hclk: Option<Hertz>,
101 pub pclk1: Option<Hertz>,
102 pub pclk2: Option<Hertz>,
103 pub pclk3: Option<Hertz>,
104 pub pclk4: Option<Hertz>,
105 pub pll1: PllConfig,
106 pub pll2: PllConfig,
107 pub pll3: PllConfig,
108 pub adc_clock_source: AdcClockSource,
109 pub voltage_scale: VoltageScale,
110}
111
112impl Default for Config {
113 fn default() -> Self {
114 Self {
115 hse: None,
116 bypass_hse: false,
117 sys_ck: None,
118 per_ck: None,
119 hclk: None,
120 pclk1: None,
121 pclk2: None,
122 pclk3: None,
123 pclk4: None,
124 pll1: Default::default(),
125 pll2: Default::default(),
126 pll3: Default::default(),
127 adc_clock_source: Default::default(),
128 voltage_scale: VoltageScale::Scale1,
129 }
130 }
131}
132
133/// Setup traceclk
134/// Returns a pll1_r_ck
135fn traceclk_setup(config: &mut Config, sys_use_pll1_p: bool) {
136 let pll1_r_ck = match (sys_use_pll1_p, config.pll1.r_ck) {
137 // pll1_p_ck selected as system clock but pll1_r_ck not
138 // set. The traceclk mux is synchronous with the system
139 // clock mux, but has pll1_r_ck as an input. In order to
140 // keep traceclk running, we force a pll1_r_ck.
141 (true, None) => Some(Hertz(unwrap!(config.pll1.p_ck).0 / 2)),
142
143 // Either pll1 not selected as system clock, free choice
144 // of pll1_r_ck. Or pll1 is selected, assume user has set
145 // a suitable pll1_r_ck frequency.
146 _ => config.pll1.r_ck,
147 };
148 config.pll1.r_ck = pll1_r_ck;
149}
150
151/// Divider calculator for pclk 1 - 4
152///
153/// Returns real pclk, bits, ppre and the timer kernel clock
154fn ppre_calculate(
155 requested_pclk: u32,
156 hclk: u32,
157 max_pclk: u32,
158 tim_pre: Option<Timpre>,
159) -> (u32, u8, u8, Option<u32>) {
160 let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk {
161 0 => panic!(),
162 1 => (0b000, 1),
163 2 => (0b100, 2),
164 3..=5 => (0b101, 4),
165 6..=11 => (0b110, 8),
166 _ => (0b111, 16),
167 };
168 let real_pclk = hclk / u32::from(ppre);
169 assert!(real_pclk <= max_pclk);
170
171 let tim_ker_clk = if let Some(tim_pre) = tim_pre {
172 let clk = match (bits, tim_pre) {
173 (0b101, Timpre::DEFAULTX2) => hclk / 2,
174 (0b110, Timpre::DEFAULTX4) => hclk / 2,
175 (0b110, Timpre::DEFAULTX2) => hclk / 4,
176 (0b111, Timpre::DEFAULTX4) => hclk / 4,
177 (0b111, Timpre::DEFAULTX2) => hclk / 8,
178 _ => hclk,
179 };
180 Some(clk)
181 } else {
182 None
183 };
184 (real_pclk, bits, ppre, tim_ker_clk)
185}
186
187/// Setup sys_ck
188/// Returns sys_ck frequency, and a pll1_p_ck
189fn sys_ck_setup(config: &mut Config, srcclk: Hertz) -> (Hertz, bool) {
190 // Compare available with wanted clocks
191 let sys_ck = config.sys_ck.unwrap_or(srcclk);
192
193 if sys_ck != srcclk {
194 // The requested system clock is not the immediately available
195 // HSE/HSI clock. Perhaps there are other ways of obtaining
196 // the requested system clock (such as `HSIDIV`) but we will
197 // ignore those for now.
198 //
199 // Therefore we must use pll1_p_ck
200 let pll1_p_ck = match config.pll1.p_ck {
201 Some(p_ck) => {
202 assert!(
203 p_ck == sys_ck,
204 "Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck"
205 );
206 Some(p_ck)
207 }
208 None => Some(sys_ck),
209 };
210 config.pll1.p_ck = pll1_p_ck;
211
212 (sys_ck, true)
213 } else {
214 // sys_ck is derived directly from a source clock
215 // (HSE/HSI). pll1_p_ck can be as requested
216 (sys_ck, false)
217 }
218}
219
220fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
221 use crate::pac::FLASH;
222
223 // ACLK in MHz, round down and subtract 1 from integers. eg.
224 // 61_999_999 -> 61MHz
225 // 62_000_000 -> 61MHz
226 // 62_000_001 -> 62MHz
227 let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000;
228
229 // See RM0433 Rev 7 Table 17. FLASH recommended number of wait
230 // states and programming delay
231 #[cfg(flash_h7)]
232 let (wait_states, progr_delay) = match vos {
233 // VOS 0 range VCORE 1.26V - 1.40V
234 VoltageScale::Scale0 => match rcc_aclk_mhz {
235 0..=69 => (0, 0),
236 70..=139 => (1, 1),
237 140..=184 => (2, 1),
238 185..=209 => (2, 2),
239 210..=224 => (3, 2),
240 225..=239 => (4, 2),
241 _ => (7, 3),
242 },
243 // VOS 1 range VCORE 1.15V - 1.26V
244 VoltageScale::Scale1 => match rcc_aclk_mhz {
245 0..=69 => (0, 0),
246 70..=139 => (1, 1),
247 140..=184 => (2, 1),
248 185..=209 => (2, 2),
249 210..=224 => (3, 2),
250 _ => (7, 3),
251 },
252 // VOS 2 range VCORE 1.05V - 1.15V
253 VoltageScale::Scale2 => match rcc_aclk_mhz {
254 0..=54 => (0, 0),
255 55..=109 => (1, 1),
256 110..=164 => (2, 1),
257 165..=224 => (3, 2),
258 _ => (7, 3),
259 },
260 // VOS 3 range VCORE 0.95V - 1.05V
261 VoltageScale::Scale3 => match rcc_aclk_mhz {
262 0..=44 => (0, 0),
263 45..=89 => (1, 1),
264 90..=134 => (2, 1),
265 135..=179 => (3, 2),
266 180..=224 => (4, 2),
267 _ => (7, 3),
268 },
269 };
270
271 // See RM0455 Rev 10 Table 16. FLASH recommended number of wait
272 // states and programming delay
273 #[cfg(flash_h7ab)]
274 let (wait_states, progr_delay) = match vos {
275 // VOS 0 range VCORE 1.25V - 1.35V
276 VoltageScale::Scale0 => match rcc_aclk_mhz {
277 0..=42 => (0, 0),
278 43..=84 => (1, 0),
279 85..=126 => (2, 1),
280 127..=168 => (3, 1),
281 169..=210 => (4, 2),
282 211..=252 => (5, 2),
283 253..=280 => (6, 3),
284 _ => (7, 3),
285 },
286 // VOS 1 range VCORE 1.15V - 1.25V
287 VoltageScale::Scale1 => match rcc_aclk_mhz {
288 0..=38 => (0, 0),
289 39..=76 => (1, 0),
290 77..=114 => (2, 1),
291 115..=152 => (3, 1),
292 153..=190 => (4, 2),
293 191..=225 => (5, 2),
294 _ => (7, 3),
295 },
296 // VOS 2 range VCORE 1.05V - 1.15V
297 VoltageScale::Scale2 => match rcc_aclk_mhz {
298 0..=34 => (0, 0),
299 35..=68 => (1, 0),
300 69..=102 => (2, 1),
301 103..=136 => (3, 1),
302 137..=160 => (4, 2),
303 _ => (7, 3),
304 },
305 // VOS 3 range VCORE 0.95V - 1.05V
306 VoltageScale::Scale3 => match rcc_aclk_mhz {
307 0..=22 => (0, 0),
308 23..=44 => (1, 0),
309 45..=66 => (2, 1),
310 67..=88 => (3, 1),
311 _ => (7, 3),
312 },
313 };
314
315 FLASH.acr().write(|w| {
316 w.set_wrhighfreq(progr_delay);
317 w.set_latency(wait_states)
318 });
319 while FLASH.acr().read().latency() != wait_states {}
320}
321
322pub enum McoClock {
323 Disabled,
324 Bypassed,
325 Divided(u8),
326}
327
328impl McoClock {
329 fn into_raw(&self) -> u8 {
330 match self {
331 McoClock::Disabled => 0,
332 McoClock::Bypassed => 1,
333 McoClock::Divided(divisor) => {
334 if *divisor > 15 {
335 panic!("Mco divisor must be less than 15. Refer to the reference manual for more information.")
336 }
337 *divisor
338 }
339 }
340 }
341}
342
343#[derive(Copy, Clone)]
344pub enum Mco1Source {
345 Hsi,
346 Lse,
347 Hse,
348 Pll1Q,
349 Hsi48,
350}
351
352impl Default for Mco1Source {
353 fn default() -> Self {
354 Self::Hsi
355 }
356}
357
358pub trait McoSource {
359 type Raw;
360
361 fn into_raw(&self) -> Self::Raw;
362}
363
364impl McoSource for Mco1Source {
365 type Raw = Mco1;
366 fn into_raw(&self) -> Self::Raw {
367 match self {
368 Mco1Source::Hsi => Mco1::HSI,
369 Mco1Source::Lse => Mco1::LSE,
370 Mco1Source::Hse => Mco1::HSE,
371 Mco1Source::Pll1Q => Mco1::PLL1_Q,
372 Mco1Source::Hsi48 => Mco1::HSI48,
373 }
374 }
375}
376
377#[derive(Copy, Clone)]
378pub enum Mco2Source {
379 SysClk,
380 Pll2Q,
381 Hse,
382 Pll1Q,
383 Csi,
384 Lsi,
385}
386
387impl Default for Mco2Source {
388 fn default() -> Self {
389 Self::SysClk
390 }
391}
392
393impl McoSource for Mco2Source {
394 type Raw = Mco2;
395 fn into_raw(&self) -> Self::Raw {
396 match self {
397 Mco2Source::SysClk => Mco2::SYSCLK,
398 Mco2Source::Pll2Q => Mco2::PLL2_P,
399 Mco2Source::Hse => Mco2::HSE,
400 Mco2Source::Pll1Q => Mco2::PLL1_P,
401 Mco2Source::Csi => Mco2::CSI,
402 Mco2Source::Lsi => Mco2::LSI,
403 }
404 }
405}
406
407pub(crate) mod sealed {
408 pub trait McoInstance {
409 type Source;
410 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
411 }
412}
413
414pub trait McoInstance: sealed::McoInstance + 'static {}
415
416pin_trait!(McoPin, McoInstance);
417
418macro_rules! impl_peri {
419 ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
420 impl sealed::McoInstance for peripherals::$peri {
421 type Source = $source;
422
423 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
424 RCC.cfgr().modify(|w| {
425 w.$set_source(source);
426 w.$set_prescaler(prescaler);
427 });
428 }
429 }
430
431 impl McoInstance for peripherals::$peri {}
432 };
433}
434
435impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre);
436impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre);
437
438pub struct Mco<'d, T: McoInstance> {
439 phantom: PhantomData<&'d mut T>,
440}
441
442impl<'d, T: McoInstance> Mco<'d, T> {
443 pub fn new(
444 _peri: impl Peripheral<P = T> + 'd,
445 pin: impl Peripheral<P = impl McoPin<T>> + 'd,
446 source: impl McoSource<Raw = T::Source>,
447 prescaler: McoClock,
448 ) -> Self {
449 into_ref!(pin);
450
451 critical_section::with(|_| unsafe {
452 T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
453 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
454 pin.set_speed(Speed::VeryHigh);
455 });
456
457 Self { phantom: PhantomData }
458 }
459}
460
461pub(crate) unsafe fn init(mut config: Config) {
462 // NB. The lower bytes of CR3 can only be written once after
463 // POR, and must be written with a valid combination. Refer to
464 // RM0433 Rev 7 6.8.4. This is partially enforced by dropping
465 // `self` at the end of this method, but of course we cannot
466 // know what happened between the previous POR and here.
467 #[cfg(pwr_h7rm0433)]
468 PWR.cr3().modify(|w| {
469 w.set_scuen(true);
470 w.set_ldoen(true);
471 w.set_bypass(false);
472 });
473
474 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
475 PWR.cr3().modify(|w| {
476 // hardcode "Direct SPMS" for now, this is what works on nucleos with the
477 // default solderbridge configuration.
478 w.set_sden(true);
479 w.set_ldoen(false);
480 });
481
482 // Validate the supply configuration. If you are stuck here, it is
483 // because the voltages on your board do not match those specified
484 // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
485 // VOS = Scale 3, so check that the voltage on the VCAP pins =
486 // 1.0V.
487 info!("a");
488 while !PWR.csr1().read().actvosrdy() {}
489 info!("b");
490
491 #[cfg(syscfg_h7)]
492 {
493 // in chips without the overdrive bit, we can go from any scale to any scale directly.
494 PWR.d3cr().modify(|w| {
495 w.set_vos(match config.voltage_scale {
496 VoltageScale::Scale0 => Vos::SCALE0,
497 VoltageScale::Scale1 => Vos::SCALE1,
498 VoltageScale::Scale2 => Vos::SCALE2,
499 VoltageScale::Scale3 => Vos::SCALE3,
500 })
501 });
502 while !PWR.d3cr().read().vosrdy() {}
503 }
504
505 #[cfg(syscfg_h7od)]
506 {
507 match config.voltage_scale {
508 VoltageScale::Scale0 => {
509 // to go to scale0, we must go to Scale1 first...
510 PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1));
511 while !PWR.d3cr().read().vosrdy() {}
512
513 // Then enable overdrive.
514 critical_section::with(|_| {
515 RCC.apb4enr().modify(|w| w.set_syscfgen(true));
516 SYSCFG.pwrcr().modify(|w| w.set_oden(1));
517 });
518 while !PWR.d3cr().read().vosrdy() {}
519 }
520 _ => {
521 // for all other scales, we can go directly.
522 PWR.d3cr().modify(|w| {
523 w.set_vos(match config.voltage_scale {
524 VoltageScale::Scale0 => unreachable!(),
525 VoltageScale::Scale1 => Vos::SCALE1,
526 VoltageScale::Scale2 => Vos::SCALE2,
527 VoltageScale::Scale3 => Vos::SCALE3,
528 })
529 });
530 while !PWR.d3cr().read().vosrdy() {}
531 }
532 }
533 }
534
535 // Freeze the core clocks, returning a Core Clocks Distribution
536 // and Reset (CCDR) structure. The actual frequency of the clocks
537 // configured is returned in the `clocks` member of the CCDR
538 // structure.
539 //
540 // Note that `freeze` will never result in a clock _faster_ than
541 // that specified. It may result in a clock that is a factor of [1,
542 // 2) slower.
543 //
544 // `syscfg` is required to enable the I/O compensation cell.
545 //
546 // # Panics
547 //
548 // If a clock specification cannot be achieved within the
549 // hardware specification then this function will panic. This
550 // function may also panic if a clock specification can be
551 // achieved, but the mechanism for doing so is not yet
552 // implemented here.
553
554 let srcclk = config.hse.unwrap_or(HSI_FREQ); // Available clocks
555 let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk);
556
557 // Configure traceclk from PLL if needed
558 traceclk_setup(&mut config, sys_use_pll1_p);
559
560 let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0);
561 let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1);
562 let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2);
563
564 let sys_ck = if sys_use_pll1_p {
565 Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
566 } else {
567 sys_ck
568 };
569
570 // This routine does not support HSIDIV != 1. To
571 // do so it would need to ensure all PLLxON bits are clear
572 // before changing the value of HSIDIV
573 let cr = RCC.cr().read();
574 assert!(cr.hsion());
575 assert!(cr.hsidiv() == Hsidiv::DIV1);
576
577 RCC.csr().modify(|w| w.set_lsion(true));
578 while !RCC.csr().read().lsirdy() {}
579
580 // per_ck from HSI by default
581 let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) {
582 (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE
583 (_, Some(CSI_FREQ)) => (CSI_FREQ, Ckpersel::CSI), // CSI
584 _ => (HSI_FREQ, Ckpersel::HSI), // HSI
585 };
586
587 // D1 Core Prescaler
588 // Set to 1
589 let d1cpre_bits = 0;
590 let d1cpre_div = 1;
591 let sys_d1cpre_ck = sys_ck.0 / d1cpre_div;
592
593 // Refer to part datasheet "General operating conditions"
594 // table for (rev V). We do not assert checks for earlier
595 // revisions which may have lower limits.
596 let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match config.voltage_scale {
597 VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000),
598 VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000),
599 VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000),
600 VoltageScale::Scale3 => (200_000_000, 100_000_000, 50_000_000),
601 };
602 assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max);
603
604 let rcc_hclk = config.hclk.map(|v| v.0).unwrap_or(sys_d1cpre_ck / 2);
605 assert!(rcc_hclk <= rcc_hclk_max);
606
607 // Estimate divisor
608 let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk {
609 0 => panic!(),
610 1 => (Hpre::DIV1, 1),
611 2 => (Hpre::DIV2, 2),
612 3..=5 => (Hpre::DIV4, 4),
613 6..=11 => (Hpre::DIV8, 8),
614 12..=39 => (Hpre::DIV16, 16),
615 40..=95 => (Hpre::DIV64, 64),
616 96..=191 => (Hpre::DIV128, 128),
617 192..=383 => (Hpre::DIV256, 256),
618 _ => (Hpre::DIV512, 512),
619 };
620 // Calculate real AXI and AHB clock
621 let rcc_hclk = sys_d1cpre_ck / hpre_div;
622 assert!(rcc_hclk <= rcc_hclk_max);
623 let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7
624 // Timer prescaler selection
625 let timpre = Timpre::DEFAULTX2;
626
627 let requested_pclk1 = config.pclk1.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
628 let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) =
629 ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre));
630
631 let requested_pclk2 = config.pclk2.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
632 let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) =
633 ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre));
634
635 let requested_pclk3 = config.pclk3.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
636 let (rcc_pclk3, ppre3_bits, ppre3, _) = ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None);
637
638 let requested_pclk4 = config.pclk4.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
639 let (rcc_pclk4, ppre4_bits, ppre4, _) = ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None);
640
641 // Start switching clocks -------------------
642
643 // Ensure CSI is on and stable
644 RCC.cr().modify(|w| w.set_csion(true));
645 while !RCC.cr().read().csirdy() {}
646
647 // Ensure HSI48 is on and stable
648 RCC.cr().modify(|w| w.set_hsi48on(true));
649 while !RCC.cr().read().hsi48on() {}
650
651 // XXX: support MCO ?
652
653 let hse_ck = match config.hse {
654 Some(hse) => {
655 // Ensure HSE is on and stable
656 RCC.cr().modify(|w| {
657 w.set_hseon(true);
658 w.set_hsebyp(config.bypass_hse);
659 });
660 while !RCC.cr().read().hserdy() {}
661 Some(hse)
662 }
663 None => None,
664 };
665
666 let pllsrc = if config.hse.is_some() { Pllsrc::HSE } else { Pllsrc::HSI };
667 RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc));
668
669 let enable_pll = |pll| {
670 RCC.cr().modify(|w| w.set_pllon(pll, true));
671 while !RCC.cr().read().pllrdy(pll) {}
672 };
673
674 if pll1_p_ck.is_some() {
675 enable_pll(0);
676 }
677
678 if pll2_p_ck.is_some() {
679 enable_pll(1);
680 }
681
682 if pll3_p_ck.is_some() {
683 enable_pll(2);
684 }
685
686 // Core Prescaler / AHB Prescaler / APB3 Prescaler
687 RCC.d1cfgr().modify(|w| {
688 w.set_d1cpre(Hpre::from_bits(d1cpre_bits));
689 w.set_d1ppre(Ppre::from_bits(ppre3_bits));
690 w.set_hpre(hpre_bits)
691 });
692 // Ensure core prescaler value is valid before future lower
693 // core voltage
694 while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {}
695
696 flash_setup(rcc_aclk, config.voltage_scale);
697
698 // APB1 / APB2 Prescaler
699 RCC.d2cfgr().modify(|w| {
700 w.set_d2ppre1(Ppre::from_bits(ppre1_bits));
701 w.set_d2ppre2(Ppre::from_bits(ppre2_bits));
702 });
703
704 // APB4 Prescaler
705 RCC.d3cfgr().modify(|w| w.set_d3ppre(Ppre::from_bits(ppre4_bits)));
706
707 // Peripheral Clock (per_ck)
708 RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
709
710 // ADC clock MUX
711 RCC.d3ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel()));
712
713 let adc_ker_ck = match config.adc_clock_source {
714 AdcClockSource::Pll2PCk => pll2_p_ck.map(Hertz),
715 AdcClockSource::Pll3RCk => pll3_r_ck.map(Hertz),
716 AdcClockSource::PerCk => Some(per_ck),
717 };
718
719 // Set timer clocks prescaler setting
720 RCC.cfgr().modify(|w| w.set_timpre(timpre));
721
722 // Select system clock source
723 let sw = match (sys_use_pll1_p, config.hse.is_some()) {
724 (true, _) => Sw::PLL1,
725 (false, true) => Sw::HSE,
726 _ => Sw::HSI,
727 };
728 RCC.cfgr().modify(|w| w.set_sw(sw));
729 while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
730
731 // IO compensation cell - Requires CSI clock and SYSCFG
732 assert!(RCC.cr().read().csirdy());
733 RCC.apb4enr().modify(|w| w.set_syscfgen(true));
734
735 // Enable the compensation cell, using back-bias voltage code
736 // provide by the cell.
737 critical_section::with(|_| {
738 SYSCFG.cccsr().modify(|w| {
739 w.set_en(true);
740 w.set_cs(false);
741 w.set_hslv(false);
742 })
743 });
744 while !SYSCFG.cccsr().read().ready() {}
745
746 let core_clocks = CoreClocks {
747 hclk: Hertz(rcc_hclk),
748 pclk1: Hertz(rcc_pclk1),
749 pclk2: Hertz(rcc_pclk2),
750 pclk3: Hertz(rcc_pclk3),
751 pclk4: Hertz(rcc_pclk4),
752 ppre1,
753 ppre2,
754 ppre3,
755 ppre4,
756 csi_ck: Some(CSI_FREQ),
757 hsi_ck: Some(HSI_FREQ),
758 hsi48_ck: Some(HSI48_FREQ),
759 lsi_ck: Some(LSI_FREQ),
760 per_ck: Some(per_ck),
761 hse_ck,
762 pll1_p_ck: pll1_p_ck.map(Hertz),
763 pll1_q_ck: pll1_q_ck.map(Hertz),
764 pll1_r_ck: pll1_r_ck.map(Hertz),
765 pll2_p_ck: pll2_p_ck.map(Hertz),
766 pll2_q_ck: pll2_q_ck.map(Hertz),
767 pll2_r_ck: pll2_r_ck.map(Hertz),
768 pll3_p_ck: pll3_p_ck.map(Hertz),
769 pll3_q_ck: pll3_q_ck.map(Hertz),
770 pll3_r_ck: pll3_r_ck.map(Hertz),
771 timx_ker_ck: rcc_timerx_ker_ck.map(Hertz),
772 timy_ker_ck: rcc_timery_ker_ck.map(Hertz),
773 adc_ker_ck,
774 sys_ck,
775 c_ck: Hertz(sys_d1cpre_ck),
776 };
777
778 set_freqs(Clocks {
779 sys: core_clocks.c_ck,
780 ahb1: core_clocks.hclk,
781 ahb2: core_clocks.hclk,
782 ahb3: core_clocks.hclk,
783 ahb4: core_clocks.hclk,
784 apb1: core_clocks.pclk1,
785 apb2: core_clocks.pclk2,
786 apb4: core_clocks.pclk4,
787 apb1_tim: core_clocks.timx_ker_ck.unwrap_or(core_clocks.pclk1),
788 apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2),
789 adc: core_clocks.adc_ker_ck,
790 });
791}
792
793mod pll {
794 use super::{Hertz, RCC};
795
796 const VCO_MIN: u32 = 150_000_000;
797 const VCO_MAX: u32 = 420_000_000;
798
799 #[derive(Default)]
800 pub struct PllConfig {
801 pub p_ck: Option<Hertz>,
802 pub q_ck: Option<Hertz>,
803 pub r_ck: Option<Hertz>,
804 }
805
806 pub(super) struct PllConfigResults {
807 pub ref_x_ck: u32,
808 pub pll_x_m: u32,
809 pub pll_x_p: u32,
810 pub vco_ck_target: u32,
811 }
812
813 fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
814 let pll_x_p = if plln == 0 {
815 if output > VCO_MAX / 2 {
816 1
817 } else {
818 ((VCO_MAX / output) | 1) - 1 // Must be even or unity
819 }
820 } else {
821 // Specific to PLL2/3, will subtract 1 later
822 if output > VCO_MAX / 2 {
823 1
824 } else {
825 VCO_MAX / output
826 }
827 };
828
829 let vco_ck = output * pll_x_p;
830
831 assert!(pll_x_p < 128);
832 assert!(vco_ck >= VCO_MIN);
833 assert!(vco_ck <= VCO_MAX);
834
835 (vco_ck, pll_x_p)
836 }
837
838 /// # Safety
839 ///
840 /// Must have exclusive access to the RCC register block
841 fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
842 use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
843
844 let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
845
846 // Input divisor, resulting in a reference clock in the range
847 // 1 to 2 MHz. Choose the highest reference clock (lowest m)
848 let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
849 assert!(pll_x_m < 64);
850
851 // Calculate resulting reference clock
852 let ref_x_ck = pll_src / pll_x_m;
853 assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
854
855 RCC.pllcfgr().modify(|w| {
856 w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO);
857 w.set_pllrge(plln, Pllrge::RANGE1);
858 });
859 PllConfigResults {
860 ref_x_ck,
861 pll_x_m,
862 pll_x_p,
863 vco_ck_target,
864 }
865 }
866
867 /// # Safety
868 ///
869 /// Must have exclusive access to the RCC register block
870 pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option<u32>, Option<u32>, Option<u32>) {
871 use crate::pac::rcc::vals::Divp;
872
873 match config.p_ck {
874 Some(requested_output) => {
875 let config_results = vco_setup(pll_src, requested_output.0, plln);
876 let PllConfigResults {
877 ref_x_ck,
878 pll_x_m,
879 pll_x_p,
880 vco_ck_target,
881 } = config_results;
882
883 RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
884
885 // Feedback divider. Integer only
886 let pll_x_n = vco_ck_target / ref_x_ck;
887 assert!(pll_x_n >= 4);
888 assert!(pll_x_n <= 512);
889 RCC.plldivr(plln).modify(|w| w.set_divn1((pll_x_n - 1) as u16));
890
891 // No FRACN
892 RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
893 let vco_ck = ref_x_ck * pll_x_n;
894
895 RCC.plldivr(plln)
896 .modify(|w| w.set_divp1(Divp::from_bits((pll_x_p - 1) as u8)));
897 RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
898
899 // Calulate additional output dividers
900 let q_ck = match config.q_ck {
901 Some(Hertz(ck)) if ck > 0 => {
902 let div = (vco_ck + ck - 1) / ck;
903 RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
904 RCC.pllcfgr().modify(|w| w.set_divqen(plln, true));
905 Some(vco_ck / div)
906 }
907 _ => None,
908 };
909 let r_ck = match config.r_ck {
910 Some(Hertz(ck)) if ck > 0 => {
911 let div = (vco_ck + ck - 1) / ck;
912 RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
913 RCC.pllcfgr().modify(|w| w.set_divren(plln, true));
914 Some(vco_ck / div)
915 }
916 _ => None,
917 };
918
919 (Some(vco_ck / pll_x_p), q_ck, r_ck)
920 }
921 None => {
922 assert!(
923 config.q_ck.is_none(),
924 "Must set PLL P clock for Q clock to take effect!"
925 );
926 assert!(
927 config.r_ck.is_none(),
928 "Must set PLL P clock for R clock to take effect!"
929 );
930 (None, None, None)
931 }
932 }
933 }
934}
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
new file mode 100644
index 000000000..2453ed821
--- /dev/null
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -0,0 +1,71 @@
1use core::marker::PhantomData;
2
3use embassy_hal_internal::into_ref;
4
5use crate::gpio::sealed::AFType;
6use crate::gpio::Speed;
7pub use crate::pac::rcc::vals::{Mco1 as Mco1Source, Mco2 as Mco2Source};
8use crate::pac::RCC;
9use crate::{peripherals, Peripheral};
10
11pub(crate) mod sealed {
12 pub trait McoInstance {
13 type Source;
14 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
15 }
16}
17
18pub trait McoInstance: sealed::McoInstance + 'static {}
19
20pin_trait!(McoPin, McoInstance);
21
22macro_rules! impl_peri {
23 ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
24 impl sealed::McoInstance for peripherals::$peri {
25 type Source = $source;
26
27 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
28 RCC.cfgr().modify(|w| {
29 w.$set_source(source);
30 w.$set_prescaler(prescaler);
31 });
32 }
33 }
34
35 impl McoInstance for peripherals::$peri {}
36 };
37}
38
39impl_peri!(MCO1, Mco1Source, set_mco1, set_mco1pre);
40impl_peri!(MCO2, Mco2Source, set_mco2, set_mco2pre);
41
42pub struct Mco<'d, T: McoInstance> {
43 phantom: PhantomData<&'d mut T>,
44}
45
46impl<'d, T: McoInstance> Mco<'d, T> {
47 /// Create a new MCO instance.
48 ///
49 /// `prescaler` must be between 1 and 15.
50 pub fn new(
51 _peri: impl Peripheral<P = T> + 'd,
52 pin: impl Peripheral<P = impl McoPin<T>> + 'd,
53 source: T::Source,
54 prescaler: u8,
55 ) -> Self {
56 into_ref!(pin);
57
58 assert!(
59 1 <= prescaler && prescaler <= 15,
60 "Mco prescaler must be between 1 and 15. Refer to the reference manual for more information."
61 );
62
63 critical_section::with(|_| unsafe {
64 T::apply_clock_settings(source, prescaler);
65 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
66 pin.set_speed(Speed::VeryHigh);
67 });
68
69 Self { phantom: PhantomData }
70 }
71}
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index ff9b9bac8..0d6b0e308 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -1,12 +1,17 @@
1#![macro_use] 1#![macro_use]
2 2
3pub(crate) mod bd;
4pub mod bus;
5use core::mem::MaybeUninit; 3use core::mem::MaybeUninit;
6 4
7pub use crate::rcc::bd::RtcClockSource; 5pub use crate::rcc::bd::RtcClockSource;
8use crate::time::Hertz; 6use crate::time::Hertz;
9 7
8pub(crate) mod bd;
9mod bus;
10#[cfg(any(stm32h5, stm32h7))]
11mod mco;
12#[cfg(any(stm32h5, stm32h7))]
13pub use mco::*;
14
10#[cfg_attr(rcc_f0, path = "f0.rs")] 15#[cfg_attr(rcc_f0, path = "f0.rs")]
11#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] 16#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")]
12#[cfg_attr(rcc_f2, path = "f2.rs")] 17#[cfg_attr(rcc_f2, path = "f2.rs")]
@@ -16,7 +21,7 @@ use crate::time::Hertz;
16#[cfg_attr(rcc_c0, path = "c0.rs")] 21#[cfg_attr(rcc_c0, path = "c0.rs")]
17#[cfg_attr(rcc_g0, path = "g0.rs")] 22#[cfg_attr(rcc_g0, path = "g0.rs")]
18#[cfg_attr(rcc_g4, path = "g4.rs")] 23#[cfg_attr(rcc_g4, path = "g4.rs")]
19#[cfg_attr(any(rcc_h7, rcc_h7ab), path = "h7.rs")] 24#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab), path = "h.rs")]
20#[cfg_attr(rcc_l0, path = "l0.rs")] 25#[cfg_attr(rcc_l0, path = "l0.rs")]
21#[cfg_attr(rcc_l1, path = "l1.rs")] 26#[cfg_attr(rcc_l1, path = "l1.rs")]
22#[cfg_attr(rcc_l4, path = "l4.rs")] 27#[cfg_attr(rcc_l4, path = "l4.rs")]
@@ -25,7 +30,6 @@ use crate::time::Hertz;
25#[cfg_attr(rcc_wb, path = "wb.rs")] 30#[cfg_attr(rcc_wb, path = "wb.rs")]
26#[cfg_attr(rcc_wba, path = "wba.rs")] 31#[cfg_attr(rcc_wba, path = "wba.rs")]
27#[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")] 32#[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")]
28#[cfg_attr(any(rcc_h5, rcc_h50), path = "h5.rs")]
29mod _version; 33mod _version;
30pub use _version::*; 34pub use _version::*;
31#[cfg(feature = "low-power")] 35#[cfg(feature = "low-power")]
@@ -53,7 +57,7 @@ pub struct Clocks {
53 pub apb2: Hertz, 57 pub apb2: Hertz,
54 #[cfg(not(any(rcc_c0, rcc_g0)))] 58 #[cfg(not(any(rcc_c0, rcc_g0)))]
55 pub apb2_tim: Hertz, 59 pub apb2_tim: Hertz,
56 #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_u5))] 60 #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5))]
57 pub apb3: Hertz, 61 pub apb3: Hertz,
58 #[cfg(any(rcc_h7, rcc_h7ab))] 62 #[cfg(any(rcc_h7, rcc_h7ab))]
59 pub apb4: Hertz, 63 pub apb4: Hertz,
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs
index 5f1e62d0a..16bf5d949 100644
--- a/examples/stm32f4/src/bin/eth.rs
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -100,6 +100,7 @@ async fn main(spawner: Spawner) -> ! {
100 let r = socket.connect(remote_endpoint).await; 100 let r = socket.connect(remote_endpoint).await;
101 if let Err(e) = r { 101 if let Err(e) = r {
102 info!("connect error: {:?}", e); 102 info!("connect error: {:?}", e);
103 Timer::after(Duration::from_secs(1)).await;
103 continue; 104 continue;
104 } 105 }
105 info!("connected!"); 106 info!("connected!");
@@ -108,7 +109,7 @@ async fn main(spawner: Spawner) -> ! {
108 let r = socket.write_all(&buf).await; 109 let r = socket.write_all(&buf).await;
109 if let Err(e) = r { 110 if let Err(e) = r {
110 info!("write error: {:?}", e); 111 info!("write error: {:?}", e);
111 continue; 112 break;
112 } 113 }
113 Timer::after(Duration::from_secs(1)).await; 114 Timer::after(Duration::from_secs(1)).await;
114 } 115 }
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index 01c38106e..93c97c8ee 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -101,6 +101,7 @@ async fn main(spawner: Spawner) -> ! {
101 let r = socket.connect(remote_endpoint).await; 101 let r = socket.connect(remote_endpoint).await;
102 if let Err(e) = r { 102 if let Err(e) = r {
103 info!("connect error: {:?}", e); 103 info!("connect error: {:?}", e);
104 Timer::after(Duration::from_secs(1)).await;
104 continue; 105 continue;
105 } 106 }
106 info!("connected!"); 107 info!("connected!");
@@ -109,7 +110,7 @@ async fn main(spawner: Spawner) -> ! {
109 let r = socket.write_all(&buf).await; 110 let r = socket.write_all(&buf).await;
110 if let Err(e) = r { 111 if let Err(e) = r {
111 info!("write error: {:?}", e); 112 info!("write error: {:?}", e);
112 continue; 113 break;
113 } 114 }
114 Timer::after(Duration::from_secs(1)).await; 115 Timer::after(Duration::from_secs(1)).await;
115 } 116 }
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
index 41ef2acaa..4e92d0647 100644
--- a/examples/stm32h5/src/bin/eth.rs
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -53,7 +53,7 @@ async fn main(spawner: Spawner) -> ! {
53 config.rcc.apb2_pre = APBPrescaler::DIV1; 53 config.rcc.apb2_pre = APBPrescaler::DIV1;
54 config.rcc.apb3_pre = APBPrescaler::DIV1; 54 config.rcc.apb3_pre = APBPrescaler::DIV1;
55 config.rcc.sys = Sysclk::Pll1P; 55 config.rcc.sys = Sysclk::Pll1P;
56 config.rcc.voltage_scale = VoltageScale::SCALE0; 56 config.rcc.voltage_scale = VoltageScale::Scale0;
57 let p = embassy_stm32::init(config); 57 let p = embassy_stm32::init(config);
58 info!("Hello World!"); 58 info!("Hello World!");
59 59
@@ -128,7 +128,7 @@ async fn main(spawner: Spawner) -> ! {
128 let r = socket.write_all(b"Hello\n").await; 128 let r = socket.write_all(b"Hello\n").await;
129 if let Err(e) = r { 129 if let Err(e) = r {
130 info!("write error: {:?}", e); 130 info!("write error: {:?}", e);
131 continue; 131 break;
132 } 132 }
133 Timer::after(Duration::from_secs(1)).await; 133 Timer::after(Duration::from_secs(1)).await;
134 } 134 }
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index 63c694aff..cbe540a06 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) {
40 config.rcc.apb2_pre = APBPrescaler::DIV2; 40 config.rcc.apb2_pre = APBPrescaler::DIV2;
41 config.rcc.apb3_pre = APBPrescaler::DIV4; 41 config.rcc.apb3_pre = APBPrescaler::DIV4;
42 config.rcc.sys = Sysclk::Pll1P; 42 config.rcc.sys = Sysclk::Pll1P;
43 config.rcc.voltage_scale = VoltageScale::SCALE0; 43 config.rcc.voltage_scale = VoltageScale::Scale0;
44 let p = embassy_stm32::init(config); 44 let p = embassy_stm32::init(config);
45 45
46 info!("Hello World!"); 46 info!("Hello World!");
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
index 0e1e28c72..77922d4bc 100644
--- a/examples/stm32h7/src/bin/adc.rs
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -5,8 +5,6 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::adc::{Adc, SampleTime}; 7use embassy_stm32::adc::{Adc, SampleTime};
8use embassy_stm32::rcc::AdcClockSource;
9use embassy_stm32::time::mhz;
10use embassy_stm32::Config; 8use embassy_stm32::Config;
11use embassy_time::{Delay, Duration, Timer}; 9use embassy_time::{Delay, Duration, Timer};
12use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
@@ -14,10 +12,34 @@ use {defmt_rtt as _, panic_probe as _};
14#[embassy_executor::main] 12#[embassy_executor::main]
15async fn main(_spawner: Spawner) { 13async fn main(_spawner: Spawner) {
16 let mut config = Config::default(); 14 let mut config = Config::default();
17 config.rcc.sys_ck = Some(mhz(400)); 15 {
18 config.rcc.hclk = Some(mhz(200)); 16 use embassy_stm32::rcc::*;
19 config.rcc.per_ck = Some(mhz(64)); 17 config.rcc.hsi = Some(Hsi::Mhz64);
20 config.rcc.adc_clock_source = AdcClockSource::PerCk; 18 config.rcc.csi = true;
19 config.rcc.pll_src = PllSource::Hsi;
20 config.rcc.pll1 = Some(Pll {
21 prediv: 4,
22 mul: 50,
23 divp: Some(2),
24 divq: Some(8), // SPI1 cksel defaults to pll1_q
25 divr: None,
26 });
27 config.rcc.pll2 = Some(Pll {
28 prediv: 4,
29 mul: 50,
30 divp: Some(8), // 100mhz
31 divq: None,
32 divr: None,
33 });
34 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
35 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
36 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
37 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
38 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
39 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
40 config.rcc.voltage_scale = VoltageScale::Scale1;
41 config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
42 }
21 let mut p = embassy_stm32::init(config); 43 let mut p = embassy_stm32::init(config);
22 44
23 info!("Hello World!"); 45 info!("Hello World!");
diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs
index 6f75a0630..de8ddc292 100644
--- a/examples/stm32h7/src/bin/camera.rs
+++ b/examples/stm32h7/src/bin/camera.rs
@@ -6,8 +6,8 @@ use embassy_executor::Spawner;
6use embassy_stm32::dcmi::{self, *}; 6use embassy_stm32::dcmi::{self, *};
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::i2c::I2c; 8use embassy_stm32::i2c::I2c;
9use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; 9use embassy_stm32::rcc::{Mco, Mco1Source};
10use embassy_stm32::time::{khz, mhz}; 10use embassy_stm32::time::khz;
11use embassy_stm32::{bind_interrupts, i2c, peripherals, Config}; 11use embassy_stm32::{bind_interrupts, i2c, peripherals, Config};
12use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use ov7725::*; 13use ov7725::*;
@@ -26,17 +26,30 @@ bind_interrupts!(struct Irqs {
26#[embassy_executor::main] 26#[embassy_executor::main]
27async fn main(_spawner: Spawner) { 27async fn main(_spawner: Spawner) {
28 let mut config = Config::default(); 28 let mut config = Config::default();
29 config.rcc.sys_ck = Some(mhz(400)); 29 {
30 config.rcc.hclk = Some(mhz(400)); 30 use embassy_stm32::rcc::*;
31 config.rcc.pll1.q_ck = Some(mhz(100)); 31 config.rcc.hsi = Some(Hsi::Mhz64);
32 config.rcc.pclk1 = Some(mhz(100)); 32 config.rcc.csi = true;
33 config.rcc.pclk2 = Some(mhz(100)); 33 config.rcc.pll_src = PllSource::Hsi;
34 config.rcc.pclk3 = Some(mhz(100)); 34 config.rcc.pll1 = Some(Pll {
35 config.rcc.pclk4 = Some(mhz(100)); 35 prediv: 4,
36 mul: 50,
37 divp: Some(2),
38 divq: Some(8), // 100mhz
39 divr: None,
40 });
41 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
42 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
43 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
44 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
45 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
46 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
47 config.rcc.voltage_scale = VoltageScale::Scale1;
48 }
36 let p = embassy_stm32::init(config); 49 let p = embassy_stm32::init(config);
37 50
38 defmt::info!("Hello World!"); 51 defmt::info!("Hello World!");
39 let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::Divided(3)); 52 let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, 3);
40 53
41 let mut led = Output::new(p.PE3, Level::High, Speed::Low); 54 let mut led = Output::new(p.PE3, Level::High, Speed::Low);
42 let cam_i2c = I2c::new( 55 let cam_i2c = I2c::new(
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index ee078286b..93df7a319 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -6,7 +6,6 @@ use cortex_m_rt::entry;
6use defmt::*; 6use defmt::*;
7use embassy_stm32::dac::{DacCh1, DacChannel, Value}; 7use embassy_stm32::dac::{DacCh1, DacChannel, Value};
8use embassy_stm32::dma::NoDma; 8use embassy_stm32::dma::NoDma;
9use embassy_stm32::time::mhz;
10use embassy_stm32::Config; 9use embassy_stm32::Config;
11use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
12 11
@@ -15,9 +14,34 @@ fn main() -> ! {
15 info!("Hello World, dude!"); 14 info!("Hello World, dude!");
16 15
17 let mut config = Config::default(); 16 let mut config = Config::default();
18 config.rcc.sys_ck = Some(mhz(400)); 17 {
19 config.rcc.hclk = Some(mhz(200)); 18 use embassy_stm32::rcc::*;
20 config.rcc.pll1.q_ck = Some(mhz(100)); 19 config.rcc.hsi = Some(Hsi::Mhz64);
20 config.rcc.csi = true;
21 config.rcc.pll_src = PllSource::Hsi;
22 config.rcc.pll1 = Some(Pll {
23 prediv: 4,
24 mul: 50,
25 divp: Some(2),
26 divq: Some(8), // SPI1 cksel defaults to pll1_q
27 divr: None,
28 });
29 config.rcc.pll2 = Some(Pll {
30 prediv: 4,
31 mul: 50,
32 divp: Some(8), // 100mhz
33 divq: None,
34 divr: None,
35 });
36 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
37 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
38 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
39 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
40 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
41 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
42 config.rcc.voltage_scale = VoltageScale::Scale1;
43 config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
44 }
21 let p = embassy_stm32::init(config); 45 let p = embassy_stm32::init(config);
22 46
23 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); 47 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index a9cb5d1ed..8c921abca 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -8,7 +8,7 @@ use embassy_stm32::dac::{DacChannel, ValueArray};
8use embassy_stm32::pac::timer::vals::{Mms, Opm}; 8use embassy_stm32::pac::timer::vals::{Mms, Opm};
9use embassy_stm32::peripherals::{TIM6, TIM7}; 9use embassy_stm32::peripherals::{TIM6, TIM7};
10use embassy_stm32::rcc::low_level::RccPeripheral; 10use embassy_stm32::rcc::low_level::RccPeripheral;
11use embassy_stm32::time::{mhz, Hertz}; 11use embassy_stm32::time::Hertz;
12use embassy_stm32::timer::low_level::Basic16bitInstance; 12use embassy_stm32::timer::low_level::Basic16bitInstance;
13use micromath::F32Ext; 13use micromath::F32Ext;
14use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
@@ -22,9 +22,34 @@ pub type Dac2Type =
22#[embassy_executor::main] 22#[embassy_executor::main]
23async fn main(spawner: Spawner) { 23async fn main(spawner: Spawner) {
24 let mut config = embassy_stm32::Config::default(); 24 let mut config = embassy_stm32::Config::default();
25 config.rcc.sys_ck = Some(mhz(400)); 25 {
26 config.rcc.hclk = Some(mhz(100)); 26 use embassy_stm32::rcc::*;
27 config.rcc.pll1.q_ck = Some(mhz(100)); 27 config.rcc.hsi = Some(Hsi::Mhz64);
28 config.rcc.csi = true;
29 config.rcc.pll_src = PllSource::Hsi;
30 config.rcc.pll1 = Some(Pll {
31 prediv: 4,
32 mul: 50,
33 divp: Some(2),
34 divq: Some(8), // SPI1 cksel defaults to pll1_q
35 divr: None,
36 });
37 config.rcc.pll2 = Some(Pll {
38 prediv: 4,
39 mul: 50,
40 divp: Some(8), // 100mhz
41 divq: None,
42 divr: None,
43 });
44 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
45 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
46 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
47 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
48 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
49 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
50 config.rcc.voltage_scale = VoltageScale::Scale1;
51 config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
52 }
28 53
29 // Initialize the board and obtain a Peripherals instance 54 // Initialize the board and obtain a Peripherals instance
30 let p: embassy_stm32::Peripherals = embassy_stm32::init(config); 55 let p: embassy_stm32::Peripherals = embassy_stm32::init(config);
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index e691c6d06..1b5d71ed3 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -10,7 +10,6 @@ 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;
14use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 13use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
15use embassy_time::{Duration, Timer}; 14use embassy_time::{Duration, Timer};
16use embedded_io_async::Write; 15use embedded_io_async::Write;
@@ -33,9 +32,27 @@ async fn net_task(stack: &'static Stack<Device>) -> ! {
33#[embassy_executor::main] 32#[embassy_executor::main]
34async fn main(spawner: Spawner) -> ! { 33async fn main(spawner: Spawner) -> ! {
35 let mut config = Config::default(); 34 let mut config = Config::default();
36 config.rcc.sys_ck = Some(mhz(400)); 35 {
37 config.rcc.hclk = Some(mhz(200)); 36 use embassy_stm32::rcc::*;
38 config.rcc.pll1.q_ck = Some(mhz(100)); 37 config.rcc.hsi = Some(Hsi::Mhz64);
38 config.rcc.csi = true;
39 config.rcc.hsi48 = true; // needed for RNG
40 config.rcc.pll_src = PllSource::Hsi;
41 config.rcc.pll1 = Some(Pll {
42 prediv: 4,
43 mul: 50,
44 divp: Some(2),
45 divq: None,
46 divr: None,
47 });
48 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
49 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
50 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
51 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
52 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
53 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
54 config.rcc.voltage_scale = VoltageScale::Scale1;
55 }
39 let p = embassy_stm32::init(config); 56 let p = embassy_stm32::init(config);
40 info!("Hello World!"); 57 info!("Hello World!");
41 58
@@ -102,6 +119,7 @@ async fn main(spawner: Spawner) -> ! {
102 let r = socket.connect(remote_endpoint).await; 119 let r = socket.connect(remote_endpoint).await;
103 if let Err(e) = r { 120 if let Err(e) = r {
104 info!("connect error: {:?}", e); 121 info!("connect error: {:?}", e);
122 Timer::after(Duration::from_secs(1)).await;
105 continue; 123 continue;
106 } 124 }
107 info!("connected!"); 125 info!("connected!");
@@ -109,7 +127,7 @@ async fn main(spawner: Spawner) -> ! {
109 let r = socket.write_all(b"Hello\n").await; 127 let r = socket.write_all(b"Hello\n").await;
110 if let Err(e) = r { 128 if let Err(e) = r {
111 info!("write error: {:?}", e); 129 info!("write error: {:?}", e);
112 continue; 130 break;
113 } 131 }
114 Timer::after(Duration::from_secs(1)).await; 132 Timer::after(Duration::from_secs(1)).await;
115 } 133 }
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index ebef54c3c..3abd31c73 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -10,7 +10,6 @@ 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;
14use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 13use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
15use embassy_time::{Duration, Timer}; 14use embassy_time::{Duration, Timer};
16use embedded_io_async::Write; 15use embedded_io_async::Write;
@@ -34,9 +33,27 @@ async fn net_task(stack: &'static Stack<Device>) -> ! {
34#[embassy_executor::main] 33#[embassy_executor::main]
35async fn main(spawner: Spawner) -> ! { 34async fn main(spawner: Spawner) -> ! {
36 let mut config = Config::default(); 35 let mut config = Config::default();
37 config.rcc.sys_ck = Some(mhz(400)); 36 {
38 config.rcc.hclk = Some(mhz(200)); 37 use embassy_stm32::rcc::*;
39 config.rcc.pll1.q_ck = Some(mhz(100)); 38 config.rcc.hsi = Some(Hsi::Mhz64);
39 config.rcc.csi = true;
40 config.rcc.hsi48 = true; // needed for RNG
41 config.rcc.pll_src = PllSource::Hsi;
42 config.rcc.pll1 = Some(Pll {
43 prediv: 4,
44 mul: 50,
45 divp: Some(2),
46 divq: None,
47 divr: None,
48 });
49 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
50 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
51 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
52 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
53 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
54 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
55 config.rcc.voltage_scale = VoltageScale::Scale1;
56 }
40 let p = embassy_stm32::init(config); 57 let p = embassy_stm32::init(config);
41 info!("Hello World!"); 58 info!("Hello World!");
42 59
@@ -108,7 +125,7 @@ async fn main(spawner: Spawner) -> ! {
108 let r = connection.write_all(b"Hello\n").await; 125 let r = connection.write_all(b"Hello\n").await;
109 if let Err(e) = r { 126 if let Err(e) = r {
110 info!("write error: {:?}", e); 127 info!("write error: {:?}", e);
111 continue; 128 break;
112 } 129 }
113 Timer::after(Duration::from_secs(1)).await; 130 Timer::after(Duration::from_secs(1)).await;
114 } 131 }
diff --git a/examples/stm32h7/src/bin/fmc.rs b/examples/stm32h7/src/bin/fmc.rs
index 85c690fe6..de0b351df 100644
--- a/examples/stm32h7/src/bin/fmc.rs
+++ b/examples/stm32h7/src/bin/fmc.rs
@@ -5,7 +5,6 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::fmc::Fmc; 7use embassy_stm32::fmc::Fmc;
8use embassy_stm32::time::mhz;
9use embassy_stm32::Config; 8use embassy_stm32::Config;
10use embassy_time::{Delay, Duration, Timer}; 9use embassy_time::{Delay, Duration, Timer};
11use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
@@ -13,9 +12,26 @@ use {defmt_rtt as _, panic_probe as _};
13#[embassy_executor::main] 12#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 13async fn main(_spawner: Spawner) {
15 let mut config = Config::default(); 14 let mut config = Config::default();
16 config.rcc.sys_ck = Some(mhz(400)); 15 {
17 config.rcc.hclk = Some(mhz(200)); 16 use embassy_stm32::rcc::*;
18 config.rcc.pll1.q_ck = Some(mhz(100)); 17 config.rcc.hsi = Some(Hsi::Mhz64);
18 config.rcc.csi = true;
19 config.rcc.pll_src = PllSource::Hsi;
20 config.rcc.pll1 = Some(Pll {
21 prediv: 4,
22 mul: 50,
23 divp: Some(2),
24 divq: Some(8), // 100mhz
25 divr: None,
26 });
27 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
28 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
29 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
30 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
31 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
32 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
33 config.rcc.voltage_scale = VoltageScale::Scale1;
34 }
19 let p = embassy_stm32::init(config); 35 let p = embassy_stm32::init(config);
20 36
21 info!("Hello World!"); 37 info!("Hello World!");
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index 45b0872b5..a1e955c39 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -6,7 +6,7 @@ use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::low_level::AFType; 7use embassy_stm32::gpio::low_level::AFType;
8use embassy_stm32::gpio::Speed; 8use embassy_stm32::gpio::Speed;
9use embassy_stm32::time::{khz, mhz, Hertz}; 9use embassy_stm32::time::{khz, Hertz};
10use embassy_stm32::timer::*; 10use embassy_stm32::timer::*;
11use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef}; 11use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef};
12use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
@@ -15,13 +15,27 @@ use {defmt_rtt as _, panic_probe as _};
15#[embassy_executor::main] 15#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
17 let mut config = Config::default(); 17 let mut config = Config::default();
18 config.rcc.sys_ck = Some(mhz(400)); 18 {
19 config.rcc.hclk = Some(mhz(400)); 19 use embassy_stm32::rcc::*;
20 config.rcc.pll1.q_ck = Some(mhz(100)); 20 config.rcc.hsi = Some(Hsi::Mhz64);
21 config.rcc.pclk1 = Some(mhz(100)); 21 config.rcc.csi = true;
22 config.rcc.pclk2 = Some(mhz(100)); 22 config.rcc.hsi48 = true; // needed for RNG
23 config.rcc.pclk3 = Some(mhz(100)); 23 config.rcc.pll_src = PllSource::Hsi;
24 config.rcc.pclk4 = Some(mhz(100)); 24 config.rcc.pll1 = Some(Pll {
25 prediv: 4,
26 mul: 50,
27 divp: Some(2),
28 divq: Some(8), // 100 Mhz
29 divr: None,
30 });
31 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
32 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
33 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
34 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
35 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
36 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
37 config.rcc.voltage_scale = VoltageScale::Scale1;
38 }
25 let p = embassy_stm32::init(config); 39 let p = embassy_stm32::init(config);
26 40
27 info!("Hello World!"); 41 info!("Hello World!");
diff --git a/examples/stm32h7/src/bin/mco.rs b/examples/stm32h7/src/bin/mco.rs
index 036455d5e..9d6d805ae 100644
--- a/examples/stm32h7/src/bin/mco.rs
+++ b/examples/stm32h7/src/bin/mco.rs
@@ -5,7 +5,7 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; 8use embassy_stm32::rcc::{Mco, Mco1Source};
9use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
@@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) {
16 16
17 let mut led = Output::new(p.PB14, Level::High, Speed::Low); 17 let mut led = Output::new(p.PB14, Level::High, Speed::Low);
18 18
19 let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::Divided(8)); 19 let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, 8);
20 20
21 loop { 21 loop {
22 info!("high"); 22 info!("high");
diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs
index aa5ec1bcf..5c8e57aa2 100644
--- a/examples/stm32h7/src/bin/pwm.rs
+++ b/examples/stm32h7/src/bin/pwm.rs
@@ -5,7 +5,7 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::OutputType; 7use embassy_stm32::gpio::OutputType;
8use embassy_stm32::time::{khz, mhz}; 8use embassy_stm32::time::khz;
9use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 9use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
10use embassy_stm32::timer::Channel; 10use embassy_stm32::timer::Channel;
11use embassy_stm32::Config; 11use embassy_stm32::Config;
@@ -15,13 +15,26 @@ use {defmt_rtt as _, panic_probe as _};
15#[embassy_executor::main] 15#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
17 let mut config = Config::default(); 17 let mut config = Config::default();
18 config.rcc.sys_ck = Some(mhz(400)); 18 {
19 config.rcc.hclk = Some(mhz(400)); 19 use embassy_stm32::rcc::*;
20 config.rcc.pll1.q_ck = Some(mhz(100)); 20 config.rcc.hsi = Some(Hsi::Mhz64);
21 config.rcc.pclk1 = Some(mhz(100)); 21 config.rcc.csi = true;
22 config.rcc.pclk2 = Some(mhz(100)); 22 config.rcc.pll_src = PllSource::Hsi;
23 config.rcc.pclk3 = Some(mhz(100)); 23 config.rcc.pll1 = Some(Pll {
24 config.rcc.pclk4 = Some(mhz(100)); 24 prediv: 4,
25 mul: 50,
26 divp: Some(2),
27 divq: None,
28 divr: None,
29 });
30 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
31 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
32 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
33 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
34 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
35 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
36 config.rcc.voltage_scale = VoltageScale::Scale1;
37 }
25 let p = embassy_stm32::init(config); 38 let p = embassy_stm32::init(config);
26 info!("Hello World!"); 39 info!("Hello World!");
27 40
diff --git a/examples/stm32h7/src/bin/rng.rs b/examples/stm32h7/src/bin/rng.rs
index 7c8c50eca..af1d6ebb8 100644
--- a/examples/stm32h7/src/bin/rng.rs
+++ b/examples/stm32h7/src/bin/rng.rs
@@ -5,7 +5,7 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::rng::Rng; 7use embassy_stm32::rng::Rng;
8use embassy_stm32::{bind_interrupts, peripherals, rng}; 8use embassy_stm32::{bind_interrupts, peripherals, rng, Config};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11bind_interrupts!(struct Irqs { 11bind_interrupts!(struct Irqs {
@@ -14,7 +14,9 @@ bind_interrupts!(struct Irqs {
14 14
15#[embassy_executor::main] 15#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
17 let p = embassy_stm32::init(Default::default()); 17 let mut config = Config::default();
18 config.rcc.hsi48 = true; // needed for RNG.
19 let p = embassy_stm32::init(config);
18 info!("Hello World!"); 20 info!("Hello World!");
19 21
20 let mut rng = Rng::new(p.RNG, Irqs); 22 let mut rng = Rng::new(p.RNG, Irqs);
diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs
index ce91b6b1c..752aefdf7 100644
--- a/examples/stm32h7/src/bin/sdmmc.rs
+++ b/examples/stm32h7/src/bin/sdmmc.rs
@@ -16,7 +16,26 @@ 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 use embassy_stm32::rcc::*;
21 config.rcc.hsi = Some(Hsi::Mhz64);
22 config.rcc.csi = true;
23 config.rcc.pll_src = PllSource::Hsi;
24 config.rcc.pll1 = Some(Pll {
25 prediv: 4,
26 mul: 50,
27 divp: Some(2),
28 divq: Some(4), // default clock chosen by SDMMCSEL. 200 Mhz
29 divr: None,
30 });
31 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
32 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
33 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
34 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
35 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
36 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
37 config.rcc.voltage_scale = VoltageScale::Scale1;
38 }
20 let p = embassy_stm32::init(config); 39 let p = embassy_stm32::init(config);
21 info!("Hello World!"); 40 info!("Hello World!");
22 41
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs
index 28bba2b8d..9fe46f031 100644
--- a/examples/stm32h7/src/bin/spi.rs
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -38,9 +38,26 @@ fn main() -> ! {
38 info!("Hello World!"); 38 info!("Hello World!");
39 39
40 let mut config = Config::default(); 40 let mut config = Config::default();
41 config.rcc.sys_ck = Some(mhz(400)); 41 {
42 config.rcc.hclk = Some(mhz(200)); 42 use embassy_stm32::rcc::*;
43 config.rcc.pll1.q_ck = Some(mhz(100)); 43 config.rcc.hsi = Some(Hsi::Mhz64);
44 config.rcc.csi = true;
45 config.rcc.pll_src = PllSource::Hsi;
46 config.rcc.pll1 = Some(Pll {
47 prediv: 4,
48 mul: 50,
49 divp: Some(2),
50 divq: Some(4), // used by SPI3. 100Mhz.
51 divr: None,
52 });
53 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
54 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
55 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
56 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
57 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
58 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
59 config.rcc.voltage_scale = VoltageScale::Scale1;
60 }
44 let p = embassy_stm32::init(config); 61 let p = embassy_stm32::init(config);
45 62
46 let mut spi_config = spi::Config::default(); 63 let mut spi_config = spi::Config::default();
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
index f6e30cfa5..88d65d5be 100644
--- a/examples/stm32h7/src/bin/spi_dma.rs
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -34,9 +34,26 @@ fn main() -> ! {
34 info!("Hello World!"); 34 info!("Hello World!");
35 35
36 let mut config = Config::default(); 36 let mut config = Config::default();
37 config.rcc.sys_ck = Some(mhz(400)); 37 {
38 config.rcc.hclk = Some(mhz(200)); 38 use embassy_stm32::rcc::*;
39 config.rcc.pll1.q_ck = Some(mhz(100)); 39 config.rcc.hsi = Some(Hsi::Mhz64);
40 config.rcc.csi = true;
41 config.rcc.pll_src = PllSource::Hsi;
42 config.rcc.pll1 = Some(Pll {
43 prediv: 4,
44 mul: 50,
45 divp: Some(2),
46 divq: Some(4), // used by SPI3. 100Mhz.
47 divr: None,
48 });
49 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
50 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
51 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
52 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
53 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
54 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
55 config.rcc.voltage_scale = VoltageScale::Scale1;
56 }
40 let p = embassy_stm32::init(config); 57 let p = embassy_stm32::init(config);
41 58
42 let mut spi_config = spi::Config::default(); 59 let mut spi_config = spi::Config::default();
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index 97291f60c..14de43568 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -4,7 +4,6 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::time::mhz;
8use embassy_stm32::usb_otg::{Driver, Instance}; 7use embassy_stm32::usb_otg::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -22,9 +21,27 @@ async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 21 info!("Hello World!");
23 22
24 let mut config = Config::default(); 23 let mut config = Config::default();
25 config.rcc.sys_ck = Some(mhz(400)); 24 {
26 config.rcc.hclk = Some(mhz(200)); 25 use embassy_stm32::rcc::*;
27 config.rcc.pll1.q_ck = Some(mhz(100)); 26 config.rcc.hsi = Some(Hsi::Mhz64);
27 config.rcc.csi = true;
28 config.rcc.hsi48 = true; // needed for USB
29 config.rcc.pll_src = PllSource::Hsi;
30 config.rcc.pll1 = Some(Pll {
31 prediv: 4,
32 mul: 50,
33 divp: Some(2),
34 divq: None,
35 divr: None,
36 });
37 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
38 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
39 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
40 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
41 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
42 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
43 config.rcc.voltage_scale = VoltageScale::Scale1;
44 }
28 let p = embassy_stm32::init(config); 45 let p = embassy_stm32::init(config);
29 46
30 // Create the driver, from the HAL. 47 // Create the driver, from the HAL.
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index ca5cb43ac..3a1b5c3ec 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -31,9 +31,32 @@ pub fn config() -> Config {
31 31
32 #[cfg(feature = "stm32h755zi")] 32 #[cfg(feature = "stm32h755zi")]
33 { 33 {
34 config.rcc.sys_ck = Some(Hertz(400_000_000)); 34 use embassy_stm32::rcc::*;
35 config.rcc.pll1.q_ck = Some(Hertz(100_000_000)); 35 config.rcc.hsi = Some(Hsi::Mhz64);
36 config.rcc.adc_clock_source = embassy_stm32::rcc::AdcClockSource::PerCk; 36 config.rcc.csi = true;
37 config.rcc.pll_src = PllSource::Hsi;
38 config.rcc.pll1 = Some(Pll {
39 prediv: 4,
40 mul: 50,
41 divp: Some(2),
42 divq: Some(8), // SPI1 cksel defaults to pll1_q
43 divr: None,
44 });
45 config.rcc.pll2 = Some(Pll {
46 prediv: 4,
47 mul: 50,
48 divp: Some(8), // 100mhz
49 divq: None,
50 divr: None,
51 });
52 config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
53 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
54 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
55 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
56 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
57 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
58 config.rcc.voltage_scale = VoltageScale::Scale1;
59 config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
37 } 60 }
38 61
39 #[cfg(feature = "stm32u585ai")] 62 #[cfg(feature = "stm32u585ai")]