use crate::{
clocks::SpeedError,
pac::RCU,
rcu_en_reset,
};
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "f3")] {
#[derive(Clone, Copy)]
pub enum PllSrc {
IRC8MDiv2,
IRC48M,
HXTAL(u32), }
}
}
#[derive(Clone, Copy)]
pub enum InputSrc {
IRC8M,
HXTAL(u32), Pll(PllSrc),
}
impl InputSrc {
pub fn bits(&self) -> u8 {
match self {
Self::IRC8M => 0b00,
Self::HXTAL(_) => 0b01,
Self::Pll(_) => 0b10,
}
}
}
#[cfg(feature = "f3")]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Prediv {
Div1 = 0b0000,
Div2 = 0b0001,
}
#[cfg(feature = "f3")]
impl Prediv {
pub fn value(&self) -> u8 {
match self {
Self::Div1 => 1,
Self::Div2 => 2,
}
}
}
#[cfg(feature = "f3")]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum PllMF {
MF2 = 0x00 | 0x00,
MF3 = 0x00 | 0x01,
MF4 = 0x00 | 0x02,
MF5 = 0x00 | 0x03,
MF6 = 0x00 | 0x04,
MF7 = 0x00 | 0x05,
MF8 = 0x00 | 0x06,
MF9 = 0x00 | 0x07,
MF10 = 0x00 | 0x08,
MF11 = 0x00 | 0x09,
MF12 = 0x00 | 0x0A,
MF13 = 0x00 | 0x0B,
MF14 = 0x00 | 0x0C,
MF15 = 0x00 | 0x0D,
MF16 = 0x00 | 0x0E,
MF17 = 0x10 | 0x00,
MF18 = 0x10 | 0x01,
MF19 = 0x10 | 0x02,
MF20 = 0x10 | 0x03,
MF21 = 0x10 | 0x04,
MF22 = 0x10 | 0x05,
MF23 = 0x10 | 0x06,
MF24 = 0x10 | 0x07,
MF25 = 0x10 | 0x08,
MF26 = 0x10 | 0x09,
MF27 = 0x10 | 0x0A,
MF28 = 0x10 | 0x0B,
MF29 = 0x10 | 0x0C,
MF30 = 0x10 | 0x0D,
MF31 = 0x10 | 0x0E,
MF32 = 0x10 | 0x0F,
MF33 = 0x20 | 0x00,
MF34 = 0x20 | 0x01,
MF35 = 0x20 | 0x02,
MF36 = 0x20 | 0x03,
MF37 = 0x20 | 0x04,
MF38 = 0x20 | 0x05,
MF39 = 0x20 | 0x06,
MF40 = 0x20 | 0x07,
MF41 = 0x20 | 0x08,
MF42 = 0x20 | 0x09,
MF43 = 0x20 | 0x0A,
MF44 = 0x20 | 0x0B,
MF45 = 0x20 | 0x0C,
MF46 = 0x20 | 0x0D,
MF47 = 0x20 | 0x0E,
MF48 = 0x20 | 0x0F,
MF49 = 0x30 | 0x00,
MF50 = 0x30 | 0x01,
MF51 = 0x30 | 0x02,
MF52 = 0x30 | 0x03,
MF53 = 0x30 | 0x04,
MF54 = 0x30 | 0x05,
MF55 = 0x30 | 0x06,
MF56 = 0x30 | 0x07,
MF57 = 0x30 | 0x08,
MF58 = 0x30 | 0x09,
MF59 = 0x30 | 0x0A,
MF60 = 0x30 | 0x0B,
MF61 = 0x30 | 0x0C,
MF62 = 0x30 | 0x0D,
MF63 = 0x30 | 0x0E,
}
#[cfg(feature = "f3")]
impl PllMF {
pub fn value(&self) -> u8 {
match self {
Self::MF2 => 2,
Self::MF3 => 3,
Self::MF4 => 4,
Self::MF5 => 5,
Self::MF6 => 6,
Self::MF7 => 7,
Self::MF8 => 8,
Self::MF9 => 9,
Self::MF10 => 10,
Self::MF11 => 11,
Self::MF12 => 12,
Self::MF13 => 13,
Self::MF14 => 14,
Self::MF15 => 15,
Self::MF16 => 16,
Self::MF17 => 17,
Self::MF18 => 18,
Self::MF19 => 19,
Self::MF20 => 20,
Self::MF21 => 21,
Self::MF22 => 22,
Self::MF23 => 23,
Self::MF24 => 24,
Self::MF25 => 25,
Self::MF26 => 26,
Self::MF27 => 27,
Self::MF28 => 28,
Self::MF29 => 29,
Self::MF30 => 30,
Self::MF31 => 31,
Self::MF32 => 32,
Self::MF33 => 33,
Self::MF34 => 34,
Self::MF35 => 35,
Self::MF36 => 36,
Self::MF37 => 37,
Self::MF38 => 38,
Self::MF39 => 39,
Self::MF40 => 40,
Self::MF41 => 41,
Self::MF42 => 42,
Self::MF43 => 43,
Self::MF44 => 44,
Self::MF45 => 45,
Self::MF46 => 46,
Self::MF47 => 47,
Self::MF48 => 48,
Self::MF49 => 49,
Self::MF50 => 50,
Self::MF51 => 51,
Self::MF52 => 52,
Self::MF53 => 53,
Self::MF54 => 54,
Self::MF55 => 55,
Self::MF56 => 56,
Self::MF57 => 57,
Self::MF58 => 58,
Self::MF59 => 59,
Self::MF60 => 60,
Self::MF61 => 61,
Self::MF62 => 62,
Self::MF63 => 63,
}
}
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum AHBclkPrescaler {
Div1 = 0b0000,
Div2 = 0b1000,
Div4 = 0b1001,
Div8 = 0b1010,
Div16 = 0b1011,
Div64 = 0b1100,
Div128 = 0b1101,
Div256 = 0b1110,
Div512 = 0b1111,
}
impl AHBclkPrescaler {
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)]
enum WaitState {
W0 = 0,
W1 = 1,
W2 = 2,
#[cfg(feature = "f4")]
W3 = 3,
#[cfg(feature = "f4")]
W4 = 4,
#[cfg(feature = "f4")]
W5 = 5,
#[cfg(feature = "f4")]
W6 = 6,
#[cfg(feature = "f4")]
W7 = 7,
}
#[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,
}
}
}
#[cfg(feature = "f3")]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum UsbPrescaler {
Div1_5 = 0,
Div1 = 1,
Div2_5 = 2,
Div2 = 3,
Div3 = 4,
Div3_5 = 5,
Div4 = 6,
}
#[cfg(feature = "f3")]
impl UsbPrescaler {
pub fn value(&self) -> f32 {
match self {
Self::Div1_5 => 1.5,
Self::Div1 => 1.,
Self::Div2_5 => 2.5,
Self::Div2 => 2.,
Self::Div3 => 3.,
Self::Div3_5 => 3.5,
Self::Div4 => 4.,
}
}
}
#[cfg(feature = "f3")]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum UsbClockSource {
PLL = 0,
IRC48M = 1,
}
pub struct Clocks {
pub input_src: InputSrc,
#[cfg(feature = "f3")]
pub prediv0: Prediv,
#[cfg(feature = "f3")]
pub pll_mul: PllMF,
#[cfg(feature = "f3")]
pub usb_pre: UsbPrescaler, #[cfg(feature = "f3")]
pub usb_clock_source: UsbClockSource,
pub ahbclk_prescaler: AHBclkPrescaler,
pub apb1_prescaler: ApbPrescaler,
pub apb2_prescaler: ApbPrescaler,
pub hse_bypass: bool,
pub clock_monitor: bool,
}
impl Clocks {
pub fn setup(&self) -> Result<(), SpeedError> {
if let Err(e) = self.validate_speeds() {
return Err(e);
}
let rcu = unsafe { &(*RCU::ptr()) };
let sysclk = self.sysclk();
let hclk = sysclk / self.ahbclk_prescaler.value() as u32;
match self.input_src {
InputSrc::HXTAL(_) => {
rcu.ctl.modify(|_, w| w.hxtalen().bit(true));
while rcu.ctl.read().hxtalstb().bit_is_clear() {}
}
InputSrc::IRC8M => {
rcu.ctl.modify(|_, w| w.irc8men().bit(true));
while rcu.ctl.read().irc8mstb().bit_is_clear() {}
}
InputSrc::Pll(pll_src) => {
match pll_src {
PllSrc::HXTAL(_) => {
rcu.ctl.modify(|_, w| w.hxtalen().bit(true));
while rcu.ctl.read().hxtalstb().bit_is_clear() {}
}
PllSrc::IRC8MDiv2 => {
rcu.ctl.modify(|_, w| w.irc8men().bit(true));
while rcu.ctl.read().irc8mstb().bit_is_clear() {}
}
PllSrc::IRC48M => {
rcu.addctl.modify(|_, w| w.irc48men().bit(true));
while rcu.addctl.read().irc48mstb().bit_is_clear() {}
}
}
}
}
if let UsbClockSource::IRC48M = self.usb_clock_source {
rcu.addctl.modify(|_, w| w.irc48men().bit(true));
while rcu.addctl.read().irc48mstb().bit_is_clear() {}
rcu.addctl.modify(|_, w|w.ck48msel().bit(true));
}
rcu.ctl.modify(|_, w| {
w.hxtalbps().bit(self.hse_bypass)
});
if let InputSrc::Pll(pll_src) = self.input_src {
rcu.ctl.modify(|_, w| w.pllen().clear_bit());
while rcu.ctl.read().pllstb().bit_is_set() {}
cfg_if! {
if #[cfg(feature = "f3")] {
rcu.cfg0.modify(|_, w| {
cfg_if! {
if #[cfg(any(feature = "f305", feature = "f307"))] {
} else {
unsafe {
w
.pllmf_3_0().bits(self.pll_mul as u8 & 0x0F)
.pllmf_4().bit(self.pll_mul as u8 & 0x10 != 0)
.pllmf_5().bit(self.pll_mul as u8 & 0x20 != 0);
match pll_src {
PllSrc::IRC8MDiv2 => w.pllsel().clear_bit(),
_ => w.pllsel().set_bit(),
};
w
}
}
}
});
if let PllSrc::IRC48M = pll_src {
rcu.cfg1.modify(|_,w| w.pllpresel().set_bit());
}
}
}
#[cfg(feature = "f3")]
rcu.cfg0.modify(|_, w| w.predv0().bit(self.prediv0 as u8 == 1));
rcu.ctl.modify(|_, w| w.pllen().set_bit());
while rcu.ctl.read().pllstb().bit_is_clear() {}
}
rcu.cfg0.modify(|_, w| unsafe {
#[cfg(not(any(feature = "f301", feature = "f3x4", feature = "f4")))]
w.usbdpsc_1_0().bits(self.usb_pre as u8 & 0x03).usbdpsc_2().bit(self.usb_pre as u8 & 0x04 != 0);
w.scs().bits(self.input_src.bits());
w.ahbpsc().bits(self.ahbclk_prescaler as u8); w.apb2psc().bits(self.apb2_prescaler as u8); w.apb1psc().bits(self.apb1_prescaler as u8) });
rcu.ctl.modify(|_, w| w.ckmen().bit(self.clock_monitor));
match self.input_src {
InputSrc::IRC8M => (),
InputSrc::Pll(pll_src) => match pll_src {
#[cfg(feature = "f3")]
PllSrc::IRC8MDiv2 => (),
#[cfg(feature = "f4")]
PllSrc::Hsi => (),
_ => {
rcu.ctl.modify(|_, w| w.irc8men().clear_bit());
}
},
InputSrc::HXTAL(_) => {
rcu.ctl.modify(|_, w| w.irc8men().clear_bit());
}
}
Ok(())
}
pub fn reselect_input(&self) {
let rcu = unsafe { &(*RCU::ptr()) };
match self.input_src {
InputSrc::HXTAL(_) => {
rcu.ctl.modify(|_, w| w.hxtalen().set_bit());
while rcu.ctl.read().hxtalstb().bit_is_clear() {}
rcu.cfg0
.modify(|_, w| unsafe { w.scs().bits(self.input_src.bits()) });
}
InputSrc::Pll(_) => {
rcu.ctl.modify(|_, w| w.hxtalen().set_bit());
while rcu.ctl.read().hxtalstb().bit_is_clear() {}
rcu.ctl.modify(|_, w| w.pllen().clear_bit());
while rcu.ctl.read().pllstb().bit_is_set() {}
rcu.cfg0
.modify(|_, w| unsafe { w.scs().bits(self.input_src.bits()) });
rcu.ctl.modify(|_, w| w.pllen().set_bit());
while rcu.ctl.read().pllstb().bit_is_clear() {}
}
InputSrc::IRC8M => (), }
}
#[cfg(feature = "f3")]
pub fn sysclk(&self) -> u32 {
match self.input_src {
InputSrc::Pll(pll_src) => match pll_src {
PllSrc::HXTAL(freq) => {
freq / self.prediv0.value() as u32 * self.pll_mul.value() as u32
},
PllSrc::IRC48M => 48_000_000,
PllSrc::IRC8MDiv2 => 4_000_000 * self.pll_mul.value() as u32,
},
InputSrc::IRC8M => 8_000_000,
InputSrc::HXTAL(freq) => freq,
}
}
pub fn pll_is_enabled(&self) -> bool {
let rcu = unsafe { &(*RCU::ptr()) };
rcu.ctl.read().pllen().bit_is_set()
}
pub fn abhclk(&self) -> u32 {
self.sysclk() / self.ahbclk_prescaler.value() as u32
}
pub fn systick(&self) -> u32 {
self.abhclk() / 8
}
pub fn usb(&self) -> u32 {
#[cfg(feature = "f3")]
return self.sysclk() / self.usb_pre.value() as u32;
#[cfg(feature = "f4")]
return 0; }
pub fn apb1(&self) -> u32 {
self.abhclk() / self.apb1_prescaler.value() as u32
}
pub fn apb1_timer(&self) -> u32 {
if let ApbPrescaler::Div1 = self.apb1_prescaler {
self.apb1()
} else {
self.apb1() * 2
}
}
pub fn apb2(&self) -> u32 {
self.abhclk() / self.apb2_prescaler.value() as u32
}
pub fn apb2_timer(&self) -> u32 {
if let ApbPrescaler::Div1 = self.apb2_prescaler {
self.apb2()
} else {
self.apb2() * 2
}
}
pub fn validate_speeds(&self) -> Result<(), SpeedError> {
#[cfg(feature = "f303")]
let (max_sys, max_ahb, max_apb1, max_apb2) = (120_000_000, 120_000_000, 60_000_000, 120_000_000);
if self.sysclk() > max_sys {
return Err(SpeedError::SysclkOutOfLimits);
}
if self.abhclk() > max_ahb {
return Err(SpeedError::HclkOutOfLimits);
}
if self.apb1() > max_apb1 {
return Err(SpeedError::Apb1OutOfLimits);
}
if self.apb2() > max_apb2 {
return Err(SpeedError::Apb2OutOfLimits);
}
Ok(())
}
}
impl Default for Clocks {
#[cfg(feature = "f3")]
fn default() -> Self {
Self {
input_src: InputSrc::Pll(PllSrc::IRC8MDiv2),
prediv0: Prediv::Div1,
pll_mul: PllMF::MF18,
usb_pre: UsbPrescaler::Div1,
usb_clock_source: UsbClockSource::PLL,
ahbclk_prescaler: AHBclkPrescaler::Div1,
apb1_prescaler: ApbPrescaler::Div2,
apb2_prescaler: ApbPrescaler::Div1,
hse_bypass: false,
clock_monitor: false,
}
}
}