use cfg_if::cfg_if;
#[cfg(not(any(feature = "h5", feature = "h7b3", feature = "h735")))]
use crate::pac::SYSCFG;
use crate::{
clocks::RccError,
error::{Error, Result},
pac::{CRS, FLASH, PWR, RCC},
util::bounded_loop,
};
#[derive(Clone, Copy, PartialEq)]
pub enum PllSrc {
None,
Csi,
Hsi(HsiDiv),
Hse(u32),
}
impl PllSrc {
pub fn bits(&self) -> u8 {
match self {
Self::Hsi(_) => 0b00,
Self::Csi => 0b01,
Self::Hse(_) => 0b10,
Self::None => 0b11,
}
}
}
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum StopWuck {
Hsi = 0,
Csi = 1,
}
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum UsbSrc {
Disabled = 0b00,
Pll1Q = 0b01,
Pll3Q = 0b10,
Hsi48 = 0b11,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum CrsSyncSrc {
#[cfg(feature = "h735")] CrsSync = 0b00,
#[cfg(not(feature = "h735"))]
Usb2 = 0b00,
Lse = 0b01,
OtgHs = 0b10,
}
#[derive(Clone, Copy, PartialEq)]
pub enum InputSrc {
Hsi(HsiDiv),
Csi,
Hse(u32), Pll1,
}
impl InputSrc {
pub fn bits(&self) -> u8 {
match self {
Self::Hsi(_) => 0b000,
Self::Csi => 0b001,
Self::Hse(_) => 0b010,
Self::Pll1 => 0b011,
}
}
}
pub struct PllCfg {
pub enabled: bool,
pub pllp_en: bool,
pub pllq_en: bool,
pub pllr_en: bool,
pub divm: u8,
pub divn: u16,
pub divp: u8,
pub divq: u8,
pub divr: u8,
}
impl Default for PllCfg {
fn default() -> Self {
cfg_if! {
if #[cfg(feature = "h5")] {
let divn = 250;
} else if #[cfg(feature = "h7b3")] {
let divn = 280;
} else {
let divn = 400;
}
}
Self {
enabled: true,
pllp_en: true,
pllq_en: false,
pllr_en: false,
#[cfg(feature = "h5")]
divm: 32, #[cfg(feature = "h7")]
divm: 32,
divn,
divp: 2,
divq: 8,
divr: 2,
}
}
}
impl PllCfg {
pub fn disabled() -> Self {
Self {
enabled: false,
pllq_en: false,
pllp_en: false,
pllr_en: false,
..Default::default()
}
}
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum HclkPrescaler {
Div1 = 0b0000,
Div2 = 0b1000,
Div4 = 0b1001,
Div8 = 0b1010,
Div16 = 0b1011,
Div64 = 0b1100,
Div128 = 0b1101,
Div256 = 0b1110,
Div512 = 0b1111,
}
impl HclkPrescaler {
pub const fn value(&self) -> u16 {
match self {
Self::Div1 => 1,
Self::Div2 => 2,
Self::Div4 => 4,
Self::Div8 => 8,
Self::Div16 => 16,
Self::Div64 => 64,
Self::Div128 => 128,
Self::Div256 => 256,
Self::Div512 => 512,
}
}
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum ApbPrescaler {
Div1 = 0b000,
Div2 = 0b100,
Div4 = 0b101,
Div8 = 0b110,
Div16 = 0b111,
}
impl ApbPrescaler {
pub const fn value(&self) -> u8 {
match self {
Self::Div1 => 1,
Self::Div2 => 2,
Self::Div4 => 4,
Self::Div8 => 8,
Self::Div16 => 16,
}
}
}
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum SaiSrc {
Pll1Q = 0b000,
Pll2P = 0b001,
Pll3P = 0b010,
I2sCkin = 0b011,
PerClk = 0100,
}
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum Spi123Src {
Pll1Q = 0b000, Pll2P = 0b001,
Pll3P = 0b010,
I2sCkin = 0b011,
PerClk = 0100,
}
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum Spi45Src {
Apb = 0b000,
Pll2Q = 0b001,
Pll3Q = 0b010,
Hsi = 0b011,
Csi = 0100,
HseCk = 0b101,
}
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum DfsdmSrc {
Pclk2 = 0,
Sysclk = 1,
}
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum CanSrc {
Hse = 0b00,
Pll1Q = 0b01,
Pll2Q = 0b10,
}
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum HsiDiv {
Div1 = 0b00,
Div2 = 0b01,
Div4 = 0b10,
Div8 = 0b11,
}
impl HsiDiv {
pub const fn value(&self) -> u8 {
match self {
Self::Div1 => 1,
Self::Div2 => 2,
Self::Div4 => 4,
Self::Div8 => 8,
}
}
}
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum VosRange {
#[cfg(not(feature = "h7b3"))]
VOS0 = 0, VOS1 = 0b11,
VOS2 = 0b10,
VOS3 = 0b01,
}
impl VosRange {
pub fn wait_states(&self, hclk: u32) -> (u8, u8) {
#[cfg(not(feature = "h735"))]
match self {
#[cfg(not(feature = "h7b3"))]
Self::VOS0 => match hclk {
0..=70_000_000 => (0, 0),
70_000_001..=140_000_000 => (1, 1),
140_000_001..=185_000_000 => (2, 1),
185_000_001..=210_000_000 => (2, 2),
210_000_001..=225_000_000 => (3, 2),
225_000_001..=240_000_000 => (4, 2),
_ => panic!(
"Can't set higher than 240Mhz HCLK with VSO0 range. (Try changing the `vos_range` setting)."
),
},
Self::VOS1 => match hclk {
0..=70_000_000 => (0, 0),
70_000_001..=140_000_000 => (1, 1),
140_000_001..=185_000_000 => (2, 1),
185_000_001..=210_000_000 => (2, 2),
210_000_001..=225_000_000 => (3, 2),
_ => panic!(
"Can't set higher than 225Mhz HCLK with VOS1 range. (Try changing the `vos_range` setting)."
),
},
Self::VOS2 => match hclk {
0..=55_000_000 => (0, 0),
55_000_001..=110_000_000 => (1, 1),
110_000_001..=165_000_000 => (2, 1),
165_000_001..=225_000_000 => (3, 2),
_ => panic!(
"Can't set higher than 225Mhz HCLK with VSO2 range. (Try changing the `vos_range` setting)."
),
},
Self::VOS3 => match hclk {
0..=45_000_000 => (0, 0),
45_000_001..=90_000_000 => (1, 1),
90_000_001..=135_000_000 => (2, 1),
135_000_001..=180_000_000 => (3, 2),
180_000_001..=225_000_000 => (4, 2),
_ => panic!(
"Can't set higher than 225Mhz HCLK with VSO3 range. (Try changing the `vos_range` setting)."
),
},
}
#[cfg(feature = "h735")]
match self {
Self::VOS0 => match hclk {
0..=70_000_000 => (0, 0b00),
70_000_001..=140_000_000 => (1, 0b01),
140_000_001..=210_000_000 => (2, 0b10),
210_000_001..=275_000_000 => (3, 0b11),
_ => panic!(
"Can't set higher than 275Mhz HCLK with VSO0 range. (Try changing the `vos_range` setting)."
),
},
Self::VOS1 => match hclk {
0..=67_000_000 => (0, 0b00),
67_000_001..=133_000_000 => (1, 0b01),
133_000_001..=200_000_000 => (2, 0b10),
_ => panic!(
"Can't set higher than 200Mhz HCLK with VOS1 range. (Try changing the `vos_range` setting)."
),
},
Self::VOS2 => match hclk {
0..=50_000_000 => (0, 0b00),
50_000_001..=100_000_000 => (1, 0b01),
100_000_001..=150_000_000 => (2, 0b10),
_ => panic!(
"Can't set higher than 150Mhz HCLK with VSO2 range. (Try changing the `vos_range` setting)."
),
},
Self::VOS3 => match hclk {
0..=35_000_000 => (0, 0b00),
35_000_001..=70_000_000 => (1, 0b01),
70_000_001..=85_000_000 => (2, 0b10),
_ => panic!(
"Can't set higher than 85Mhz HCLK with VSO3 range. (Try changing the `vos_range` setting)."
),
},
}
}
}
pub struct Clocks {
pub input_src: InputSrc,
pub pll_src: PllSrc,
pub pll1: PllCfg,
pub pll2: PllCfg,
pub pll3: PllCfg,
#[cfg(feature = "h7")]
pub d1_core_prescaler: HclkPrescaler,
pub hclk_prescaler: HclkPrescaler,
pub d1_prescaler: ApbPrescaler,
pub d2_prescaler1: ApbPrescaler,
pub d2_prescaler2: ApbPrescaler,
#[cfg(feature = "h7")]
pub d3_prescaler: ApbPrescaler,
pub hse_bypass: bool,
pub usb_src: UsbSrc,
pub security_system: bool,
pub hsi48_on: bool,
pub stop_wuck: StopWuck,
pub vos_range: VosRange,
pub sai1_src: SaiSrc,
#[cfg(not(feature = "h735"))]
pub sai23_src: SaiSrc,
pub sai4a_src: SaiSrc,
pub sai4b_src: SaiSrc,
pub spi123_src: Spi123Src,
pub spi45_src: Spi45Src,
pub dfsdm1_src: DfsdmSrc,
pub can_src: CanSrc,
}
impl Clocks {
pub fn setup(&self) -> Result<()> {
if let Err(e) = self.validate_speeds() {
return Err(e);
}
let rcc = unsafe { &(*RCC::ptr()) };
let flash = unsafe { &(*FLASH::ptr()) };
let pwr = unsafe { &(*PWR::ptr()) };
#[cfg(feature = "h7")]
{
rcc.apb4enr().modify(|_, w| w.syscfgen().bit(true));
rcc.apb4rstr().modify(|_, w| w.syscfgrst().bit(true));
rcc.apb4rstr().modify(|_, w| w.syscfgrst().clear_bit());
}
match self.vos_range {
#[cfg(not(any(feature = "h5", feature = "h7b3", feature = "h735")))]
VosRange::VOS0 => {
let syscfg = unsafe { &(*SYSCFG::ptr()) };
cfg_if! {
if #[cfg(feature = "h7")] {
pwr.d3cr()
.modify(|_, w| unsafe { w.vos().bits(VosRange::VOS1 as u8) });
bounded_loop!(
pwr.d3cr().read().vosrdy().bit_is_clear(),
Error::RegisterUnchanged
);
} else {
pwr.voscr()
.modify(|_, w| unsafe { w.vos().bits(VosRange::VOS1 as u8) });
bounded_loop!(
pwr.vossr().read().vosrdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
}
syscfg.pwrcr().modify(|_, w| w.oden().bit(true));
#[cfg(feature = "h7")]
bounded_loop!(
pwr.d3cr().read().vosrdy().bit_is_clear(),
Error::RegisterUnchanged
);
#[cfg(feature = "h5")]
bounded_loop!(
pwr.vossr().read().vosrdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
_ => {
#[cfg(feature = "h7")]
pwr.d3cr()
.modify(|_, w| unsafe { w.vos().bits(self.vos_range as u8) });
#[cfg(feature = "h5")]
pwr.voscr()
.modify(|_, w| unsafe { w.vos().bits(self.vos_range as u8) });
}
}
let wait_states = self.vos_range.wait_states(self.hclk());
flash.acr().modify(|_, w| unsafe {
w.latency().bits(wait_states.0);
w.wrhighfreq().bits(wait_states.1)
});
match self.input_src {
InputSrc::Csi => {
rcc.cr().modify(|_, w| w.csion().bit(true));
bounded_loop!(
rcc.cr().read().csirdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
InputSrc::Hse(_) => {
rcc.cr().modify(|_, w| w.hseon().bit(true));
bounded_loop!(
rcc.cr().read().hserdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
InputSrc::Hsi(div) => {
rcc.cr().modify(|_, w| unsafe {
w.hsidiv().bits(div as u8);
w.hsion().bit(true)
});
bounded_loop!(
rcc.cr().read().hsirdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
InputSrc::Pll1 => {
match self.pll_src {
PllSrc::Csi => {
rcc.cr().modify(|_, w| w.csion().bit(true));
bounded_loop!(
rcc.cr().read().csirdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
PllSrc::Hse(_) => {
rcc.cr().modify(|_, w| w.hseon().bit(true));
bounded_loop!(
rcc.cr().read().hserdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
PllSrc::Hsi(div) => {
rcc.cr().modify(|_, w| unsafe {
w.hsidiv().bits(div as u8);
w.hsion().bit(true)
});
bounded_loop!(
rcc.cr().read().hsirdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
PllSrc::None => {}
}
}
}
rcc.cr().modify(|_, w| {
w.hsebyp().bit(self.hse_bypass)
});
rcc.cfgr().modify(|_, w| unsafe {
w.sw().bits(self.input_src.bits());
w.stopwuck().bit(self.stop_wuck as u8 != 0)
});
#[cfg(feature = "h7")]
rcc.d1cfgr().modify(|_, w| unsafe {
w.d1cpre().bits(self.d1_core_prescaler as u8);
w.d1ppre().bits(self.d1_prescaler as u8);
w.hpre().bits(self.hclk_prescaler as u8)
});
#[cfg(feature = "h7")]
rcc.d2cfgr().modify(|_, w| unsafe {
w.d2ppre1().bits(self.d2_prescaler1 as u8);
w.d2ppre2().bits(self.d2_prescaler2 as u8)
});
#[cfg(feature = "h7")]
rcc.d3cfgr()
.modify(|_, w| unsafe { w.d3ppre().bits(self.d3_prescaler as u8) });
#[cfg(feature = "h5")]
rcc.cfgr2().modify(|_, w| unsafe {
w.ppre1().bits(self.d1_prescaler as u8);
w.ppre2().bits(self.d2_prescaler1 as u8);
w.ppre3().bits(self.d2_prescaler2 as u8);
w.hpre().bits(self.hclk_prescaler as u8)
});
#[cfg(not(any(feature = "h7b3", feature = "h5")))]
rcc.d2ccip1r().modify(|_, w| unsafe {
w.sai1sel().bits(self.sai1_src as u8);
#[cfg(not(feature = "h735"))]
w.sai23sel().bits(self.sai23_src as u8);
w.spi123sel().bits(self.spi123_src as u8);
w.spi45sel().bits(self.spi45_src as u8);
w.dfsdm1sel().bit(self.dfsdm1_src as u8 != 0);
w.fdcansel().bits(self.can_src as u8)
});
#[cfg(not(any(feature = "h7b3", feature = "h5")))]
rcc.d2ccip2r()
.modify(|_, w| unsafe { w.usbsel().bits(self.usb_src as u8) });
#[cfg(not(any(feature = "h7b3", feature = "h5")))]
rcc.d3ccipr().modify(|_, w| unsafe {
w.sai4asel().bits(self.sai4a_src as u8);
w.sai4bsel().bits(self.sai4b_src as u8)
});
#[cfg(feature = "h5")]
rcc.ccipr3().modify(|_, w| unsafe {
w.spi1sel().bits(self.spi123_src as u8);
w.spi2sel().bits(self.spi123_src as u8);
w.spi3sel().bits(self.spi45_src as u8);
w.spi4sel().bits(self.spi45_src as u8);
w.spi5sel().bits(self.spi123_src as u8)
});
#[cfg(feature = "h5")]
rcc.ccipr4.modify(|_, w| unsafe {
w.usbfssel().bits(self.usb_src as u8)
});
#[cfg(feature = "h5")]
rcc.ccipr5.modify(|_, w| unsafe {
w.sai1sel().bits(self.sai1_src as u8);
w.sai2sel().bits(self.sai23_src as u8);
w.fdcan12sel().bits(self.can_src as u8)
});
rcc.cr()
.modify(|_, w| w.hsecsson().bit(self.security_system));
#[cfg(feature = "h7")]
rcc.pllckselr()
.modify(|_, w| unsafe { w.pllsrc().bits(self.pll_src.bits()) });
if let InputSrc::Pll1 = self.input_src {
rcc.cr().modify(|_, w| w.pll1on().clear_bit());
bounded_loop!(
rcc.cr().read().pll1rdy().bit_is_set(),
Error::RegisterUnchanged
);
let pll1_rng_val = match self.pll_input_speed(self.pll_src, 1) {
1_000_000..=2_000_000 => 0b00,
2_000_001..=4_000_000 => 0b01,
4_000_001..=8_000_000 => 0b10,
8_000_001..=16_000_000 => 0b11,
_ => panic!("PLL1 input source must be between 1Mhz and 16Mhz."),
};
let pll1_vco = match self.pll_input_speed(self.pll_src, 1) {
1_000_000..=2_000_000 => 1,
2_000_001..=16_000_000 => 0,
_ => panic!("PLL1 input source must be between 1Mhz and 16Mhz."),
};
#[cfg(feature = "h7")]
rcc.pllckselr()
.modify(|_, w| unsafe { w.divm1().bits(self.pll1.divm) });
#[cfg(feature = "h7")]
rcc.pllcfgr().modify(|_, w| unsafe {
w.pll1rge().bits(pll1_rng_val);
w.pll1vcosel().bit(pll1_vco != 0);
w.divp1en().bit(true);
w.divq1en().bit(self.pll1.pllq_en);
w.divr1en().bit(self.pll1.pllr_en)
});
#[cfg(feature = "h5")]
rcc.pll1cfgr().modify(|_, w| unsafe {
w.pll1src().bits(self.pll_src.bits());
w.divm1().bits(self.pll1.divm);
w.pll1rge().bits(pll1_rng_val);
w.pll1vcosel().bit(pll1_vco != 0);
w.pll1pen().bit(true);
w.pll1qen().bit(self.pll1.pllq_en);
w.pll1ren().bit(self.pll1.pllr_en)
});
#[cfg(feature = "h7")]
rcc.pll1divr().modify(|_, w| unsafe {
w.divn1().bits(self.pll1.divn - 1);
w.divp1().bits(self.pll1.divp - 1);
w.divq1().bits(self.pll1.divq - 1);
w.divr1().bits(self.pll1.divr - 1)
});
#[cfg(feature = "h5")]
rcc.pll1divr().modify(|_, w| unsafe {
w.pll1n().bits(self.pll1.divn - 1);
w.pll1p().bits(self.pll1.divp - 1);
w.pll1q().bits(self.pll1.divq - 1);
w.pll1r().bits(self.pll1.divr - 1)
});
rcc.cr().modify(|_, w| w.pll1on().bit(true));
bounded_loop!(
rcc.cr().read().pll1rdy().bit_is_set(),
Error::RegisterUnchanged
);
}
if self.pll2.enabled {
rcc.cr().modify(|_, w| w.pll2on().clear_bit());
bounded_loop!(
rcc.cr().read().pll2rdy().bit_is_set(),
Error::RegisterUnchanged
);
let pll2_rng_val = match self.pll_input_speed(self.pll_src, 2) {
1_000_000..=2_000_000 => 0b00,
2_000_001..=4_000_000 => 0b01,
4_000_001..=8_000_000 => 0b10,
8_000_001..=16_000_000 => 0b11,
_ => panic!("PLL2 input source must be between 1Mhz and 16Mhz."),
};
let pll2_vco = match self.pll_input_speed(self.pll_src, 2) {
0..=2_000_000 => 0,
_ => 1,
};
#[cfg(feature = "h7")]
rcc.pllckselr()
.modify(|_, w| unsafe { w.divm2().bits(self.pll2.divm) });
#[cfg(feature = "h7")]
rcc.pllcfgr().modify(|_, w| unsafe {
w.pll2rge().bits(pll2_rng_val);
w.pll2vcosel().bit(pll2_vco != 0);
w.divp2en().bit(self.pll2.pllp_en);
w.divq2en().bit(self.pll2.pllq_en);
w.divr2en().bit(self.pll2.pllr_en)
});
#[cfg(feature = "h5")]
rcc.pll2cfgr().modify(|_, w| unsafe {
w.pll2src().bits(self.pll_src.bits());
w.pll2rge().bits(pll2_rng_val);
w.pll2vcosel().bit(pll2_vco != 0);
w.pll2pen().bit(self.pll2.pllp_en);
w.pll2qen().bit(self.pll2.pllq_en);
w.pll2ren().bit(self.pll2.pllr_en)
});
#[cfg(feature = "h7")]
rcc.pll2divr().modify(|_, w| unsafe {
w.divn2().bits(self.pll2.divn - 1);
#[cfg(not(any(feature = "h753", feature = "h753v")))] w.divp2().bits(self.pll2.divp - 1);
w.divq2().bits(self.pll2.divq - 1);
w.divr2().bits(self.pll2.divr - 1)
});
#[cfg(feature = "h5")]
rcc.pll2divr().modify(|_, w| unsafe {
w.pll2n().bits(self.pll2.divn - 1);
w.pll2p().bits(self.pll2.divp - 1);
w.pll2q().bits(self.pll2.divq - 1);
w.pll2r().bits(self.pll2.divr - 1)
});
rcc.cr().modify(|_, w| w.pll2on().bit(true));
bounded_loop!(
rcc.cr().read().pll2rdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
if self.pll3.enabled {
rcc.cr().modify(|_, w| w.pll3on().clear_bit());
bounded_loop!(
rcc.cr().read().pll3rdy().bit_is_set(),
Error::RegisterUnchanged
);
let pll3_rng_val = match self.pll_input_speed(self.pll_src, 3) {
1_000_000..=2_000_000 => 0b00,
2_000_001..=4_000_000 => 0b01,
4_000_001..=8_000_000 => 0b10,
8_000_001..=16_000_000 => 0b11,
_ => panic!("PLL3 input source must be between 1Mhz and 16Mhz."),
};
let pll3_vco = match self.pll_input_speed(self.pll_src, 3) {
0..=2_000_000 => 0,
_ => 1,
};
#[cfg(feature = "h7")]
rcc.pllckselr()
.modify(|_, w| unsafe { w.divm3().bits(self.pll3.divm) });
#[cfg(feature = "h7")]
rcc.pllcfgr().modify(|_, w| unsafe {
w.pll3rge().bits(pll3_rng_val);
w.pll3vcosel().bit(pll3_vco != 0);
w.divp3en().bit(self.pll3.pllp_en);
w.divq3en().bit(self.pll3.pllq_en);
w.divr3en().bit(self.pll3.pllr_en)
});
#[cfg(feature = "h5")]
rcc.pll3cfgr().modify(|_, w| unsafe {
w.pll3src().bits(self.pll_src.bits());
w.pll3rge().bits(pll3_rng_val);
w.pll3vcosel().bit(pll3_vco != 0);
w.pll3pen().bit(self.pll3.pllp_en);
w.pll3qen().bit(self.pll3.pllq_en);
w.pll3ren().bit(self.pll3.pllr_en)
});
#[cfg(feature = "h7")]
rcc.pll3divr().modify(|_, w| unsafe {
w.divn3().bits(self.pll3.divn - 1);
w.divp3().bits(self.pll3.divp - 1);
w.divq3().bits(self.pll3.divq - 1);
w.divr3().bits(self.pll3.divr - 1)
});
#[cfg(feature = "h5")]
rcc.pll3divr().modify(|_, w| unsafe {
w.pll3n().bits(self.pll3.divn - 1);
w.pll3p().bits(self.pll3.divp - 1);
w.pll3q().bits(self.pll3.divq - 1);
w.pll3r().bits(self.pll3.divr - 1)
});
rcc.cr().modify(|_, w| w.pll3on().bit(true));
bounded_loop!(
rcc.cr().read().pll3rdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
if self.hsi48_on {
rcc.cr().modify(|_, w| w.hsi48on().bit(true));
bounded_loop!(
rcc.cr().read().hsi48rdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
Ok(())
}
pub fn reselect_input(&self) -> Result<()> {
let rcc = unsafe { &(*RCC::ptr()) };
match self.input_src {
InputSrc::Hse(_) => {
rcc.cr().modify(|_, w| w.hseon().bit(true));
bounded_loop!(
rcc.cr().read().hserdy().bit_is_clear(),
Error::RegisterUnchanged
);
rcc.cfgr()
.modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
}
InputSrc::Pll1 => {
match self.pll_src {
PllSrc::Hse(_) => {
rcc.cr().modify(|_, w| w.hseon().bit(true));
bounded_loop!(
rcc.cr().read().hserdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
PllSrc::Hsi(div) => {
rcc.cr().modify(|_, w| unsafe {
w.hsidiv().bits(div as u8); w.hsion().bit(true)
});
bounded_loop!(
rcc.cr().read().hsirdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
PllSrc::Csi => (), PllSrc::None => (),
}
rcc.cr().modify(|_, w| w.pll1on().clear_bit());
bounded_loop!(
rcc.cr().read().pll1rdy().bit_is_set(),
Error::RegisterUnchanged
);
rcc.cfgr()
.modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
rcc.cr().modify(|_, w| w.pll1on().bit(true));
bounded_loop!(
rcc.cr().read().pll1rdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
InputSrc::Hsi(div) => {
{
rcc.cr().modify(|_, w| unsafe {
w.hsidiv().bits(div as u8); w.hsion().bit(true)
});
bounded_loop!(
rcc.cr().read().hsirdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
}
InputSrc::Csi => (), }
Ok(())
}
pub const fn pll_input_speed(&self, pll_src: PllSrc, pll_num: u8) -> u32 {
let input_freq = match pll_src {
PllSrc::Csi => 4_000_000,
PllSrc::Hsi(div) => 64_000_000 / (div.value() as u32),
PllSrc::Hse(freq) => freq,
PllSrc::None => 0,
};
match pll_num {
1 => input_freq / (self.pll1.divm as u32),
2 => input_freq / (self.pll2.divm as u32),
3 => input_freq / (self.pll3.divm as u32),
_ => panic!("Pll num must be between 1 and 3."),
}
}
pub const fn vco_output_freq(&self, pll_src: PllSrc, pll_num: u8) -> u32 {
let input_speed = self.pll_input_speed(pll_src, pll_num);
match pll_num {
1 => input_speed * self.pll1.divn as u32,
2 => input_speed * self.pll2.divn as u32,
3 => input_speed * self.pll3.divn as u32,
_ => panic!("Pll num must be between 1 and 3."),
}
}
pub fn pll_is_enabled(&self) -> bool {
let rcc = unsafe { &(*RCC::ptr()) };
rcc.cr().read().pll1on().bit_is_set()
}
pub const fn sysclk(&self) -> u32 {
match self.input_src {
InputSrc::Pll1 => {
self.pll_input_speed(self.pll_src, 1) * self.pll1.divn as u32
/ self.pll1.divp as u32
}
InputSrc::Csi => 4_000_000,
InputSrc::Hsi(div) => 64_000_000 / (div.value() as u32),
InputSrc::Hse(freq) => freq,
}
}
#[cfg(feature = "h7")]
pub const fn d1cpreclk(&self) -> u32 {
self.sysclk() / self.d1_core_prescaler.value() as u32
}
pub const fn hclk(&self) -> u32 {
#[cfg(feature = "h7")]
return self.sysclk()
/ self.d1_core_prescaler.value() as u32
/ self.hclk_prescaler.value() as u32;
#[cfg(feature = "h5")]
return self.sysclk() / self.hclk_prescaler.value() as u32;
}
pub const fn systick(&self) -> u32 {
#[cfg(feature = "h7")]
return self.d1cpreclk();
#[cfg(feature = "h5")]
return self.sysclk();
}
pub const fn usb(&self) -> u32 {
0 }
pub const fn apb1(&self) -> u32 {
self.hclk() / self.d2_prescaler1.value() as u32
}
pub const fn apb1_timer(&self) -> u32 {
if let ApbPrescaler::Div1 = self.d2_prescaler1 {
self.apb1()
} else {
self.apb1() * 2
}
}
pub const fn apb2(&self) -> u32 {
self.hclk() / self.d2_prescaler2.value() as u32
}
pub const fn apb2_timer(&self) -> u32 {
if let ApbPrescaler::Div1 = self.d2_prescaler2 {
self.apb2()
} else {
self.apb2() * 2
}
}
pub const fn sai1_speed(&self) -> u32 {
let pll_src = match self.input_src {
InputSrc::Pll1 => self.pll_src,
InputSrc::Csi => PllSrc::Csi,
InputSrc::Hsi(div) => PllSrc::Hsi(div),
InputSrc::Hse(freq) => PllSrc::Hse(freq),
};
match self.sai1_src {
SaiSrc::Pll1Q => {
self.pll_input_speed(pll_src, 1) * self.pll1.divn as u32 / self.pll1.divq as u32
}
SaiSrc::Pll2P => {
self.pll_input_speed(pll_src, 1) * self.pll2.divn as u32 / self.pll2.divp as u32
}
SaiSrc::Pll3P => {
self.pll_input_speed(pll_src, 1) * self.pll3.divn as u32 / self.pll3.divp as u32
}
SaiSrc::I2sCkin => unimplemented!(),
SaiSrc::PerClk => unimplemented!(),
}
}
pub fn validate_speeds(&self) -> Result<()> {
cfg_if! {
if #[cfg(feature = "h735")] {
let max_sysclk = 480_000_000;
} else {
let max_sysclk = 550_000_000;
}
}
let max_hclk = 240_000_000;
let max_apb = 120_000_000;
if self.pll1.divm > 63
|| self.pll1.divm > 63
|| self.pll3.divm > 63
|| self.pll1.divn > 512
|| self.pll2.divn > 512
|| self.pll3.divn > 512
|| self.pll1.divp > 128
|| self.pll2.divp > 128
|| self.pll3.divp > 128
|| self.pll1.divp < 2
|| self.pll2.divp < 2
|| self.pll3.divp < 2
{
return Err(Error::RccError(RccError::Speed));
}
if let InputSrc::Pll1 = self.input_src {
let pll_input_speed = self.pll_input_speed(self.pll_src, 1);
if pll_input_speed < 1_000_000 || pll_input_speed > 16_000_000 {
return Err(Error::RccError(RccError::Speed));
}
let vco_speed = self.vco_output_freq(self.pll_src, 1);
if pll_input_speed >= 2_000_000 && (vco_speed < 192_000_000 || vco_speed > 960_000_000)
{
return Err(Error::RccError(RccError::Speed));
}
if pll_input_speed < 2_000_000 && (vco_speed < 150_000_000 || vco_speed > 420_000_000) {
return Err(Error::RccError(RccError::Speed));
}
}
if self.sysclk() > max_sysclk {
return Err(Error::RccError(RccError::Speed));
}
if self.hclk() > max_hclk {
return Err(Error::RccError(RccError::Speed));
}
if self.apb1() > max_apb {
return Err(Error::RccError(RccError::Speed));
}
if self.apb2() > max_apb {
return Err(Error::RccError(RccError::Speed));
}
Ok(())
}
}
impl Default for Clocks {
fn default() -> Self {
Self {
input_src: InputSrc::Pll1,
pll_src: PllSrc::Hsi(HsiDiv::Div1),
pll1: PllCfg::default(),
pll2: PllCfg::disabled(),
pll3: PllCfg::disabled(),
#[cfg(feature = "h7")]
d1_core_prescaler: HclkPrescaler::Div1,
d1_prescaler: ApbPrescaler::Div2,
#[cfg(feature = "h5")]
hclk_prescaler: HclkPrescaler::Div1,
#[cfg(feature = "h7")]
hclk_prescaler: HclkPrescaler::Div2,
#[cfg(feature = "h5")]
d2_prescaler1: ApbPrescaler::Div1,
#[cfg(feature = "h7")]
d2_prescaler1: ApbPrescaler::Div2,
#[cfg(feature = "h5")]
d2_prescaler2: ApbPrescaler::Div1,
#[cfg(feature = "h7")]
d2_prescaler2: ApbPrescaler::Div2,
#[cfg(feature = "h7")]
d3_prescaler: ApbPrescaler::Div2,
hse_bypass: false,
usb_src: UsbSrc::Hsi48,
security_system: false,
hsi48_on: false,
stop_wuck: StopWuck::Hsi,
vos_range: VosRange::VOS1,
sai1_src: SaiSrc::Pll1Q,
#[cfg(not(feature = "h735"))]
sai23_src: SaiSrc::Pll1Q,
sai4a_src: SaiSrc::Pll1Q,
sai4b_src: SaiSrc::Pll1Q,
spi123_src: Spi123Src::Pll1Q,
spi45_src: Spi45Src::Apb,
dfsdm1_src: DfsdmSrc::Pclk2,
can_src: CanSrc::Pll1Q,
}
}
}
#[cfg(not(feature = "h7b3"))] impl Clocks {
pub fn full_speed() -> Self {
cfg_if! {
if #[cfg(feature = "h735")] {
let divn = 260;
let divp = 1;
} else {
let divn = 480;
let divp = 2;
}
}
Self {
pll1: PllCfg {
divn,
divp,
..Default::default()
},
vos_range: VosRange::VOS0,
..Default::default()
}
}
}
#[cfg(not(feature = "h5"))] pub fn enable_crs(sync_src: CrsSyncSrc) {
let crs = unsafe { &(*CRS::ptr()) };
let rcc = unsafe { &(*RCC::ptr()) };
rcc.apb1henr().modify(|_, w| w.crsen().bit(true));
crs.cfgr()
.modify(|_, w| unsafe { w.syncsrc().bits(sync_src as u8) });
crs.cr().modify(|_, w| {
w.autotrimen().bit(true);
w.cen().bit(true)
});
}