use cfg_if::cfg_if;
#[cfg(not(any(feature = "h5", feature = "h7b3", feature = "h735")))]
use crate::pac::SYSCFG;
use crate::{
clocks::RccError,
pac::{CRS, FLASH, PWR, RCC},
MAX_ITERS,
};
#[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 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 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 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<(), RccError> {
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().set_bit());
rcc.apb4rstr.modify(|_, w| w.syscfgrst().set_bit());
rcc.apb4rstr.modify(|_, w| w.syscfgrst().clear_bit());
}
let mut i = 0;
macro_rules! wait_hang {
($i:expr) => {
i += 1;
if i >= MAX_ITERS {
return Err(RccError::Hardware);
}
};
}
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) });
i = 0;
while pwr.d3cr.read().vosrdy().bit_is_clear() {wait_hang!(i);}
} else {
pwr.voscr
.modify(|_, w| unsafe { w.vos().bits(VosRange::VOS1 as u8) });
i = 0;
while pwr.vossr.read().vosrdy().bit_is_clear() {wait_hang!(i);}
}
}
syscfg.pwrcr.modify(|_, w| w.oden().set_bit());
i = 0;
#[cfg(feature = "h7")]
while pwr.d3cr.read().vosrdy().bit_is_clear() {
wait_hang!(i);
}
#[cfg(feature = "h5")]
while pwr.vossr.read().vosrdy().bit_is_clear() {
wait_hang!(i);
}
}
_ => {
#[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));
i = 0;
while rcc.cr.read().csirdy().bit_is_clear() {
wait_hang!(i);
}
}
InputSrc::Hse(_) => {
rcc.cr.modify(|_, w| w.hseon().bit(true));
i = 0;
while rcc.cr.read().hserdy().bit_is_clear() {
wait_hang!(i);
}
}
InputSrc::Hsi(div) => {
rcc.cr.modify(|_, w| unsafe {
w.hsidiv().bits(div as u8);
w.hsion().bit(true)
});
i = 0;
while rcc.cr.read().hsirdy().bit_is_clear() {
wait_hang!(i);
}
}
InputSrc::Pll1 => {
match self.pll_src {
PllSrc::Csi => {
rcc.cr.modify(|_, w| w.csion().bit(true));
i = 0;
while rcc.cr.read().csirdy().bit_is_clear() {
wait_hang!(i);
}
}
PllSrc::Hse(_) => {
rcc.cr.modify(|_, w| w.hseon().bit(true));
i = 0;
while rcc.cr.read().hserdy().bit_is_clear() {
wait_hang!(i);
}
}
PllSrc::Hsi(div) => {
rcc.cr.modify(|_, w| unsafe {
w.hsidiv().bits(div as u8);
w.hsion().bit(true)
});
i = 0;
while rcc.cr.read().hsirdy().bit_is_clear() {
wait_hang!(i);
}
}
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| w.pllsrc().bits(self.pll_src.bits()));
if let InputSrc::Pll1 = self.input_src {
rcc.cr.modify(|_, w| w.pll1on().clear_bit());
while rcc.cr.read().pll1rdy().bit_is_set() {}
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) {
0..=2_000_000 => 0,
_ => 1,
};
#[cfg(feature = "h7")]
rcc.pllckselr.modify(|_, w| w.divm1().bits(self.pll1.divm));
#[cfg(feature = "h7")]
rcc.pllcfgr.modify(|_, w| {
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().set_bit());
i = 0;
while rcc.cr.read().pll1rdy().bit_is_clear() {
wait_hang!(i);
}
}
if self.pll2.enabled {
rcc.cr.modify(|_, w| w.pll2on().clear_bit());
i = 0;
while rcc.cr.read().pll2rdy().bit_is_set() {
wait_hang!(i);
}
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| w.divm2().bits(self.pll2.divm));
#[cfg(feature = "h7")]
rcc.pllcfgr.modify(|_, w| {
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);
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().set_bit());
i = 0;
while rcc.cr.read().pll2rdy().bit_is_clear() {
wait_hang!(i);
}
}
if self.pll3.enabled {
rcc.cr.modify(|_, w| w.pll3on().clear_bit());
i = 0;
while rcc.cr.read().pll3rdy().bit_is_set() {
wait_hang!(i);
}
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| w.divm3().bits(self.pll3.divm));
#[cfg(feature = "h7")]
rcc.pllcfgr.modify(|_, w| {
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().set_bit());
i = 0;
while rcc.cr.read().pll3rdy().bit_is_clear() {
wait_hang!(i);
}
}
if self.hsi48_on {
rcc.cr.modify(|_, w| w.hsi48on().set_bit());
i = 0;
while rcc.cr.read().hsi48rdy().bit_is_clear() {
wait_hang!(i);
}
}
Ok(())
}
pub fn reselect_input(&self) -> Result<(), RccError> {
let rcc = unsafe { &(*RCC::ptr()) };
let mut i = 0;
macro_rules! wait_hang {
($i:expr) => {
i += 1;
if i >= MAX_ITERS {
return Err(RccError::Hardware);
}
};
}
match self.input_src {
InputSrc::Hse(_) => {
rcc.cr.modify(|_, w| w.hseon().set_bit());
i = 0;
while rcc.cr.read().hserdy().bit_is_clear() {
wait_hang!(i);
}
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().set_bit());
i = 0;
while rcc.cr.read().hserdy().bit_is_clear() {
wait_hang!(i);
}
}
PllSrc::Hsi(div) => {
rcc.cr.modify(|_, w| unsafe {
w.hsidiv().bits(div as u8); w.hsion().bit(true)
});
i = 0;
while rcc.cr.read().hsirdy().bit_is_clear() {
wait_hang!(i);
}
}
PllSrc::Csi => (), PllSrc::None => (),
}
rcc.cr.modify(|_, w| w.pll1on().clear_bit());
i = 0;
while rcc.cr.read().pll1rdy().bit_is_set() {
wait_hang!(i);
}
rcc.cfgr
.modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
rcc.cr.modify(|_, w| w.pll1on().set_bit());
i = 0;
while rcc.cr.read().pll1rdy().bit_is_clear() {
wait_hang!(i);
}
}
InputSrc::Hsi(div) => {
{
rcc.cr.modify(|_, w| unsafe {
w.hsidiv().bits(div as u8); w.hsion().bit(true)
});
i = 0;
while rcc.cr.read().hsirdy().bit_is_clear() {
wait_hang!(i);
}
}
}
InputSrc::Csi => (), }
Ok(())
}
pub 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 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 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 fn d1cpreclk(&self) -> u32 {
self.sysclk() / self.d1_core_prescaler.value() as u32
}
pub 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 fn systick(&self) -> u32 {
#[cfg(feature = "h7")]
return self.d1cpreclk();
#[cfg(feature = "h5")]
return self.sysclk();
}
pub fn usb(&self) -> u32 {
0 }
pub fn apb1(&self) -> u32 {
self.hclk() / self.d2_prescaler1.value() as u32
}
pub fn apb1_timer(&self) -> u32 {
if let ApbPrescaler::Div1 = self.d2_prescaler1 {
self.apb1()
} else {
self.apb1() * 2
}
}
pub fn apb2(&self) -> u32 {
self.hclk() / self.d2_prescaler2.value() as u32
}
pub fn apb2_timer(&self) -> u32 {
if let ApbPrescaler::Div1 = self.d2_prescaler2 {
self.apb2()
} else {
self.apb2() * 2
}
}
pub 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<(), RccError> {
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(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(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(RccError::Speed);
}
if pll_input_speed < 2_000_000 && (vco_speed < 150_000_000 || vco_speed > 420_000_000) {
return Err(RccError::Speed);
}
}
if self.sysclk() > max_sysclk {
return Err(RccError::Speed);
}
if self.hclk() > max_hclk {
return Err(RccError::Speed);
}
if self.apb1() > max_apb {
return Err(RccError::Speed);
}
if self.apb2() > max_apb {
return Err(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().set_bit());
crs.cfgr
.modify(|_, w| unsafe { w.syncsrc().bits(sync_src as u8) });
crs.cr.modify(|_, w| {
w.autotrimen().set_bit();
w.cen().set_bit()
});
}