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 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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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!");
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue