2023-04-22 21:26:40 +02:00
|
|
|
use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw};
|
2022-06-12 22:15:44 +02:00
|
|
|
|
2023-08-27 15:35:13 +02:00
|
|
|
pub use super::bus::{AHBPrescaler, APBPrescaler};
|
2022-01-04 23:58:13 +01:00
|
|
|
use crate::pac::{FLASH, RCC};
|
2021-11-08 20:27:33 +01:00
|
|
|
use crate::rcc::{set_freqs, Clocks};
|
2022-07-11 00:36:10 +02:00
|
|
|
use crate::time::Hertz;
|
2021-11-08 20:20:31 +01:00
|
|
|
|
2022-07-10 19:59:36 +02:00
|
|
|
/// HSI speed
|
|
|
|
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
|
|
|
|
|
|
|
|
/// LSI speed
|
|
|
|
pub const LSI_FREQ: Hertz = Hertz(32_000);
|
2021-11-08 20:20:31 +01:00
|
|
|
|
2023-08-27 15:35:13 +02:00
|
|
|
pub use super::bus::VoltageScale;
|
2022-01-04 23:58:13 +01:00
|
|
|
|
2021-11-08 20:20:31 +01:00
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub enum ClockSrc {
|
|
|
|
MSI(MSIRange),
|
|
|
|
HSE(Hertz),
|
|
|
|
HSI16,
|
|
|
|
PLL1R(PllSrc, PllM, PllN, PllClkDiv),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub enum PllSrc {
|
|
|
|
MSI(MSIRange),
|
|
|
|
HSE(Hertz),
|
|
|
|
HSI16,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Into<Pllsrc> for PllSrc {
|
|
|
|
fn into(self) -> Pllsrc {
|
|
|
|
match self {
|
|
|
|
PllSrc::MSI(..) => Pllsrc::MSIS,
|
|
|
|
PllSrc::HSE(..) => Pllsrc::HSE,
|
|
|
|
PllSrc::HSI16 => Pllsrc::HSI16,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
seq_macro::seq!(N in 2..=128 {
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub enum PllClkDiv {
|
|
|
|
NotDivided,
|
|
|
|
#(
|
2022-06-18 02:15:48 +02:00
|
|
|
Div~N = (N-1),
|
2021-11-08 20:20:31 +01:00
|
|
|
)*
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PllClkDiv {
|
|
|
|
fn to_div(&self) -> u8 {
|
|
|
|
match self {
|
|
|
|
PllClkDiv::NotDivided => 1,
|
|
|
|
#(
|
2022-08-17 15:01:07 +02:00
|
|
|
PllClkDiv::Div~N => N + 1,
|
2021-11-08 20:20:31 +01:00
|
|
|
)*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
impl Into<u8> for PllClkDiv {
|
|
|
|
fn into(self) -> u8 {
|
|
|
|
(self as u8) + 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
seq_macro::seq!(N in 4..=512 {
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub enum PllN {
|
|
|
|
NotMultiplied,
|
|
|
|
#(
|
2022-08-17 15:01:07 +02:00
|
|
|
Mul~N = N-1,
|
2021-11-08 20:20:31 +01:00
|
|
|
)*
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PllN {
|
|
|
|
fn to_mul(&self) -> u16 {
|
|
|
|
match self {
|
|
|
|
PllN::NotMultiplied => 1,
|
|
|
|
#(
|
2022-08-17 15:01:07 +02:00
|
|
|
PllN::Mul~N => N + 1,
|
2021-11-08 20:20:31 +01:00
|
|
|
)*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
impl Into<u16> for PllN {
|
|
|
|
fn into(self) -> u16 {
|
|
|
|
(self as u16) + 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pre-division
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub enum PllM {
|
|
|
|
NotDivided = 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 Into<Pllm> for PllM {
|
|
|
|
fn into(self) -> Pllm {
|
2023-06-29 01:51:19 +02:00
|
|
|
Pllm::from_bits(self as u8)
|
2021-11-08 20:20:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Into<Sw> for ClockSrc {
|
|
|
|
fn into(self) -> Sw {
|
|
|
|
match self {
|
|
|
|
ClockSrc::MSI(..) => Sw::MSIS,
|
|
|
|
ClockSrc::HSE(..) => Sw::HSE,
|
|
|
|
ClockSrc::HSI16 => Sw::HSI16,
|
2023-09-16 03:44:01 +02:00
|
|
|
ClockSrc::PLL1R(..) => Sw::PLL1_R,
|
2021-11-08 20:20:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
|
pub enum MSIRange {
|
|
|
|
Range48mhz = 48_000_000,
|
|
|
|
Range24mhz = 24_000_000,
|
|
|
|
Range16mhz = 16_000_000,
|
|
|
|
Range12mhz = 12_000_000,
|
|
|
|
Range4mhz = 4_000_000,
|
|
|
|
Range2mhz = 2_000_000,
|
|
|
|
Range1_33mhz = 1_330_000,
|
|
|
|
Range1mhz = 1_000_000,
|
|
|
|
Range3_072mhz = 3_072_000,
|
|
|
|
Range1_536mhz = 1_536_000,
|
|
|
|
Range1_024mhz = 1_024_000,
|
|
|
|
Range768khz = 768_000,
|
|
|
|
Range400khz = 400_000,
|
|
|
|
Range200khz = 200_000,
|
|
|
|
Range133khz = 133_000,
|
|
|
|
Range100khz = 100_000,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Into<u32> for MSIRange {
|
|
|
|
fn into(self) -> u32 {
|
|
|
|
self as u32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Into<Msirange> for MSIRange {
|
|
|
|
fn into(self) -> Msirange {
|
|
|
|
match self {
|
|
|
|
MSIRange::Range48mhz => Msirange::RANGE_48MHZ,
|
|
|
|
MSIRange::Range24mhz => Msirange::RANGE_24MHZ,
|
|
|
|
MSIRange::Range16mhz => Msirange::RANGE_16MHZ,
|
|
|
|
MSIRange::Range12mhz => Msirange::RANGE_12MHZ,
|
|
|
|
MSIRange::Range4mhz => Msirange::RANGE_4MHZ,
|
|
|
|
MSIRange::Range2mhz => Msirange::RANGE_2MHZ,
|
|
|
|
MSIRange::Range1_33mhz => Msirange::RANGE_1_33MHZ,
|
|
|
|
MSIRange::Range1mhz => Msirange::RANGE_1MHZ,
|
|
|
|
MSIRange::Range3_072mhz => Msirange::RANGE_3_072MHZ,
|
|
|
|
MSIRange::Range1_536mhz => Msirange::RANGE_1_536MHZ,
|
|
|
|
MSIRange::Range1_024mhz => Msirange::RANGE_1_024MHZ,
|
|
|
|
MSIRange::Range768khz => Msirange::RANGE_768KHZ,
|
|
|
|
MSIRange::Range400khz => Msirange::RANGE_400KHZ,
|
|
|
|
MSIRange::Range200khz => Msirange::RANGE_200KHZ,
|
|
|
|
MSIRange::Range133khz => Msirange::RANGE_133KHZ,
|
|
|
|
MSIRange::Range100khz => Msirange::RANGE_100KHZ,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for MSIRange {
|
|
|
|
fn default() -> Self {
|
|
|
|
MSIRange::Range4mhz
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct Config {
|
2022-01-04 11:18:59 +01:00
|
|
|
pub mux: ClockSrc,
|
|
|
|
pub ahb_pre: AHBPrescaler,
|
|
|
|
pub apb1_pre: APBPrescaler,
|
|
|
|
pub apb2_pre: APBPrescaler,
|
|
|
|
pub apb3_pre: APBPrescaler,
|
2023-01-11 17:57:22 +01:00
|
|
|
pub hsi48: bool,
|
2021-11-08 20:20:31 +01:00
|
|
|
}
|
2021-11-02 17:03:56 +01:00
|
|
|
|
2022-01-04 11:18:59 +01:00
|
|
|
impl Default for Config {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
2021-11-08 20:20:31 +01:00
|
|
|
mux: ClockSrc::MSI(MSIRange::default()),
|
2023-09-17 00:41:11 +02:00
|
|
|
ahb_pre: AHBPrescaler::DIV1,
|
|
|
|
apb1_pre: APBPrescaler::DIV1,
|
|
|
|
apb2_pre: APBPrescaler::DIV1,
|
|
|
|
apb3_pre: APBPrescaler::DIV1,
|
2023-01-11 17:57:22 +01:00
|
|
|
hsi48: false,
|
2021-11-08 20:20:31 +01:00
|
|
|
}
|
2021-11-02 17:03:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:58:13 +01:00
|
|
|
pub(crate) unsafe fn init(config: Config) {
|
|
|
|
let sys_clk = match config.mux {
|
|
|
|
ClockSrc::MSI(range) => {
|
|
|
|
RCC.icscr1().modify(|w| {
|
|
|
|
let bits: Msirange = range.into();
|
|
|
|
w.set_msisrange(bits);
|
|
|
|
w.set_msirgsel(Msirgsel::RCC_ICSCR1);
|
|
|
|
});
|
|
|
|
RCC.cr().write(|w| {
|
|
|
|
w.set_msipllen(false);
|
|
|
|
w.set_msison(true);
|
|
|
|
});
|
|
|
|
while !RCC.cr().read().msisrdy() {}
|
2021-11-08 20:20:31 +01:00
|
|
|
|
2022-01-04 23:58:13 +01:00
|
|
|
range.into()
|
|
|
|
}
|
|
|
|
ClockSrc::HSE(freq) => {
|
|
|
|
RCC.cr().write(|w| w.set_hseon(true));
|
|
|
|
while !RCC.cr().read().hserdy() {}
|
2021-11-08 20:20:31 +01:00
|
|
|
|
2022-01-04 23:58:13 +01:00
|
|
|
freq.0
|
2021-11-08 20:20:31 +01:00
|
|
|
}
|
2022-01-04 23:58:13 +01:00
|
|
|
ClockSrc::HSI16 => {
|
|
|
|
RCC.cr().write(|w| w.set_hsion(true));
|
|
|
|
while !RCC.cr().read().hsirdy() {}
|
2021-11-08 20:20:31 +01:00
|
|
|
|
2022-07-10 19:59:36 +02:00
|
|
|
HSI_FREQ.0
|
2022-01-04 23:58:13 +01:00
|
|
|
}
|
|
|
|
ClockSrc::PLL1R(src, m, n, div) => {
|
|
|
|
let freq = match src {
|
2023-01-11 17:57:22 +01:00
|
|
|
PllSrc::MSI(_) => {
|
|
|
|
// TODO: enable MSI
|
|
|
|
MSIRange::default().into()
|
|
|
|
}
|
|
|
|
PllSrc::HSE(hertz) => {
|
|
|
|
// TODO: enable HSE
|
|
|
|
hertz.0
|
|
|
|
}
|
|
|
|
PllSrc::HSI16 => {
|
|
|
|
RCC.cr().write(|w| w.set_hsion(true));
|
|
|
|
while !RCC.cr().read().hsirdy() {}
|
|
|
|
|
|
|
|
HSI_FREQ.0
|
|
|
|
}
|
2022-01-04 23:58:13 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// disable
|
|
|
|
RCC.cr().modify(|w| w.set_pllon(0, false));
|
|
|
|
while RCC.cr().read().pllrdy(0) {}
|
|
|
|
|
|
|
|
let vco = freq * n as u8 as u32;
|
|
|
|
let pll_ck = vco / (div as u8 as u32 + 1);
|
|
|
|
|
|
|
|
RCC.pll1cfgr().write(|w| {
|
|
|
|
w.set_pllm(m.into());
|
|
|
|
w.set_pllsrc(src.into());
|
2023-01-11 17:57:22 +01:00
|
|
|
w.set_pllren(true);
|
2021-11-08 20:20:31 +01:00
|
|
|
});
|
|
|
|
|
2022-01-04 23:58:13 +01:00
|
|
|
RCC.pll1divr().modify(|w| {
|
|
|
|
w.set_pllr(div.to_div());
|
|
|
|
w.set_plln(n.to_mul());
|
2021-11-08 20:20:31 +01:00
|
|
|
});
|
|
|
|
|
2022-01-04 23:58:13 +01:00
|
|
|
// Enable PLL
|
|
|
|
RCC.cr().modify(|w| w.set_pllon(0, true));
|
|
|
|
while !RCC.cr().read().pllrdy(0) {}
|
2021-11-08 20:20:31 +01:00
|
|
|
|
2022-01-04 23:58:13 +01:00
|
|
|
pll_ck
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-01-11 17:57:22 +01:00
|
|
|
if config.hsi48 {
|
|
|
|
RCC.cr().modify(|w| w.set_hsi48on(true));
|
|
|
|
while !RCC.cr().read().hsi48rdy() {}
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:58:13 +01:00
|
|
|
// TODO make configurable
|
2023-04-22 21:26:40 +02:00
|
|
|
let power_vos = VoltageScale::Scale3;
|
2022-01-04 23:58:13 +01:00
|
|
|
|
|
|
|
// states and programming delay
|
|
|
|
let wait_states = match power_vos {
|
|
|
|
// VOS 0 range VCORE 1.26V - 1.40V
|
2023-04-22 21:26:40 +02:00
|
|
|
VoltageScale::Scale0 => {
|
2022-01-04 23:58:13 +01:00
|
|
|
if sys_clk < 32_000_000 {
|
|
|
|
0
|
|
|
|
} else if sys_clk < 64_000_000 {
|
|
|
|
1
|
|
|
|
} else if sys_clk < 96_000_000 {
|
|
|
|
2
|
|
|
|
} else if sys_clk < 128_000_000 {
|
|
|
|
3
|
|
|
|
} else {
|
|
|
|
4
|
2021-11-08 20:20:31 +01:00
|
|
|
}
|
2022-01-04 23:58:13 +01:00
|
|
|
}
|
|
|
|
// VOS 1 range VCORE 1.15V - 1.26V
|
2023-04-22 21:26:40 +02:00
|
|
|
VoltageScale::Scale1 => {
|
2022-01-04 23:58:13 +01:00
|
|
|
if sys_clk < 30_000_000 {
|
|
|
|
0
|
|
|
|
} else if sys_clk < 60_000_000 {
|
|
|
|
1
|
|
|
|
} else if sys_clk < 90_000_000 {
|
|
|
|
2
|
|
|
|
} else {
|
|
|
|
3
|
2021-11-08 20:20:31 +01:00
|
|
|
}
|
2022-01-04 23:58:13 +01:00
|
|
|
}
|
|
|
|
// VOS 2 range VCORE 1.05V - 1.15V
|
2023-04-22 21:26:40 +02:00
|
|
|
VoltageScale::Scale2 => {
|
2022-01-04 23:58:13 +01:00
|
|
|
if sys_clk < 24_000_000 {
|
|
|
|
0
|
|
|
|
} else if sys_clk < 48_000_000 {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
2
|
2021-11-08 20:20:31 +01:00
|
|
|
}
|
2022-01-04 23:58:13 +01:00
|
|
|
}
|
|
|
|
// VOS 3 range VCORE 0.95V - 1.05V
|
2023-04-22 21:26:40 +02:00
|
|
|
VoltageScale::Scale3 => {
|
2022-01-04 23:58:13 +01:00
|
|
|
if sys_clk < 12_000_000 {
|
|
|
|
0
|
|
|
|
} else {
|
|
|
|
1
|
2021-11-08 20:20:31 +01:00
|
|
|
}
|
|
|
|
}
|
2022-01-04 23:58:13 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
FLASH.acr().modify(|w| {
|
|
|
|
w.set_latency(wait_states);
|
|
|
|
});
|
|
|
|
|
|
|
|
RCC.cfgr1().modify(|w| {
|
|
|
|
w.set_sw(config.mux.into());
|
|
|
|
});
|
|
|
|
|
|
|
|
RCC.cfgr2().modify(|w| {
|
|
|
|
w.set_hpre(config.ahb_pre.into());
|
|
|
|
w.set_ppre1(config.apb1_pre.into());
|
|
|
|
w.set_ppre2(config.apb2_pre.into());
|
|
|
|
});
|
|
|
|
|
|
|
|
RCC.cfgr3().modify(|w| {
|
|
|
|
w.set_ppre3(config.apb3_pre.into());
|
|
|
|
});
|
|
|
|
|
|
|
|
let ahb_freq: u32 = match config.ahb_pre {
|
2023-09-17 00:41:11 +02:00
|
|
|
AHBPrescaler::DIV1 => sys_clk,
|
2022-01-04 23:58:13 +01:00
|
|
|
pre => {
|
|
|
|
let pre: u8 = pre.into();
|
|
|
|
let pre = 1 << (pre as u32 - 7);
|
|
|
|
sys_clk / pre
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
2023-09-17 00:41:11 +02:00
|
|
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
2022-01-04 23:58:13 +01:00
|
|
|
pre => {
|
|
|
|
let pre: u8 = pre.into();
|
|
|
|
let pre: u8 = 1 << (pre - 3);
|
|
|
|
let freq = ahb_freq / pre as u32;
|
|
|
|
(freq, freq * 2)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
2023-09-17 00:41:11 +02:00
|
|
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
2022-01-04 23:58:13 +01:00
|
|
|
pre => {
|
|
|
|
let pre: u8 = pre.into();
|
|
|
|
let pre: u8 = 1 << (pre - 3);
|
2023-03-17 04:21:39 +01:00
|
|
|
let freq = ahb_freq / pre as u32;
|
2022-01-04 23:58:13 +01:00
|
|
|
(freq, freq * 2)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre {
|
2023-09-17 00:41:11 +02:00
|
|
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
2022-01-04 23:58:13 +01:00
|
|
|
pre => {
|
|
|
|
let pre: u8 = pre.into();
|
|
|
|
let pre: u8 = 1 << (pre - 3);
|
2023-03-17 04:21:39 +01:00
|
|
|
let freq = ahb_freq / pre as u32;
|
2022-01-04 23:58:13 +01:00
|
|
|
(freq, freq * 2)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
set_freqs(Clocks {
|
2022-07-11 00:36:10 +02:00
|
|
|
sys: Hertz(sys_clk),
|
|
|
|
ahb1: Hertz(ahb_freq),
|
|
|
|
ahb2: Hertz(ahb_freq),
|
|
|
|
ahb3: Hertz(ahb_freq),
|
|
|
|
apb1: Hertz(apb1_freq),
|
|
|
|
apb2: Hertz(apb2_freq),
|
|
|
|
apb3: Hertz(apb3_freq),
|
|
|
|
apb1_tim: Hertz(apb1_tim_freq),
|
|
|
|
apb2_tim: Hertz(apb2_tim_freq),
|
2022-01-04 23:58:13 +01:00
|
|
|
});
|
2021-11-08 20:20:31 +01:00
|
|
|
}
|