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