aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/rcc/u5.rs346
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs7
2 files changed, 267 insertions, 86 deletions
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index d9a531285..14b8577df 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -1,7 +1,7 @@
1use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw}; 1use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllmboost, Pllrge, Pllsrc, Sw};
2 2
3pub use super::bus::{AHBPrescaler, APBPrescaler}; 3pub use super::bus::{AHBPrescaler, APBPrescaler};
4use crate::pac::{FLASH, RCC}; 4use crate::pac::{FLASH, PWR, RCC};
5use crate::rcc::{set_freqs, Clocks}; 5use crate::rcc::{set_freqs, Clocks};
6use crate::time::Hertz; 6use crate::time::Hertz;
7 7
@@ -15,23 +15,86 @@ pub use crate::pac::pwr::vals::Vos as VoltageScale;
15 15
16#[derive(Copy, Clone)] 16#[derive(Copy, Clone)]
17pub enum ClockSrc { 17pub enum ClockSrc {
18 /// Use an internal medium speed oscillator (MSIS) as the system clock.
18 MSI(MSIRange), 19 MSI(MSIRange),
20 /// Use the external high speed clock as the system clock.
21 ///
22 /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must
23 /// never exceed 50 MHz.
19 HSE(Hertz), 24 HSE(Hertz),
25 /// Use the 16 MHz internal high speed oscillator as the system clock.
20 HSI16, 26 HSI16,
21 PLL1R(PllSrc, PllM, PllN, PllClkDiv), 27 /// Use PLL1 as the system clock.
28 PLL1R(PllConfig),
29}
30
31impl Default for ClockSrc {
32 fn default() -> Self {
33 // The default system clock source is MSIS @ 4 MHz, per RM0456 § 11.4.9
34 ClockSrc::MSI(MSIRange::Range4mhz)
35 }
36}
37
38#[derive(Clone, Copy, Debug)]
39pub struct PllConfig {
40 /// The clock source for the PLL.
41 pub source: PllSrc,
42 /// The PLL prescaler.
43 ///
44 /// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz.
45 pub m: PllM,
46 /// The PLL multiplier.
47 ///
48 /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544
49 /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`.
50 pub n: PllN,
51 /// The divider for the R output.
52 ///
53 /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r`
54 /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default
55 /// `Config { voltage_range }`.
56 pub r: PllClkDiv,
57}
58
59impl PllConfig {
60 /// A configuration for HSI16 / 1 * 10 / 1 = 160 MHz
61 pub const fn hsi16_160mhz() -> Self {
62 PllConfig {
63 source: PllSrc::HSI16,
64 m: PllM::NotDivided,
65 n: PllN::Mul10,
66 r: PllClkDiv::NotDivided,
67 }
68 }
69
70 /// A configuration for MSIS @ 48 MHz / 3 * 10 / 1 = 160 MHz
71 pub const fn msis_160mhz() -> Self {
72 PllConfig {
73 source: PllSrc::MSIS(MSIRange::Range48mhz),
74 m: PllM::Div3,
75 n: PllN::Mul10,
76 r: PllClkDiv::NotDivided,
77 }
78 }
22} 79}
23 80
24#[derive(Clone, Copy, Debug)] 81#[derive(Clone, Copy, Debug)]
25pub enum PllSrc { 82pub enum PllSrc {
26 MSI(MSIRange), 83 /// Use an internal medium speed oscillator as the PLL source.
84 MSIS(MSIRange),
85 /// Use the external high speed clock as the system PLL source.
86 ///
87 /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must
88 /// never exceed 50 MHz.
27 HSE(Hertz), 89 HSE(Hertz),
90 /// Use the 16 MHz internal high speed oscillator as the PLL source.
28 HSI16, 91 HSI16,
29} 92}
30 93
31impl Into<Pllsrc> for PllSrc { 94impl Into<Pllsrc> for PllSrc {
32 fn into(self) -> Pllsrc { 95 fn into(self) -> Pllsrc {
33 match self { 96 match self {
34 PllSrc::MSI(..) => Pllsrc::MSIS, 97 PllSrc::MSIS(..) => Pllsrc::MSIS,
35 PllSrc::HSE(..) => Pllsrc::HSE, 98 PllSrc::HSE(..) => Pllsrc::HSE,
36 PllSrc::HSI16 => Pllsrc::HSI16, 99 PllSrc::HSI16 => Pllsrc::HSI16,
37 } 100 }
@@ -41,57 +104,45 @@ impl Into<Pllsrc> for PllSrc {
41seq_macro::seq!(N in 2..=128 { 104seq_macro::seq!(N in 2..=128 {
42 #[derive(Copy, Clone, Debug)] 105 #[derive(Copy, Clone, Debug)]
43 pub enum PllClkDiv { 106 pub enum PllClkDiv {
44 NotDivided, 107 NotDivided = 1,
45 #( 108 #(
46 Div~N = (N-1), 109 Div~N = N,
47 )* 110 )*
48 } 111 }
49 112
50 impl PllClkDiv { 113 impl PllClkDiv {
51 fn to_div(&self) -> u8 { 114 fn to_div(&self) -> u8 {
52 match self { 115 match self {
53 PllClkDiv::NotDivided => 1, 116 PllClkDiv::NotDivided => 0,
54 #( 117 #(
55 PllClkDiv::Div~N => N + 1, 118 PllClkDiv::Div~N => N - 1,
56 )* 119 )*
57 } 120 }
58 } 121 }
59 } 122 }
60}); 123});
61 124
62impl Into<u8> for PllClkDiv {
63 fn into(self) -> u8 {
64 (self as u8) + 1
65 }
66}
67
68seq_macro::seq!(N in 4..=512 { 125seq_macro::seq!(N in 4..=512 {
69 #[derive(Copy, Clone, Debug)] 126 #[derive(Copy, Clone, Debug)]
70 pub enum PllN { 127 pub enum PllN {
71 NotMultiplied, 128 NotMultiplied = 1,
72 #( 129 #(
73 Mul~N = N-1, 130 Mul~N = N,
74 )* 131 )*
75 } 132 }
76 133
77 impl PllN { 134 impl PllN {
78 fn to_mul(&self) -> u16 { 135 fn to_mul(&self) -> u16 {
79 match self { 136 match self {
80 PllN::NotMultiplied => 1, 137 PllN::NotMultiplied => 0,
81 #( 138 #(
82 PllN::Mul~N => N + 1, 139 PllN::Mul~N => N - 1,
83 )* 140 )*
84 } 141 }
85 } 142 }
86 } 143 }
87}); 144});
88 145
89impl Into<u16> for PllN {
90 fn into(self) -> u16 {
91 (self as u16) + 1
92 }
93}
94
95// Pre-division 146// Pre-division
96#[derive(Copy, Clone, Debug)] 147#[derive(Copy, Clone, Debug)]
97pub enum PllM { 148pub enum PllM {
@@ -132,6 +183,7 @@ impl Into<Sw> for ClockSrc {
132 183
133#[derive(Debug, Copy, Clone)] 184#[derive(Debug, Copy, Clone)]
134pub enum MSIRange { 185pub enum MSIRange {
186 /// The 48 MHz MSI speed is unavailable in `VoltageScale::RANGE4`.
135 Range48mhz = 48_000_000, 187 Range48mhz = 48_000_000,
136 Range24mhz = 24_000_000, 188 Range24mhz = 24_000_000,
137 Range16mhz = 16_000_000, 189 Range16mhz = 16_000_000,
@@ -179,12 +231,6 @@ impl Into<Msirange> for MSIRange {
179 } 231 }
180} 232}
181 233
182impl Default for MSIRange {
183 fn default() -> Self {
184 MSIRange::Range4mhz
185 }
186}
187
188#[derive(Copy, Clone)] 234#[derive(Copy, Clone)]
189pub struct Config { 235pub struct Config {
190 pub mux: ClockSrc, 236 pub mux: ClockSrc,
@@ -193,103 +239,220 @@ pub struct Config {
193 pub apb2_pre: APBPrescaler, 239 pub apb2_pre: APBPrescaler,
194 pub apb3_pre: APBPrescaler, 240 pub apb3_pre: APBPrescaler,
195 pub hsi48: bool, 241 pub hsi48: bool,
242 /// The voltage range influences the maximum clock frequencies for different parts of the
243 /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks
244 /// exceeding 55 MHz require at least `RANGE2`.
245 ///
246 /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits.
247 pub voltage_range: VoltageScale,
248}
249
250impl Config {
251 unsafe fn init_hsi16(&self) -> Hertz {
252 RCC.cr().write(|w| w.set_hsion(true));
253 while !RCC.cr().read().hsirdy() {}
254
255 HSI_FREQ
256 }
257
258 unsafe fn init_hse(&self, frequency: Hertz) -> Hertz {
259 // Check frequency limits per RM456 § 11.4.10
260 match self.voltage_range {
261 VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => {
262 assert!(frequency.0 <= 50_000_000);
263 }
264 VoltageScale::RANGE4 => {
265 assert!(frequency.0 <= 25_000_000);
266 }
267 }
268
269 // Enable HSE, and wait for it to stabilize
270 RCC.cr().write(|w| w.set_hseon(true));
271 while !RCC.cr().read().hserdy() {}
272
273 frequency
274 }
275
276 unsafe fn init_msis(&self, range: MSIRange) -> Hertz {
277 // Check MSI output per RM0456 § 11.4.10
278 match self.voltage_range {
279 VoltageScale::RANGE4 => {
280 assert!(range as u32 <= 24_000_000);
281 }
282 _ => {}
283 }
284
285 // RM0456 § 11.8.2: spin until MSIS is off or MSIS is ready before setting its range
286 loop {
287 let cr = RCC.cr().read();
288 if cr.msison() == false || cr.msisrdy() == true {
289 break;
290 }
291 }
292
293 RCC.icscr1().modify(|w| {
294 let bits: Msirange = range.into();
295 w.set_msisrange(bits);
296 w.set_msirgsel(Msirgsel::RCC_ICSCR1);
297 });
298 RCC.cr().write(|w| {
299 w.set_msipllen(false);
300 w.set_msison(true);
301 });
302 while !RCC.cr().read().msisrdy() {}
303 Hertz(range as u32)
304 }
196} 305}
197 306
198impl Default for Config { 307impl Default for Config {
199 fn default() -> Self { 308 fn default() -> Self {
200 Self { 309 Self {
201 mux: ClockSrc::MSI(MSIRange::default()), 310 mux: ClockSrc::default(),
202 ahb_pre: AHBPrescaler::DIV1, 311 ahb_pre: AHBPrescaler::DIV1,
203 apb1_pre: APBPrescaler::DIV1, 312 apb1_pre: APBPrescaler::DIV1,
204 apb2_pre: APBPrescaler::DIV1, 313 apb2_pre: APBPrescaler::DIV1,
205 apb3_pre: APBPrescaler::DIV1, 314 apb3_pre: APBPrescaler::DIV1,
206 hsi48: false, 315 hsi48: false,
316 voltage_range: VoltageScale::RANGE3,
207 } 317 }
208 } 318 }
209} 319}
210 320
211pub(crate) unsafe fn init(config: Config) { 321pub(crate) unsafe fn init(config: Config) {
322 // Ensure PWR peripheral clock is enabled
323 RCC.ahb3enr().modify(|w| {
324 w.set_pwren(true);
325 });
326 RCC.ahb3enr().read(); // synchronize
327
328 // Set the requested power mode
329 PWR.vosr().modify(|w| {
330 w.set_vos(config.voltage_range);
331 });
332 while !PWR.vosr().read().vosrdy() {}
333
212 let sys_clk = match config.mux { 334 let sys_clk = match config.mux {
213 ClockSrc::MSI(range) => { 335 ClockSrc::MSI(range) => config.init_msis(range),
214 RCC.icscr1().modify(|w| { 336 ClockSrc::HSE(freq) => config.init_hse(freq),
215 let bits: Msirange = range.into(); 337 ClockSrc::HSI16 => config.init_hsi16(),
216 w.set_msisrange(bits); 338 ClockSrc::PLL1R(pll) => {
217 w.set_msirgsel(Msirgsel::RCC_ICSCR1); 339 // Configure the PLL source
218 }); 340 let source_clk = match pll.source {
219 RCC.cr().write(|w| { 341 PllSrc::MSIS(range) => config.init_msis(range),
220 w.set_msipllen(false); 342 PllSrc::HSE(hertz) => config.init_hse(hertz),
221 w.set_msison(true); 343 PllSrc::HSI16 => config.init_hsi16(),
222 }); 344 };
223 while !RCC.cr().read().msisrdy() {}
224 345
225 range.into() 346 // Calculate the reference clock, which is the source divided by m
226 } 347 let reference_clk = source_clk / (pll.m as u8 as u32 + 1);
227 ClockSrc::HSE(freq) => {
228 RCC.cr().write(|w| w.set_hseon(true));
229 while !RCC.cr().read().hserdy() {}
230 348
231 freq.0 349 // Check limits per RM0456 § 11.4.6
232 } 350 assert!(Hertz::mhz(4) <= reference_clk && reference_clk <= Hertz::mhz(16));
233 ClockSrc::HSI16 => {
234 RCC.cr().write(|w| w.set_hsion(true));
235 while !RCC.cr().read().hsirdy() {}
236 351
237 HSI_FREQ.0 352 // Calculate the PLL1 VCO clock and PLL1 R output clock
238 } 353 let pll1_clk = reference_clk * (pll.n as u8 as u32);
239 ClockSrc::PLL1R(src, m, n, div) => { 354 let pll1r_clk = pll1_clk / (pll.r as u8 as u32);
240 let freq = match src { 355
241 PllSrc::MSI(_) => { 356 // Check system clock per RM0456 § 11.4.9
242 // TODO: enable MSI 357 assert!(pll1r_clk <= Hertz::mhz(160));
243 MSIRange::default().into() 358
359 // Check PLL clocks per RM0456 § 11.4.10
360 match config.voltage_range {
361 VoltageScale::RANGE1 => {
362 assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544));
363 assert!(pll1r_clk <= Hertz::mhz(208));
244 } 364 }
245 PllSrc::HSE(hertz) => { 365 VoltageScale::RANGE2 => {
246 // TODO: enable HSE 366 assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544));
247 hertz.0 367 assert!(pll1r_clk <= Hertz::mhz(110));
248 } 368 }
249 PllSrc::HSI16 => { 369 VoltageScale::RANGE3 => {
250 RCC.cr().write(|w| w.set_hsion(true)); 370 assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(330));
251 while !RCC.cr().read().hsirdy() {} 371 assert!(pll1r_clk <= Hertz::mhz(55));
372 }
373 VoltageScale::RANGE4 => {
374 panic!("PLL is unavailable in voltage range 4");
375 }
376 }
252 377
253 HSI_FREQ.0 378 // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler
379 // value that results in an output between 4 and 16 MHz for the PWR EPOD boost
380 let mboost = if pll1r_clk >= Hertz::mhz(55) {
381 // source_clk can be up to 50 MHz, so there's just a few cases:
382 if source_clk > Hertz::mhz(32) {
383 // Divide by 4, giving EPOD 8-12.5 MHz
384 Pllmboost::DIV4
385 } else if source_clk > Hertz::mhz(16) {
386 // Divide by 2, giving EPOD 8-16 MHz
387 Pllmboost::DIV2
388 } else {
389 // Bypass, giving EPOD 4-16 MHz
390 Pllmboost::BYPASS
254 } 391 }
392 } else {
393 // Nothing to do
394 Pllmboost::BYPASS
255 }; 395 };
256 396
257 // disable 397 // Disable the PLL, and wait for it to disable
258 RCC.cr().modify(|w| w.set_pllon(0, false)); 398 RCC.cr().modify(|w| w.set_pllon(0, false));
259 while RCC.cr().read().pllrdy(0) {} 399 while RCC.cr().read().pllrdy(0) {}
260 400
261 let vco = freq * n as u8 as u32; 401 // Configure the PLL
262 let pll_ck = vco / (div as u8 as u32 + 1);
263
264 RCC.pll1cfgr().write(|w| { 402 RCC.pll1cfgr().write(|w| {
265 w.set_pllm(m.into()); 403 // Configure PLL1 source and prescaler
266 w.set_pllsrc(src.into()); 404 w.set_pllsrc(pll.source.into());
405 w.set_pllm(pll.m.into());
406
407 // Configure PLL1 input frequncy range
408 let input_range = if reference_clk <= Hertz::mhz(8) {
409 Pllrge::FREQ_4TO8MHZ
410 } else {
411 Pllrge::FREQ_8TO16MHZ
412 };
413 w.set_pllrge(input_range);
414
415 // Set the prescaler for PWR EPOD
416 w.set_pllmboost(mboost);
417
418 // Enable PLL1R output
267 w.set_pllren(true); 419 w.set_pllren(true);
268 }); 420 });
269 421
422 // Configure the PLL divisors
270 RCC.pll1divr().modify(|w| { 423 RCC.pll1divr().modify(|w| {
271 w.set_pllr(div.to_div()); 424 // Set the VCO multiplier
272 w.set_plln(n.to_mul()); 425 w.set_plln(pll.n.to_mul());
426 // Set the R output divisor
427 w.set_pllr(pll.r.to_div());
273 }); 428 });
274 429
275 // Enable PLL 430 // Do we need the EPOD booster to reach the target clock speed per § 10.5.4?
431 if pll1r_clk >= Hertz::mhz(55) {
432 // Enable the booster
433 PWR.vosr().modify(|w| {
434 w.set_boosten(true);
435 });
436 while !PWR.vosr().read().boostrdy() {}
437 }
438
439 // Enable the PLL
276 RCC.cr().modify(|w| w.set_pllon(0, true)); 440 RCC.cr().modify(|w| w.set_pllon(0, true));
277 while !RCC.cr().read().pllrdy(0) {} 441 while !RCC.cr().read().pllrdy(0) {}
278 442
279 pll_ck 443 pll1r_clk
280 } 444 }
281 }; 445 }
446 .0;
282 447
283 if config.hsi48 { 448 if config.hsi48 {
284 RCC.cr().modify(|w| w.set_hsi48on(true)); 449 RCC.cr().modify(|w| w.set_hsi48on(true));
285 while !RCC.cr().read().hsi48rdy() {} 450 while !RCC.cr().read().hsi48rdy() {}
286 } 451 }
287 452
288 // TODO make configurable 453 // The clock source is ready
289 let power_vos = VoltageScale::RANGE3; 454 // Calculate and set the flash wait states
290 455 let wait_states = match config.voltage_range {
291 // states and programming delay
292 let wait_states = match power_vos {
293 // VOS 1 range VCORE 1.26V - 1.40V 456 // VOS 1 range VCORE 1.26V - 1.40V
294 VoltageScale::RANGE1 => { 457 VoltageScale::RANGE1 => {
295 if sys_clk < 32_000_000 { 458 if sys_clk < 32_000_000 {
@@ -335,21 +498,34 @@ pub(crate) unsafe fn init(config: Config) {
335 } 498 }
336 } 499 }
337 }; 500 };
338
339 FLASH.acr().modify(|w| { 501 FLASH.acr().modify(|w| {
340 w.set_latency(wait_states); 502 w.set_latency(wait_states);
341 }); 503 });
342 504
505 // Switch the system clock source
343 RCC.cfgr1().modify(|w| { 506 RCC.cfgr1().modify(|w| {
344 w.set_sw(config.mux.into()); 507 w.set_sw(config.mux.into());
345 }); 508 });
346 509
510 // RM0456 § 11.4.9 specifies maximum bus frequencies per voltage range, but the maximum bus
511 // frequency for each voltage range exactly matches the maximum permitted PLL output frequency.
512 // Given that:
513 //
514 // 1. Any bus frequency can never exceed the system clock frequency;
515 // 2. We checked the PLL output frequency if we're using it as a system clock;
516 // 3. The maximum HSE frequencies at each voltage range are lower than the bus limits, and
517 // we checked the HSE frequency if configured as a system clock; and
518 // 4. The maximum frequencies from the other clock sources are lower than the lowest bus
519 // frequency limit
520 //
521 // ...then we do not need to perform additional bus-related frequency checks.
522
523 // Configure the bus prescalers
347 RCC.cfgr2().modify(|w| { 524 RCC.cfgr2().modify(|w| {
348 w.set_hpre(config.ahb_pre.into()); 525 w.set_hpre(config.ahb_pre.into());
349 w.set_ppre1(config.apb1_pre.into()); 526 w.set_ppre1(config.apb1_pre.into());
350 w.set_ppre2(config.apb2_pre.into()); 527 w.set_ppre2(config.apb2_pre.into());
351 }); 528 });
352
353 RCC.cfgr3().modify(|w| { 529 RCC.cfgr3().modify(|w| {
354 w.set_ppre3(config.apb3_pre.into()); 530 w.set_ppre3(config.apb3_pre.into());
355 }); 531 });
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index 9e47fb18a..278bd30f0 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -23,7 +23,12 @@ async fn main(_spawner: Spawner) {
23 info!("Hello World!"); 23 info!("Hello World!");
24 24
25 let mut config = Config::default(); 25 let mut config = Config::default();
26 config.rcc.mux = ClockSrc::PLL1R(PllSrc::HSI16, PllM::Div2, PllN::Mul10, PllClkDiv::NotDivided); 26 config.rcc.mux = ClockSrc::PLL1R(PllConfig {
27 source: PllSrc::HSI16,
28 m: PllM::Div2,
29 n: PllN::Mul10,
30 r: PllClkDiv::NotDivided,
31 });
27 //config.rcc.mux = ClockSrc::MSI(MSIRange::Range48mhz); 32 //config.rcc.mux = ClockSrc::MSI(MSIRange::Range48mhz);
28 config.rcc.hsi48 = true; 33 config.rcc.hsi48 = true;
29 34