stm32/rcc: g4: consistent PllSource, add pll pqr limits, simplify a bit.
This commit is contained in:
parent
20760ff4f7
commit
b4567bb8c5
6 changed files with 123 additions and 120 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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!");
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue