diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 79bdbeb77..cd2d2a8a2 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -1,12 +1,9 @@ -use stm32_metapac::flash::vals::Latency; -use stm32_metapac::rcc::vals::Sw; -use stm32_metapac::FLASH; - +use crate::pac::flash::vals::Latency; pub use crate::pac::rcc::vals::{ - Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, - Ppre as APBPrescaler, Sw as Sysclk, + Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, + Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; -use crate::pac::{PWR, RCC}; +use crate::pac::{FLASH, PWR, RCC}; use crate::time::Hertz; /// HSI speed @@ -37,7 +34,7 @@ pub struct Hse { /// frequency ranges for each of these settings. pub struct Pll { /// PLL Source clock selection. - pub source: Pllsrc, + pub source: PllSource, /// PLL pre-divider pub prediv: PllPreDiv, @@ -73,7 +70,7 @@ pub struct Config { /// PLL Configuration pub pll: Option, - /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration + /// If PLL is requested as the main clock source in the `sys` field then the PLL configuration /// MUST turn on the PLLR output. pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, @@ -112,6 +109,7 @@ impl Default for Config { } } +#[derive(Default)] pub struct PllFreq { pub pll_p: Option, pub pll_q: Option, @@ -154,91 +152,91 @@ pub(crate) unsafe fn init(config: Config) { // Configure HSI48 if required let hsi48 = config.hsi48.map(super::init_hsi48); - let pll_freq = config.pll.map(|pll_config| { - let src_freq = match pll_config.source { - Pllsrc::HSI => unwrap!(hsi), - Pllsrc::HSE => unwrap!(hse), - _ => unreachable!(), - }; + let pll = config + .pll + .map(|pll_config| { + let src_freq = match pll_config.source { + PllSource::HSI => unwrap!(hsi), + PllSource::HSE => unwrap!(hse), + _ => unreachable!(), + }; - // Disable PLL before configuration - RCC.cr().modify(|w| w.set_pllon(false)); - while RCC.cr().read().pllrdy() {} + // Disable PLL before configuration + RCC.cr().modify(|w| w.set_pllon(false)); + while RCC.cr().read().pllrdy() {} - let in_freq = src_freq / pll_config.prediv; - assert!(max::PLL_IN.contains(&in_freq)); - let internal_freq = in_freq * pll_config.mul; + let in_freq = src_freq / pll_config.prediv; + assert!(max::PLL_IN.contains(&in_freq)); + let internal_freq = in_freq * pll_config.mul; - assert!(max::PLL_VCO.contains(&internal_freq)); + assert!(max::PLL_VCO.contains(&internal_freq)); - RCC.pllcfgr().write(|w| { - w.set_plln(pll_config.mul); - w.set_pllm(pll_config.prediv); - w.set_pllsrc(pll_config.source.into()); - }); - - let pll_p_freq = pll_config.divp.map(|div_p| { - RCC.pllcfgr().modify(|w| { - w.set_pllp(div_p); - w.set_pllpen(true); + RCC.pllcfgr().write(|w| { + w.set_plln(pll_config.mul); + w.set_pllm(pll_config.prediv); + w.set_pllsrc(pll_config.source.into()); }); - let freq = internal_freq / div_p; - assert!(max::PCLK.contains(&freq)); - freq - }); - let pll_q_freq = pll_config.divq.map(|div_q| { - RCC.pllcfgr().modify(|w| { - w.set_pllq(div_q); - w.set_pllqen(true); + let pll_p_freq = pll_config.divp.map(|div_p| { + RCC.pllcfgr().modify(|w| { + w.set_pllp(div_p); + w.set_pllpen(true); + }); + let freq = internal_freq / div_p; + assert!(max::PLL_P.contains(&freq)); + freq }); - let freq = internal_freq / div_q; - assert!(max::PCLK.contains(&freq)); - freq - }); - let pll_r_freq = pll_config.divr.map(|div_r| { - RCC.pllcfgr().modify(|w| { - w.set_pllr(div_r); - w.set_pllren(true); + let pll_q_freq = pll_config.divq.map(|div_q| { + RCC.pllcfgr().modify(|w| { + w.set_pllq(div_q); + w.set_pllqen(true); + }); + let freq = internal_freq / div_q; + assert!(max::PLL_Q.contains(&freq)); + freq }); - let freq = internal_freq / div_r; - assert!(max::PCLK.contains(&freq)); - freq - }); - // Enable the PLL - RCC.cr().modify(|w| w.set_pllon(true)); - while !RCC.cr().read().pllrdy() {} + let pll_r_freq = pll_config.divr.map(|div_r| { + RCC.pllcfgr().modify(|w| { + w.set_pllr(div_r); + w.set_pllren(true); + }); + let freq = internal_freq / div_r; + assert!(max::PLL_R.contains(&freq)); + freq + }); - PllFreq { - pll_p: pll_p_freq, - pll_q: pll_q_freq, - pll_r: pll_r_freq, - } - }); + // Enable the PLL + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} - let (sys_clk, sw) = match config.sys { - Sysclk::HSI => (HSI_FREQ, Sw::HSI), - Sysclk::HSE => (unwrap!(hse), Sw::HSE), - Sysclk::PLL1_R => { - assert!(pll_freq.is_some()); - assert!(pll_freq.as_ref().unwrap().pll_r.is_some()); + PllFreq { + pll_p: pll_p_freq, + pll_q: pll_q_freq, + pll_r: pll_r_freq, + } + }) + .unwrap_or_default(); - let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0; - - assert!(max::SYSCLK.contains(&Hertz(freq))); - - (Hertz(freq), Sw::PLL1_R) - } + let sys = match config.sys { + Sysclk::HSI => unwrap!(hsi), + Sysclk::HSE => unwrap!(hse), + Sysclk::PLL1_R => unwrap!(pll.pll_r), _ => unreachable!(), }; - // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. - let hclk = sys_clk / config.ahb_pre; + assert!(max::SYSCLK.contains(&sys)); + // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. + let hclk = sys / config.ahb_pre; assert!(max::HCLK.contains(&hclk)); + let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); + let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); + assert!(max::PCLK.contains(&pclk2)); + assert!(max::PCLK.contains(&pclk2)); + // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) if config.boost { // RM0440 p235 @@ -253,23 +251,28 @@ pub(crate) unsafe fn init(config: Config) { // 4. Configure and switch to new frequency } + let latency = match (config.boost, hclk.0) { + (true, ..=34_000_000) => Latency::WS0, + (true, ..=68_000_000) => Latency::WS1, + (true, ..=102_000_000) => Latency::WS2, + (true, ..=136_000_000) => Latency::WS3, + (true, _) => Latency::WS4, + + (false, ..=36_000_000) => Latency::WS0, + (false, ..=60_000_000) => Latency::WS1, + (false, ..=90_000_000) => Latency::WS2, + (false, ..=120_000_000) => Latency::WS3, + (false, _) => Latency::WS4, + }; + // Configure flash read access latency based on boost mode and frequency (RM0440 p98) FLASH.acr().modify(|w| { - 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, - (true, ..=136_000_000) => Latency::WS3, - (true, _) => Latency::WS4, - - (false, ..=36_000_000) => Latency::WS0, - (false, ..=60_000_000) => Latency::WS1, - (false, ..=90_000_000) => Latency::WS2, - (false, ..=120_000_000) => Latency::WS3, - (false, _) => Latency::WS4, - }) + w.set_latency(latency); }); + // Spin until the effective flash latency is set. + while FLASH.acr().read().latency() != latency {} + 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); @@ -277,17 +280,14 @@ pub(crate) unsafe fn init(config: Config) { // Now that boost mode and flash read access latency are configured, set up SYSCLK RCC.cfgr().modify(|w| { - w.set_sw(sw); + w.set_sw(config.sys); w.set_hpre(config.ahb_pre); w.set_ppre1(config.apb1_pre); w.set_ppre2(config.apb2_pre); }); - 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); - if config.low_power_run { - assert!(sys_clk <= Hertz(2_000_000)); + assert!(sys <= Hertz(2_000_000)); PWR.cr1().modify(|w| w.set_lpr(true)); } @@ -296,17 +296,18 @@ pub(crate) unsafe fn init(config: Config) { config.mux.init(); set_clocks!( - sys: Some(sys_clk), + sys: Some(sys), hclk1: Some(hclk), hclk2: Some(hclk), hclk3: Some(hclk), - pclk1: Some(apb1_freq), - pclk1_tim: Some(apb1_tim_freq), - pclk2: Some(apb2_freq), - pclk2_tim: Some(apb2_tim_freq), - pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p), - pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q), - pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r), + pclk1: Some(pclk1), + pclk1_tim: Some(pclk1_tim), + pclk2: Some(pclk2), + pclk2_tim: Some(pclk2_tim), + pll1_p: pll.pll_p, + pll1_q: pll.pll_q, + pll1_r: pll.pll_r, + hsi: hsi, hse: hse, hsi48: hsi48, rtc: rtc, @@ -342,4 +343,7 @@ mod max { /// PLL VCO (internal) Frequency Range (STM32G474 Datasheet p123, Table 46) pub(crate) const PLL_VCO: RangeInclusive = Hertz(96_000_000)..=Hertz(344_000_000); + pub(crate) const PLL_P: RangeInclusive = Hertz(2_064_500)..=Hertz(170_000_000); + pub(crate) const PLL_Q: RangeInclusive = Hertz(8_000_000)..=Hertz(170_000_000); + pub(crate) const PLL_R: RangeInclusive = Hertz(8_000_000)..=Hertz(170_000_000); } diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index f81335f93..ae64bc8e4 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { { use embassy_stm32::rcc::*; config.rcc.pll = Some(Pll { - source: Pllsrc::HSI, + source: PllSource::HSI, prediv: PllPreDiv::DIV4, mul: PllMul::MUL85, divp: None, diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 93b206de8..4373a89a8 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { mode: HseMode::Oscillator, }); config.rcc.pll = Some(Pll { - source: Pllsrc::HSE, + source: PllSource::HSE, prediv: PllPreDiv::DIV6, mul: PllMul::MUL85, divp: None, diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs index 2609abfa2..08ed95b34 100644 --- a/examples/stm32g4/src/bin/pll.rs +++ b/examples/stm32g4/src/bin/pll.rs @@ -3,7 +3,6 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk}; use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -11,20 +10,20 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - - config.rcc.hsi = true; - config.rcc.pll = Some(Pll { - source: Pllsrc::HSI, - prediv: PllPreDiv::DIV4, - mul: PllMul::MUL85, - divp: None, - divq: None, - // Main system clock at 170 MHz - divr: Some(PllRDiv::DIV2), - }); - - config.rcc.sys = Sysclk::PLL1_R; - + { + use embassy_stm32::rcc::*; + config.rcc.hsi = true; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, + // Main system clock at 170 MHz + divr: Some(PllRDiv::DIV2), + }); + config.rcc.sys = Sysclk::PLL1_R; + } let _p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index 90caaae14..dc95aa6e5 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { mode: HseMode::Oscillator, }); config.rcc.pll = Some(Pll { - source: Pllsrc::HSE, + source: PllSource::HSE, prediv: PllPreDiv::DIV2, mul: PllMul::MUL72, divp: None, diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index cf3e04a4b..c3f39c04f 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -456,7 +456,7 @@ pub fn config() -> Config { mode: HseMode::Oscillator, }); config.rcc.pll = Some(Pll { - source: Pllsrc::HSE, + source: PllSource::HSE, prediv: PllPreDiv::DIV6, mul: PllMul::MUL85, divp: None,