177 lines
4.6 KiB
Rust

pub use crate::pac::pwr::vals::Vos as VoltageScale;
use crate::pac::rcc::regs::Cfgr1;
pub use crate::pac::rcc::vals::{
Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as ClockSrc,
};
use crate::pac::{FLASH, RCC};
use crate::time::Hertz;
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
// HSE speed
pub const HSE_FREQ: Hertz = Hertz(32_000_000);
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Hse {
pub prescaler: HsePrescaler,
}
/// Clocks configuration
pub struct Config {
// base clock sources
pub hsi: bool,
pub hse: Option<Hse>,
// sysclk, buses.
pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
pub apb7_pre: APBPrescaler,
// low speed LSI/LSE/RTC
pub ls: super::LsConfig,
pub adc_clock_source: AdcClockSource,
pub voltage_scale: VoltageScale,
}
impl Default for Config {
#[inline]
fn default() -> Config {
Config {
hse: None,
hsi: true,
mux: ClockSrc::HSI,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
apb7_pre: APBPrescaler::DIV1,
ls: Default::default(),
adc_clock_source: AdcClockSource::HCLK1,
voltage_scale: VoltageScale::RANGE2,
}
}
}
fn hsi_enable() {
RCC.cr().modify(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
}
pub(crate) unsafe fn init(config: Config) {
// Switch to HSI to prevent problems with PLL configuration.
if !RCC.cr().read().hsion() {
hsi_enable()
}
if RCC.cfgr1().read().sws() != ClockSrc::HSI {
// Set HSI as a clock source, reset prescalers.
RCC.cfgr1().write_value(Cfgr1::default());
// Wait for clock switch status bits to change.
while RCC.cfgr1().read().sws() != ClockSrc::HSI {}
}
// Set voltage scale
crate::pac::PWR.vosr().write(|w| w.set_vos(config.voltage_scale));
while !crate::pac::PWR.vosr().read().vosrdy() {}
let rtc = config.ls.init();
let hsi = config.hsi.then(|| {
hsi_enable();
HSI_FREQ
});
let hse = config.hse.map(|hse| {
RCC.cr().write(|w| {
w.set_hseon(true);
w.set_hsepre(hse.prescaler);
});
while !RCC.cr().read().hserdy() {}
HSE_FREQ
});
let sys_clk = match config.mux {
ClockSrc::HSE => hse.unwrap(),
ClockSrc::HSI => hsi.unwrap(),
ClockSrc::_RESERVED_1 => unreachable!(),
ClockSrc::PLL1_R => todo!(),
};
assert!(sys_clk.0 <= 100_000_000);
let hclk1 = sys_clk / config.ahb_pre;
let hclk2 = hclk1;
let hclk4 = hclk1;
// TODO: hclk5
let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre);
let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
let (pclk7, _) = super::util::calc_pclk(hclk1, config.apb7_pre);
// Set flash wait states
let flash_latency = match config.voltage_scale {
VoltageScale::RANGE1 => match sys_clk.0 {
..=32_000_000 => 0,
..=64_000_000 => 1,
..=96_000_000 => 2,
..=100_000_000 => 3,
_ => 4,
},
VoltageScale::RANGE2 => match sys_clk.0 {
..=8_000_000 => 0,
..=16_000_000 => 1,
_ => 2,
},
};
FLASH.acr().modify(|w| w.set_latency(flash_latency));
while FLASH.acr().read().latency() != flash_latency {}
// Set sram wait states
let _sram_latency = match config.voltage_scale {
VoltageScale::RANGE1 => 0,
VoltageScale::RANGE2 => match sys_clk.0 {
..=12_000_000 => 0,
..=16_000_000 => 1,
_ => 2,
},
};
// TODO: Set the SRAM wait states
RCC.cfgr1().modify(|w| {
w.set_sw(config.mux);
});
while RCC.cfgr1().read().sws() != config.mux {}
RCC.cfgr2().modify(|w| {
w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre);
});
RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source));
set_clocks!(
sys: Some(sys_clk),
hclk1: Some(hclk1),
hclk2: Some(hclk2),
hclk4: Some(hclk4),
pclk1: Some(pclk1),
pclk2: Some(pclk2),
pclk7: Some(pclk7),
pclk1_tim: Some(pclk1_tim),
pclk2_tim: Some(pclk2_tim),
rtc: rtc,
hse: hse,
hsi: hsi,
// TODO
lse: None,
lsi: None,
pll1_q: None,
);
}