aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-10-18 03:16:36 +0200
committerDario Nieuwenhuis <[email protected]>2023-10-18 05:01:11 +0200
commit67010d123c874383f48ccd5c1b2287907677e460 (patch)
tree806c4259519c3883e697c1327cf1231b92ea1005
parent361fde35cf37e5c8171ab470449e85ad44da4e52 (diff)
stm32/rcc: refactor f7.
-rw-r--r--embassy-stm32/src/rcc/f7.rs503
-rw-r--r--examples/stm32f7/src/bin/eth.rs22
-rw-r--r--examples/stm32f7/src/bin/hello.rs4
-rw-r--r--examples/stm32f7/src/bin/sdmmc.rs23
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs25
-rw-r--r--tests/stm32/src/common.rs18
6 files changed, 333 insertions, 262 deletions
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs
index 7c6c150d9..a984e4f4b 100644
--- a/embassy-stm32/src/rcc/f7.rs
+++ b/embassy-stm32/src/rcc/f7.rs
@@ -1,5 +1,7 @@
1use crate::pac::pwr::vals::Vos; 1pub use crate::pac::rcc::vals::{
2use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllp, Pllq, Pllsrc, Ppre, Sw}; 2 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp, Pllq, Pllr, Pllsrc as PllSource,
3 Ppre as APBPrescaler, Sw as Sysclk,
4};
3use crate::pac::{FLASH, PWR, RCC}; 5use crate::pac::{FLASH, PWR, RCC};
4use crate::rcc::{set_freqs, Clocks}; 6use crate::rcc::{set_freqs, Clocks};
5use crate::time::Hertz; 7use crate::time::Hertz;
@@ -7,299 +9,304 @@ use crate::time::Hertz;
7/// HSI speed 9/// HSI speed
8pub const HSI_FREQ: Hertz = Hertz(16_000_000); 10pub const HSI_FREQ: Hertz = Hertz(16_000_000);
9 11
10/// Clocks configuration 12#[derive(Clone, Copy, Eq, PartialEq)]
11#[non_exhaustive] 13pub enum HseMode {
12#[derive(Default)] 14 /// crystal/ceramic oscillator (HSEBYP=0)
13pub struct Config { 15 Oscillator,
14 pub hse: Option<Hertz>, 16 /// external analog clock (low swing) (HSEBYP=1)
15 pub bypass_hse: bool, 17 Bypass,
16 pub hclk: Option<Hertz>,
17 pub sys_ck: Option<Hertz>,
18 pub pclk1: Option<Hertz>,
19 pub pclk2: Option<Hertz>,
20
21 pub pll48: bool,
22 pub ls: super::LsConfig,
23} 18}
24 19
25fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { 20#[derive(Clone, Copy, Eq, PartialEq)]
26 let sysclk = pllsysclk.unwrap_or(pllsrcclk); 21pub struct Hse {
27 if pllsysclk.is_none() && !pll48clk { 22 /// HSE frequency.
28 RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8))); 23 pub freq: Hertz,
29 24 /// HSE mode.
30 return PllResults { 25 pub mode: HseMode,
31 use_pll: false, 26}
32 pllsysclk: None,
33 pll48clk: None,
34 };
35 }
36 // Input divisor from PLL source clock, must result to frequency in
37 // the range from 1 to 2 MHz
38 let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
39 let pllm_max = pllsrcclk / 1_000_000;
40
41 // Sysclk output divisor must be one of 2, 4, 6 or 8
42 let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
43
44 let target_freq = if pll48clk { 48_000_000 } else { sysclk * sysclk_div };
45
46 // Find the lowest pllm value that minimize the difference between
47 // target frequency and the real vco_out frequency.
48 let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
49 let vco_in = pllsrcclk / pllm;
50 let plln = target_freq / vco_in;
51 target_freq - vco_in * plln
52 }));
53
54 let vco_in = pllsrcclk / pllm;
55 assert!((1_000_000..=2_000_000).contains(&vco_in));
56
57 // Main scaler, must result in >= 100MHz (>= 192MHz for F401)
58 // and <= 432MHz, min 50, max 432
59 let plln = if pll48clk {
60 // try the different valid pllq according to the valid
61 // main scaller values, and take the best
62 let pllq = unwrap!((4..=9).min_by_key(|pllq| {
63 let plln = 48_000_000 * pllq / vco_in;
64 let pll48_diff = 48_000_000 - vco_in * plln / pllq;
65 let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
66 (pll48_diff, sysclk_diff)
67 }));
68 48_000_000 * pllq / vco_in
69 } else {
70 sysclk * sysclk_div / vco_in
71 };
72 27
73 let pllp = (sysclk_div / 2) - 1; 28#[derive(Clone, Copy)]
29pub struct Pll {
30 /// PLL pre-divider (DIVM).
31 pub prediv: PllPreDiv,
74 32
75 let pllq = (vco_in * plln + 47_999_999) / 48_000_000; 33 /// PLL multiplication factor.
76 let real_pll48clk = vco_in * plln / pllq; 34 pub mul: PllMul,
77 35
78 RCC.pllcfgr().modify(|w| { 36 /// PLL P division factor. If None, PLL P output is disabled.
79 w.set_pllm(Pllm::from_bits(pllm as u8)); 37 pub divp: Option<Pllp>,
80 w.set_plln(Plln::from_bits(plln as u16)); 38 /// PLL Q division factor. If None, PLL Q output is disabled.
81 w.set_pllp(Pllp::from_bits(pllp as u8)); 39 pub divq: Option<Pllq>,
82 w.set_pllq(Pllq::from_bits(pllq as u8)); 40 /// PLL R division factor. If None, PLL R output is disabled.
83 w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)); 41 pub divr: Option<Pllr>,
84 }); 42}
85 43
86 let real_pllsysclk = vco_in * plln / sysclk_div; 44/// Configuration of the core clocks
45#[non_exhaustive]
46pub struct Config {
47 pub hsi: bool,
48 pub hse: Option<Hse>,
49 pub sys: Sysclk,
87 50
88 PllResults { 51 pub pll_src: PllSource,
89 use_pll: true,
90 pllsysclk: Some(real_pllsysclk),
91 pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
92 }
93}
94 52
95fn flash_setup(sysclk: u32) { 53 pub pll: Option<Pll>,
96 use crate::pac::flash::vals::Latency; 54 pub plli2s: Option<Pll>,
55 pub pllsai: Option<Pll>,
97 56
98 // Be conservative with voltage ranges 57 pub ahb_pre: AHBPrescaler,
99 const FLASH_LATENCY_STEP: u32 = 30_000_000; 58 pub apb1_pre: APBPrescaler,
59 pub apb2_pre: APBPrescaler,
100 60
101 critical_section::with(|_| { 61 pub ls: super::LsConfig,
102 FLASH
103 .acr()
104 .modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
105 });
106} 62}
107 63
108pub(crate) unsafe fn init(config: Config) { 64impl Default for Config {
109 if let Some(hse) = config.hse { 65 fn default() -> Self {
110 if config.bypass_hse { 66 Self {
111 assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0)); 67 hsi: true,
112 } else { 68 hse: None,
113 assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0)); 69 sys: Sysclk::HSI,
70 pll_src: PllSource::HSI,
71 pll: None,
72 plli2s: None,
73 pllsai: None,
74
75 ahb_pre: AHBPrescaler::DIV1,
76 apb1_pre: APBPrescaler::DIV1,
77 apb2_pre: APBPrescaler::DIV1,
78
79 ls: Default::default(),
114 } 80 }
115 } 81 }
82}
116 83
117 let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0); 84pub(crate) unsafe fn init(config: Config) {
118 let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); 85 // always enable overdrive for now. Make it configurable in the future.
119 let sysclk_on_pll = sysclk != pllsrcclk; 86 PWR.cr1().modify(|w| w.set_oden(true));
87 while !PWR.csr1().read().odrdy() {}
88
89 PWR.cr1().modify(|w| w.set_odswen(true));
90 while !PWR.csr1().read().odswrdy() {}
91
92 // Configure HSI
93 let hsi = match config.hsi {
94 false => {
95 RCC.cr().modify(|w| w.set_hsion(false));
96 None
97 }
98 true => {
99 RCC.cr().modify(|w| w.set_hsion(true));
100 while !RCC.cr().read().hsirdy() {}
101 Some(HSI_FREQ)
102 }
103 };
120 104
121 assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk)); 105 // Configure HSE
106 let hse = match config.hse {
107 None => {
108 RCC.cr().modify(|w| w.set_hseon(false));
109 None
110 }
111 Some(hse) => {
112 match hse.mode {
113 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)),
114 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)),
115 }
116
117 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
118 RCC.cr().modify(|w| w.set_hseon(true));
119 while !RCC.cr().read().hserdy() {}
120 Some(hse.freq)
121 }
122 };
122 123
123 let plls = setup_pll( 124 // Configure PLLs.
124 pllsrcclk, 125 let pll_input = PllInput {
125 config.hse.is_some(), 126 hse,
126 if sysclk_on_pll { Some(sysclk) } else { None }, 127 hsi,
127 config.pll48, 128 source: config.pll_src,
128 ); 129 };
130 let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
131 let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input);
132 let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input);
133
134 // Configure sysclk
135 let sys = match config.sys {
136 Sysclk::HSI => unwrap!(hsi),
137 Sysclk::HSE => unwrap!(hse),
138 Sysclk::PLL1_P => unwrap!(pll.p),
139 _ => unreachable!(),
140 };
129 141
130 if config.pll48 { 142 let hclk = sys / config.ahb_pre;
131 let freq = unwrap!(plls.pll48clk); 143 let (pclk1, pclk1_tim) = calc_pclk(hclk, config.apb1_pre);
144 let (pclk2, pclk2_tim) = calc_pclk(hclk, config.apb2_pre);
132 145
133 assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32); 146 assert!(max::SYSCLK.contains(&sys));
134 } 147 assert!(max::HCLK.contains(&hclk));
148 assert!(max::PCLK1.contains(&pclk1));
149 assert!(max::PCLK2.contains(&pclk2));
135 150
136 let sysclk = if sysclk_on_pll { unwrap!(plls.pllsysclk) } else { sysclk }; 151 let rtc = config.ls.init();
137
138 // AHB prescaler
139 let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
140 let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
141 0 => unreachable!(),
142 1 => (Hpre::DIV1, 1),
143 2 => (Hpre::DIV2, 2),
144 3..=5 => (Hpre::DIV4, 4),
145 6..=11 => (Hpre::DIV8, 8),
146 12..=39 => (Hpre::DIV16, 16),
147 40..=95 => (Hpre::DIV64, 64),
148 96..=191 => (Hpre::DIV128, 128),
149 192..=383 => (Hpre::DIV256, 256),
150 _ => (Hpre::DIV512, 512),
151 };
152 152
153 // Calculate real AHB clock 153 flash_setup(hclk);
154 let hclk = sysclk / hpre_div;
155 154
156 assert!(hclk <= max::HCLK_MAX); 155 RCC.cfgr().modify(|w| {
156 w.set_sw(config.sys);
157 w.set_hpre(config.ahb_pre);
158 w.set_ppre1(config.apb1_pre);
159 w.set_ppre2(config.apb2_pre);
160 });
161 while RCC.cfgr().read().sws() != config.sys {}
157 162
158 let pclk1 = config 163 set_freqs(Clocks {
159 .pclk1 164 sys,
160 .map(|p| p.0) 165 hclk1: hclk,
161 .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk)); 166 hclk2: hclk,
167 hclk3: hclk,
168 pclk1,
169 pclk2,
170 pclk1_tim,
171 pclk2_tim,
172 rtc,
173 pll1_q: pll.q,
174 });
175}
162 176
163 let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 { 177struct PllInput {
164 0 => unreachable!(), 178 source: PllSource,
165 1 => (0b000, 1), 179 hsi: Option<Hertz>,
166 2 => (0b100, 2), 180 hse: Option<Hertz>,
167 3..=5 => (0b101, 4), 181}
168 6..=11 => (0b110, 8),
169 _ => (0b111, 16),
170 };
171 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
172
173 // Calculate real APB1 clock
174 let pclk1 = hclk / ppre1;
175 assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1));
176
177 let pclk2 = config
178 .pclk2
179 .map(|p| p.0)
180 .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
181 let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
182 0 => unreachable!(),
183 1 => (0b000, 1),
184 2 => (0b100, 2),
185 3..=5 => (0b101, 4),
186 6..=11 => (0b110, 8),
187 _ => (0b111, 16),
188 };
189 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
190 182
191 // Calculate real APB2 clock 183#[derive(Default)]
192 let pclk2 = hclk / ppre2; 184#[allow(unused)]
193 assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2)); 185struct PllOutput {
186 p: Option<Hertz>,
187 q: Option<Hertz>,
188 r: Option<Hertz>,
189}
194 190
195 flash_setup(sysclk); 191#[derive(PartialEq, Eq, Clone, Copy)]
192enum PllInstance {
193 Pll,
194 Plli2s,
195 Pllsai,
196}
196 197
197 if config.hse.is_some() { 198fn pll_enable(instance: PllInstance, enabled: bool) {
198 RCC.cr().modify(|w| { 199 match instance {
199 w.set_hsebyp(config.bypass_hse); 200 PllInstance::Pll => {
200 w.set_hseon(true); 201 RCC.cr().modify(|w| w.set_pllon(enabled));
201 }); 202 while RCC.cr().read().pllrdy() != enabled {}
202 while !RCC.cr().read().hserdy() {} 203 }
204 PllInstance::Plli2s => {
205 RCC.cr().modify(|w| w.set_plli2son(enabled));
206 while RCC.cr().read().plli2srdy() != enabled {}
207 }
208 PllInstance::Pllsai => {
209 RCC.cr().modify(|w| w.set_pllsaion(enabled));
210 while RCC.cr().read().pllsairdy() != enabled {}
211 }
203 } 212 }
213}
204 214
205 if plls.use_pll { 215fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput {
206 RCC.cr().modify(|w| w.set_pllon(false)); 216 // Disable PLL
217 pll_enable(instance, false);
207 218
208 // setup VOSScale 219 let Some(pll) = config else { return PllOutput::default() };
209 let vos_scale = if sysclk <= 144_000_000 {
210 3
211 } else if sysclk <= 168_000_000 {
212 2
213 } else {
214 1
215 };
216 PWR.cr1().modify(|w| {
217 w.set_vos(match vos_scale {
218 3 => Vos::SCALE3,
219 2 => Vos::SCALE2,
220 1 => Vos::SCALE1,
221 _ => panic!("Invalid VOS Scale."),
222 })
223 });
224
225 RCC.cr().modify(|w| w.set_pllon(true));
226
227 if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
228 PWR.cr1().modify(|w| w.set_oden(true));
229 while !PWR.csr1().read().odrdy() {}
230
231 PWR.cr1().modify(|w| w.set_odswen(true));
232 while !PWR.csr1().read().odswrdy() {}
233 }
234 220
235 while !RCC.cr().read().pllrdy() {} 221 let pll_src = match input.source {
236 } 222 PllSource::HSE => input.hse,
223 PllSource::HSI => input.hsi,
224 };
237 225
238 RCC.cfgr().modify(|w| { 226 let pll_src = pll_src.unwrap();
239 w.set_ppre2(Ppre::from_bits(ppre2_bits)); 227
240 w.set_ppre1(Ppre::from_bits(ppre1_bits)); 228 let in_freq = pll_src / pll.prediv;
241 w.set_hpre(hpre_bits); 229 assert!(max::PLL_IN.contains(&in_freq));
242 }); 230 let vco_freq = in_freq * pll.mul;
231 assert!(max::PLL_VCO.contains(&vco_freq));
232
233 let p = pll.divp.map(|div| vco_freq / div);
234 let q = pll.divq.map(|div| vco_freq / div);
235 let r = pll.divr.map(|div| vco_freq / div);
236
237 macro_rules! write_fields {
238 ($w:ident) => {
239 $w.set_plln(pll.mul);
240 if let Some(divp) = pll.divp {
241 $w.set_pllp(divp);
242 }
243 if let Some(divq) = pll.divq {
244 $w.set_pllq(divq);
245 }
246 if let Some(divr) = pll.divr {
247 $w.set_pllr(divr);
248 }
249 };
250 }
243 251
244 // Wait for the new prescalers to kick in 252 match instance {
245 // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write" 253 PllInstance::Pll => RCC.pllcfgr().write(|w| {
246 cortex_m::asm::delay(16); 254 w.set_pllm(pll.prediv);
255 w.set_pllsrc(input.source);
256 write_fields!(w);
257 }),
258 PllInstance::Plli2s => RCC.plli2scfgr().write(|w| {
259 write_fields!(w);
260 }),
261 PllInstance::Pllsai => RCC.pllsaicfgr().write(|w| {
262 write_fields!(w);
263 }),
264 }
247 265
248 RCC.cfgr().modify(|w| { 266 // Enable PLL
249 w.set_sw(if sysclk_on_pll { 267 pll_enable(instance, true);
250 Sw::PLL1_P
251 } else if config.hse.is_some() {
252 Sw::HSE
253 } else {
254 Sw::HSI
255 })
256 });
257 268
258 let rtc = config.ls.init(); 269 PllOutput { p, q, r }
259 270}
260 set_freqs(Clocks {
261 sys: Hertz(sysclk),
262 pclk1: Hertz(pclk1),
263 pclk2: Hertz(pclk2),
264 271
265 pclk1_tim: Hertz(pclk1 * timer_mul1), 272fn flash_setup(clk: Hertz) {
266 pclk2_tim: Hertz(pclk2 * timer_mul2), 273 use crate::pac::flash::vals::Latency;
267 274
268 hclk1: Hertz(hclk), 275 // Be conservative with voltage ranges
269 hclk2: Hertz(hclk), 276 const FLASH_LATENCY_STEP: u32 = 30_000_000;
270 hclk3: Hertz(hclk),
271 277
272 pll1_q: plls.pll48clk.map(Hertz), 278 let latency = (clk.0 - 1) / FLASH_LATENCY_STEP;
279 debug!("flash: latency={}", latency);
273 280
274 rtc, 281 let latency = Latency::from_bits(latency as u8);
282 FLASH.acr().write(|w| {
283 w.set_latency(latency);
275 }); 284 });
285 while FLASH.acr().read().latency() != latency {}
276} 286}
277 287
278struct PllResults { 288fn calc_pclk<D>(hclk: Hertz, ppre: D) -> (Hertz, Hertz)
279 use_pll: bool, 289where
280 pllsysclk: Option<u32>, 290 Hertz: core::ops::Div<D, Output = Hertz>,
281 pll48clk: Option<u32>, 291{
292 let pclk = hclk / ppre;
293 let pclk_tim = if hclk == pclk { pclk } else { pclk * 2u32 };
294 (pclk, pclk_tim)
282} 295}
283 296
284mod max { 297mod max {
285 pub(crate) const HSE_OSC_MIN: u32 = 4_000_000; 298 use core::ops::RangeInclusive;
286 pub(crate) const HSE_OSC_MAX: u32 = 26_000_000;
287 pub(crate) const HSE_BYPASS_MIN: u32 = 1_000_000;
288 pub(crate) const HSE_BYPASS_MAX: u32 = 50_000_000;
289
290 pub(crate) const HCLK_MAX: u32 = 216_000_000;
291 pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 180_000_000;
292 299
293 pub(crate) const SYSCLK_MIN: u32 = 12_500_000; 300 use crate::time::Hertz;
294 pub(crate) const SYSCLK_MAX: u32 = 216_000_000;
295 301
296 pub(crate) const PCLK1_MIN: u32 = SYSCLK_MIN; 302 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(26_000_000);
297 pub(crate) const PCLK1_MAX: u32 = SYSCLK_MAX / 4; 303 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(50_000_000);
298 304
299 pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN; 305 pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(12_500_000)..=Hertz(216_000_000);
300 pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2; 306 pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(12_500_000)..=Hertz(216_000_000);
307 pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(12_500_000)..=Hertz(216_000_000 / 4);
308 pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(12_500_000)..=Hertz(216_000_000 / 2);
301 309
302 // USB specification allows +-0.25% 310 pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(2_100_000);
303 pub(crate) const PLL_48_CLK: u32 = 48_000_000; 311 pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(100_000_000)..=Hertz(432_000_000);
304 pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
305} 312}
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index d50473b9d..7c6c419a6 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -10,7 +10,7 @@ use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, PacketQueue}; 10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH; 11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng; 12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz; 13use embassy_stm32::time::Hertz;
14use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 14use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
15use embassy_time::Timer; 15use embassy_time::Timer;
16use embedded_io_async::Write; 16use embedded_io_async::Write;
@@ -33,7 +33,25 @@ async fn net_task(stack: &'static Stack<Device>) -> ! {
33#[embassy_executor::main] 33#[embassy_executor::main]
34async fn main(spawner: Spawner) -> ! { 34async fn main(spawner: Spawner) -> ! {
35 let mut config = Config::default(); 35 let mut config = Config::default();
36 config.rcc.sys_ck = Some(mhz(200)); 36 {
37 use embassy_stm32::rcc::*;
38 config.rcc.hse = Some(Hse {
39 freq: Hertz(8_000_000),
40 mode: HseMode::Bypass,
41 });
42 config.rcc.pll_src = PllSource::HSE;
43 config.rcc.pll = Some(Pll {
44 prediv: PllPreDiv::DIV4,
45 mul: PllMul::MUL216,
46 divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz
47 divq: None,
48 divr: None,
49 });
50 config.rcc.ahb_pre = AHBPrescaler::DIV1;
51 config.rcc.apb1_pre = APBPrescaler::DIV4;
52 config.rcc.apb2_pre = APBPrescaler::DIV2;
53 config.rcc.sys = Sysclk::PLL1_P;
54 }
37 let p = embassy_stm32::init(config); 55 let p = embassy_stm32::init(config);
38 56
39 info!("Hello World!"); 57 info!("Hello World!");
diff --git a/examples/stm32f7/src/bin/hello.rs b/examples/stm32f7/src/bin/hello.rs
index 27ee83aa5..a2a287110 100644
--- a/examples/stm32f7/src/bin/hello.rs
+++ b/examples/stm32f7/src/bin/hello.rs
@@ -4,15 +4,13 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::time::Hertz;
8use embassy_stm32::Config; 7use embassy_stm32::Config;
9use embassy_time::Timer; 8use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
11 10
12#[embassy_executor::main] 11#[embassy_executor::main]
13async fn main(_spawner: Spawner) -> ! { 12async fn main(_spawner: Spawner) -> ! {
14 let mut config = Config::default(); 13 let config = Config::default();
15 config.rcc.sys_ck = Some(Hertz(84_000_000));
16 let _p = embassy_stm32::init(config); 14 let _p = embassy_stm32::init(config);
17 15
18 loop { 16 loop {
diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs
index 9d43892a0..430aa781f 100644
--- a/examples/stm32f7/src/bin/sdmmc.rs
+++ b/examples/stm32f7/src/bin/sdmmc.rs
@@ -5,7 +5,7 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::sdmmc::Sdmmc; 7use embassy_stm32::sdmmc::Sdmmc;
8use embassy_stm32::time::mhz; 8use embassy_stm32::time::{mhz, Hertz};
9use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
@@ -16,8 +16,25 @@ bind_interrupts!(struct Irqs {
16#[embassy_executor::main] 16#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
18 let mut config = Config::default(); 18 let mut config = Config::default();
19 config.rcc.sys_ck = Some(mhz(200)); 19 {
20 config.rcc.pll48 = true; 20 use embassy_stm32::rcc::*;
21 config.rcc.hse = Some(Hse {
22 freq: Hertz(8_000_000),
23 mode: HseMode::Bypass,
24 });
25 config.rcc.pll_src = PllSource::HSE;
26 config.rcc.pll = Some(Pll {
27 prediv: PllPreDiv::DIV4,
28 mul: PllMul::MUL216,
29 divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz
30 divq: Some(Pllq::DIV9), // 8mhz / 4 * 216 / 9 = 48Mhz
31 divr: None,
32 });
33 config.rcc.ahb_pre = AHBPrescaler::DIV1;
34 config.rcc.apb1_pre = APBPrescaler::DIV4;
35 config.rcc.apb2_pre = APBPrescaler::DIV2;
36 config.rcc.sys = Sysclk::PLL1_P;
37 }
21 let p = embassy_stm32::init(config); 38 let p = embassy_stm32::init(config);
22 39
23 info!("Hello World!"); 40 info!("Hello World!");
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index a2c76178b..2f832c234 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -4,7 +4,7 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::time::mhz; 7use embassy_stm32::time::Hertz;
8use embassy_stm32::usb_otg::{Driver, Instance}; 8use embassy_stm32::usb_otg::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -22,10 +22,25 @@ async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 22 info!("Hello World!");
23 23
24 let mut config = Config::default(); 24 let mut config = Config::default();
25 config.rcc.hse = Some(mhz(8)); 25 {
26 config.rcc.pll48 = true; 26 use embassy_stm32::rcc::*;
27 config.rcc.sys_ck = Some(mhz(200)); 27 config.rcc.hse = Some(Hse {
28 28 freq: Hertz(8_000_000),
29 mode: HseMode::Bypass,
30 });
31 config.rcc.pll_src = PllSource::HSE;
32 config.rcc.pll = Some(Pll {
33 prediv: PllPreDiv::DIV4,
34 mul: PllMul::MUL216,
35 divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz
36 divq: Some(Pllq::DIV9), // 8mhz / 4 * 216 / 9 = 48Mhz
37 divr: None,
38 });
39 config.rcc.ahb_pre = AHBPrescaler::DIV1;
40 config.rcc.apb1_pre = APBPrescaler::DIV4;
41 config.rcc.apb2_pre = APBPrescaler::DIV2;
42 config.rcc.sys = Sysclk::PLL1_P;
43 }
29 let p = embassy_stm32::init(config); 44 let p = embassy_stm32::init(config);
30 45
31 // Create the driver, from the HAL. 46 // Create the driver, from the HAL.
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 9f1307ce5..7bc741416 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -233,7 +233,23 @@ pub fn config() -> Config {
233 233
234 #[cfg(feature = "stm32f767zi")] 234 #[cfg(feature = "stm32f767zi")]
235 { 235 {
236 config.rcc.sys_ck = Some(Hertz(200_000_000)); 236 use embassy_stm32::rcc::*;
237 config.rcc.hse = Some(Hse {
238 freq: Hertz(8_000_000),
239 mode: HseMode::Bypass,
240 });
241 config.rcc.pll_src = PllSource::HSE;
242 config.rcc.pll = Some(Pll {
243 prediv: PllPreDiv::DIV4,
244 mul: PllMul::MUL216,
245 divp: Some(Pllp::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz.
246 divq: None,
247 divr: None,
248 });
249 config.rcc.ahb_pre = AHBPrescaler::DIV1;
250 config.rcc.apb1_pre = APBPrescaler::DIV4;
251 config.rcc.apb2_pre = APBPrescaler::DIV2;
252 config.rcc.sys = Sysclk::PLL1_P;
237 } 253 }
238 254
239 #[cfg(feature = "stm32h563zi")] 255 #[cfg(feature = "stm32h563zi")]