use cfg_if::cfg_if;
#[cfg(any(feature = "l4", feature = "l5", feature = "wb", feature = "g4"))]
use crate::pac::CRS;
#[cfg(not(any(feature = "wb", feature = "wl")))]
use crate::util::rcc_en_reset;
use crate::{
clocks::RccError,
error::{Error, Result},
pac::{self, FLASH, RCC},
util::bounded_loop,
};
#[cfg(not(any(feature = "g0", feature = "wl", feature = "c0")))]
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum Clk48Src {
Hsi48 = 0b00, #[cfg(not(feature = "g4"))]
PllSai1 = 0b01, Pllq = 0b10,
#[cfg(msi)]
Msi = 0b11,
}
#[cfg(feature = "c071")]
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum Clk48Src {
HsiUsb48 = 0,
Hse = 1,
}
#[cfg(any(feature = "l4", feature = "l5", feature = "wb", feature = "g4"))]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum CrsSyncSrc {
Gpio = 0b00,
Lse = 0b01,
Usb = 0b10,
}
#[cfg(not(any(feature = "g0", feature = "g4", feature = "c0")))]
#[derive(Clone, Copy, PartialEq)]
pub enum PllSrc {
None,
Msi(MsiRange),
Hsi,
Hse(u32),
}
#[cfg(any(feature = "g0", feature = "g4", feature = "c0"))]
#[derive(Clone, Copy, PartialEq)]
pub enum PllSrc {
None,
Hsi,
Hse(u32),
}
impl PllSrc {
pub fn bits(&self) -> u8 {
#[cfg(not(any(feature = "g0", feature = "g4", feature = "c0")))]
match self {
Self::None => 0b00,
Self::Msi(_) => 0b01,
Self::Hsi => 0b10,
Self::Hse(_) => 0b11,
}
#[cfg(any(feature = "g0", feature = "g4", feature = "c0"))]
match self {
Self::None => 0b00,
Self::Hsi => 0b10,
Self::Hse(_) => 0b11,
}
}
}
#[cfg(any(feature = "l4", feature = "l5", feature = "wb", feature = "wl"))]
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum StopWuck {
Msi = 0,
Hsi = 1,
}
cfg_if! {
if #[cfg(feature = "c0")] {
#[derive(Clone, Copy, PartialEq)]
pub enum InputSrc {
Hsi,
Hse(u32), #[cfg(feature = "c071")]
HsiUsb48,
Lsi,
Lse,
}
impl InputSrc {
pub fn bits(&self) -> u8 {
match self {
Self::Hsi => 0b000,
Self::Hse(_) => 0b001,
#[cfg(feature = "c071")]
Self::HsiUsb48 => 0b010,
Self::Lsi => 0b011,
Self::Lse => 0b100,
}
}
}
} else if #[cfg(feature = "g0")] {
#[derive(Clone, Copy, PartialEq)]
pub enum InputSrc {
Hsi,
Hse(u32), Pll(PllSrc),
Lsi,
Lse,
}
impl InputSrc {
pub fn bits(&self) -> u8 {
match self {
Self::Hsi => 0b000,
Self::Hse(_) => 0b001,
Self::Pll(_) => 0b010,
Self::Lsi => 0b011,
Self::Lse => 0b100,
}
}
}
} else if #[cfg(feature = "g4")] {
#[derive(Clone, Copy, PartialEq)]
pub enum InputSrc {
Hsi,
Hse(u32), Pll(PllSrc),
}
impl InputSrc {
pub fn bits(&self) -> u8 {
match self {
Self::Hsi => 0b01,
Self::Hse(_) => 0b10,
Self::Pll(_) => 0b11,
}
}
}
} else { #[derive(Clone, Copy, PartialEq)]
pub enum InputSrc {
Msi(MsiRange),
Hsi,
Hse(u32), Pll(PllSrc),
}
impl InputSrc {
pub fn bits(&self) -> u8 {
match self {
Self::Msi(_) => 0b00,
Self::Hsi => 0b01,
Self::Hse(_) => 0b10,
Self::Pll(_) => 0b11,
}
}
}
}
}
#[cfg(feature = "wb")]
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum RfWakeupSrc {
NoClock = 0b00,
Lse = 0b01,
Hse = 0b11,
}
#[derive(Clone, Copy)]
#[repr(u8)]
enum WaitState {
W0 = 0,
W1 = 1,
#[cfg(not(feature = "c0"))]
W2 = 2,
#[cfg(not(any(feature = "wl", feature = "c0")))]
W3 = 3,
#[cfg(not(any(feature = "wb", feature = "wl", feature = "c0")))]
W4 = 4,
#[cfg(feature = "l5")]
W5 = 5,
}
#[cfg(not(any(feature = "g0", feature = "g4", feature = "c0")))]
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum MsiRange {
R100k = 0b0000,
R200k = 0b0001,
R400k = 0b0010,
R800k = 0b0011,
R1M = 0b0100,
R2M = 0b0101,
R4M = 0b0110, R8M = 0b0111,
R16M = 0b1000,
R24M = 0b1001,
R32M = 0b1010,
R48M = 0b1011,
}
#[cfg(not(any(feature = "g0", feature = "g4", feature = "c0")))]
impl MsiRange {
const fn value(&self) -> u32 {
match self {
Self::R100k => 100_000,
Self::R200k => 200_000,
Self::R400k => 400_000,
Self::R800k => 800_000,
Self::R1M => 1_000_000,
Self::R2M => 2_000_000,
Self::R4M => 4_000_000,
Self::R8M => 8_000_000,
Self::R16M => 16_000_000,
Self::R24M => 24_000_000,
Self::R32M => 32_000_000,
Self::R48M => 48_000_000,
}
}
}
#[cfg(feature = "c0")]
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum HsiDiv {
Div1 = 0b000,
Div2 = 0b001,
Div4 = 0b010,
Div8 = 0b011,
Div16 = 0b100,
Div32 = 0b101,
Div64 = 0b110,
Div128 = 0b111,
}
#[cfg(feature = "c0")]
impl HsiDiv {
pub const fn value(&self) -> u32 {
match self {
HsiDiv::Div1 => 1,
HsiDiv::Div2 => 2,
HsiDiv::Div4 => 4,
HsiDiv::Div8 => 8,
HsiDiv::Div16 => 16,
HsiDiv::Div32 => 32,
HsiDiv::Div64 => 64,
HsiDiv::Div128 => 128,
}
}
}
#[cfg(feature = "c071")]
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum SysDiv {
Div1 = 0b000,
Div2 = 0b001,
Div3 = 0b010,
Div4 = 0b011,
Div5 = 0b100,
Div6 = 0b101,
Div7 = 0b110,
Div8 = 0b111,
}
#[cfg(feature = "c071")]
impl SysDiv {
pub const fn value(&self) -> u32 {
match self {
SysDiv::Div1 => 1,
SysDiv::Div2 => 2,
SysDiv::Div3 => 3,
SysDiv::Div4 => 4,
SysDiv::Div5 => 5,
SysDiv::Div6 => 6,
SysDiv::Div7 => 7,
SysDiv::Div8 => 8,
}
}
}
pub struct PllCfg {
pub enabled: bool,
pub pllr_en: bool,
pub pllq_en: bool,
pub pllp_en: bool,
pub divm: Pllm,
pub divn: u8,
pub divr: Pllr,
pub divq: Pllr,
pub divp: Pllp,
pub pdiv: u8,
}
impl Default for PllCfg {
fn default() -> Self {
Self {
enabled: true,
pllr_en: true,
pllq_en: false,
pllp_en: false,
divm: Pllm::Div4,
#[cfg(feature = "l4")]
divn: 40,
#[cfg(feature = "l5")]
divn: 55,
#[cfg(feature = "g0")]
divn: 32,
#[cfg(feature = "g4")]
divn: 85,
#[cfg(feature = "wb")]
divn: 64,
#[cfg(feature = "wl")]
divn: 24,
#[cfg(feature = "c0")]
divn: 24, #[cfg(not(feature = "wb"))]
divr: Pllr::Div2,
#[cfg(feature = "wb")]
divr: Pllr::Div4,
divq: Pllr::Div4,
divp: Pllp::Div7,
pdiv: 0,
}
}
}
impl PllCfg {
pub fn disabled() -> Self {
Self {
enabled: false,
pllp_en: false,
pllr_en: false,
pllq_en: false,
..Default::default()
}
}
pub const fn pvalue(&self) -> u8 {
match self.pdiv {
0 => self.divp.value(),
pdiv => pdiv,
}
}
}
#[cfg(not(any(feature = "l5", feature = "g4")))]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Pllm {
Div1 = 0b000,
Div2 = 0b001,
Div3 = 0b010,
Div4 = 0b011,
Div5 = 0b100,
Div6 = 0b101,
Div7 = 0b110,
Div8 = 0b111,
}
#[cfg(any(feature = "l5", feature = "g4"))]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Pllm {
Div1 = 0b0000,
Div2 = 0b0001,
Div3 = 0b0010,
Div4 = 0b0011,
Div5 = 0b0100,
Div6 = 0b0101,
Div7 = 0b0110,
Div8 = 0b0111,
Div9 = 0b1000,
Div10 = 0b1001,
Div11 = 0b1010,
Div12 = 0b1011,
Div13 = 0b1100,
Div14 = 0b1101,
Div15 = 0b1110,
Div16 = 0b1111,
}
impl Pllm {
pub const fn value(&self) -> u8 {
#[cfg(not(any(feature = "l5", feature = "g4")))]
match self {
Self::Div1 => 1,
Self::Div2 => 2,
Self::Div3 => 3,
Self::Div4 => 4,
Self::Div5 => 5,
Self::Div6 => 6,
Self::Div7 => 7,
Self::Div8 => 8,
}
#[cfg(any(feature = "l5", feature = "g4"))]
match self {
Self::Div1 => 1,
Self::Div2 => 2,
Self::Div3 => 3,
Self::Div4 => 4,
Self::Div5 => 5,
Self::Div6 => 6,
Self::Div7 => 7,
Self::Div8 => 8,
Self::Div9 => 9,
Self::Div10 => 10,
Self::Div11 => 11,
Self::Div12 => 12,
Self::Div13 => 13,
Self::Div14 => 14,
Self::Div15 => 15,
Self::Div16 => 16,
}
}
}
#[cfg(any(feature = "g0", feature = "wb"))]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Pllr {
Div2 = 0b001,
Div3 = 0b010,
Div4 = 0b011,
Div5 = 0b100,
Div6 = 0b101,
Div7 = 0b110,
Div8 = 0b111,
}
#[cfg(any(feature = "g0", feature = "wb"))]
impl Pllr {
pub const fn value(&self) -> u8 {
match self {
Self::Div2 => 2,
Self::Div3 => 3,
Self::Div4 => 4,
Self::Div5 => 5,
Self::Div6 => 6,
Self::Div7 => 7,
Self::Div8 => 8,
}
}
}
#[cfg(not(any(feature = "g0", feature = "wb")))]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Pllr {
Div2 = 0b00,
Div4 = 0b01,
Div6 = 0b10,
Div8 = 0b11,
}
#[cfg(not(any(feature = "g0", feature = "wb")))]
impl Pllr {
pub const fn value(&self) -> u8 {
match self {
Self::Div2 => 2,
Self::Div4 => 4,
Self::Div6 => 6,
Self::Div8 => 8,
}
}
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Pllp {
Div7 = 0,
Div17 = 1,
}
impl Pllp {
pub const fn value(&self) -> u8 {
match self {
Self::Div7 => 7,
Self::Div17 => 17,
}
}
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum HclkPrescaler {
Div1 = 0b0000,
#[cfg(feature = "wb")]
Div3 = 0b0001,
#[cfg(feature = "wb")]
Div5 = 0b0010,
#[cfg(feature = "wb")]
Div6 = 0b0101,
#[cfg(feature = "wb")]
Div10 = 0b0110,
#[cfg(feature = "wb")]
Div32 = 0b0111,
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,
#[cfg(feature = "wb")]
Self::Div3 => 3,
#[cfg(feature = "wb")]
Self::Div5 => 5,
#[cfg(feature = "wb")]
Self::Div6 => 6,
#[cfg(feature = "wb")]
Self::Div10 => 10,
#[cfg(feature = "wb")]
Self::Div32 => 32,
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 {
PllSai1P = 0b00,
Pllp = 0b01,
Hsi = 0b10,
ExtClk = 0b11,
}
#[cfg(any(feature = "g0", feature = "g4"))]
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum CanSrc {
Hse = 0b00,
PllQ = 0b01,
Pclk = 0b10,
}
#[cfg(not(any(feature = "f", feature = "l", feature = "g0")))]
#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum LpUartSrc {
Pclk = 0b00,
Sysclk = 0b01,
Hsi16 = 0b10,
Lse = 0b11,
}
pub struct Clocks {
pub input_src: InputSrc,
#[cfg(not(feature = "c0"))]
pub pll: PllCfg,
#[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "c0")))]
pub pllsai1: PllCfg,
#[cfg(any(feature = "l4x5", feature = "l4x6"))]
pub pllsai2: PllCfg,
pub hclk_prescaler: HclkPrescaler,
#[cfg(feature = "wb")]
pub hclk2_prescaler: HclkPrescaler,
#[cfg(feature = "wl")]
pub hclk3_prescaler: HclkPrescaler,
#[cfg(feature = "wb")]
pub hclk4_prescaler: HclkPrescaler,
pub apb1_prescaler: ApbPrescaler,
#[cfg(not(any(feature = "g0", feature = "c0")))]
pub apb2_prescaler: ApbPrescaler,
#[cfg(not(any(feature = "g0", feature = "wl", feature = "c011", feature = "c031")))]
pub clk48_src: Clk48Src,
#[cfg(not(any(feature = "f", feature = "l", feature = "g0", feature = "c0")))]
pub lpuart_src: LpUartSrc,
pub hse_bypass: bool,
pub security_system: bool,
#[cfg(not(any(feature = "g0", feature = "wl", feature = "c011", feature = "c031")))]
pub hsi48_on: bool,
#[cfg(any(feature = "l4", feature = "l5", feature = "wb", feature = "wl"))]
pub stop_wuck: StopWuck,
#[cfg(feature = "wb")]
pub rf_wakeup_src: RfWakeupSrc,
#[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "c0")))]
pub sai1_src: SaiSrc,
#[cfg(feature = "g4")]
pub boost_mode: bool,
#[cfg(any(feature = "g0", feature = "g4"))]
pub can_src: CanSrc,
#[cfg(feature = "c0")]
pub hsi_div: HsiDiv,
#[cfg(feature = "c071")]
pub sys_div: SysDiv,
}
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()) };
#[cfg(feature = "l5")]
let icache = unsafe { &(*pac::ICACHE::ptr()) };
#[cfg(not(any(feature = "wb", feature = "wl")))]
rcc_en_reset!(apb2, syscfg, rcc);
let sysclk = self.sysclk();
cfg_if! {
if #[cfg(feature = "wb")] {
let hclk = sysclk / self.hclk4_prescaler.value() as u32;
} else if #[cfg(feature = "wl")] {
let hclk = sysclk / self.hclk3_prescaler.value() as u32;
} else {
let hclk = sysclk / self.hclk_prescaler.value() as u32;
}
}
cfg_if! {
if #[cfg(feature = "g4")] {
if self.boost_mode {
rcc.cfgr().modify(|_, w| unsafe { w.hpre().bits(HclkPrescaler::Div2 as u8) });
let pwr = unsafe { &(*pac::PWR::ptr()) };
pwr.cr5().modify(|_, w| w.r1mode().clear_bit());
}
}
}
cfg_if! {
if #[cfg(feature = "l4")] { let wait_state = if hclk <= 16_000_000 {
WaitState::W0
} else if hclk <= 32_000_000 {
WaitState::W1
} else if hclk <= 48_000_000 {
WaitState::W2
} else if hclk <= 64_000_000 {
WaitState::W3
} else {
WaitState::W4
};
} else if #[cfg(feature = "l5")] { let wait_state = if hclk <= 20_000_000 {
WaitState::W0
} else if hclk <= 40_000_000 {
WaitState::W1
} else if hclk <= 60_000_000 {
WaitState::W2
} else if hclk <= 80_000_000 {
WaitState::W3
} else if hclk <= 100_000_000 {
WaitState::W4
} else {
WaitState::W5
};
} else if #[cfg(feature = "g0")] { let wait_state = if hclk <= 24_000_000 {
WaitState::W0
} else if hclk <= 48_000_000 {
WaitState::W1
} else {
WaitState::W2
};
} else if #[cfg(feature = "c0")] { let wait_state = if hclk <= 24_000_000 {
WaitState::W0
} else {
WaitState::W1
};
} else if #[cfg(feature = "wb")] { let wait_state = if hclk <= 18_000_000 {
WaitState::W0
} else if hclk <= 36_000_000 {
WaitState::W1
} else if hclk <= 54_000_000 {
WaitState::W2
} else {
WaitState::W3
};
} else if #[cfg(any(feature = "wb", feature = "wl"))] { let wait_state = if hclk <= 18_000_000 {
WaitState::W0
} else if hclk <= 36_000_000 {
WaitState::W1
} else {
WaitState::W2
};
} else { let wait_state = if self.boost_mode {
if hclk <= 34_000_000 {
WaitState::W0
} else if hclk <= 68_000_000 {
WaitState::W1
} else if hclk <= 102_000_000 {
WaitState::W2
} else if hclk <= 136_000_000 {
WaitState::W3
} else {
WaitState::W4
}
} else {
if hclk <= 30_000_000 {
WaitState::W0
} else if hclk <= 60_000_000 {
WaitState::W1
} else if hclk <= 90_000_000 {
WaitState::W2
} else if hclk <= 120_000_000 {
WaitState::W3
} else {
WaitState::W4
}
};
}
}
#[cfg(not(feature = "l5"))]
flash.acr().modify(|_, w| unsafe {
#[cfg(not(any(feature = "g0", feature = "c0")))]
w.dcrst().bit(true);
w.icrst().bit(true)
});
#[cfg(not(feature = "l5"))]
flash.acr().modify(|_, w| unsafe {
w.latency().bits(wait_state as u8);
#[cfg(not(any(feature = "g0", feature = "c0")))]
w.dcen().bit(true);
w.icen().bit(true);
w.prften().bit(true)
});
#[cfg(feature = "l5")]
flash
.acr()
.modify(|_, w| unsafe { w.latency().bits(wait_state as u8) });
match self.input_src {
#[cfg(msi)]
InputSrc::Msi(range) => {
rcc.cr().modify(|_, w| w.msion().clear_bit());
bounded_loop!(
rcc.cr().read().msirdy().bit_is_set(),
Error::RegisterUnchanged
);
rcc.cr().modify(|_, w| unsafe {
w.msirange().bits(range as u8);
#[cfg(not(any(feature = "wb", feature = "wl")))]
w.msirgsel().bit(true);
w.msion().bit(true)
});
bounded_loop!(
rcc.cr().read().msirdy().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 => {
rcc.cr().modify(|_, w| w.hsion().bit(true));
bounded_loop!(
rcc.cr().read().hsirdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
#[cfg(not(feature = "c0"))]
InputSrc::Pll(pll_src) => {
match pll_src {
#[cfg(msi)]
PllSrc::Msi(range) => {
rcc.cr().modify(|_, w| unsafe {
w.msirange().bits(range as u8);
#[cfg(not(any(feature = "wb", feature = "wl")))]
w.msirgsel().bit(true);
w.msion().bit(true)
});
bounded_loop!(
rcc.cr().read().msirdy().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 => {
rcc.cr().modify(|_, w| w.hsion().bit(true));
bounded_loop!(
rcc.cr().read().hsirdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
PllSrc::None => {}
}
}
#[cfg(feature = "g0")]
InputSrc::Lsi => {
rcc.csr().modify(|_, w| w.lsion().bit(true));
bounded_loop!(
rcc.csr().read().lsirdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
#[cfg(feature = "g0")]
InputSrc::Lse => {
rcc.bdcr().modify(|_, w| w.lseon().bit(true));
bounded_loop!(
rcc.bdcr().read().lserdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
#[cfg(feature = "c0")]
InputSrc::Lsi => {
rcc.csr2().modify(|_, w| w.lsion().bit(true));
bounded_loop!(
rcc.csr2().read().lsirdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
#[cfg(feature = "c0")]
InputSrc::Lse => {
rcc.csr1().modify(|_, w| w.lseon().bit(true));
bounded_loop!(
rcc.csr1().read().lserdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
#[cfg(feature = "c071")]
InputSrc::HsiUsb48 => {
}
}
rcc.cr().modify(|_, w| unsafe {
#[cfg(feature = "c0")]
w.hsidiv().bits(self.hsi_div as u8);
#[cfg(feature = "c071")]
w.sysdiv().bits(self.sys_div as u8);
#[cfg(feature = "wl")]
return w.hsebyppwr().bit(self.hse_bypass);
#[cfg(not(feature = "wl"))]
w.hsebyp().bit(self.hse_bypass)
});
rcc.cfgr().modify(|_, w| unsafe {
w.sw().bits(self.input_src.bits());
w.hpre().bits(self.hclk_prescaler as u8);
#[cfg(not(any(feature = "g0", feature = "c0")))]
w.ppre2().bits(self.apb2_prescaler as u8); #[cfg(any(feature = "l4", feature = "l5"))]
w.stopwuck().bit(self.stop_wuck as u8 != 0);
#[cfg(not(any(feature = "g0", feature = "c0")))]
return w.ppre1().bits(self.apb1_prescaler as u8); #[cfg(any(feature = "g0", feature = "c0"))]
return w.ppre().bits(self.apb1_prescaler as u8);
});
#[cfg(feature = "wb")]
rcc.extcfgr().modify(|_, w| unsafe {
w.c2hpre().bits(self.hclk2_prescaler as u8);
w.shdhpre().bits(self.hclk4_prescaler as u8)
});
#[cfg(feature = "wl")]
rcc.extcfgr()
.modify(|_, w| unsafe { w.shdhpre().bits(self.hclk3_prescaler as u8) });
rcc.cr().modify(|_, w| w.csson().bit(self.security_system));
#[cfg(not(feature = "c0"))]
if let InputSrc::Pll(pll_src) = self.input_src {
rcc.cr().modify(|_, w| w.pllon().clear_bit());
bounded_loop!(
rcc.cr().read().pllrdy().bit_is_set(),
Error::RegisterUnchanged
);
rcc.pllcfgr().modify(|_, w| unsafe {
w.pllsrc().bits(pll_src.bits());
w.pllren().bit(true);
w.pllqen().bit(self.pll.pllq_en);
w.pllpen().bit(self.pll.pllp_en);
w.plln().bits(self.pll.divn);
w.pllm().bits(self.pll.divm as u8);
w.pllr().bits(self.pll.divr as u8);
#[cfg(not(any(
feature = "wb",
feature = "wl",
feature = "l4x5",
feature = "l4x3",
feature = "g0"
)))]
w.pllpdiv().bits(self.pll.pdiv);
#[cfg(not(any(feature = "wb", feature = "wl", feature = "g0")))]
w.pllp().bit(self.pll.divp as u8 != 0);
#[cfg(any(feature = "wb", feature = "wl", feature = "g0"))]
w.pllp().bits(self.pll.divp as u8);
w.pllq().bits(self.pll.divq as u8)
});
rcc.pllcfgr().modify(|_, w| {
w.pllpen().bit(true);
w.pllqen().bit(true);
w.pllren().bit(true)
});
cfg_if! {
if #[cfg(all(any(feature = "l4", feature = "l5"), not(feature = "l412")))] {
rcc.pllsai1cfgr().modify(|_, w| unsafe {
w.pllsai1ren().bit(self.pllsai1.pllr_en);
w.pllsai1qen().bit(self.pllsai1.pllq_en);
w.pllsai1pen().bit(self.pllsai1.pllp_en);
w.pllsai1n().bits(self.pllsai1.divn);
#[cfg(not(any(feature = "l4x5", feature = "l4x3")))]
w.pllsai1pdiv().bits(self.pllsai1.pdiv);
w.pllsai1r().bits(self.pllsai1.divr as u8);
w.pllsai1q().bits(self.pllsai1.divq as u8);
w.pllsai1p().bit(self.pllsai1.divp as u8 != 0)
});
#[cfg(any(feature = "l4x5", feature = "l4x6"))]
rcc.pllsai2cfgr().modify(|_, w| unsafe {
w.pllsai2ren().bit(self.pllsai1.pllr_en);
w.pllsai2pen().bit(self.pllsai1.pllp_en);
w.pllsai2n().bits(self.pllsai1.divn);
#[cfg(not(feature = "l4x5"))]
w.pllsai2pdiv().bits(self.pllsai1.pdiv);
w.pllsai2r().bits(self.pllsai1.divr as u8);
w.pllsai2p().bit(self.pllsai1.divp as u8 != 0)
});
} else if #[cfg(feature = "wb")] {
rcc.pllsai1cfgr().modify(|_, w| unsafe {
w.pllren().bit(self.pllsai1.pllr_en);
w.pllqen().bit(self.pllsai1.pllq_en);
w.pllpen().bit(self.pllsai1.pllp_en);
w.plln().bits(self.pllsai1.divn);
w.pllr().bits(self.pllsai1.divr as u8);
w.pllq().bits(self.pllsai1.divq as u8);
w.pllp().bits(self.pllsai1.divp as u8)
});
}
}
rcc.cr().modify(|_, w| w.pllon().bit(true));
bounded_loop!(
rcc.cr().read().pllrdy().bit_is_clear(),
Error::RegisterUnchanged
);
cfg_if! {
if #[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "l412")))] {
if self.pllsai1.enabled {
rcc.cr().modify(|_, w| w.pllsai1on().bit(true));
bounded_loop!(
rcc.cr().read().pllsai1rdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
#[cfg(any(feature = "l4x5", feature = "l4x6",))]
if self.pllsai2.enabled {
rcc.cr().modify(|_, w| w.pllsai2on().bit(true));
bounded_loop!(
rcc.cr().read().pllsai2rdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
}
}
}
#[cfg(not(any(feature = "g0", feature = "wl", feature = "c0")))]
if self.hsi48_on {
rcc.crrcr().modify(|_, w| w.hsi48on().bit(true));
bounded_loop!(
rcc.crrcr().read().hsi48rdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
#[cfg(feature = "c071")]
if self.hsi48_on {
rcc.cr().modify(|_, w| w.hsiusb48on().bit(true));
bounded_loop!(
rcc.cr().read().hsiusb48rdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
#[cfg(not(any(
feature = "g0",
feature = "g4",
feature = "wl",
feature = "l5",
feature = "l412",
feature = "c0",
)))]
rcc.ccipr()
.modify(|_, w| unsafe { w.sai1sel().bits(self.sai1_src as u8) });
#[cfg(feature = "g4")]
rcc.ccipr()
.modify(|_, w| unsafe { w.fdcansel().bits(self.can_src as u8) });
#[cfg(feature = "g0c1")]
rcc.ccipr2()
.modify(|_, w| unsafe { w.fdcansel().bits(self.can_src as u8) });
#[cfg(feature = "l5")]
rcc.ccipr2()
.modify(|_, w| unsafe { w.sai1sel().bits(self.sai1_src as u8) });
#[cfg(any(feature = "l4", feature = "g4"))]
rcc.ccipr()
.modify(|_, w| unsafe { w.clk48sel().bits(self.clk48_src as u8) });
#[cfg(feature = "l5")]
rcc.ccipr1()
.modify(|_, w| unsafe { w.clk48msel().bits(self.clk48_src as u8) });
#[cfg(feature = "c071")]
rcc.ccipr2()
.modify(|_, w| unsafe { w.usbsel().bit(self.clk48_src as u8 != 0) });
#[cfg(not(any(feature = "f", feature = "l", feature = "g0", feature = "c0")))]
rcc.ccipr()
.modify(|_, w| unsafe { w.lpuart1sel().bits(self.lpuart_src as u8) });
cfg_if! {
if #[cfg(any(feature = "l4", feature = "l5"))] {
match self.input_src {
InputSrc::Msi(_) => (),
InputSrc::Pll(pll_src) => {
match pll_src {
PllSrc::Msi(_) => (),
_ => {
rcc.cr().modify(|_, w| w.msion().clear_bit());
}
}
}
_ => {
rcc.cr().modify(|_, w| w.msion().clear_bit());
}
}
} else {
match self.input_src {
InputSrc::Hsi => (),
#[cfg(not(feature = "c0"))]
InputSrc::Pll(pll_src) => {
match pll_src {
PllSrc::Hsi => (),
_ => {
rcc.cr().modify(|_, w| w.hsion().clear_bit());
}
}
}
_ => {
rcc.cr().modify(|_, w| w.hsion().clear_bit());
}
}
}
}
#[cfg(feature = "wb")]
rcc.csr()
.modify(|_, w| unsafe { w.rfwkpsel().bits(self.rf_wakeup_src as u8) });
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()) });
}
#[cfg(not(feature = "c0"))]
InputSrc::Pll(pll_src) => {
match 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 => {
#[cfg(any(feature = "l4", feature = "l5"))]
if let StopWuck::Msi = self.stop_wuck {
rcc.cr().modify(|_, w| w.hsion().bit(true));
bounded_loop!(
rcc.cr().read().hsirdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
}
#[cfg(msi)]
PllSrc::Msi(range) => {
#[cfg(not(feature = "wb"))]
rcc.cr().modify(|_, w| unsafe {
w.msirange().bits(range as u8);
w.msirgsel().bit(true)
});
#[cfg(feature = "wb")]
rcc.cr()
.modify(|_, w| unsafe { w.msirange().bits(range as u8) });
if let StopWuck::Hsi = self.stop_wuck {
rcc.cr().modify(|_, w| w.msion().bit(true));
bounded_loop!(
rcc.cr().read().msirdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
}
PllSrc::None => (),
}
rcc.cr().modify(|_, w| w.pllon().clear_bit());
bounded_loop!(
rcc.cr().read().pllrdy().bit_is_set(),
Error::RegisterUnchanged
);
rcc.cfgr()
.modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
rcc.cr().modify(|_, w| w.pllon().bit(true));
bounded_loop!(
rcc.cr().read().pllrdy().bit_is_clear(),
Error::RegisterUnchanged
);
}
InputSrc::Hsi => {
{
#[cfg(msi)]
if let StopWuck::Msi = self.stop_wuck {
rcc.cr().modify(|_, w| w.hsion().bit(true));
bounded_loop!(
rcc.cr().read().hsirdy().bit_is_clear(),
Error::RegisterUnchanged
);
rcc.cfgr()
.modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
}
}
}
#[cfg(msi)]
InputSrc::Msi(range) => {
#[cfg(not(feature = "wb"))]
rcc.cr().modify(|_, w| unsafe {
w.msirange().bits(range as u8);
w.msirgsel().bit(true)
});
#[cfg(feature = "wb")]
rcc.cr()
.modify(|_, w| unsafe { w.msirange().bits(range as u8) });
if let StopWuck::Hsi = self.stop_wuck {
rcc.cr().modify(|_, w| w.msion().bit(true));
bounded_loop!(
rcc.cr().read().msirdy().bit_is_clear(),
Error::RegisterUnchanged
);
rcc.cfgr()
.modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
}
}
#[cfg(feature = "g0")]
InputSrc::Lsi => {
rcc.csr().modify(|_, w| w.lsion().bit(true));
bounded_loop!(
rcc.csr().read().lsirdy().bit_is_clear(),
Error::RegisterUnchanged
);
rcc.cfgr()
.modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
}
#[cfg(feature = "c0")]
InputSrc::Lsi => {
rcc.csr2().modify(|_, w| w.lsion().bit(true));
bounded_loop!(
rcc.csr2().read().lsirdy().bit_is_clear(),
Error::RegisterUnchanged
);
rcc.cfgr()
.modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
}
#[cfg(feature = "g0")]
InputSrc::Lse => {
rcc.bdcr().modify(|_, w| w.lseon().bit(true));
bounded_loop!(
rcc.bdcr().read().lserdy().bit_is_clear(),
Error::RegisterUnchanged
);
rcc.cfgr()
.modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
}
#[cfg(feature = "c0")]
InputSrc::Lse => {
rcc.csr1().modify(|_, w| w.lseon().bit(true));
bounded_loop!(
rcc.csr1().read().lserdy().bit_is_clear(),
Error::RegisterUnchanged
);
rcc.cfgr()
.modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
}
#[cfg(feature = "c071")]
InputSrc::HsiUsb48 => {
}
}
Ok(())
}
#[cfg(any(feature = "l4", feature = "l5"))]
pub fn change_msi_speed(&mut self, range: MsiRange) -> Result<()> {
let rcc = unsafe { &(*RCC::ptr()) };
match self.input_src {
InputSrc::Msi(_) => (),
_ => panic!("Only change MSI speed using this function if MSI is the input source."),
}
bounded_loop!(
rcc.cr().read().msirdy().bit_is_clear(),
Error::RegisterUnchanged
);
rcc.cr()
.modify(|_, w| unsafe { w.msirange().bits(range as u8).msirgsel().bit(true) });
self.input_src = InputSrc::Msi(range);
Ok(())
}
#[cfg(msi)]
pub fn enable_msi_48(&self) -> Result<()> {
let rcc = unsafe { &(*RCC::ptr()) };
if let InputSrc::Msi(_) = self.input_src {
panic!(
"Only use this function to set up MSI as 48MHz oscillator\
if not using it as the input source."
);
}
if let InputSrc::Pll(pll_src) = self.input_src {
if let PllSrc::Msi(_) = pll_src {
panic!(
"Only use this function to set up MSI as 48MHz oscillator \
if not using it as the input source."
);
}
}
rcc.cr().modify(|_, w| w.msion().clear_bit());
bounded_loop!(
rcc.cr().read().msirdy().bit_is_set(),
Error::RegisterUnchanged
);
#[cfg(not(feature = "wb"))]
rcc.cr().modify(|_, w| unsafe {
w.msirange()
.bits(MsiRange::R48M as u8)
.msirgsel()
.bit(true)
.msipllen()
.bit(true)
.msion()
.bit(true)
});
bounded_loop!(
rcc.cr().read().msirdy().bit_is_clear(),
Error::RegisterUnchanged
);
Ok(())
}
pub const fn sysclk(&self) -> u32 {
let clk = match self.input_src {
#[cfg(not(feature = "c0"))]
InputSrc::Pll(pll_src) => {
let input_freq = match pll_src {
#[cfg(not(any(feature = "g0", feature = "g4")))]
PllSrc::Msi(range) => range.value() as u32,
PllSrc::Hsi => 16_000_000,
PllSrc::Hse(freq) => freq,
PllSrc::None => unimplemented!(),
};
input_freq / self.pll.divm.value() as u32 * self.pll.divn as u32
/ self.pll.divr.value() as u32
}
#[cfg(msi)]
InputSrc::Msi(range) => range.value() as u32,
#[cfg(not(feature = "c0"))]
InputSrc::Hsi => 16_000_000,
#[cfg(feature = "c0")]
InputSrc::Hsi => 48_000_000 / self.hsi_div.value(),
InputSrc::Hse(freq) => freq,
#[cfg(any(feature = "g0", feature = "c0"))]
InputSrc::Lsi => 32_000,
#[cfg(any(feature = "g0", feature = "c0"))]
InputSrc::Lse => 32_768,
#[cfg(feature = "c071")]
InputSrc::HsiUsb48 => 48_000_000,
};
#[cfg(feature = "c071")]
return clk / self.sys_div.value();
#[cfg(not(feature = "c071"))]
return clk;
}
#[cfg(not(feature = "c0"))]
pub fn pll_is_enabled(&self) -> bool {
let rcc = unsafe { &(*RCC::ptr()) };
rcc.cr().read().pllon().bit_is_set()
}
pub const fn hclk(&self) -> u32 {
self.sysclk() / self.hclk_prescaler.value() as u32
}
pub const fn systick(&self) -> u32 {
self.hclk()
}
cfg_if! {
if #[cfg(any(feature = "g0", feature = "wl"))] {
pub const fn usb(&self) -> u32 {
unimplemented!();
}
} else if #[cfg(any(feature = "g4", feature = "c071"))] {
pub const fn usb(&self) -> u32 {
48_000_000 }
} else if #[cfg(feature = "c071")] {
match self.clk48_src {
Clk48Src::HsiUsb48 => 48_000_000,
Clk48Src::Hse => unimplemented!(),
}
} else { #[cfg(not(feature = "c0"))]
pub const fn usb(&self) -> u32 {
match self.clk48_src {
Clk48Src::Hsi48 => 48_000_000,
Clk48Src::PllSai1 => unimplemented!(),
Clk48Src::Pllq => unimplemented!(),
Clk48Src::Msi => unimplemented!(),
}
}
}
}
pub const fn apb1(&self) -> u32 {
self.hclk() / self.apb1_prescaler.value() as u32
}
pub const fn apb1_timer(&self) -> u32 {
if let ApbPrescaler::Div1 = self.apb1_prescaler {
self.apb1()
} else {
self.apb1() * 2
}
}
cfg_if! {
if #[cfg(feature = "g0")] {
pub const fn apb2(&self) -> u32 {
self.hclk() / self.apb1_prescaler.value() as u32
}
pub const fn apb2_timer(&self) -> u32 {
if let ApbPrescaler::Div1 = self.apb1_prescaler {
self.apb2()
} else {
self.apb2() * 2
}
}
} else if #[cfg(not(feature = "c0"))] {
pub const fn apb2(&self) -> u32 {
self.hclk() / self.apb2_prescaler.value() as u32
}
pub const fn apb2_timer(&self) -> u32 {
if let ApbPrescaler::Div1 = self.apb2_prescaler {
self.apb2()
} else {
self.apb2() * 2
}
}
}
}
#[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "c0")))]
pub const fn sai1_speed(&self) -> u32 {
let pll_src = match self.input_src {
InputSrc::Msi(msi_rng) => PllSrc::Msi(msi_rng),
InputSrc::Hsi => PllSrc::Hsi,
InputSrc::Hse(freq) => PllSrc::Hse(freq),
InputSrc::Pll(pll_src) => pll_src,
};
let input_freq = match pll_src {
PllSrc::Msi(range) => range.value() as u32,
PllSrc::Hsi => 16_000_000,
PllSrc::Hse(freq) => freq,
PllSrc::None => unimplemented!(),
};
match self.sai1_src {
SaiSrc::PllSai1P => {
input_freq / self.pll.divm.value() as u32 * self.pllsai1.divn as u32
/ self.pllsai1.pvalue() as u32
}
SaiSrc::Pllp => {
input_freq / self.pll.divm.value() as u32 * self.pll.divn as u32
/ self.pll.pvalue() as u32
}
SaiSrc::Hsi => 16_000_000,
SaiSrc::ExtClk => unimplemented!(),
}
}
#[cfg(feature = "c0")] pub fn validate_speeds(&self) -> Result<()> {
Ok(()) }
#[cfg(not(feature = "c0"))] pub fn validate_speeds(&self) -> Result<()> {
#[cfg(feature = "l4")]
let max_clock = 80_000_000;
#[cfg(feature = "l5")]
let max_clock = 110_000_000;
#[cfg(feature = "g0")]
let max_clock = 64_000_000;
#[cfg(feature = "g4")]
let max_clock = 170_000_000;
#[cfg(feature = "wb")]
let max_clock = 64_000_000;
#[cfg(feature = "wl")]
let max_clock = 48_000_000;
#[cfg(feature = "c0")]
let max_clock = 48_000_000;
#[cfg(any(feature = "l4", feature = "l5", feature = "wb"))]
if self.pll.divn < 7
|| self.pll.divn > 86
|| self.pllsai1.divn < 7
|| self.pllsai1.divn > 86
{
return Err(Error::RccError(RccError::Speed));
}
if self.pll.pdiv == 1 {
return Err(Error::RccError(RccError::Speed));
}
#[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "c0")))]
if self.pllsai1.pdiv == 1 {
return Err(Error::RccError(RccError::Speed));
}
#[cfg(any(feature = "l4x5", feature = "l4x6"))]
if self.pllsai2.pdiv == 1 {
return Err(Error::RccError(RccError::Speed));
}
#[cfg(feature = "g0")]
if self.pll.divn < 9 || self.pll.divn > 86 {
return Err(Error::RccError(RccError::Speed));
}
#[cfg(feature = "g4")]
if self.pll.divn < 8 || self.pll.divn > 127 {
return Err(Error::RccError(RccError::Speed));
}
if self.sysclk() > max_clock {
return Err(Error::RccError(RccError::Speed));
}
if self.hclk() > max_clock {
return Err(Error::RccError(RccError::Speed));
}
if self.apb1() > max_clock {
return Err(Error::RccError(RccError::Speed));
}
#[cfg(not(feature = "g0"))]
if self.apb2() > max_clock {
return Err(Error::RccError(RccError::Speed));
}
Ok(())
}
}
impl Default for Clocks {
fn default() -> Self {
Self {
#[cfg(not(feature = "c0"))]
input_src: InputSrc::Pll(PllSrc::Hsi),
#[cfg(feature = "c0")]
input_src: InputSrc::Hsi,
#[cfg(not(feature = "c0"))]
pll: PllCfg::default(),
#[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "c0")))]
pllsai1: PllCfg::disabled(),
#[cfg(any(feature = "l4x5", feature = "l4x6"))]
pllsai2: PllCfg::disabled(),
hclk_prescaler: HclkPrescaler::Div1,
#[cfg(feature = "wb")]
hclk2_prescaler: HclkPrescaler::Div2,
#[cfg(feature = "wl")]
hclk3_prescaler: HclkPrescaler::Div1,
#[cfg(feature = "wb")]
hclk4_prescaler: HclkPrescaler::Div1,
apb1_prescaler: ApbPrescaler::Div1,
#[cfg(not(any(feature = "g0", feature = "c0")))]
apb2_prescaler: ApbPrescaler::Div1,
#[cfg(not(any(feature = "g0", feature = "wl", feature = "c0")))]
clk48_src: Clk48Src::Hsi48,
#[cfg(feature = "c071")]
clk48_src: Clk48Src::HsiUsb48,
#[cfg(not(any(feature = "f", feature = "l", feature = "g0", feature = "c0")))]
lpuart_src: LpUartSrc::Pclk,
hse_bypass: false,
security_system: false,
#[cfg(not(any(feature = "g0", feature = "wl", feature = "c011", feature = "c031")))]
hsi48_on: false,
#[cfg(any(feature = "l4", feature = "l5", feature = "wb", feature = "wl"))]
stop_wuck: StopWuck::Msi,
#[cfg(feature = "wb")]
rf_wakeup_src: RfWakeupSrc::Lse,
#[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "c0")))]
sai1_src: SaiSrc::Pllp,
#[cfg(feature = "g4")]
boost_mode: true,
#[cfg(any(feature = "g0", feature = "g4"))]
can_src: CanSrc::Pclk,
#[cfg(feature = "c0")]
hsi_div: HsiDiv::Div4, #[cfg(feature = "c071")]
sys_div: SysDiv::Div1, }
}
}
#[cfg(any(feature = "l4", feature = "l5", feature = "g4", feature = "wb"))]
pub fn enable_crs(sync_src: CrsSyncSrc) {
let crs = unsafe { &(*CRS::ptr()) };
let rcc = unsafe { &(*RCC::ptr()) };
cfg_if! {
if #[cfg(feature = "l4x5")] {
let val = rcc.apb1enr1().read().bits();
rcc.apb1enr1().write(|w| unsafe { w.bits(val | (1 << 24)) });
} else {
rcc.apb1enr1().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)
});
}