diff options
| author | Barnaby Walters <[email protected]> | 2024-02-17 00:30:16 +0100 |
|---|---|---|
| committer | Barnaby Walters <[email protected]> | 2024-02-17 00:30:16 +0100 |
| commit | 6d7458dac7e768425342910e04a75c85e667cb82 (patch) | |
| tree | 029c3303956762ff7b8d9e8c7ad5fdf131bc8597 | |
| parent | a24087c36c60e97f8b0aaefe57111c3a2edd6e8a (diff) | |
Refinements
* Implemented boost mode dance (RM0440 p234-245, 6.5.1)
* Enabled boost mode in usb_serial example, tested on hardware
* Removed hard requirement of a valid 48MHz source (HSI48 is checked if
requested, PLL passed through as-is and assumed to be valid)
* Used calc_pclk to calculate APB frequencies
* Refactored 48MHz configuration code to remove unnecessary let and block
* Renamed ahb_freq to hclk for clarity and consistency
| -rw-r--r-- | embassy-stm32/src/rcc/g4.rs | 67 | ||||
| -rw-r--r-- | examples/stm32g4/src/bin/usb_serial.rs | 1 |
2 files changed, 33 insertions, 35 deletions
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 0c1a1e4b1..382ffbead 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs | |||
| @@ -242,17 +242,25 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 242 | }; | 242 | }; |
| 243 | 243 | ||
| 244 | // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. | 244 | // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. |
| 245 | let ahb_freq = sys_clk / config.ahb_pre; | 245 | let hclk = sys_clk / config.ahb_pre; |
| 246 | 246 | ||
| 247 | // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) | 247 | // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) |
| 248 | // TODO: according to RM0440 p235, when switching from range1-normal to range1-boost, it’s necessary to divide | 248 | if config.boost { |
| 249 | // SYSCLK by 2 using the AHB prescaler, set boost and flash read latency, switch system frequency, wait 1us and | 249 | // RM0440 p235 |
| 250 | // reconfigure the AHB prescaler as desired. Unclear whether this is always necessary. | 250 | // “The sequence to switch from Range1 normal mode to Range1 boost mode is: |
| 251 | PWR.cr5().modify(|w| w.set_r1mode(!config.boost)); | 251 | // 1. The system clock must be divided by 2 using the AHB prescaler before switching to a higher system frequency. |
| 252 | RCC.cfgr().modify(|w| w.set_hpre(AHBPrescaler::DIV2)); | ||
| 253 | // 2. Clear the R1MODE bit in the PWR_CR5 register. (enables boost mode) | ||
| 254 | PWR.cr5().modify(|w| w.set_r1mode(false)); | ||
| 255 | |||
| 256 | // Below: | ||
| 257 | // 3. Adjust wait states according to new freq target | ||
| 258 | // 4. Configure and switch to new frequency | ||
| 259 | } | ||
| 252 | 260 | ||
| 253 | // Configure flash read access latency based on boost mode and frequency (RM0440 p98) | 261 | // Configure flash read access latency based on boost mode and frequency (RM0440 p98) |
| 254 | FLASH.acr().modify(|w| { | 262 | FLASH.acr().modify(|w| { |
| 255 | w.set_latency(match (config.boost, ahb_freq.0) { | 263 | w.set_latency(match (config.boost, hclk.0) { |
| 256 | (true, ..=34_000_000) => Latency::WS0, | 264 | (true, ..=34_000_000) => Latency::WS0, |
| 257 | (true, ..=68_000_000) => Latency::WS1, | 265 | (true, ..=68_000_000) => Latency::WS1, |
| 258 | (true, ..=102_000_000) => Latency::WS2, | 266 | (true, ..=102_000_000) => Latency::WS2, |
| @@ -267,6 +275,11 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 267 | }) | 275 | }) |
| 268 | }); | 276 | }); |
| 269 | 277 | ||
| 278 | if config.boost { | ||
| 279 | // 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK clock frequency. | ||
| 280 | cortex_m::asm::delay(16); | ||
| 281 | } | ||
| 282 | |||
| 270 | // Now that boost mode and flash read access latency are configured, set up SYSCLK | 283 | // Now that boost mode and flash read access latency are configured, set up SYSCLK |
| 271 | RCC.cfgr().modify(|w| { | 284 | RCC.cfgr().modify(|w| { |
| 272 | w.set_sw(sw); | 285 | w.set_sw(sw); |
| @@ -275,30 +288,16 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 275 | w.set_ppre2(config.apb2_pre); | 288 | w.set_ppre2(config.apb2_pre); |
| 276 | }); | 289 | }); |
| 277 | 290 | ||
| 278 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | 291 | let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre); |
| 279 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | 292 | let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre); |
| 280 | pre => { | ||
| 281 | let freq = ahb_freq / pre; | ||
| 282 | (freq, freq * 2u32) | ||
| 283 | } | ||
| 284 | }; | ||
| 285 | |||
| 286 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 287 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 288 | pre => { | ||
| 289 | let freq = ahb_freq / pre; | ||
| 290 | (freq, freq * 2u32) | ||
| 291 | } | ||
| 292 | }; | ||
| 293 | 293 | ||
| 294 | // Configure the 48MHz clock source for USB and RNG peripherals. | 294 | // Configure the 48MHz clock source for USB and RNG peripherals. |
| 295 | { | 295 | RCC.ccipr().modify(|w| { |
| 296 | let source = match config.clk48_src { | 296 | w.set_clk48sel(match config.clk48_src { |
| 297 | Clk48Src::PLL1_Q => { | 297 | Clk48Src::PLL1_Q => { |
| 298 | // Make sure the PLLQ is enabled and running at 48Mhz | 298 | // Not checking that PLL1_Q is 48MHz here so as not to require the user to have a 48MHz clock. |
| 299 | let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q); | 299 | // Peripherals which require one (USB, RNG) should check that they‘re driven by a valid 48MHz |
| 300 | assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000); | 300 | // clock at init. |
| 301 | |||
| 302 | crate::pac::rcc::vals::Clk48sel::PLL1_Q | 301 | crate::pac::rcc::vals::Clk48sel::PLL1_Q |
| 303 | } | 302 | } |
| 304 | Clk48Src::HSI48 => { | 303 | Clk48Src::HSI48 => { |
| @@ -307,10 +306,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 307 | crate::pac::rcc::vals::Clk48sel::HSI48 | 306 | crate::pac::rcc::vals::Clk48sel::HSI48 |
| 308 | } | 307 | } |
| 309 | _ => unreachable!(), | 308 | _ => unreachable!(), |
| 310 | }; | 309 | }) |
| 311 | 310 | }); | |
| 312 | RCC.ccipr().modify(|w| w.set_clk48sel(source)); | ||
| 313 | } | ||
| 314 | 311 | ||
| 315 | RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source)); | 312 | RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source)); |
| 316 | RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); | 313 | RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); |
| @@ -339,9 +336,9 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 339 | 336 | ||
| 340 | set_clocks!( | 337 | set_clocks!( |
| 341 | sys: Some(sys_clk), | 338 | sys: Some(sys_clk), |
| 342 | hclk1: Some(ahb_freq), | 339 | hclk1: Some(hclk), |
| 343 | hclk2: Some(ahb_freq), | 340 | hclk2: Some(hclk), |
| 344 | hclk3: Some(ahb_freq), | 341 | hclk3: Some(hclk), |
| 345 | pclk1: Some(apb1_freq), | 342 | pclk1: Some(apb1_freq), |
| 346 | pclk1_tim: Some(apb1_tim_freq), | 343 | pclk1_tim: Some(apb1_tim_freq), |
| 347 | pclk2: Some(apb2_freq), | 344 | pclk2: Some(apb2_freq), |
| @@ -355,7 +352,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 355 | ); | 352 | ); |
| 356 | } | 353 | } |
| 357 | 354 | ||
| 358 | // TODO: if necessary, make more of these gated behind cfg attrs | 355 | // TODO: if necessary, make more of these, gated behind cfg attrs |
| 359 | mod max { | 356 | mod max { |
| 360 | use core::ops::RangeInclusive; | 357 | use core::ops::RangeInclusive; |
| 361 | 358 | ||
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index 353ac1799..989fef5b0 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs | |||
| @@ -44,6 +44,7 @@ async fn main(_spawner: Spawner) { | |||
| 44 | }); | 44 | }); |
| 45 | 45 | ||
| 46 | config.rcc.sys = Sysclk::PLL1_R; | 46 | config.rcc.sys = Sysclk::PLL1_R; |
| 47 | config.rcc.boost = true; // BOOST! | ||
| 47 | 48 | ||
| 48 | if USE_HSI48 { | 49 | if USE_HSI48 { |
| 49 | // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. | 50 | // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. |
