use core::ops::RangeInclusive;
use crate::pac;
use crate::pac::pwr::vals::Vos;
#[cfg(stm32h5)]
pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
#[cfg(stm32h7)]
pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
pub use crate::pac::rcc::vals::{
Ckpersel as PerClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul,
Pllsrc as PllSource, Sw as Sysclk,
};
use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
pub const HSI_FREQ: Hertz = Hertz(64_000_000);
pub const CSI_FREQ: Hertz = Hertz(4_000_000);
const VCO_RANGE: RangeInclusive<Hertz> = Hertz(150_000_000)..=Hertz(420_000_000);
#[cfg(any(stm32h5, pwr_h7rm0455))]
const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(128_000_000)..=Hertz(560_000_000);
#[cfg(pwr_h7rm0468)]
const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(192_000_000)..=Hertz(836_000_000);
#[cfg(any(pwr_h7rm0399, pwr_h7rm0433))]
const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(192_000_000)..=Hertz(960_000_000);
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum VoltageScale {
Scale0,
Scale1,
Scale2,
Scale3,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum HseMode {
Oscillator,
Bypass,
#[cfg(any(rcc_h5, rcc_h50))]
BypassDigital,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Hse {
pub freq: Hertz,
pub mode: HseMode,
}
#[derive(Clone, Copy)]
pub struct Pll {
pub source: PllSource,
pub prediv: PllPreDiv,
pub mul: PllMul,
pub divp: Option<PllDiv>,
pub divq: Option<PllDiv>,
pub divr: Option<PllDiv>,
}
fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz {
match (tim, apb) {
(TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk,
(TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk,
(TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32,
(TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32,
(TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32,
(TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk,
(TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk,
(TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk,
(TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32,
(TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32,
_ => unreachable!(),
}
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum TimerPrescaler {
DefaultX2,
DefaultX4,
}
impl From<TimerPrescaler> for Timpre {
fn from(value: TimerPrescaler) -> Self {
match value {
TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2,
TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4,
}
}
}
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
#[derive(PartialEq)]
pub enum SupplyConfig {
Default,
LDO,
DirectSMPS,
SMPSLDO(SMPSSupplyVoltage),
SMPSExternalLDO(SMPSSupplyVoltage),
SMPSExternalLDOBypass(SMPSSupplyVoltage),
SMPSDisabledLDOBypass,
}
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
#[derive(PartialEq)]
pub enum SMPSSupplyVoltage {
V1_8,
V2_5,
}
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
impl SMPSSupplyVoltage {
fn to_u8(&self) -> u8 {
match self {
SMPSSupplyVoltage::V1_8 => 0b01,
SMPSSupplyVoltage::V2_5 => 0b10,
}
}
}
#[non_exhaustive]
pub struct Config {
pub hsi: Option<HSIPrescaler>,
pub hse: Option<Hse>,
pub csi: bool,
pub hsi48: Option<super::Hsi48Config>,
pub sys: Sysclk,
pub pll1: Option<Pll>,
pub pll2: Option<Pll>,
#[cfg(any(rcc_h5, stm32h7))]
pub pll3: Option<Pll>,
pub d1c_pre: AHBPrescaler,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
pub apb3_pre: APBPrescaler,
#[cfg(stm32h7)]
pub apb4_pre: APBPrescaler,
pub per_clock_source: PerClockSource,
pub adc_clock_source: AdcClockSource,
pub timer_prescaler: TimerPrescaler,
pub voltage_scale: VoltageScale,
pub ls: super::LsConfig,
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
pub supply_config: SupplyConfig,
}
impl Default for Config {
fn default() -> Self {
Self {
hsi: Some(HSIPrescaler::DIV1),
hse: None,
csi: false,
hsi48: Some(Default::default()),
sys: Sysclk::HSI,
pll1: None,
pll2: None,
#[cfg(any(rcc_h5, stm32h7))]
pll3: None,
d1c_pre: AHBPrescaler::DIV1,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
apb3_pre: APBPrescaler::DIV1,
#[cfg(stm32h7)]
apb4_pre: APBPrescaler::DIV1,
per_clock_source: PerClockSource::HSI,
#[cfg(stm32h5)]
adc_clock_source: AdcClockSource::HCLK1,
#[cfg(stm32h7)]
adc_clock_source: AdcClockSource::PER,
timer_prescaler: TimerPrescaler::DefaultX2,
voltage_scale: VoltageScale::Scale0,
ls: Default::default(),
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
supply_config: SupplyConfig::Default,
}
}
}
pub(crate) unsafe fn init(config: Config) {
#[cfg(pwr_h7rm0433)]
PWR.cr3().modify(|w| {
w.set_scuen(true);
w.set_ldoen(true);
w.set_bypass(false);
});
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
{
match config.supply_config {
SupplyConfig::Default => {
PWR.cr3().modify(|w| {
w.set_sdlevel(0b00);
w.set_sdexthp(false);
w.set_sden(true);
w.set_ldoen(true);
w.set_bypass(false);
});
}
SupplyConfig::LDO => {
PWR.cr3().modify(|w| {
w.set_sden(false);
w.set_ldoen(true);
w.set_bypass(false);
});
}
SupplyConfig::DirectSMPS => {
PWR.cr3().modify(|w| {
w.set_sdexthp(false);
w.set_sden(true);
w.set_ldoen(false);
w.set_bypass(false);
});
}
SupplyConfig::SMPSLDO(ref smps_supply_voltage)
| SupplyConfig::SMPSExternalLDO(ref smps_supply_voltage)
| SupplyConfig::SMPSExternalLDOBypass(ref smps_supply_voltage) => {
PWR.cr3().modify(|w| {
w.set_sdlevel(smps_supply_voltage.to_u8());
w.set_sdexthp(matches!(
config.supply_config,
SupplyConfig::SMPSExternalLDO(_) | SupplyConfig::SMPSExternalLDOBypass(_)
));
w.set_sden(true);
w.set_ldoen(matches!(
config.supply_config,
SupplyConfig::SMPSLDO(_) | SupplyConfig::SMPSExternalLDO(_)
));
w.set_bypass(matches!(config.supply_config, SupplyConfig::SMPSExternalLDOBypass(_)));
});
}
SupplyConfig::SMPSDisabledLDOBypass => {
PWR.cr3().modify(|w| {
w.set_sden(false);
w.set_ldoen(false);
w.set_bypass(true);
});
}
}
}
#[cfg(any(pwr_h7rm0433, pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
while !PWR.csr1().read().actvosrdy() {}
#[cfg(any(pwr_h5, pwr_h50))]
{
PWR.voscr().modify(|w| {
w.set_vos(match config.voltage_scale {
VoltageScale::Scale0 => Vos::SCALE0,
VoltageScale::Scale1 => Vos::SCALE1,
VoltageScale::Scale2 => Vos::SCALE2,
VoltageScale::Scale3 => Vos::SCALE3,
})
});
while !PWR.vossr().read().vosrdy() {}
}
#[cfg(syscfg_h7)]
{
PWR.d3cr().modify(|w| {
w.set_vos(match config.voltage_scale {
VoltageScale::Scale0 => Vos::SCALE0,
VoltageScale::Scale1 => Vos::SCALE1,
VoltageScale::Scale2 => Vos::SCALE2,
VoltageScale::Scale3 => Vos::SCALE3,
})
});
while !PWR.d3cr().read().vosrdy() {}
}
#[cfg(syscfg_h7od)]
{
match config.voltage_scale {
VoltageScale::Scale0 => {
PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1));
while !PWR.d3cr().read().vosrdy() {}
critical_section::with(|_| pac::SYSCFG.pwrcr().modify(|w| w.set_oden(1)));
while !PWR.d3cr().read().vosrdy() {}
}
_ => {
PWR.d3cr().modify(|w| {
w.set_vos(match config.voltage_scale {
VoltageScale::Scale0 => unreachable!(),
VoltageScale::Scale1 => Vos::SCALE1,
VoltageScale::Scale2 => Vos::SCALE2,
VoltageScale::Scale3 => Vos::SCALE3,
})
});
while !PWR.d3cr().read().vosrdy() {}
}
}
}
let hsi = match config.hsi {
None => {
RCC.cr().modify(|w| w.set_hsion(false));
None
}
Some(hsidiv) => {
RCC.cr().modify(|w| {
w.set_hsidiv(hsidiv);
w.set_hsion(true);
});
while !RCC.cr().read().hsirdy() {}
Some(HSI_FREQ / hsidiv)
}
};
let hse = match config.hse {
None => {
RCC.cr().modify(|w| w.set_hseon(false));
None
}
Some(hse) => {
RCC.cr().modify(|w| {
w.set_hsebyp(hse.mode != HseMode::Oscillator);
#[cfg(any(rcc_h5, rcc_h50))]
w.set_hseext(match hse.mode {
HseMode::Oscillator | HseMode::Bypass => pac::rcc::vals::Hseext::ANALOG,
HseMode::BypassDigital => pac::rcc::vals::Hseext::DIGITAL,
});
});
RCC.cr().modify(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
Some(hse.freq)
}
};
let _hsi48 = config.hsi48.map(super::init_hsi48);
RCC.cr().modify(|w| w.set_csion(config.csi));
let csi = match config.csi {
false => None,
true => {
while !RCC.cr().read().csirdy() {}
Some(CSI_FREQ)
}
};
#[cfg(stm32h7)]
{
let plls = [&config.pll1, &config.pll2, &config.pll3];
if !super::util::all_equal(plls.into_iter().flatten().map(|p| p.source)) {
panic!("Source must be equal across all enabled PLLs.")
};
}
let pll_input = PllInput { csi, hse, hsi };
let pll1 = init_pll(0, config.pll1, &pll_input);
let pll2 = init_pll(1, config.pll2, &pll_input);
#[cfg(any(rcc_h5, stm32h7))]
let pll3 = init_pll(2, config.pll3, &pll_input);
let sys = match config.sys {
Sysclk::HSI => unwrap!(hsi),
Sysclk::HSE => unwrap!(hse),
Sysclk::CSI => unwrap!(csi),
Sysclk::PLL1_P => unwrap!(pll1.p),
_ => unreachable!(),
};
#[cfg(stm32h5)]
let (hclk_max, pclk_max) = match config.voltage_scale {
VoltageScale::Scale0 => (Hertz(250_000_000), Hertz(250_000_000)),
VoltageScale::Scale1 => (Hertz(200_000_000), Hertz(200_000_000)),
VoltageScale::Scale2 => (Hertz(150_000_000), Hertz(150_000_000)),
VoltageScale::Scale3 => (Hertz(100_000_000), Hertz(100_000_000)),
};
#[cfg(pwr_h7rm0455)]
let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
VoltageScale::Scale0 => (Hertz(280_000_000), Hertz(280_000_000), Hertz(140_000_000)),
VoltageScale::Scale1 => (Hertz(225_000_000), Hertz(225_000_000), Hertz(112_500_000)),
VoltageScale::Scale2 => (Hertz(160_000_000), Hertz(160_000_000), Hertz(80_000_000)),
VoltageScale::Scale3 => (Hertz(88_000_000), Hertz(88_000_000), Hertz(44_000_000)),
};
#[cfg(pwr_h7rm0468)]
let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
VoltageScale::Scale0 => (Hertz(520_000_000), Hertz(275_000_000), Hertz(137_500_000)),
VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)),
VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)),
VoltageScale::Scale3 => (Hertz(170_000_000), Hertz(85_000_000), Hertz(42_500_000)),
};
#[cfg(all(stm32h7, not(any(pwr_h7rm0455, pwr_h7rm0468))))]
let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)),
VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)),
VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)),
VoltageScale::Scale3 => (Hertz(200_000_000), Hertz(100_000_000), Hertz(50_000_000)),
};
#[cfg(stm32h7)]
let hclk = {
let d1cpre_clk = sys / config.d1c_pre;
assert!(d1cpre_clk <= d1cpre_clk_max);
sys / config.ahb_pre
};
#[cfg(stm32h5)]
let hclk = sys / config.ahb_pre;
assert!(hclk <= hclk_max);
let apb1 = hclk / config.apb1_pre;
let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler);
assert!(apb1 <= pclk_max);
let apb2 = hclk / config.apb2_pre;
let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler);
assert!(apb2 <= pclk_max);
let apb3 = hclk / config.apb3_pre;
assert!(apb3 <= pclk_max);
#[cfg(stm32h7)]
let apb4 = hclk / config.apb4_pre;
#[cfg(stm32h7)]
assert!(apb4 <= pclk_max);
let _per_ck = match config.per_clock_source {
Ckpersel::HSI => hsi,
Ckpersel::CSI => csi,
Ckpersel::HSE => hse,
_ => unreachable!(),
};
#[cfg(stm32h7)]
let adc = match config.adc_clock_source {
AdcClockSource::PLL2_P => pll2.p,
AdcClockSource::PLL3_R => pll3.r,
AdcClockSource::PER => _per_ck,
_ => unreachable!(),
};
#[cfg(stm32h5)]
let adc = match config.adc_clock_source {
AdcClockSource::HCLK1 => Some(hclk),
AdcClockSource::SYS => Some(sys),
AdcClockSource::PLL2_R => pll2.r,
AdcClockSource::HSE => hse,
AdcClockSource::HSI => hsi,
AdcClockSource::CSI => csi,
_ => unreachable!(),
};
flash_setup(hclk, config.voltage_scale);
let rtc = config.ls.init();
#[cfg(stm32h7)]
{
RCC.d1cfgr().modify(|w| {
w.set_d1cpre(config.d1c_pre);
w.set_d1ppre(config.apb3_pre);
w.set_hpre(config.ahb_pre);
});
while RCC.d1cfgr().read().d1cpre() != config.d1c_pre {}
RCC.d2cfgr().modify(|w| {
w.set_d2ppre1(config.apb1_pre);
w.set_d2ppre2(config.apb2_pre);
});
RCC.d3cfgr().modify(|w| {
w.set_d3ppre(config.apb4_pre);
});
RCC.d1ccipr().modify(|w| {
w.set_ckpersel(config.per_clock_source);
});
RCC.d3ccipr().modify(|w| {
w.set_adcsel(config.adc_clock_source);
});
}
#[cfg(stm32h5)]
{
RCC.cfgr2().modify(|w| w.set_hpre(config.ahb_pre));
while RCC.cfgr2().read().hpre() != config.ahb_pre {}
RCC.cfgr2().modify(|w| {
w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre);
w.set_ppre3(config.apb3_pre);
});
RCC.ccipr5().modify(|w| {
w.set_ckpersel(config.per_clock_source);
w.set_adcdacsel(config.adc_clock_source)
});
}
RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
RCC.cfgr().modify(|w| w.set_sw(config.sys));
while RCC.cfgr().read().sws() != config.sys {}
#[cfg(stm32h7)] if csi.is_some() {
critical_section::with(|_| {
pac::SYSCFG.cccsr().modify(|w| {
w.set_en(true);
w.set_cs(false);
w.set_hslv(false);
})
});
while !pac::SYSCFG.cccsr().read().ready() {}
}
set_freqs(Clocks {
sys,
hclk1: hclk,
hclk2: hclk,
hclk3: hclk,
hclk4: hclk,
pclk1: apb1,
pclk2: apb2,
pclk3: apb3,
#[cfg(stm32h7)]
pclk4: apb4,
#[cfg(stm32h5)]
pclk4: Hertz(1),
pclk1_tim: apb1_tim,
pclk2_tim: apb2_tim,
adc,
rtc,
#[cfg(any(stm32h5, stm32h7))]
hsi: None,
#[cfg(stm32h5)]
hsi48: None,
#[cfg(stm32h5)]
lsi: None,
#[cfg(any(stm32h5, stm32h7))]
csi: None,
#[cfg(any(stm32h5, stm32h7))]
lse: None,
#[cfg(any(stm32h5, stm32h7))]
hse: None,
#[cfg(any(stm32h5, stm32h7))]
pll1_q: pll1.q,
#[cfg(any(stm32h5, stm32h7))]
pll2_p: pll2.p,
#[cfg(any(stm32h5, stm32h7))]
pll2_q: pll2.q,
#[cfg(any(stm32h5, stm32h7))]
pll2_r: pll2.r,
#[cfg(any(rcc_h5, stm32h7))]
pll3_p: pll3.p,
#[cfg(any(rcc_h5, stm32h7))]
pll3_q: pll3.q,
#[cfg(any(rcc_h5, stm32h7))]
pll3_r: pll3.r,
#[cfg(rcc_h50)]
pll3_p: None,
#[cfg(rcc_h50)]
pll3_q: None,
#[cfg(rcc_h50)]
pll3_r: None,
#[cfg(stm32h5)]
audioclk: None,
#[cfg(any(stm32h5, stm32h7))]
per: None,
#[cfg(stm32h7)]
rcc_pclk_d3: None,
});
}
struct PllInput {
hsi: Option<Hertz>,
hse: Option<Hertz>,
csi: Option<Hertz>,
}
struct PllOutput {
p: Option<Hertz>,
#[allow(dead_code)]
q: Option<Hertz>,
#[allow(dead_code)]
r: Option<Hertz>,
}
fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
let Some(config) = config else {
RCC.cr().modify(|w| w.set_pllon(num, false));
while RCC.cr().read().pllrdy(num) {}
#[cfg(stm32h7)]
RCC.pllckselr().write(|w| w.set_divm(num, PllPreDiv::from_bits(0)));
#[cfg(stm32h5)]
RCC.pllcfgr(num).write(|w| w.set_divm(PllPreDiv::from_bits(0)));
return PllOutput {
p: None,
q: None,
r: None,
};
};
let in_clk = match config.source {
PllSource::DISABLE => panic!("must not set PllSource::Disable"),
PllSource::HSI => unwrap!(input.hsi),
PllSource::HSE => unwrap!(input.hse),
PllSource::CSI => unwrap!(input.csi),
};
let ref_clk = in_clk / config.prediv as u32;
let ref_range = match ref_clk.0 {
..=1_999_999 => Pllrge::RANGE1,
..=3_999_999 => Pllrge::RANGE2,
..=7_999_999 => Pllrge::RANGE4,
..=16_000_000 => Pllrge::RANGE8,
x => panic!("pll ref_clk out of range: {} mhz", x),
};
let wide_allowed = ref_range != Pllrge::RANGE1;
let vco_clk = ref_clk * config.mul;
let vco_range = if VCO_RANGE.contains(&vco_clk) {
Pllvcosel::MEDIUMVCO
} else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) {
Pllvcosel::WIDEVCO
} else {
panic!("pll vco_clk out of range: {} mhz", vco_clk.0)
};
let p = config.divp.map(|div| {
if num == 0 {
#[cfg(not(pwr_h7rm0468))]
assert!(div.to_bits() % 2 == 1);
#[cfg(pwr_h7rm0468)]
assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0);
}
vco_clk / div
});
let q = config.divq.map(|div| vco_clk / div);
let r = config.divr.map(|div| vco_clk / div);
#[cfg(stm32h5)]
RCC.pllcfgr(num).write(|w| {
w.set_pllsrc(config.source);
w.set_divm(config.prediv);
w.set_pllvcosel(vco_range);
w.set_pllrge(ref_range);
w.set_pllfracen(false);
w.set_pllpen(p.is_some());
w.set_pllqen(q.is_some());
w.set_pllren(r.is_some());
});
#[cfg(stm32h7)]
{
RCC.pllckselr().modify(|w| {
w.set_divm(num, config.prediv);
w.set_pllsrc(config.source);
});
RCC.pllcfgr().modify(|w| {
w.set_pllvcosel(num, vco_range);
w.set_pllrge(num, ref_range);
w.set_pllfracen(num, false);
w.set_divpen(num, p.is_some());
w.set_divqen(num, q.is_some());
w.set_divren(num, r.is_some());
});
}
RCC.plldivr(num).write(|w| {
w.set_plln(config.mul);
w.set_pllp(config.divp.unwrap_or(PllDiv::DIV2));
w.set_pllq(config.divq.unwrap_or(PllDiv::DIV2));
w.set_pllr(config.divr.unwrap_or(PllDiv::DIV2));
});
RCC.cr().modify(|w| w.set_pllon(num, true));
while !RCC.cr().read().pllrdy(num) {}
PllOutput { p, q, r }
}
fn flash_setup(clk: Hertz, vos: VoltageScale) {
#[cfg(stm32h5)]
let (latency, wrhighfreq) = match (vos, clk.0) {
(VoltageScale::Scale0, ..=42_000_000) => (0, 0),
(VoltageScale::Scale0, ..=84_000_000) => (1, 0),
(VoltageScale::Scale0, ..=126_000_000) => (2, 1),
(VoltageScale::Scale0, ..=168_000_000) => (3, 1),
(VoltageScale::Scale0, ..=210_000_000) => (4, 2),
(VoltageScale::Scale0, ..=250_000_000) => (5, 2),
(VoltageScale::Scale1, ..=34_000_000) => (0, 0),
(VoltageScale::Scale1, ..=68_000_000) => (1, 0),
(VoltageScale::Scale1, ..=102_000_000) => (2, 1),
(VoltageScale::Scale1, ..=136_000_000) => (3, 1),
(VoltageScale::Scale1, ..=170_000_000) => (4, 2),
(VoltageScale::Scale1, ..=200_000_000) => (5, 2),
(VoltageScale::Scale2, ..=30_000_000) => (0, 0),
(VoltageScale::Scale2, ..=60_000_000) => (1, 0),
(VoltageScale::Scale2, ..=90_000_000) => (2, 1),
(VoltageScale::Scale2, ..=120_000_000) => (3, 1),
(VoltageScale::Scale2, ..=150_000_000) => (4, 2),
(VoltageScale::Scale3, ..=20_000_000) => (0, 0),
(VoltageScale::Scale3, ..=40_000_000) => (1, 0),
(VoltageScale::Scale3, ..=60_000_000) => (2, 1),
(VoltageScale::Scale3, ..=80_000_000) => (3, 1),
(VoltageScale::Scale3, ..=100_000_000) => (4, 2),
_ => unreachable!(),
};
#[cfg(all(flash_h7, not(pwr_h7rm0468)))]
let (latency, wrhighfreq) = match (vos, clk.0) {
(VoltageScale::Scale0, ..=70_000_000) => (0, 0),
(VoltageScale::Scale0, ..=140_000_000) => (1, 1),
(VoltageScale::Scale0, ..=185_000_000) => (2, 1),
(VoltageScale::Scale0, ..=210_000_000) => (2, 2),
(VoltageScale::Scale0, ..=225_000_000) => (3, 2),
(VoltageScale::Scale0, ..=240_000_000) => (4, 2),
(VoltageScale::Scale1, ..=70_000_000) => (0, 0),
(VoltageScale::Scale1, ..=140_000_000) => (1, 1),
(VoltageScale::Scale1, ..=185_000_000) => (2, 1),
(VoltageScale::Scale1, ..=210_000_000) => (2, 2),
(VoltageScale::Scale1, ..=225_000_000) => (3, 2),
(VoltageScale::Scale2, ..=55_000_000) => (0, 0),
(VoltageScale::Scale2, ..=110_000_000) => (1, 1),
(VoltageScale::Scale2, ..=165_000_000) => (2, 1),
(VoltageScale::Scale2, ..=224_000_000) => (3, 2),
(VoltageScale::Scale3, ..=45_000_000) => (0, 0),
(VoltageScale::Scale3, ..=90_000_000) => (1, 1),
(VoltageScale::Scale3, ..=135_000_000) => (2, 1),
(VoltageScale::Scale3, ..=180_000_000) => (3, 2),
(VoltageScale::Scale3, ..=224_000_000) => (4, 2),
_ => unreachable!(),
};
#[cfg(all(flash_h7, pwr_h7rm0468))]
let (latency, wrhighfreq) = match (vos, clk.0) {
(VoltageScale::Scale0, ..=70_000_000) => (0, 0),
(VoltageScale::Scale0, ..=140_000_000) => (1, 1),
(VoltageScale::Scale0, ..=210_000_000) => (2, 2),
(VoltageScale::Scale0, ..=275_000_000) => (3, 3),
(VoltageScale::Scale1, ..=67_000_000) => (0, 0),
(VoltageScale::Scale1, ..=133_000_000) => (1, 1),
(VoltageScale::Scale1, ..=200_000_000) => (2, 2),
(VoltageScale::Scale2, ..=50_000_000) => (0, 0),
(VoltageScale::Scale2, ..=100_000_000) => (1, 1),
(VoltageScale::Scale2, ..=150_000_000) => (2, 2),
(VoltageScale::Scale3, ..=35_000_000) => (0, 0),
(VoltageScale::Scale3, ..=70_000_000) => (1, 1),
(VoltageScale::Scale3, ..=85_000_000) => (2, 2),
_ => unreachable!(),
};
#[cfg(flash_h7ab)]
let (latency, wrhighfreq) = match (vos, clk.0) {
(VoltageScale::Scale0, ..=42_000_000) => (0, 0),
(VoltageScale::Scale0, ..=84_000_000) => (1, 0),
(VoltageScale::Scale0, ..=126_000_000) => (2, 1),
(VoltageScale::Scale0, ..=168_000_000) => (3, 1),
(VoltageScale::Scale0, ..=210_000_000) => (4, 2),
(VoltageScale::Scale0, ..=252_000_000) => (5, 2),
(VoltageScale::Scale0, ..=280_000_000) => (6, 3),
(VoltageScale::Scale1, ..=38_000_000) => (0, 0),
(VoltageScale::Scale1, ..=76_000_000) => (1, 0),
(VoltageScale::Scale1, ..=114_000_000) => (2, 1),
(VoltageScale::Scale1, ..=152_000_000) => (3, 1),
(VoltageScale::Scale1, ..=190_000_000) => (4, 2),
(VoltageScale::Scale1, ..=225_000_000) => (5, 2),
(VoltageScale::Scale2, ..=34) => (0, 0),
(VoltageScale::Scale2, ..=68) => (1, 0),
(VoltageScale::Scale2, ..=102) => (2, 1),
(VoltageScale::Scale2, ..=136) => (3, 1),
(VoltageScale::Scale2, ..=160) => (4, 2),
(VoltageScale::Scale3, ..=22) => (0, 0),
(VoltageScale::Scale3, ..=44) => (1, 0),
(VoltageScale::Scale3, ..=66) => (2, 1),
(VoltageScale::Scale3, ..=88) => (3, 1),
_ => unreachable!(),
};
debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
FLASH.acr().write(|w| {
w.set_wrhighfreq(wrhighfreq);
w.set_latency(latency);
});
while FLASH.acr().read().latency() != latency {}
}