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 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<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.
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<Hertz>,
pub pll_q: Option<Hertz>,
@ -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> = 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::*;
config.rcc.pll = Some(Pll {
source: Pllsrc::HSI,
source: PllSource::HSI,
prediv: PllPreDiv::DIV4,
mul: PllMul::MUL85,
divp: None,

View File

@ -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,

View File

@ -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!");

View File

@ -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,

View File

@ -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,