diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-10-06 23:38:15 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-10-06 23:38:15 +0000 |
| commit | 3bf8e4de5ffba9428752835b45a546a8e420a288 (patch) | |
| tree | 7bf3f671a231a9de0512f16d8470eafe4924ff4e | |
| parent | 7a2b8481f7f574947e346b51ed3fe938f3a0fb58 (diff) | |
| parent | 38e7709a24982231a6a68dca4dddb75eb934c6bf (diff) | |
Merge pull request #2015 from willglynn/stm32u5_faster_clocks
stm32: u5: implement >55 MHz clock speeds
| -rw-r--r-- | embassy-stm32/src/rcc/u5.rs | 346 | ||||
| -rw-r--r-- | examples/stm32u5/src/bin/usb_serial.rs | 7 |
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 @@ | |||
| 1 | use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw}; | 1 | use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllmboost, Pllrge, Pllsrc, Sw}; |
| 2 | 2 | ||
| 3 | pub use super::bus::{AHBPrescaler, APBPrescaler}; | 3 | pub use super::bus::{AHBPrescaler, APBPrescaler}; |
| 4 | use crate::pac::{FLASH, RCC}; | 4 | use crate::pac::{FLASH, PWR, RCC}; |
| 5 | use crate::rcc::{set_freqs, Clocks}; | 5 | use crate::rcc::{set_freqs, Clocks}; |
| 6 | use crate::time::Hertz; | 6 | use 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)] |
| 17 | pub enum ClockSrc { | 17 | pub 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 | |||
| 31 | impl 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)] | ||
| 39 | pub 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 | |||
| 59 | impl 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)] |
| 25 | pub enum PllSrc { | 82 | pub 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 | ||
| 31 | impl Into<Pllsrc> for PllSrc { | 94 | impl 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 { | |||
| 41 | seq_macro::seq!(N in 2..=128 { | 104 | seq_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 | ||
| 62 | impl Into<u8> for PllClkDiv { | ||
| 63 | fn into(self) -> u8 { | ||
| 64 | (self as u8) + 1 | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | seq_macro::seq!(N in 4..=512 { | 125 | seq_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 | ||
| 89 | impl 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)] |
| 97 | pub enum PllM { | 148 | pub enum PllM { |
| @@ -132,6 +183,7 @@ impl Into<Sw> for ClockSrc { | |||
| 132 | 183 | ||
| 133 | #[derive(Debug, Copy, Clone)] | 184 | #[derive(Debug, Copy, Clone)] |
| 134 | pub enum MSIRange { | 185 | pub 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 | ||
| 182 | impl Default for MSIRange { | ||
| 183 | fn default() -> Self { | ||
| 184 | MSIRange::Range4mhz | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | #[derive(Copy, Clone)] | 234 | #[derive(Copy, Clone)] |
| 189 | pub struct Config { | 235 | pub 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 | |||
| 250 | impl 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 | ||
| 198 | impl Default for Config { | 307 | impl 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 | ||
| 211 | pub(crate) unsafe fn init(config: Config) { | 321 | pub(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 | ||
