stm32/rcc: change family-specific code from dirs to single files.
Consistent with how other peripherals handle their versions.
This commit is contained in:
parent
b2a85ee519
commit
b06e705a73
@ -201,7 +201,7 @@ impl<'d> Rcc<'d> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
|
let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
|
||||||
let clocks = rcc.freeze();
|
let clocks = rcc.freeze();
|
||||||
set_freqs(clocks);
|
set_freqs(clocks);
|
@ -207,7 +207,7 @@ impl<'d> Rcc<'d> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
|
let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
|
||||||
let clocks = rcc.freeze();
|
let clocks = rcc.freeze();
|
||||||
set_freqs(clocks);
|
set_freqs(clocks);
|
@ -54,7 +54,7 @@ struct PllConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize and Set the clock frequencies
|
/// Initialize and Set the clock frequencies
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
||||||
let clocks = Rcc::new(r, config).freeze();
|
let clocks = Rcc::new(r, config).freeze();
|
||||||
set_freqs(clocks);
|
set_freqs(clocks);
|
@ -5,9 +5,6 @@ use crate::time::Hertz;
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use embassy::util::Unborrow;
|
use embassy::util::Unborrow;
|
||||||
|
|
||||||
mod max;
|
|
||||||
use max::{PCLK1_MAX, PCLK2_MAX};
|
|
||||||
|
|
||||||
const HSI: u32 = 16_000_000;
|
const HSI: u32 = 16_000_000;
|
||||||
|
|
||||||
/// Clocks configutation
|
/// Clocks configutation
|
||||||
@ -88,7 +85,7 @@ impl<'d> Rcc<'d> {
|
|||||||
.config
|
.config
|
||||||
.pclk1
|
.pclk1
|
||||||
.map(|p| p.0)
|
.map(|p| p.0)
|
||||||
.unwrap_or_else(|| core::cmp::min(PCLK1_MAX, hclk));
|
.unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
|
||||||
let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
|
let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
|
||||||
0 => unreachable!(),
|
0 => unreachable!(),
|
||||||
1 => (0b000, 1),
|
1 => (0b000, 1),
|
||||||
@ -101,13 +98,13 @@ impl<'d> Rcc<'d> {
|
|||||||
|
|
||||||
// Calculate real APB1 clock
|
// Calculate real APB1 clock
|
||||||
let pclk1 = hclk / ppre1;
|
let pclk1 = hclk / ppre1;
|
||||||
assert!(pclk1 <= PCLK1_MAX);
|
assert!(pclk1 <= max::PCLK1_MAX);
|
||||||
|
|
||||||
let pclk2 = self
|
let pclk2 = self
|
||||||
.config
|
.config
|
||||||
.pclk2
|
.pclk2
|
||||||
.map(|p| p.0)
|
.map(|p| p.0)
|
||||||
.unwrap_or_else(|| core::cmp::min(PCLK2_MAX, hclk));
|
.unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
|
||||||
let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
|
let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
|
||||||
0 => unreachable!(),
|
0 => unreachable!(),
|
||||||
1 => (0b000, 1),
|
1 => (0b000, 1),
|
||||||
@ -120,7 +117,7 @@ impl<'d> Rcc<'d> {
|
|||||||
|
|
||||||
// Calculate real APB2 clock
|
// Calculate real APB2 clock
|
||||||
let pclk2 = hclk / ppre2;
|
let pclk2 = hclk / ppre2;
|
||||||
assert!(pclk2 <= PCLK2_MAX);
|
assert!(pclk2 <= max::PCLK2_MAX);
|
||||||
|
|
||||||
Self::flash_setup(sysclk);
|
Self::flash_setup(sysclk);
|
||||||
|
|
||||||
@ -298,7 +295,7 @@ impl<'d> Rcc<'d> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
||||||
let clocks = Rcc::new(r, config).freeze();
|
let clocks = Rcc::new(r, config).freeze();
|
||||||
set_freqs(clocks);
|
set_freqs(clocks);
|
||||||
@ -309,3 +306,27 @@ struct PllResults {
|
|||||||
pllsysclk: Option<u32>,
|
pllsysclk: Option<u32>,
|
||||||
pll48clk: Option<u32>,
|
pll48clk: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod max {
|
||||||
|
#[cfg(stm32f401)]
|
||||||
|
pub(crate) const SYSCLK_MAX: u32 = 84_000_000;
|
||||||
|
|
||||||
|
#[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
|
||||||
|
pub(crate) const SYSCLK_MAX: u32 = 168_000_000;
|
||||||
|
|
||||||
|
#[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
|
||||||
|
pub(crate) const SYSCLK_MAX: u32 = 100_000_000;
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,
|
||||||
|
))]
|
||||||
|
pub(crate) const SYSCLK_MAX: u32 = 180_000_000;
|
||||||
|
|
||||||
|
#[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
|
||||||
|
pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX;
|
||||||
|
|
||||||
|
#[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
|
||||||
|
pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
|
||||||
|
|
||||||
|
pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2;
|
||||||
|
}
|
@ -1,21 +0,0 @@
|
|||||||
#[cfg(stm32f401)]
|
|
||||||
pub(crate) const SYSCLK_MAX: u32 = 84_000_000;
|
|
||||||
|
|
||||||
#[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
|
|
||||||
pub(crate) const SYSCLK_MAX: u32 = 168_000_000;
|
|
||||||
|
|
||||||
#[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
|
|
||||||
pub(crate) const SYSCLK_MAX: u32 = 100_000_000;
|
|
||||||
|
|
||||||
#[cfg(any(
|
|
||||||
stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,
|
|
||||||
))]
|
|
||||||
pub(crate) const SYSCLK_MAX: u32 = 180_000_000;
|
|
||||||
|
|
||||||
#[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
|
|
||||||
pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX;
|
|
||||||
|
|
||||||
#[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
|
|
||||||
pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
|
|
||||||
|
|
||||||
pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2;
|
|
@ -1,5 +1,3 @@
|
|||||||
mod max;
|
|
||||||
|
|
||||||
use crate::pac::{FLASH, PWR, RCC};
|
use crate::pac::{FLASH, PWR, RCC};
|
||||||
use crate::peripherals;
|
use crate::peripherals;
|
||||||
use crate::rcc::{get_freqs, set_freqs, Clocks};
|
use crate::rcc::{get_freqs, set_freqs, Clocks};
|
||||||
@ -334,7 +332,7 @@ impl<'d> Rcc<'d> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
||||||
let clocks = Rcc::new(r, config).freeze();
|
let clocks = Rcc::new(r, config).freeze();
|
||||||
set_freqs(clocks);
|
set_freqs(clocks);
|
||||||
@ -345,3 +343,25 @@ struct PllResults {
|
|||||||
pllsysclk: Option<u32>,
|
pllsysclk: Option<u32>,
|
||||||
pll48clk: Option<u32>,
|
pll48clk: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod max {
|
||||||
|
pub(crate) const HSE_OSC_MIN: u32 = 4_000_000;
|
||||||
|
pub(crate) const HSE_OSC_MAX: u32 = 26_000_000;
|
||||||
|
pub(crate) const HSE_BYPASS_MIN: u32 = 1_000_000;
|
||||||
|
pub(crate) const HSE_BYPASS_MAX: u32 = 50_000_000;
|
||||||
|
|
||||||
|
pub(crate) const HCLK_MAX: u32 = 216_000_000;
|
||||||
|
pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 180_000_000;
|
||||||
|
|
||||||
|
pub(crate) const SYSCLK_MIN: u32 = 12_500_000;
|
||||||
|
pub(crate) const SYSCLK_MAX: u32 = 216_000_000;
|
||||||
|
|
||||||
|
pub(crate) const PCLK1_MIN: u32 = SYSCLK_MIN;
|
||||||
|
pub(crate) const PCLK1_MAX: u32 = SYSCLK_MAX / 4;
|
||||||
|
|
||||||
|
pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN;
|
||||||
|
pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
|
||||||
|
|
||||||
|
pub(crate) const PLL_48_CLK: u32 = 48_000_000;
|
||||||
|
pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
pub(crate) const HSE_OSC_MIN: u32 = 4_000_000;
|
|
||||||
pub(crate) const HSE_OSC_MAX: u32 = 26_000_000;
|
|
||||||
pub(crate) const HSE_BYPASS_MIN: u32 = 1_000_000;
|
|
||||||
pub(crate) const HSE_BYPASS_MAX: u32 = 50_000_000;
|
|
||||||
|
|
||||||
pub(crate) const HCLK_MAX: u32 = 216_000_000;
|
|
||||||
pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 180_000_000;
|
|
||||||
|
|
||||||
pub(crate) const SYSCLK_MIN: u32 = 12_500_000;
|
|
||||||
pub(crate) const SYSCLK_MAX: u32 = 216_000_000;
|
|
||||||
|
|
||||||
pub(crate) const PCLK1_MIN: u32 = SYSCLK_MIN;
|
|
||||||
pub(crate) const PCLK1_MAX: u32 = SYSCLK_MAX / 4;
|
|
||||||
|
|
||||||
pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN;
|
|
||||||
pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
|
|
||||||
|
|
||||||
pub(crate) const PLL_48_CLK: u32 = 48_000_000;
|
|
||||||
pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
|
|
@ -227,7 +227,7 @@ impl RccExt for RCC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
||||||
let clocks = r.freeze(config);
|
let clocks = r.freeze(config);
|
||||||
set_freqs(clocks);
|
set_freqs(clocks);
|
@ -203,7 +203,7 @@ impl RccExt for RCC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
||||||
let clocks = r.freeze(config);
|
let clocks = r.freeze(config);
|
||||||
set_freqs(clocks);
|
set_freqs(clocks);
|
@ -13,8 +13,6 @@ use crate::pwr::{Power, VoltageScale};
|
|||||||
use crate::rcc::{set_freqs, Clocks};
|
use crate::rcc::{set_freqs, Clocks};
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
|
|
||||||
mod pll;
|
|
||||||
use pll::pll_setup;
|
|
||||||
pub use pll::PllConfig;
|
pub use pll::PllConfig;
|
||||||
|
|
||||||
const HSI: Hertz = Hertz(64_000_000);
|
const HSI: Hertz = Hertz(64_000_000);
|
||||||
@ -116,11 +114,11 @@ impl<'d> Rcc<'d> {
|
|||||||
|
|
||||||
// NOTE(unsafe) We have exclusive access to the RCC
|
// NOTE(unsafe) We have exclusive access to the RCC
|
||||||
let (pll1_p_ck, pll1_q_ck, pll1_r_ck) =
|
let (pll1_p_ck, pll1_q_ck, pll1_r_ck) =
|
||||||
unsafe { pll_setup(srcclk.0, &self.config.pll1, 0) };
|
unsafe { pll::pll_setup(srcclk.0, &self.config.pll1, 0) };
|
||||||
let (pll2_p_ck, pll2_q_ck, pll2_r_ck) =
|
let (pll2_p_ck, pll2_q_ck, pll2_r_ck) =
|
||||||
unsafe { pll_setup(srcclk.0, &self.config.pll2, 1) };
|
unsafe { pll::pll_setup(srcclk.0, &self.config.pll2, 1) };
|
||||||
let (pll3_p_ck, pll3_q_ck, pll3_r_ck) =
|
let (pll3_p_ck, pll3_q_ck, pll3_r_ck) =
|
||||||
unsafe { pll_setup(srcclk.0, &self.config.pll3, 2) };
|
unsafe { pll::pll_setup(srcclk.0, &self.config.pll3, 2) };
|
||||||
|
|
||||||
let sys_ck = if sys_use_pll1_p {
|
let sys_ck = if sys_use_pll1_p {
|
||||||
Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
|
Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
|
||||||
@ -683,7 +681,7 @@ impl<'d, T: McoInstance> Mco<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let mut power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal(), false);
|
let mut power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal(), false);
|
||||||
let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
|
let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
|
||||||
let core_clocks = rcc.freeze(&mut power);
|
let core_clocks = rcc.freeze(&mut power);
|
||||||
@ -700,3 +698,151 @@ pub unsafe fn init(config: Config) {
|
|||||||
apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2),
|
apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod pll {
|
||||||
|
use super::{Hertz, RCC};
|
||||||
|
|
||||||
|
const VCO_MIN: u32 = 150_000_000;
|
||||||
|
const VCO_MAX: u32 = 420_000_000;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct PllConfig {
|
||||||
|
pub p_ck: Option<Hertz>,
|
||||||
|
pub q_ck: Option<Hertz>,
|
||||||
|
pub r_ck: Option<Hertz>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct PllConfigResults {
|
||||||
|
pub ref_x_ck: u32,
|
||||||
|
pub pll_x_m: u32,
|
||||||
|
pub pll_x_p: u32,
|
||||||
|
pub vco_ck_target: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
|
||||||
|
let pll_x_p = if plln == 0 {
|
||||||
|
if output > VCO_MAX / 2 {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
((VCO_MAX / output) | 1) - 1 // Must be even or unity
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Specific to PLL2/3, will subtract 1 later
|
||||||
|
if output > VCO_MAX / 2 {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
VCO_MAX / output
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let vco_ck = output + pll_x_p;
|
||||||
|
|
||||||
|
assert!(pll_x_p < 128);
|
||||||
|
assert!(vco_ck >= VCO_MIN);
|
||||||
|
assert!(vco_ck <= VCO_MAX);
|
||||||
|
|
||||||
|
(vco_ck, pll_x_p)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Must have exclusive access to the RCC register block
|
||||||
|
unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
|
||||||
|
use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
|
||||||
|
|
||||||
|
let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
|
||||||
|
|
||||||
|
// Input divisor, resulting in a reference clock in the range
|
||||||
|
// 1 to 2 MHz. Choose the highest reference clock (lowest m)
|
||||||
|
let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
|
||||||
|
assert!(pll_x_m < 64);
|
||||||
|
|
||||||
|
// Calculate resulting reference clock
|
||||||
|
let ref_x_ck = pll_src / pll_x_m;
|
||||||
|
assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
|
||||||
|
|
||||||
|
RCC.pllcfgr().modify(|w| {
|
||||||
|
w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO);
|
||||||
|
w.set_pllrge(plln, Pllrge::RANGE1);
|
||||||
|
});
|
||||||
|
PllConfigResults {
|
||||||
|
ref_x_ck,
|
||||||
|
pll_x_m,
|
||||||
|
pll_x_p,
|
||||||
|
vco_ck_target,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Must have exclusive access to the RCC register block
|
||||||
|
pub(super) unsafe fn pll_setup(
|
||||||
|
pll_src: u32,
|
||||||
|
config: &PllConfig,
|
||||||
|
plln: usize,
|
||||||
|
) -> (Option<u32>, Option<u32>, Option<u32>) {
|
||||||
|
use crate::pac::rcc::vals::Divp;
|
||||||
|
|
||||||
|
match config.p_ck {
|
||||||
|
Some(requested_output) => {
|
||||||
|
let config_results = vco_setup(pll_src, requested_output.0, plln);
|
||||||
|
let PllConfigResults {
|
||||||
|
ref_x_ck,
|
||||||
|
pll_x_m,
|
||||||
|
pll_x_p,
|
||||||
|
vco_ck_target,
|
||||||
|
} = config_results;
|
||||||
|
|
||||||
|
RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
|
||||||
|
|
||||||
|
// Feedback divider. Integer only
|
||||||
|
let pll_x_n = vco_ck_target / ref_x_ck;
|
||||||
|
assert!(pll_x_n >= 4);
|
||||||
|
assert!(pll_x_n <= 512);
|
||||||
|
RCC.plldivr(plln)
|
||||||
|
.modify(|w| w.set_divn1((pll_x_n - 1) as u16));
|
||||||
|
|
||||||
|
// No FRACN
|
||||||
|
RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
|
||||||
|
let vco_ck = ref_x_ck * pll_x_n;
|
||||||
|
|
||||||
|
RCC.plldivr(plln)
|
||||||
|
.modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8)));
|
||||||
|
RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
|
||||||
|
|
||||||
|
// Calulate additional output dividers
|
||||||
|
let q_ck = match config.q_ck {
|
||||||
|
Some(Hertz(ck)) if ck > 0 => {
|
||||||
|
let div = (vco_ck + ck - 1) / ck;
|
||||||
|
RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
|
||||||
|
RCC.pllcfgr().modify(|w| w.set_divqen(plln, true));
|
||||||
|
Some(vco_ck / div)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let r_ck = match config.r_ck {
|
||||||
|
Some(Hertz(ck)) if ck > 0 => {
|
||||||
|
let div = (vco_ck + ck - 1) / ck;
|
||||||
|
RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
|
||||||
|
RCC.pllcfgr().modify(|w| w.set_divren(plln, true));
|
||||||
|
Some(vco_ck / div)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
(Some(vco_ck / pll_x_p), q_ck, r_ck)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
assert!(
|
||||||
|
config.q_ck.is_none(),
|
||||||
|
"Must set PLL P clock for Q clock to take effect!"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
config.r_ck.is_none(),
|
||||||
|
"Must set PLL P clock for R clock to take effect!"
|
||||||
|
);
|
||||||
|
(None, None, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,145 +0,0 @@
|
|||||||
use super::{Hertz, RCC};
|
|
||||||
|
|
||||||
const VCO_MIN: u32 = 150_000_000;
|
|
||||||
const VCO_MAX: u32 = 420_000_000;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct PllConfig {
|
|
||||||
pub p_ck: Option<Hertz>,
|
|
||||||
pub q_ck: Option<Hertz>,
|
|
||||||
pub r_ck: Option<Hertz>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) struct PllConfigResults {
|
|
||||||
pub ref_x_ck: u32,
|
|
||||||
pub pll_x_m: u32,
|
|
||||||
pub pll_x_p: u32,
|
|
||||||
pub vco_ck_target: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
|
|
||||||
let pll_x_p = if plln == 0 {
|
|
||||||
if output > VCO_MAX / 2 {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
((VCO_MAX / output) | 1) - 1 // Must be even or unity
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Specific to PLL2/3, will subtract 1 later
|
|
||||||
if output > VCO_MAX / 2 {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
VCO_MAX / output
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let vco_ck = output + pll_x_p;
|
|
||||||
|
|
||||||
assert!(pll_x_p < 128);
|
|
||||||
assert!(vco_ck >= VCO_MIN);
|
|
||||||
assert!(vco_ck <= VCO_MAX);
|
|
||||||
|
|
||||||
(vco_ck, pll_x_p)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Must have exclusive access to the RCC register block
|
|
||||||
unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
|
|
||||||
use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
|
|
||||||
|
|
||||||
let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
|
|
||||||
|
|
||||||
// Input divisor, resulting in a reference clock in the range
|
|
||||||
// 1 to 2 MHz. Choose the highest reference clock (lowest m)
|
|
||||||
let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
|
|
||||||
assert!(pll_x_m < 64);
|
|
||||||
|
|
||||||
// Calculate resulting reference clock
|
|
||||||
let ref_x_ck = pll_src / pll_x_m;
|
|
||||||
assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
|
|
||||||
|
|
||||||
RCC.pllcfgr().modify(|w| {
|
|
||||||
w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO);
|
|
||||||
w.set_pllrge(plln, Pllrge::RANGE1);
|
|
||||||
});
|
|
||||||
PllConfigResults {
|
|
||||||
ref_x_ck,
|
|
||||||
pll_x_m,
|
|
||||||
pll_x_p,
|
|
||||||
vco_ck_target,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Must have exclusive access to the RCC register block
|
|
||||||
pub(super) unsafe fn pll_setup(
|
|
||||||
pll_src: u32,
|
|
||||||
config: &PllConfig,
|
|
||||||
plln: usize,
|
|
||||||
) -> (Option<u32>, Option<u32>, Option<u32>) {
|
|
||||||
use crate::pac::rcc::vals::Divp;
|
|
||||||
|
|
||||||
match config.p_ck {
|
|
||||||
Some(requested_output) => {
|
|
||||||
let config_results = vco_setup(pll_src, requested_output.0, plln);
|
|
||||||
let PllConfigResults {
|
|
||||||
ref_x_ck,
|
|
||||||
pll_x_m,
|
|
||||||
pll_x_p,
|
|
||||||
vco_ck_target,
|
|
||||||
} = config_results;
|
|
||||||
|
|
||||||
RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
|
|
||||||
|
|
||||||
// Feedback divider. Integer only
|
|
||||||
let pll_x_n = vco_ck_target / ref_x_ck;
|
|
||||||
assert!(pll_x_n >= 4);
|
|
||||||
assert!(pll_x_n <= 512);
|
|
||||||
RCC.plldivr(plln)
|
|
||||||
.modify(|w| w.set_divn1((pll_x_n - 1) as u16));
|
|
||||||
|
|
||||||
// No FRACN
|
|
||||||
RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
|
|
||||||
let vco_ck = ref_x_ck * pll_x_n;
|
|
||||||
|
|
||||||
RCC.plldivr(plln)
|
|
||||||
.modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8)));
|
|
||||||
RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
|
|
||||||
|
|
||||||
// Calulate additional output dividers
|
|
||||||
let q_ck = match config.q_ck {
|
|
||||||
Some(Hertz(ck)) if ck > 0 => {
|
|
||||||
let div = (vco_ck + ck - 1) / ck;
|
|
||||||
RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
|
|
||||||
RCC.pllcfgr().modify(|w| w.set_divqen(plln, true));
|
|
||||||
Some(vco_ck / div)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
let r_ck = match config.r_ck {
|
|
||||||
Some(Hertz(ck)) if ck > 0 => {
|
|
||||||
let div = (vco_ck + ck - 1) / ck;
|
|
||||||
RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
|
|
||||||
RCC.pllcfgr().modify(|w| w.set_divren(plln, true));
|
|
||||||
Some(vco_ck / div)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
(Some(vco_ck / pll_x_p), q_ck, r_ck)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
assert!(
|
|
||||||
config.q_ck.is_none(),
|
|
||||||
"Must set PLL P clock for Q clock to take effect!"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
config.r_ck.is_none(),
|
|
||||||
"Must set PLL P clock for R clock to take effect!"
|
|
||||||
);
|
|
||||||
(None, None, None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -430,7 +430,7 @@ impl RccExt for RCC {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct HSI48(());
|
pub struct HSI48(());
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
||||||
let clocks = r.freeze(config);
|
let clocks = r.freeze(config);
|
||||||
set_freqs(clocks);
|
set_freqs(clocks);
|
@ -254,7 +254,7 @@ impl RccExt for RCC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
||||||
let clocks = r.freeze(config);
|
let clocks = r.freeze(config);
|
||||||
set_freqs(clocks);
|
set_freqs(clocks);
|
@ -482,7 +482,7 @@ impl RccExt for RCC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
||||||
let clocks = r.freeze(config);
|
let clocks = r.freeze(config);
|
||||||
set_freqs(clocks);
|
set_freqs(clocks);
|
@ -4,6 +4,23 @@ use crate::peripherals;
|
|||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
|
#[cfg_attr(any(rcc_f0, rcc_f0x0), path = "f0.rs")]
|
||||||
|
#[cfg_attr(rcc_f1, path = "f1.rs")]
|
||||||
|
#[cfg_attr(rcc_f3, path = "f3.rs")]
|
||||||
|
#[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")]
|
||||||
|
#[cfg_attr(rcc_f7, path = "f7.rs")]
|
||||||
|
#[cfg_attr(rcc_g0, path = "g0.rs")]
|
||||||
|
#[cfg_attr(rcc_g4, path = "g4.rs")]
|
||||||
|
#[cfg_attr(any(rcc_h7, rcc_h7ab), path = "h7.rs")]
|
||||||
|
#[cfg_attr(rcc_l0, path = "l0.rs")]
|
||||||
|
#[cfg_attr(rcc_l1, path = "l1.rs")]
|
||||||
|
#[cfg_attr(rcc_l4, path = "l4.rs")]
|
||||||
|
#[cfg_attr(rcc_u5, path = "u5.rs")]
|
||||||
|
#[cfg_attr(rcc_wb, path = "wb.rs")]
|
||||||
|
#[cfg_attr(rcc_wl5, path = "wl5.rs")]
|
||||||
|
mod _version;
|
||||||
|
pub use _version::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Clocks {
|
pub struct Clocks {
|
||||||
pub sys: Hertz,
|
pub sys: Hertz,
|
||||||
@ -59,61 +76,15 @@ static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
|
|||||||
/// Sets the clock frequencies
|
/// Sets the clock frequencies
|
||||||
///
|
///
|
||||||
/// Safety: Sets a mutable global.
|
/// Safety: Sets a mutable global.
|
||||||
pub unsafe fn set_freqs(freqs: Clocks) {
|
pub(crate) unsafe fn set_freqs(freqs: Clocks) {
|
||||||
CLOCK_FREQS.as_mut_ptr().write(freqs);
|
CLOCK_FREQS.as_mut_ptr().write(freqs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Safety: Reads a mutable global.
|
/// Safety: Reads a mutable global.
|
||||||
pub unsafe fn get_freqs() -> &'static Clocks {
|
pub(crate) unsafe fn get_freqs() -> &'static Clocks {
|
||||||
&*CLOCK_FREQS.as_ptr()
|
&*CLOCK_FREQS.as_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(rcc_h7)] {
|
|
||||||
mod h7;
|
|
||||||
pub use h7::*;
|
|
||||||
} else if #[cfg(rcc_l0)] {
|
|
||||||
mod l0;
|
|
||||||
pub use l0::*;
|
|
||||||
} else if #[cfg(rcc_l1)] {
|
|
||||||
mod l1;
|
|
||||||
pub use l1::*;
|
|
||||||
} else if #[cfg(rcc_l4)] {
|
|
||||||
mod l4;
|
|
||||||
pub use l4::*;
|
|
||||||
} else if #[cfg(rcc_f1)] {
|
|
||||||
mod f1;
|
|
||||||
pub use f1::*;
|
|
||||||
} else if #[cfg(rcc_f3)] {
|
|
||||||
mod f3;
|
|
||||||
pub use f3::*;
|
|
||||||
} else if #[cfg(rcc_f4)] {
|
|
||||||
mod f4;
|
|
||||||
pub use f4::*;
|
|
||||||
} else if #[cfg(rcc_f7)] {
|
|
||||||
mod f7;
|
|
||||||
pub use f7::*;
|
|
||||||
} else if #[cfg(rcc_wb)] {
|
|
||||||
mod wb;
|
|
||||||
pub use wb::*;
|
|
||||||
} else if #[cfg(rcc_wl5)] {
|
|
||||||
mod wl5x;
|
|
||||||
pub use wl5x::*;
|
|
||||||
} else if #[cfg(any(rcc_f0, rcc_f0x0))] {
|
|
||||||
mod f0;
|
|
||||||
pub use f0::*;
|
|
||||||
} else if #[cfg(any(rcc_g0))] {
|
|
||||||
mod g0;
|
|
||||||
pub use g0::*;
|
|
||||||
} else if #[cfg(any(rcc_g4))] {
|
|
||||||
mod g4;
|
|
||||||
pub use g4::*;
|
|
||||||
} else if #[cfg(any(rcc_u5))] {
|
|
||||||
mod u5;
|
|
||||||
pub use u5::*;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
pub trait RccPeripheral {
|
pub trait RccPeripheral {
|
||||||
fn frequency() -> crate::time::Hertz;
|
fn frequency() -> crate::time::Hertz;
|
||||||
|
@ -502,7 +502,7 @@ impl RccExt for RCC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
||||||
let power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal());
|
let power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal());
|
||||||
let clocks = r.freeze(config, &power);
|
let clocks = r.freeze(config, &power);
|
@ -206,7 +206,7 @@ impl RccExt for RCC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
||||||
let clocks = r.freeze(config);
|
let clocks = r.freeze(config);
|
||||||
set_freqs(clocks);
|
set_freqs(clocks);
|
@ -229,7 +229,7 @@ impl RccExt for RCC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
let r = <peripherals::RCC as embassy::util::Steal>::steal();
|
||||||
let clocks = r.freeze(config);
|
let clocks = r.freeze(config);
|
||||||
set_freqs(clocks);
|
set_freqs(clocks);
|
Loading…
Reference in New Issue
Block a user