stm32/rcc: g4: consistent PllSource, add pll pqr limits, simplify a bit.

This commit is contained in:
Dario Nieuwenhuis 2024-03-03 23:18:29 +01:00
parent 20760ff4f7
commit b4567bb8c5
6 changed files with 123 additions and 120 deletions

View file

@ -1,12 +1,9 @@
use stm32_metapac::flash::vals::Latency; use crate::pac::flash::vals::Latency;
use stm32_metapac::rcc::vals::Sw;
use stm32_metapac::FLASH;
pub use crate::pac::rcc::vals::{ 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, Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv,
Ppre as APBPrescaler, Sw as Sysclk, Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
}; };
use crate::pac::{PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::time::Hertz; use crate::time::Hertz;
/// HSI speed /// HSI speed
@ -37,7 +34,7 @@ pub struct Hse {
/// frequency ranges for each of these settings. /// frequency ranges for each of these settings.
pub struct Pll { pub struct Pll {
/// PLL Source clock selection. /// PLL Source clock selection.
pub source: Pllsrc, pub source: PllSource,
/// PLL pre-divider /// PLL pre-divider
pub prediv: PllPreDiv, pub prediv: PllPreDiv,
@ -73,7 +70,7 @@ pub struct Config {
/// PLL Configuration /// PLL Configuration
pub pll: Option<Pll>, pub pll: Option<Pll>,
/// 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. /// MUST turn on the PLLR output.
pub ahb_pre: AHBPrescaler, pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler, pub apb1_pre: APBPrescaler,
@ -112,6 +109,7 @@ impl Default for Config {
} }
} }
#[derive(Default)]
pub struct PllFreq { pub struct PllFreq {
pub pll_p: Option<Hertz>, pub pll_p: Option<Hertz>,
pub pll_q: Option<Hertz>, pub pll_q: Option<Hertz>,
@ -154,91 +152,91 @@ pub(crate) unsafe fn init(config: Config) {
// Configure HSI48 if required // Configure HSI48 if required
let hsi48 = config.hsi48.map(super::init_hsi48); let hsi48 = config.hsi48.map(super::init_hsi48);
let pll_freq = config.pll.map(|pll_config| { let pll = config
let src_freq = match pll_config.source { .pll
Pllsrc::HSI => unwrap!(hsi), .map(|pll_config| {
Pllsrc::HSE => unwrap!(hse), let src_freq = match pll_config.source {
_ => unreachable!(), PllSource::HSI => unwrap!(hsi),
}; PllSource::HSE => unwrap!(hse),
_ => unreachable!(),
};
// Disable PLL before configuration // Disable PLL before configuration
RCC.cr().modify(|w| w.set_pllon(false)); RCC.cr().modify(|w| w.set_pllon(false));
while RCC.cr().read().pllrdy() {} while RCC.cr().read().pllrdy() {}
let in_freq = src_freq / pll_config.prediv; let in_freq = src_freq / pll_config.prediv;
assert!(max::PLL_IN.contains(&in_freq)); assert!(max::PLL_IN.contains(&in_freq));
let internal_freq = in_freq * pll_config.mul; 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| { RCC.pllcfgr().write(|w| {
w.set_plln(pll_config.mul); w.set_plln(pll_config.mul);
w.set_pllm(pll_config.prediv); w.set_pllm(pll_config.prediv);
w.set_pllsrc(pll_config.source.into()); 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);
}); });
let freq = internal_freq / div_p;
assert!(max::PCLK.contains(&freq));
freq
});
let pll_q_freq = pll_config.divq.map(|div_q| { let pll_p_freq = pll_config.divp.map(|div_p| {
RCC.pllcfgr().modify(|w| { RCC.pllcfgr().modify(|w| {
w.set_pllq(div_q); w.set_pllp(div_p);
w.set_pllqen(true); 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| { let pll_q_freq = pll_config.divq.map(|div_q| {
RCC.pllcfgr().modify(|w| { RCC.pllcfgr().modify(|w| {
w.set_pllr(div_r); w.set_pllq(div_q);
w.set_pllren(true); 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 let pll_r_freq = pll_config.divr.map(|div_r| {
RCC.cr().modify(|w| w.set_pllon(true)); RCC.pllcfgr().modify(|w| {
while !RCC.cr().read().pllrdy() {} w.set_pllr(div_r);
w.set_pllren(true);
});
let freq = internal_freq / div_r;
assert!(max::PLL_R.contains(&freq));
freq
});
PllFreq { // Enable the PLL
pll_p: pll_p_freq, RCC.cr().modify(|w| w.set_pllon(true));
pll_q: pll_q_freq, while !RCC.cr().read().pllrdy() {}
pll_r: pll_r_freq,
}
});
let (sys_clk, sw) = match config.sys { PllFreq {
Sysclk::HSI => (HSI_FREQ, Sw::HSI), pll_p: pll_p_freq,
Sysclk::HSE => (unwrap!(hse), Sw::HSE), pll_q: pll_q_freq,
Sysclk::PLL1_R => { pll_r: pll_r_freq,
assert!(pll_freq.is_some()); }
assert!(pll_freq.as_ref().unwrap().pll_r.is_some()); })
.unwrap_or_default();
let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0; let sys = match config.sys {
Sysclk::HSI => unwrap!(hsi),
assert!(max::SYSCLK.contains(&Hertz(freq))); Sysclk::HSE => unwrap!(hse),
Sysclk::PLL1_R => unwrap!(pll.pll_r),
(Hertz(freq), Sw::PLL1_R)
}
_ => unreachable!(), _ => unreachable!(),
}; };
// Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. assert!(max::SYSCLK.contains(&sys));
let hclk = sys_clk / config.ahb_pre;
// 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)); 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!) // Configure Core Boost mode ([RM0440] p234 inverted because setting r1mode to 0 enables boost mode!)
if config.boost { if config.boost {
// RM0440 p235 // RM0440 p235
@ -253,23 +251,28 @@ pub(crate) unsafe fn init(config: Config) {
// 4. Configure and switch to new frequency // 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) // Configure flash read access latency based on boost mode and frequency (RM0440 p98)
FLASH.acr().modify(|w| { FLASH.acr().modify(|w| {
w.set_latency(match (config.boost, hclk.0) { w.set_latency(latency);
(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,
})
}); });
// Spin until the effective flash latency is set.
while FLASH.acr().read().latency() != latency {}
if config.boost { if config.boost {
// 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK clock frequency. // 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK clock frequency.
cortex_m::asm::delay(16); 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 // Now that boost mode and flash read access latency are configured, set up SYSCLK
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(config.sys);
w.set_hpre(config.ahb_pre); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_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 { 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)); PWR.cr1().modify(|w| w.set_lpr(true));
} }
@ -296,17 +296,18 @@ pub(crate) unsafe fn init(config: Config) {
config.mux.init(); config.mux.init();
set_clocks!( set_clocks!(
sys: Some(sys_clk), sys: Some(sys),
hclk1: Some(hclk), hclk1: Some(hclk),
hclk2: Some(hclk), hclk2: Some(hclk),
hclk3: Some(hclk), hclk3: Some(hclk),
pclk1: Some(apb1_freq), pclk1: Some(pclk1),
pclk1_tim: Some(apb1_tim_freq), pclk1_tim: Some(pclk1_tim),
pclk2: Some(apb2_freq), pclk2: Some(pclk2),
pclk2_tim: Some(apb2_tim_freq), pclk2_tim: Some(pclk2_tim),
pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p), pll1_p: pll.pll_p,
pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q), pll1_q: pll.pll_q,
pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r), pll1_r: pll.pll_r,
hsi: hsi,
hse: hse, hse: hse,
hsi48: hsi48, hsi48: hsi48,
rtc: rtc, rtc: rtc,
@ -342,4 +343,7 @@ mod max {
/// PLL VCO (internal) Frequency Range (STM32G474 Datasheet p123, Table 46) /// PLL VCO (internal) Frequency Range (STM32G474 Datasheet p123, Table 46)
pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(96_000_000)..=Hertz(344_000_000); pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(96_000_000)..=Hertz(344_000_000);
pub(crate) const PLL_P: RangeInclusive<Hertz> = Hertz(2_064_500)..=Hertz(170_000_000);
pub(crate) const PLL_Q: RangeInclusive<Hertz> = Hertz(8_000_000)..=Hertz(170_000_000);
pub(crate) const PLL_R: RangeInclusive<Hertz> = Hertz(8_000_000)..=Hertz(170_000_000);
} }

View file

@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
{ {
use embassy_stm32::rcc::*; use embassy_stm32::rcc::*;
config.rcc.pll = Some(Pll { config.rcc.pll = Some(Pll {
source: Pllsrc::HSI, source: PllSource::HSI,
prediv: PllPreDiv::DIV4, prediv: PllPreDiv::DIV4,
mul: PllMul::MUL85, mul: PllMul::MUL85,
divp: None, divp: None,

View file

@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
mode: HseMode::Oscillator, mode: HseMode::Oscillator,
}); });
config.rcc.pll = Some(Pll { config.rcc.pll = Some(Pll {
source: Pllsrc::HSE, source: PllSource::HSE,
prediv: PllPreDiv::DIV6, prediv: PllPreDiv::DIV6,
mul: PllMul::MUL85, mul: PllMul::MUL85,
divp: None, divp: None,

View file

@ -3,7 +3,6 @@
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk};
use embassy_stm32::Config; use embassy_stm32::Config;
use embassy_time::Timer; use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -11,20 +10,20 @@ use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = Config::default(); let mut config = Config::default();
{
config.rcc.hsi = true; use embassy_stm32::rcc::*;
config.rcc.pll = Some(Pll { config.rcc.hsi = true;
source: Pllsrc::HSI, config.rcc.pll = Some(Pll {
prediv: PllPreDiv::DIV4, source: PllSource::HSI,
mul: PllMul::MUL85, prediv: PllPreDiv::DIV4,
divp: None, mul: PllMul::MUL85,
divq: None, divp: None,
// Main system clock at 170 MHz divq: None,
divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz
}); divr: Some(PllRDiv::DIV2),
});
config.rcc.sys = Sysclk::PLL1_R; config.rcc.sys = Sysclk::PLL1_R;
}
let _p = embassy_stm32::init(config); let _p = embassy_stm32::init(config);
info!("Hello World!"); info!("Hello World!");

View file

@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
mode: HseMode::Oscillator, mode: HseMode::Oscillator,
}); });
config.rcc.pll = Some(Pll { config.rcc.pll = Some(Pll {
source: Pllsrc::HSE, source: PllSource::HSE,
prediv: PllPreDiv::DIV2, prediv: PllPreDiv::DIV2,
mul: PllMul::MUL72, mul: PllMul::MUL72,
divp: None, divp: None,

View file

@ -456,7 +456,7 @@ pub fn config() -> Config {
mode: HseMode::Oscillator, mode: HseMode::Oscillator,
}); });
config.rcc.pll = Some(Pll { config.rcc.pll = Some(Pll {
source: Pllsrc::HSE, source: PllSource::HSE,
prediv: PllPreDiv::DIV6, prediv: PllPreDiv::DIV6,
mul: PllMul::MUL85, mul: PllMul::MUL85,
divp: None, divp: None,