aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarnaby Walters <[email protected]>2024-02-17 00:30:16 +0100
committerBarnaby Walters <[email protected]>2024-02-17 00:30:16 +0100
commit6d7458dac7e768425342910e04a75c85e667cb82 (patch)
tree029c3303956762ff7b8d9e8c7ad5fdf131bc8597
parenta24087c36c60e97f8b0aaefe57111c3a2edd6e8a (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.rs67
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs1
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
359mod max { 356mod 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.