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
This commit is contained in:
Barnaby Walters 2024-02-17 00:30:16 +01:00
parent a24087c36c
commit 6d7458dac7
2 changed files with 33 additions and 35 deletions

View file

@ -242,17 +242,25 @@ pub(crate) unsafe fn init(config: Config) {
};
// Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency.
let ahb_freq = sys_clk / config.ahb_pre;
let hclk = sys_clk / config.ahb_pre;
// Configure Core Boost mode ([RM0440] p234 inverted because setting r1mode to 0 enables boost mode!)
// TODO: according to RM0440 p235, when switching from range1-normal to range1-boost, its necessary to divide
// SYSCLK by 2 using the AHB prescaler, set boost and flash read latency, switch system frequency, wait 1us and
// reconfigure the AHB prescaler as desired. Unclear whether this is always necessary.
PWR.cr5().modify(|w| w.set_r1mode(!config.boost));
if config.boost {
// RM0440 p235
// “The sequence to switch from Range1 normal mode to Range1 boost mode is:
// 1. The system clock must be divided by 2 using the AHB prescaler before switching to a higher system frequency.
RCC.cfgr().modify(|w| w.set_hpre(AHBPrescaler::DIV2));
// 2. Clear the R1MODE bit in the PWR_CR5 register. (enables boost mode)
PWR.cr5().modify(|w| w.set_r1mode(false));
// Below:
// 3. Adjust wait states according to new freq target
// 4. Configure and switch to new frequency
}
// Configure flash read access latency based on boost mode and frequency (RM0440 p98)
FLASH.acr().modify(|w| {
w.set_latency(match (config.boost, ahb_freq.0) {
w.set_latency(match (config.boost, hclk.0) {
(true, ..=34_000_000) => Latency::WS0,
(true, ..=68_000_000) => Latency::WS1,
(true, ..=102_000_000) => Latency::WS2,
@ -267,6 +275,11 @@ pub(crate) unsafe fn init(config: Config) {
})
});
if config.boost {
// 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK clock frequency.
cortex_m::asm::delay(16);
}
// Now that boost mode and flash read access latency are configured, set up SYSCLK
RCC.cfgr().modify(|w| {
w.set_sw(sw);
@ -275,30 +288,16 @@ pub(crate) unsafe fn init(config: Config) {
w.set_ppre2(config.apb2_pre);
});
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / pre;
(freq, freq * 2u32)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / pre;
(freq, freq * 2u32)
}
};
let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre);
let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre);
// Configure the 48MHz clock source for USB and RNG peripherals.
{
let source = match config.clk48_src {
RCC.ccipr().modify(|w| {
w.set_clk48sel(match config.clk48_src {
Clk48Src::PLL1_Q => {
// Make sure the PLLQ is enabled and running at 48Mhz
let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q);
assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000);
// Not checking that PLL1_Q is 48MHz here so as not to require the user to have a 48MHz clock.
// Peripherals which require one (USB, RNG) should check that theyre driven by a valid 48MHz
// clock at init.
crate::pac::rcc::vals::Clk48sel::PLL1_Q
}
Clk48Src::HSI48 => {
@ -307,10 +306,8 @@ pub(crate) unsafe fn init(config: Config) {
crate::pac::rcc::vals::Clk48sel::HSI48
}
_ => unreachable!(),
};
RCC.ccipr().modify(|w| w.set_clk48sel(source));
}
})
});
RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source));
RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
@ -339,9 +336,9 @@ pub(crate) unsafe fn init(config: Config) {
set_clocks!(
sys: Some(sys_clk),
hclk1: Some(ahb_freq),
hclk2: Some(ahb_freq),
hclk3: Some(ahb_freq),
hclk1: Some(hclk),
hclk2: Some(hclk),
hclk3: Some(hclk),
pclk1: Some(apb1_freq),
pclk1_tim: Some(apb1_tim_freq),
pclk2: Some(apb2_freq),
@ -355,7 +352,7 @@ pub(crate) unsafe fn init(config: Config) {
);
}
// TODO: if necessary, make more of these gated behind cfg attrs
// TODO: if necessary, make more of these, gated behind cfg attrs
mod max {
use core::ops::RangeInclusive;

View file

@ -44,6 +44,7 @@ async fn main(_spawner: Spawner) {
});
config.rcc.sys = Sysclk::PLL1_R;
config.rcc.boost = true; // BOOST!
if USE_HSI48 {
// Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.