use crate::pac::rcc::cfgr::{HPRE_A, SW_A};
use crate::pac::{self, rcc, RCC};
use fugit::HertzU32 as Hertz;
use fugit::RateExtU32;
#[cfg(not(feature = "gpio-f410"))]
use pll::I2sPll;
use pll::MainPll;
#[cfg(any(feature = "gpio-f427", feature = "gpio-f446", feature = "gpio-f469"))]
use pll::SaiPll;
mod pll;
mod enable;
use crate::pac::rcc::RegisterBlock as RccRB;
pub trait RccBus: crate::Sealed {
type Bus;
}
#[allow(clippy::missing_safety_doc)]
pub trait Enable: RccBus {
fn enable(rcc: &RccRB);
fn disable(rcc: &RccRB);
fn is_enabled() -> bool;
#[inline]
fn is_disabled() -> bool {
!Self::is_enabled()
}
unsafe fn enable_unchecked() {
let rcc = &*pac::RCC::ptr();
Self::enable(rcc);
}
unsafe fn disable_unchecked() {
let rcc = pac::RCC::ptr();
Self::disable(&*rcc);
}
}
#[allow(clippy::missing_safety_doc)]
pub trait LPEnable: RccBus {
fn enable_in_low_power(rcc: &RccRB);
fn disable_in_low_power(rcc: &RccRB);
fn is_enabled_in_low_power() -> bool;
#[inline]
fn is_disabled_in_low_power() -> bool {
!Self::is_enabled_in_low_power()
}
unsafe fn enable_in_low_power_unchecked() {
let rcc = pac::RCC::ptr();
Self::enable_in_low_power(&*rcc);
}
unsafe fn disable_in_low_power_unchecked() {
let rcc = pac::RCC::ptr();
Self::disable_in_low_power(&*rcc);
}
}
#[allow(clippy::missing_safety_doc)]
pub trait Reset: RccBus {
fn reset(rcc: &RccRB);
unsafe fn reset_unchecked() {
let rcc = pac::RCC::ptr();
Self::reset(&*rcc);
}
}
pub trait RccExt {
fn constrain(self) -> Rcc;
}
pub trait BusClock {
fn clock(clocks: &Clocks) -> Hertz;
}
pub trait BusTimerClock {
fn timer_clock(clocks: &Clocks) -> Hertz;
}
impl<T> BusClock for T
where
T: RccBus,
T::Bus: BusClock,
{
fn clock(clocks: &Clocks) -> Hertz {
T::Bus::clock(clocks)
}
}
impl<T> BusTimerClock for T
where
T: RccBus,
T::Bus: BusTimerClock,
{
fn timer_clock(clocks: &Clocks) -> Hertz {
T::Bus::timer_clock(clocks)
}
}
macro_rules! bus_struct {
($( $(#[$attr:meta])* $busX:ident => ($EN:ident, $en:ident, $LPEN:ident, $lpen:ident, $RST:ident, $rst:ident, $doc:literal),)+) => {
$(
$(#[$attr])*
#[doc = $doc]
pub struct $busX {
_0: (),
}
$(#[$attr])*
impl $busX {
pub(crate) fn enr(rcc: &RccRB) -> &rcc::$EN {
&rcc.$en
}
pub(crate) fn lpenr(rcc: &RccRB) -> &rcc::$LPEN {
&rcc.$lpen
}
pub(crate) fn rstr(rcc: &RccRB) -> &rcc::$RST {
&rcc.$rst
}
}
)+
};
}
bus_struct! {
APB1 => (APB1ENR, apb1enr, APB1LPENR, apb1lpenr, APB1RSTR, apb1rstr, "Advanced Peripheral Bus 1 (APB1) registers"),
APB2 => (APB2ENR, apb2enr, APB2LPENR, apb2lpenr, APB2RSTR, apb2rstr, "Advanced Peripheral Bus 2 (APB2) registers"),
AHB1 => (AHB1ENR, ahb1enr, AHB1LPENR, ahb1lpenr, AHB1RSTR, ahb1rstr, "Advanced High-performance Bus 1 (AHB1) registers"),
#[cfg(not(feature = "gpio-f410"))]
AHB2 => (AHB2ENR, ahb2enr, AHB2LPENR, ahb2lpenr, AHB2RSTR, ahb2rstr, "Advanced High-performance Bus 2 (AHB2) registers"),
}
#[cfg(any(feature = "fsmc", feature = "fmc"))]
pub struct AHB3 {
_0: (),
}
#[cfg(any(feature = "fsmc", feature = "fmc"))]
impl AHB3 {
#[inline(always)]
fn enr(rcc: &RccRB) -> &rcc::AHB3ENR {
&rcc.ahb3enr
}
#[cfg(feature = "fmc")]
#[inline(always)]
fn lpenr(rcc: &RccRB) -> &rcc::AHB3LPENR {
&rcc.ahb3lpenr
}
#[inline(always)]
fn rstr(rcc: &RccRB) -> &rcc::AHB3RSTR {
&rcc.ahb3rstr
}
}
impl BusClock for AHB1 {
fn clock(clocks: &Clocks) -> Hertz {
clocks.hclk
}
}
#[cfg(not(feature = "gpio-f410"))]
impl BusClock for AHB2 {
fn clock(clocks: &Clocks) -> Hertz {
clocks.hclk
}
}
#[cfg(any(feature = "fsmc", feature = "fmc"))]
impl BusClock for AHB3 {
fn clock(clocks: &Clocks) -> Hertz {
clocks.hclk
}
}
impl BusClock for APB1 {
fn clock(clocks: &Clocks) -> Hertz {
clocks.pclk1
}
}
impl BusClock for APB2 {
fn clock(clocks: &Clocks) -> Hertz {
clocks.pclk2
}
}
impl BusTimerClock for APB1 {
fn timer_clock(clocks: &Clocks) -> Hertz {
clocks.timclk1
}
}
impl BusTimerClock for APB2 {
fn timer_clock(clocks: &Clocks) -> Hertz {
clocks.timclk2
}
}
impl RccExt for RCC {
fn constrain(self) -> Rcc {
Rcc {
cfgr: CFGR {
hse: None,
hse_bypass: false,
hclk: None,
pclk1: None,
pclk2: None,
sysclk: None,
pll48clk: false,
i2s_ckin: None,
#[cfg(any(
feature = "gpio-f401",
feature = "gpio-f410",
feature = "gpio-f411",
feature = "gpio-f417",
feature = "gpio-f427",
feature = "gpio-f469",
))]
i2s_clk: None,
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
i2s_apb1_clk: None,
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
i2s_apb2_clk: None,
#[cfg(feature = "sai1")]
sai1_clk: None,
#[cfg(feature = "sai1")]
sai2_clk: None,
},
}
}
}
pub struct Rcc {
pub cfgr: CFGR,
}
pub const HSI: u32 = 16_000_000; #[cfg(any(
feature = "gpio-f401",
feature = "gpio-f410",
feature = "gpio-f411",
feature = "gpio-f412",
feature = "gpio-f413",
feature = "gpio-f417",
feature = "gpio-f427",
feature = "gpio-f469",
))]
pub const SYSCLK_MIN: u32 = 24_000_000;
#[cfg(feature = "gpio-f446")]
pub const SYSCLK_MIN: u32 = 12_500_000;
#[cfg(feature = "gpio-f401")]
pub const SYSCLK_MAX: u32 = 84_000_000;
#[cfg(feature = "gpio-f417")]
pub const SYSCLK_MAX: u32 = 168_000_000;
#[cfg(any(
feature = "gpio-f410",
feature = "gpio-f411",
feature = "gpio-f412",
feature = "gpio-f413",
))]
pub const SYSCLK_MAX: u32 = 100_000_000;
#[cfg(any(feature = "gpio-f427", feature = "gpio-f446", feature = "gpio-f469"))]
pub const SYSCLK_MAX: u32 = 180_000_000;
#[cfg(any(
feature = "gpio-f401",
feature = "gpio-f410",
feature = "gpio-f411",
feature = "gpio-f412",
feature = "gpio-f413",
))]
pub const PCLK2_MAX: u32 = SYSCLK_MAX;
#[cfg(not(any(
feature = "gpio-f401",
feature = "gpio-f410",
feature = "gpio-f411",
feature = "gpio-f412",
feature = "gpio-f413",
)))]
pub const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
pub const PCLK1_MAX: u32 = PCLK2_MAX / 2;
pub struct CFGR {
hse: Option<u32>,
hse_bypass: bool,
hclk: Option<u32>,
pclk1: Option<u32>,
pclk2: Option<u32>,
sysclk: Option<u32>,
pll48clk: bool,
i2s_ckin: Option<u32>,
#[cfg(any(
feature = "gpio-f401",
feature = "gpio-f410",
feature = "gpio-f411",
feature = "gpio-f417",
feature = "gpio-f427",
feature = "gpio-f469",
))]
i2s_clk: Option<u32>,
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
i2s_apb1_clk: Option<u32>,
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
i2s_apb2_clk: Option<u32>,
#[cfg(feature = "sai1")]
sai1_clk: Option<u32>,
#[cfg(feature = "sai1")]
sai2_clk: Option<u32>,
}
impl CFGR {
pub fn use_hse(mut self, freq: Hertz) -> Self {
self.hse = Some(freq.raw());
self
}
pub fn bypass_hse_oscillator(self) -> Self {
Self {
hse_bypass: true,
..self
}
}
pub fn hclk(mut self, freq: Hertz) -> Self {
self.hclk = Some(freq.raw());
self
}
pub fn pclk1(mut self, freq: Hertz) -> Self {
self.pclk1 = Some(freq.raw());
self
}
pub fn pclk2(mut self, freq: Hertz) -> Self {
self.pclk2 = Some(freq.raw());
self
}
pub fn sysclk(mut self, freq: Hertz) -> Self {
self.sysclk = Some(freq.raw());
self
}
pub fn require_pll48clk(mut self) -> Self {
self.pll48clk = true;
self
}
pub fn i2s_ckin(mut self, freq: Hertz) -> Self {
self.i2s_ckin = Some(freq.raw());
self
}
#[cfg(any(
feature = "gpio-f401",
feature = "gpio-f410",
feature = "gpio-f411",
feature = "gpio-f417",
feature = "gpio-f427",
feature = "gpio-f469",
))]
pub fn i2s_clk(mut self, freq: Hertz) -> Self {
self.i2s_clk = Some(freq.raw());
self
}
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
pub fn i2s_apb1_clk(mut self, freq: Hertz) -> Self {
self.i2s_apb1_clk = Some(freq.raw());
self
}
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
pub fn i2s_apb2_clk(mut self, freq: Hertz) -> Self {
self.i2s_apb2_clk = Some(freq.raw());
self
}
#[cfg(any(feature = "gpio-f413", feature = "gpio-f427", feature = "gpio-f469"))]
pub fn saia_clk(mut self, freq: Hertz) -> Self {
self.sai1_clk = Some(freq.raw());
self
}
#[cfg(any(feature = "gpio-f413", feature = "gpio-f427", feature = "gpio-f469"))]
pub fn saib_clk(mut self, freq: Hertz) -> Self {
self.sai2_clk = Some(freq.raw());
self
}
#[cfg(feature = "gpio-f446")]
pub fn sai1_clk(mut self, freq: Hertz) -> Self {
self.sai1_clk = Some(freq.raw());
self
}
#[cfg(feature = "gpio-f446")]
pub fn sai2_clk(mut self, freq: Hertz) -> Self {
self.sai2_clk = Some(freq.raw());
self
}
#[cfg(feature = "gpio-f410")]
#[inline(always)]
fn pll_setup(&self, pllsrcclk: u32, pllsysclk: Option<u32>) -> PllSetup {
let i2s_clocks = self.i2s_clocks();
let main_pll = if let Some(i2s_clk) = i2s_clocks.pll_i2s_clk {
MainPll::setup_with_i2s(
pllsrcclk,
self.hse.is_some(),
pllsysclk,
self.pll48clk,
i2s_clk,
)
} else {
MainPll::fast_setup(pllsrcclk, self.hse.is_some(), pllsysclk, self.pll48clk)
};
PllSetup {
use_pll: main_pll.use_pll,
pllsysclk: main_pll.pllsysclk,
pll48clk: main_pll.pll48clk,
i2s: i2s_clocks.real(main_pll.plli2sclk, self.i2s_ckin),
}
}
#[cfg(feature = "gpio-f413")]
#[inline(always)]
fn pll_setup(&self, pllsrcclk: u32, pllsysclk: Option<u32>) -> PllSetup {
let rcc = unsafe { &*RCC::ptr() };
let i2s_clocks = self.i2s_clocks();
let sai_clocks = self.sai_clocks();
let main_pll = MainPll::fast_setup(pllsrcclk, self.hse.is_some(), pllsysclk, self.pll48clk);
let (i2s_pll, real_sai_clk) = if let Some(i2s_clk) = i2s_clocks.pll_i2s_clk {
let i2s_pll = I2sPll::setup(pllsrcclk, Some(i2s_clk));
if let Some(sai_clk) = sai_clocks.pll_sai_clk {
let div = u32::min(
u32::max((i2s_pll.plli2sclk.unwrap() + (sai_clk >> 1)) / sai_clk, 1),
31,
);
rcc.dckcfgr.modify(|_, w| w.plli2sdivr().bits(div as u8));
let real_sai_clk = sai_clk / div;
(i2s_pll, Some(real_sai_clk))
} else {
(i2s_pll, None)
}
} else if let Some(pll_sai_clk) = sai_clocks.pll_sai_clk {
let (i2s_pll, real_sai_clk, div) = (1..31)
.map(|div| {
let i2s_pll = I2sPll::setup(pllsrcclk, Some(pll_sai_clk * div));
let real_clk = i2s_pll.plli2sclk.unwrap() / div;
(i2s_pll, real_clk, div)
})
.min_by_key(|(_, real_clk, _)| (*real_clk as i32 - pll_sai_clk as i32).abs())
.unwrap();
rcc.dckcfgr.modify(|_, w| w.plli2sdivr().bits(div as u8));
(i2s_pll, Some(real_sai_clk))
} else {
(I2sPll::unused(), None)
};
PllSetup {
use_pll: main_pll.use_pll,
use_i2spll: i2s_pll.use_pll,
pllsysclk: main_pll.pllsysclk,
pll48clk: main_pll.pll48clk,
i2s: i2s_clocks.real(i2s_pll.plli2sclk, self.i2s_ckin),
sai: sai_clocks.real(real_sai_clk, self.i2s_ckin),
}
}
#[cfg(any(feature = "gpio-f411", feature = "gpio-f412", feature = "gpio-f446"))]
#[inline(always)]
fn pll_setup(&self, pllsrcclk: u32, pllsysclk: Option<u32>) -> PllSetup {
let i2s_clocks = self.i2s_clocks();
#[cfg(feature = "gpio-f446")]
let sai_clocks = self.sai_clocks();
let main_pll = MainPll::fast_setup(pllsrcclk, self.hse.is_some(), pllsysclk, self.pll48clk);
let i2s_pll = I2sPll::setup(pllsrcclk, i2s_clocks.pll_i2s_clk);
#[cfg(feature = "gpio-f446")]
let sai_pll = SaiPll::setup(pllsrcclk, sai_clocks.pll_sai_clk);
PllSetup {
use_pll: main_pll.use_pll,
use_i2spll: i2s_pll.use_pll,
#[cfg(feature = "gpio-f446")]
use_saipll: sai_pll.use_pll,
pllsysclk: main_pll.pllsysclk,
pll48clk: main_pll.pll48clk,
i2s: i2s_clocks.real(i2s_pll.plli2sclk, self.i2s_ckin),
#[cfg(feature = "gpio-f446")]
sai: sai_clocks.real(sai_pll.sai_clk, self.i2s_ckin),
}
}
#[cfg(any(
feature = "gpio-f401",
feature = "gpio-f417",
feature = "gpio-f427",
feature = "gpio-f469",
))]
#[inline(always)]
fn pll_setup(&self, pllsrcclk: u32, pllsysclk: Option<u32>) -> PllSetup {
let i2s_clocks = self.i2s_clocks();
#[cfg(any(feature = "gpio-f427", feature = "gpio-f469"))]
let sai_clocks = self.sai_clocks();
let main_pll = MainPll::fast_setup(pllsrcclk, self.hse.is_some(), pllsysclk, self.pll48clk);
let i2s_pll = I2sPll::setup_shared_m(pllsrcclk, main_pll.m, i2s_clocks.pll_i2s_clk);
#[cfg(any(feature = "gpio-f427", feature = "gpio-f469"))]
let sai_pll =
SaiPll::setup_shared_m(pllsrcclk, main_pll.m.or(i2s_pll.m), sai_clocks.pll_sai_clk);
PllSetup {
use_pll: main_pll.use_pll,
use_i2spll: i2s_pll.use_pll,
#[cfg(any(feature = "gpio-f427", feature = "gpio-f469"))]
use_saipll: sai_pll.use_pll,
pllsysclk: main_pll.pllsysclk,
pll48clk: main_pll.pll48clk,
i2s: i2s_clocks.real(i2s_pll.plli2sclk, self.i2s_ckin),
#[cfg(any(feature = "gpio-f427", feature = "gpio-f469"))]
sai: sai_clocks.real(sai_pll.sai_clk, self.i2s_ckin),
}
}
#[cfg(feature = "sai1")]
fn sai_clocks(&self) -> SaiClocks {
let sai1_ext = self.sai1_clk.is_some() && self.sai1_clk == self.i2s_ckin;
#[cfg(not(feature = "gpio-f446"))]
let sai2_ext = self.sai2_clk.is_some() && self.sai2_clk == self.i2s_ckin;
let pll_sai_clk = if sai1_ext { None } else { self.sai1_clk };
#[cfg(feature = "gpio-f446")]
let pll_sai_clk2 = self.sai2_clk;
#[cfg(not(feature = "gpio-f446"))]
let pll_sai_clk2 = if sai2_ext { None } else { self.sai2_clk };
if pll_sai_clk.is_some() && pll_sai_clk2.is_some() && pll_sai_clk != pll_sai_clk2 {
panic!("only one SAI PLL frequency implemented");
}
SaiClocks {
sai1_ext,
#[cfg(not(feature = "gpio-f446"))]
sai2_ext,
pll_sai_clk,
}
}
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
fn i2s_clocks(&self) -> I2sClocks {
let i2s_apb1_ext = self.i2s_apb1_clk.is_some() && self.i2s_apb1_clk == self.i2s_ckin;
let i2s_apb2_ext = self.i2s_apb2_clk.is_some() && self.i2s_apb2_clk == self.i2s_ckin;
let pll_i2s_clk = if i2s_apb1_ext {
None
} else {
self.i2s_apb1_clk
};
let pll_i2s_clk2 = if i2s_apb2_ext {
None
} else {
self.i2s_apb2_clk
};
if pll_i2s_clk.is_some() && pll_i2s_clk2.is_some() && pll_i2s_clk != pll_i2s_clk2 {
panic!("only one I2S PLL frequency implemented");
}
I2sClocks {
i2s_apb1_ext,
i2s_apb2_ext,
pll_i2s_clk,
}
}
#[cfg(not(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446")))]
fn i2s_clocks(&self) -> I2sClocks {
let i2s_ext = self.i2s_clk.is_some() && self.i2s_clk == self.i2s_ckin;
let pll_i2s_clk = if i2s_ext { None } else { self.i2s_clk };
I2sClocks {
i2s_ext,
pll_i2s_clk,
}
}
fn flash_setup(sysclk: u32) {
use crate::pac::FLASH;
#[cfg(any(
feature = "gpio-f401",
feature = "gpio-f417",
feature = "gpio-f410",
feature = "gpio-f411",
feature = "gpio-f412",
feature = "gpio-f427",
feature = "gpio-f446",
feature = "gpio-f469",
))]
let flash_latency_step = 30_000_000;
#[cfg(feature = "gpio-f413")]
let flash_latency_step = 25_000_000;
unsafe {
let flash = &(*FLASH::ptr());
flash.acr.modify(|_, w| {
w.latency().bits(((sysclk - 1) / flash_latency_step) as u8);
w.prften().set_bit();
w.icen().set_bit();
w.dcen().set_bit()
})
}
}
pub fn freeze(self) -> Clocks {
self.freeze_internal(false)
}
pub unsafe fn freeze_unchecked(self) -> Clocks {
self.freeze_internal(true)
}
fn freeze_internal(self, unchecked: bool) -> Clocks {
let rcc = unsafe { &*RCC::ptr() };
let pllsrcclk = self.hse.unwrap_or(HSI);
let sysclk = self.sysclk.unwrap_or(pllsrcclk);
let sysclk_on_pll = sysclk != pllsrcclk;
let plls = self.pll_setup(pllsrcclk, sysclk_on_pll.then_some(sysclk));
let sysclk = if sysclk_on_pll {
plls.pllsysclk.unwrap()
} else {
sysclk
};
assert!(unchecked || !sysclk_on_pll || (SYSCLK_MIN..=SYSCLK_MAX).contains(&sysclk));
let hclk = self.hclk.unwrap_or(sysclk);
let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
0 => unreachable!(),
1 => (HPRE_A::Div1, 1),
2 => (HPRE_A::Div2, 2),
3..=5 => (HPRE_A::Div4, 4),
6..=11 => (HPRE_A::Div8, 8),
12..=39 => (HPRE_A::Div16, 16),
40..=95 => (HPRE_A::Div64, 64),
96..=191 => (HPRE_A::Div128, 128),
192..=383 => (HPRE_A::Div256, 256),
_ => (HPRE_A::Div512, 512),
};
let hclk = sysclk / hpre_div;
let pclk1 = self
.pclk1
.unwrap_or_else(|| core::cmp::min(PCLK1_MAX, hclk));
let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
0 => unreachable!(),
1 => (0b000, 1u8),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let pclk1 = hclk / u32::from(ppre1);
assert!(unchecked || pclk1 <= PCLK1_MAX);
let pclk2 = self
.pclk2
.unwrap_or_else(|| core::cmp::min(PCLK2_MAX, hclk));
let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
0 => unreachable!(),
1 => (0b000, 1u8),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let pclk2 = hclk / u32::from(ppre2);
assert!(unchecked || pclk2 <= PCLK2_MAX);
Self::flash_setup(sysclk);
if self.hse.is_some() {
rcc.cr.modify(|_, w| {
if self.hse_bypass {
w.hsebyp().bypassed();
}
w.hseon().set_bit()
});
while rcc.cr.read().hserdy().bit_is_clear() {}
}
if plls.use_pll {
rcc.cr.modify(|_, w| w.pllon().set_bit());
#[cfg(any(feature = "gpio-f427", feature = "gpio-f446", feature = "gpio-f469"))]
if hclk > 168_000_000 {
rcc.apb1enr.modify(|_, w| w.pwren().set_bit());
cortex_m::asm::dsb();
let pwr = unsafe { &*crate::pac::PWR::ptr() };
pwr.cr.modify(|_, w| w.oden().set_bit());
while pwr.csr.read().odrdy().bit_is_clear() {}
pwr.cr.modify(|_, w| w.odswen().set_bit());
while pwr.csr.read().odswrdy().bit_is_clear() {}
}
while rcc.cr.read().pllrdy().bit_is_clear() {}
}
#[cfg(not(feature = "gpio-f410"))]
if plls.use_i2spll {
rcc.cr.modify(|_, w| w.plli2son().set_bit());
while rcc.cr.read().plli2srdy().bit_is_clear() {}
}
#[cfg(any(feature = "gpio-f427", feature = "gpio-f446", feature = "gpio-f469"))]
if plls.use_saipll {
rcc.cr.modify(|_, w| w.pllsaion().set_bit());
while rcc.cr.read().pllsairdy().bit_is_clear() {}
}
plls.i2s.config_clocksel();
#[cfg(feature = "sai1")]
plls.sai.config_clocksel();
rcc.cfgr.modify(|_, w| unsafe {
w.ppre2().bits(ppre2_bits);
w.ppre1().bits(ppre1_bits);
w.hpre().variant(hpre_bits)
});
cortex_m::asm::delay(16);
rcc.cfgr.modify(|_, w| {
w.sw().variant(if sysclk_on_pll {
SW_A::Pll
} else if self.hse.is_some() {
SW_A::Hse
} else {
SW_A::Hsi
})
});
let pclk_mul = if ppre1 == 1 { 1 } else { 2 };
let timclk1 = Hertz::from_raw(pclk1 * pclk_mul);
let pclk_mul = if ppre2 == 1 { 1 } else { 2 };
let timclk2 = Hertz::from_raw(pclk2 * pclk_mul);
let clocks = Clocks {
hclk: hclk.Hz(),
pclk1: pclk1.Hz(),
pclk2: pclk2.Hz(),
timclk1,
timclk2,
sysclk: sysclk.Hz(),
pll48clk: plls.pll48clk.map(Hertz::from_raw),
#[cfg(not(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446")))]
i2s_clk: plls.i2s.i2s_clk.map(Hertz::from_raw),
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
i2s_apb1_clk: plls.i2s.i2s_apb1_clk.map(Hertz::from_raw),
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
i2s_apb2_clk: plls.i2s.i2s_apb2_clk.map(Hertz::from_raw),
#[cfg(any(feature = "gpio-f413", feature = "gpio-f427", feature = "gpio-f469"))]
saia_clk: plls.sai.sai1_clk.map(Hertz::from_raw),
#[cfg(any(feature = "gpio-f413", feature = "gpio-f427", feature = "gpio-f469"))]
saib_clk: plls.sai.sai2_clk.map(Hertz::from_raw),
#[cfg(feature = "sai2")]
sai1_clk: plls.sai.sai1_clk.map(Hertz::from_raw),
#[cfg(feature = "sai2")]
sai2_clk: plls.sai.sai2_clk.map(Hertz::from_raw),
};
if self.pll48clk {
assert!(clocks.is_pll48clk_valid());
}
clocks
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct PllSetup {
use_pll: bool,
#[cfg(not(feature = "gpio-f410"))]
use_i2spll: bool,
#[cfg(any(feature = "gpio-f427", feature = "gpio-f446", feature = "gpio-f469"))]
use_saipll: bool,
pllsysclk: Option<u32>,
pll48clk: Option<u32>,
i2s: RealI2sClocks,
#[cfg(feature = "sai1")]
sai: RealSaiClocks,
}
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct I2sClocks {
i2s_apb1_ext: bool,
i2s_apb2_ext: bool,
pll_i2s_clk: Option<u32>,
}
#[cfg(not(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446")))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct I2sClocks {
i2s_ext: bool,
pll_i2s_clk: Option<u32>,
}
impl I2sClocks {
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
fn real(&self, pll_i2s_clk: Option<u32>, i2s_ckin: Option<u32>) -> RealI2sClocks {
RealI2sClocks {
i2s_apb1_ext: self.i2s_apb1_ext,
i2s_apb2_ext: self.i2s_apb2_ext,
i2s_apb1_clk: if self.i2s_apb1_ext {
i2s_ckin
} else {
pll_i2s_clk
},
i2s_apb2_clk: if self.i2s_apb2_ext {
i2s_ckin
} else {
pll_i2s_clk
},
}
}
#[cfg(not(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446")))]
fn real(&self, pll_i2s_clk: Option<u32>, i2s_ckin: Option<u32>) -> RealI2sClocks {
RealI2sClocks {
i2s_ext: self.i2s_ext,
i2s_clk: if self.i2s_ext { i2s_ckin } else { pll_i2s_clk },
}
}
}
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct RealI2sClocks {
i2s_apb1_ext: bool,
i2s_apb2_ext: bool,
i2s_apb1_clk: Option<u32>,
i2s_apb2_clk: Option<u32>,
}
#[cfg(not(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446")))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct RealI2sClocks {
i2s_ext: bool,
i2s_clk: Option<u32>,
}
impl RealI2sClocks {
fn config_clocksel(&self) {
let rcc = unsafe { &*RCC::ptr() };
#[cfg(not(any(
feature = "gpio-f410",
feature = "gpio-f412",
feature = "gpio-f413",
feature = "gpio-f446",
)))]
rcc.cfgr.modify(|_, w| {
if self.i2s_ext {
w.i2ssrc().ckin()
} else {
w.i2ssrc().plli2s()
}
});
#[cfg(feature = "gpio-f410")]
rcc.dckcfgr.modify(|_, w| {
if self.i2s_ext {
w.i2ssrc().i2s_ckin()
} else {
w.i2ssrc().pllclkr()
}
});
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
rcc.dckcfgr.modify(|_, w| {
if self.i2s_apb1_ext {
w.i2s1src().i2s_ckin()
} else {
w.i2s1src().plli2sr()
};
if self.i2s_apb2_ext {
w.i2s2src().i2s_ckin()
} else {
w.i2s2src().plli2sr()
}
});
}
}
#[cfg(feature = "sai1")]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct SaiClocks {
sai1_ext: bool,
#[cfg(not(feature = "gpio-f446"))]
sai2_ext: bool,
pll_sai_clk: Option<u32>,
}
#[cfg(feature = "sai1")]
impl SaiClocks {
fn real(&self, pll_sai_clk: Option<u32>, i2s_ckin: Option<u32>) -> RealSaiClocks {
RealSaiClocks {
sai1_ext: self.sai1_ext,
#[cfg(not(feature = "gpio-f446"))]
sai2_ext: self.sai2_ext,
sai1_clk: if self.sai1_ext { i2s_ckin } else { pll_sai_clk },
#[cfg(not(feature = "gpio-f446"))]
sai2_clk: if self.sai2_ext { i2s_ckin } else { pll_sai_clk },
#[cfg(feature = "gpio-f446")]
sai2_clk: pll_sai_clk,
}
}
}
#[cfg(feature = "sai1")]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct RealSaiClocks {
sai1_ext: bool,
#[cfg(not(feature = "gpio-f446"))]
sai2_ext: bool,
sai1_clk: Option<u32>,
sai2_clk: Option<u32>,
}
#[cfg(feature = "sai1")]
impl RealSaiClocks {
fn config_clocksel(&self) {
let rcc = unsafe { &*RCC::ptr() };
#[cfg(not(feature = "gpio-f446"))]
rcc.dckcfgr.modify(|_, w| {
if self.sai1_ext {
w.sai1asrc().i2s_ckin()
} else {
w.sai1asrc().pllsai()
};
if self.sai2_ext {
w.sai1bsrc().i2s_ckin()
} else {
w.sai1bsrc().pllsai()
}
});
#[cfg(feature = "gpio-f446")]
rcc.dckcfgr.modify(|_, w| {
if self.sai1_ext {
w.sai1src().i2s_ckin()
} else {
w.sai1src().pllsai()
}
});
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Clocks {
hclk: Hertz,
pclk1: Hertz,
pclk2: Hertz,
timclk1: Hertz,
timclk2: Hertz,
sysclk: Hertz,
pll48clk: Option<Hertz>,
#[cfg(not(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446")))]
i2s_clk: Option<Hertz>,
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
i2s_apb1_clk: Option<Hertz>,
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
i2s_apb2_clk: Option<Hertz>,
#[cfg(any(feature = "gpio-f413", feature = "gpio-f427", feature = "gpio-f469"))]
saia_clk: Option<Hertz>,
#[cfg(any(feature = "gpio-f413", feature = "gpio-f427", feature = "gpio-f469"))]
saib_clk: Option<Hertz>,
#[cfg(feature = "gpio-f446")]
sai1_clk: Option<Hertz>,
#[cfg(feature = "gpio-f446")]
sai2_clk: Option<Hertz>,
}
impl Clocks {
pub fn hclk(&self) -> Hertz {
self.hclk
}
pub fn pclk1(&self) -> Hertz {
self.pclk1
}
pub fn pclk2(&self) -> Hertz {
self.pclk2
}
pub fn timclk1(&self) -> Hertz {
self.timclk1
}
pub fn timclk2(&self) -> Hertz {
self.timclk2
}
pub fn sysclk(&self) -> Hertz {
self.sysclk
}
pub fn pll48clk(&self) -> Option<Hertz> {
self.pll48clk
}
pub fn is_pll48clk_valid(&self) -> bool {
self.pll48clk
.map(|freq| 48_000_000_u32.abs_diff(freq.raw()) <= 120_000)
.unwrap_or_default()
}
#[cfg(not(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446")))]
pub fn i2s_clk(&self) -> Option<Hertz> {
self.i2s_clk
}
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
pub fn i2s_apb1_clk(&self) -> Option<Hertz> {
self.i2s_apb1_clk
}
#[cfg(any(feature = "gpio-f412", feature = "gpio-f413", feature = "gpio-f446"))]
pub fn i2s_apb2_clk(&self) -> Option<Hertz> {
self.i2s_apb2_clk
}
#[cfg(any(feature = "gpio-f413", feature = "gpio-f427", feature = "gpio-f469"))]
pub fn saia_clk(&self) -> Option<Hertz> {
self.saia_clk
}
#[cfg(any(feature = "gpio-f413", feature = "gpio-f427", feature = "gpio-f469"))]
pub fn saib_clk(&self) -> Option<Hertz> {
self.saib_clk
}
#[cfg(feature = "gpio-f446")]
pub fn sai1_clk(&self) -> Option<Hertz> {
self.sai1_clk
}
#[cfg(feature = "gpio-f446")]
pub fn sai2_clk(&self) -> Option<Hertz> {
self.sai2_clk
}
}