diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 3f5f12f06..24af17327 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5bf4bec597bdf0d85402789b40c3a37b0f5a8e76" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ae5bb5fe696a7e61fb41b8b797372aed8103a82" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5bf4bec597bdf0d85402789b40c3a37b0f5a8e76", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ae5bb5fe696a7e61fb41b8b797372aed8103a82", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 25866e446..0a5e67b4a 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -1,208 +1,230 @@ -#[cfg(rcc_f3)] -use crate::pac::adccommon::vals::Ckmode; use crate::pac::flash::vals::Latency; -pub use crate::pac::rcc::vals::Adcpres; -use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; +pub use crate::pac::rcc::vals::{ + Adcpres as AdcPllPrescaler, Hpre as AHBPrescaler, Pllmul as PllMul, Ppre as APBPrescaler, Prediv as PllPreDiv, + Sw as Sysclk, +}; +use crate::pac::rcc::vals::{Pllsrc, Usbpre}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(8_000_000); -#[cfg(rcc_f3)] -impl From for Ckmode { - fn from(value: AdcClockSource) -> Self { - match value { - AdcClockSource::BusDiv1 => Ckmode::SYNCDIV1, - AdcClockSource::BusDiv2 => Ckmode::SYNCDIV2, - AdcClockSource::BusDiv4 => Ckmode::SYNCDIV4, - _ => unreachable!(), - } - } +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum HseMode { + /// crystal/ceramic oscillator (HSEBYP=0) + Oscillator, + /// external analog clock (low swing) (HSEBYP=1) + Bypass, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hse { + /// HSE frequency. + pub freq: Hertz, + /// HSE mode. + pub mode: HseMode, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum PllSource { + HSE, + HSI, +} + +#[derive(Clone, Copy)] +pub struct Pll { + pub src: PllSource, + + /// PLL pre-divider. + /// + /// On some F3 chips, this must be 2 if `src == HSI`. Init will panic if this is not the case. + pub prediv: PllPreDiv, + + /// PLL multiplication factor. + pub mul: PllMul, } #[derive(Clone, Copy)] pub enum AdcClockSource { - Pll(Adcpres), - BusDiv1, - BusDiv2, - BusDiv4, + Pll(AdcPllPrescaler), + Hclk(AdcHclkPrescaler), } -impl AdcClockSource { - pub fn bus_div(&self) -> u32 { - match self { - Self::BusDiv1 => 1, - Self::BusDiv2 => 2, - Self::BusDiv4 => 4, - _ => unreachable!(), - } - } +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum AdcHclkPrescaler { + Div1, + Div2, + Div4, } -#[derive(Default)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum HrtimClockSource { - #[default] BusClk, PllClk, } /// Clocks configutation #[non_exhaustive] -#[derive(Default)] pub struct Config { - /// Frequency of HSE oscillator - /// 4MHz to 32MHz - pub hse: Option, - /// Bypass HSE for an external clock - pub bypass_hse: bool, - /// Frequency of the System Clock - pub sysclk: Option, - /// Frequency of AHB bus - pub hclk: Option, - /// Frequency of APB1 bus - /// - Max frequency 36MHz - pub pclk1: Option, - /// Frequency of APB2 bus - /// - Max frequency with HSE is 72MHz - /// - Max frequency without HSE is 64MHz - pub pclk2: Option, - /// USB clock setup - /// It is valid only when, - /// - HSE is enabled, - /// - The System clock frequency is either 48MHz or 72MHz - /// - APB1 clock has a minimum frequency of 10MHz - pub pll48: bool, - #[cfg(rcc_f3)] - /// ADC clock setup - /// - For AHB, a psc of 4 or less must be used - pub adc: Option, - #[cfg(rcc_f3)] - /// ADC clock setup - /// - For AHB, a psc of 4 or less must be used - pub adc34: Option, + pub hsi: bool, + pub hse: Option, + pub sys: Sysclk, + + pub pll: Option, + + pub ahb_pre: AHBPrescaler, + pub apb1_pre: APBPrescaler, + pub apb2_pre: APBPrescaler, + + #[cfg(not(rcc_f37))] + pub adc: AdcClockSource, + #[cfg(all(not(rcc_f37), adc3_common))] + pub adc34: AdcClockSource, #[cfg(stm32f334)] pub hrtim: HrtimClockSource, + pub ls: super::LsConfig, } -// Information required to setup the PLL clock -#[derive(Clone, Copy)] -struct PllConfig { - pll_src: Pllsrc, - pll_mul: Pllmul, - pll_div: Option, +impl Default for Config { + fn default() -> Self { + Self { + hsi: true, + hse: None, + sys: Sysclk::HSI, + pll: None, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, + ls: Default::default(), + + #[cfg(not(rcc_f37))] + adc: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), + #[cfg(all(not(rcc_f37), adc3_common))] + adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), + #[cfg(stm32f334)] + hrtim: HrtimClockSource::BusClk, + } + } } /// Initialize and Set the clock frequencies pub(crate) unsafe fn init(config: Config) { - // Calculate the real System clock, and PLL configuration if applicable - let (sysclk, pll_config) = get_sysclk(&config); - assert!(sysclk.0 <= 72_000_000); - - // Calculate real AHB clock - let hclk = config.hclk.map(|h| h).unwrap_or(sysclk); - let hpre = match sysclk.0 / hclk.0 { - 0 => unreachable!(), - 1 => Hpre::DIV1, - 2 => Hpre::DIV2, - 3..=5 => Hpre::DIV4, - 6..=11 => Hpre::DIV8, - 12..=39 => Hpre::DIV16, - 40..=95 => Hpre::DIV64, - 96..=191 => Hpre::DIV128, - 192..=383 => Hpre::DIV256, - _ => Hpre::DIV512, + // Configure HSI + let hsi = match config.hsi { + false => { + RCC.cr().modify(|w| w.set_hsion(false)); + None + } + true => { + RCC.cr().modify(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + Some(HSI_FREQ) + } }; - let hclk = sysclk / hpre; - assert!(hclk <= Hertz(72_000_000)); - // Calculate real APB1 clock - let pclk1 = config.pclk1.unwrap_or(hclk); - let ppre1 = match hclk / pclk1 { - 0 => unreachable!(), - 1 => Ppre::DIV1, - 2 => Ppre::DIV2, - 3..=5 => Ppre::DIV4, - 6..=11 => Ppre::DIV8, - _ => Ppre::DIV16, - }; - let timer_mul1 = if ppre1 == Ppre::DIV1 { 1u32 } else { 2 }; - let pclk1 = hclk / ppre1; - assert!(pclk1 <= Hertz(36_000_000)); + // Configure HSE + let hse = match config.hse { + None => { + RCC.cr().modify(|w| w.set_hseon(false)); + None + } + Some(hse) => { + match hse.mode { + HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + } - // Calculate real APB2 clock - let pclk2 = config.pclk2.unwrap_or(hclk); - let ppre2 = match hclk / pclk2 { - 0 => unreachable!(), - 1 => Ppre::DIV1, - 2 => Ppre::DIV2, - 3..=5 => Ppre::DIV4, - 6..=11 => Ppre::DIV8, - _ => Ppre::DIV16, + RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); + RCC.cr().modify(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + Some(hse.freq) + } }; - let timer_mul2 = if ppre2 == Ppre::DIV1 { 1u32 } else { 2 }; - let pclk2 = hclk / ppre2; - assert!(pclk2 <= Hertz(72_000_000)); + + // Enable PLL + // RM0316: "Reserved, must be kept at reset value." + let pll = config.pll.map(|pll| { + let (src_val, src_freq) = match pll.src { + #[cfg(rcc_f3v3)] + PllSource::HSI => (Pllsrc::HSI_DIV_PREDIV, unwrap!(hsi)), + #[cfg(not(rcc_f3v3))] + PllSource::HSI => { + if pll.prediv != PllPreDiv::DIV2 { + panic!("if PLL source is HSI, PLL prediv must be 2."); + } + (Pllsrc::HSI_DIV2, unwrap!(hsi)) + } + PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), + }; + let in_freq = src_freq / pll.prediv; + assert!(max::PLL_IN.contains(&in_freq)); + let out_freq = in_freq * pll.mul; + assert!(max::PLL_OUT.contains(&out_freq)); + + RCC.cfgr2().modify(|w| w.set_prediv(pll.prediv)); + RCC.cfgr().modify(|w| { + w.set_pllmul(pll.mul); + w.set_pllsrc(src_val); + }); + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} + + out_freq + }); + + let usb = match pll { + Some(Hertz(72_000_000)) => { + RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1_5)); + Some(Hertz(48_000_000)) + } + Some(Hertz(48_000_000)) => { + RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1)); + Some(Hertz(48_000_000)) + } + _ => None, + }; + + // Configure sysclk + let sys = match config.sys { + Sysclk::HSI => unwrap!(hsi), + Sysclk::HSE => unwrap!(hse), + Sysclk::PLL1_P => unwrap!(pll), + _ => unreachable!(), + }; + + let hclk = sys / config.ahb_pre; + let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); + let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); + + assert!(max::HCLK.contains(&hclk)); + assert!(max::PCLK1.contains(&pclk1)); + assert!(max::PCLK2.contains(&pclk2)); // Set latency based on HCLK frquency - // RM0316: "The prefetch buffer must be kept on when using a prescaler - // different from 1 on the AHB clock.", "Half-cycle access cannot be - // used when there is a prescaler different from 1 on the AHB clock" + let latency = match hclk.0 { + ..=24_000_000 => Latency::WS0, + ..=48_000_000 => Latency::WS1, + _ => Latency::WS2, + }; FLASH.acr().modify(|w| { - w.set_latency(if hclk <= Hertz(24_000_000) { - Latency::WS0 - } else if hclk <= Hertz(48_000_000) { - Latency::WS1 - } else { - Latency::WS2 - }); - if hpre != Hpre::DIV1 { + w.set_latency(latency); + // RM0316: "The prefetch buffer must be kept on when using a prescaler + // different from 1 on the AHB clock.", "Half-cycle access cannot be + // used when there is a prescaler different from 1 on the AHB clock" + if config.ahb_pre != AHBPrescaler::DIV1 { w.set_hlfcya(false); w.set_prftbe(true); } }); - // Enable HSE - // RM0316: "Bits 31:26 Reserved, must be kept at reset value." - if config.hse.is_some() { - RCC.cr().modify(|w| { - w.set_hsebyp(config.bypass_hse); - // We turn on clock security to switch to HSI when HSE fails - w.set_csson(true); - w.set_hseon(true); - }); - while !RCC.cr().read().hserdy() {} - } - - // Enable PLL - // RM0316: "Reserved, must be kept at reset value." - if let Some(ref pll_config) = pll_config { - RCC.cfgr().modify(|w| { - w.set_pllmul(pll_config.pll_mul); - w.set_pllsrc(pll_config.pll_src); - }); - if let Some(pll_div) = pll_config.pll_div { - RCC.cfgr2().modify(|w| w.set_prediv(pll_div)); - } - RCC.cr().modify(|w| w.set_pllon(true)); - while !RCC.cr().read().pllrdy() {} - } - - // CFGR has been written before (PLL) don't overwrite these settings - if config.pll48 { - let usb_pre = get_usb_pre(&config, sysclk, pclk1, &pll_config); - RCC.cfgr().modify(|w| { - w.set_usbpre(usb_pre); - }); - } - // Set prescalers // CFGR has been written before (PLL, PLL48) don't overwrite these settings RCC.cfgr().modify(|w| { - w.set_ppre2(ppre2); - w.set_ppre1(ppre1); - w.set_hpre(hpre); + w.set_ppre2(config.apb1_pre); + w.set_ppre1(config.apb2_pre); + w.set_hpre(config.ahb_pre); }); // Wait for the new prescalers to kick in @@ -211,53 +233,60 @@ pub(crate) unsafe fn init(config: Config) { cortex_m::asm::delay(16); // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings - RCC.cfgr().modify(|w| { - w.set_sw(match (pll_config, config.hse) { - (Some(_), _) => Sw::PLL1_P, - (None, Some(_)) => Sw::HSE, - (None, None) => Sw::HSI, - }) - }); + RCC.cfgr().modify(|w| w.set_sw(config.sys)); - #[cfg(rcc_f3)] - let adc = config.adc.map(|adc| match adc { + let rtc = config.ls.init(); + + #[cfg(not(rcc_f37))] + use crate::pac::adccommon::vals::Ckmode; + + #[cfg(not(rcc_f37))] + let adc = match config.adc { AdcClockSource::Pll(adcpres) => { - RCC.cfgr2().modify(|w| { - // Make sure that we're using the PLL - pll_config.unwrap(); - w.set_adc12pres(adcpres); + RCC.cfgr2().modify(|w| w.set_adc12pres(adcpres)); + crate::pac::ADC_COMMON + .ccr() + .modify(|w| w.set_ckmode(Ckmode::ASYNCHRONOUS)); - sysclk / adcpres - }) + unwrap!(pll) / adcpres } - _ => crate::pac::ADC_COMMON.ccr().modify(|w| { - assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1)); + AdcClockSource::Hclk(adcpres) => { + assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1)); - w.set_ckmode(adc.into()); + let (div, ckmode) = match adcpres { + AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNCDIV1), + AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNCDIV2), + AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNCDIV4), + }; + crate::pac::ADC_COMMON.ccr().modify(|w| w.set_ckmode(ckmode)); - sysclk / adc.bus_div() - }), - }); + hclk / div + } + }; - #[cfg(all(rcc_f3, adc3_common))] - let adc34 = config.adc34.map(|adc| match adc { + #[cfg(all(not(rcc_f37), adc3_common))] + let adc34 = match config.adc34 { AdcClockSource::Pll(adcpres) => { - RCC.cfgr2().modify(|w| { - // Make sure that we're using the PLL - pll_config.unwrap(); - w.set_adc34pres(adcpres); + RCC.cfgr2().modify(|w| w.set_adc34pres(adcpres)); + crate::pac::ADC3_COMMON + .ccr() + .modify(|w| w.set_ckmode(Ckmode::ASYNCHRONOUS)); - sysclk / adcpres - }) + unwrap!(pll) / adcpres } - _ => crate::pac::ADC_COMMON.ccr().modify(|w| { - assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1)); + AdcClockSource::Hclk(adcpres) => { + assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1)); - w.set_ckmode(adc.into()); + let (div, ckmode) = match adcpres { + AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNCDIV1), + AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNCDIV2), + AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNCDIV4), + }; + crate::pac::ADC3_COMMON.ccr().modify(|w| w.set_ckmode(ckmode)); - sysclk / adc.bus_div() - }), - }); + hclk / div + } + }; #[cfg(stm32f334)] let hrtim = match config.hrtim { @@ -267,195 +296,49 @@ pub(crate) unsafe fn init(config: Config) { use crate::pac::rcc::vals::Timsw; // Make sure that we're using the PLL - pll_config.unwrap(); - assert!((pclk2 == sysclk) || (pclk2 * 2u32 == sysclk)); + let pll = unwrap!(pll); + assert!((pclk2 == pll) || (pclk2 * 2u32 == pll)); RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL1_P)); - Some(sysclk * 2u32) + Some(pll * 2u32) } }; - let rtc = config.ls.init(); - set_clocks!( - hsi: None, - lse: None, - pll1_p: None, - sys: Some(sysclk), + hsi: hsi, + hse: hse, + pll1_p: pll, + sys: Some(sys), pclk1: Some(pclk1), pclk2: Some(pclk2), - pclk1_tim: Some(pclk1 * timer_mul1), - pclk2_tim: Some(pclk2 * timer_mul2), + pclk1_tim: Some(pclk1_tim), + pclk2_tim: Some(pclk2_tim), hclk1: Some(hclk), - #[cfg(rcc_f3)] - adc: adc, - #[cfg(all(rcc_f3, adc3_common))] - adc34: adc34, - #[cfg(all(rcc_f3, not(adc3_common)))] - adc34: None, + #[cfg(not(rcc_f37))] + adc: Some(adc), + #[cfg(all(not(rcc_f37), adc3_common))] + adc34: Some(adc34), #[cfg(stm32f334)] hrtim: hrtim, rtc: rtc, + usb: usb, + lse: None, ); } -#[inline] -fn get_sysclk(config: &Config) -> (Hertz, Option) { - match (config.sysclk, config.hse) { - (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None), - (Some(sysclk), None) if sysclk == HSI_FREQ => (HSI_FREQ, None), - // If the user selected System clock is different from HSI or HSE - // we will have to setup PLL clock source - (Some(sysclk), _) => { - let (sysclk, pll_config) = calc_pll(config, sysclk); - (sysclk, Some(pll_config)) - } - (None, Some(hse)) => (hse, None), - (None, None) => (HSI_FREQ, None), - } -} +mod max { + use core::ops::RangeInclusive; -#[inline] -fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { - // Calculates the Multiplier and the Divisor to arrive at - // the required System clock from PLL source frequency - let get_mul_div = |sysclk, pllsrcclk| { - let bus_div = gcd(sysclk, pllsrcclk); - let mut multiplier = sysclk / bus_div; - let mut divisor = pllsrcclk / bus_div; - // Minimum PLL multiplier is two - if multiplier == 1 { - multiplier *= 2; - divisor *= 2; - } - assert!(multiplier <= 16); - assert!(divisor <= 16); - (multiplier, divisor) - }; - // Based on the source of Pll, we calculate the actual system clock - // frequency, PLL's source identifier, multiplier and divisor - let (act_sysclk, pll_src, pll_mul, pll_div) = match config.hse { - Some(Hertz(hse)) => { - let (multiplier, divisor) = get_mul_div(sysclk, hse); - ( - Hertz((hse / divisor) * multiplier), - Pllsrc::HSE_DIV_PREDIV, - into_pll_mul(multiplier), - Some(into_pre_div(divisor)), - ) - } - None => { - cfg_if::cfg_if! { - // For some chips PREDIV is always two, and cannot be changed - if #[cfg(any(flashsize_d, flashsize_e))] { - let (multiplier, divisor) = get_mul_div(sysclk, HSI_FREQ.0); - ( - Hertz((HSI_FREQ.0 / divisor) * multiplier), - Pllsrc::HSI_DIV_PREDIV, - into_pll_mul(multiplier), - Some(into_pre_div(divisor)), - ) - } else { - let pllsrcclk = HSI_FREQ.0 / 2; - let multiplier = sysclk / pllsrcclk; - assert!(multiplier <= 16); - ( - Hertz(pllsrcclk * multiplier), - Pllsrc::HSI_DIV2, - into_pll_mul(multiplier), - None, - ) - } - } - } - }; - ( - act_sysclk, - PllConfig { - pll_src, - pll_mul, - pll_div, - }, - ) -} + use crate::time::Hertz; -#[inline] -#[allow(unused_variables)] -fn get_usb_pre(config: &Config, sysclk: Hertz, pclk1: Hertz, pll_config: &Option) -> Usbpre { - cfg_if::cfg_if! { - // Some chips do not have USB - if #[cfg(any(stm32f301, stm32f318, stm32f334))] { - panic!("USB clock not supported by the chip"); - } else { - let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= Hertz(10_000_000)); - match (usb_ok, sysclk) { - (true, Hertz(72_000_000)) => Usbpre::DIV1_5, - (true, Hertz(48_000_000)) => Usbpre::DIV1, - _ => panic!( - "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz" - ), - } - } - } -} + pub(crate) const HSE_OSC: RangeInclusive = Hertz(4_000_000)..=Hertz(32_000_000); + pub(crate) const HSE_BYP: RangeInclusive = Hertz(1_000_000)..=Hertz(32_000_000); -// This function assumes cases when multiplier is one and it -// being greater than 16 is made impossible -#[inline] -fn into_pll_mul(multiplier: u32) -> Pllmul { - match multiplier { - 2 => Pllmul::MUL2, - 3 => Pllmul::MUL3, - 4 => Pllmul::MUL4, - 5 => Pllmul::MUL5, - 6 => Pllmul::MUL6, - 7 => Pllmul::MUL7, - 8 => Pllmul::MUL8, - 9 => Pllmul::MUL9, - 10 => Pllmul::MUL10, - 11 => Pllmul::MUL11, - 12 => Pllmul::MUL12, - 13 => Pllmul::MUL13, - 14 => Pllmul::MUL14, - 15 => Pllmul::MUL15, - 16 => Pllmul::MUL16, - _ => unreachable!(), - } -} + pub(crate) const HCLK: RangeInclusive = Hertz(0)..=Hertz(72_000_000); + pub(crate) const PCLK1: RangeInclusive = Hertz(0)..=Hertz(36_000_000); + pub(crate) const PCLK2: RangeInclusive = Hertz(0)..=Hertz(72_000_000); -// This function assumes the incoming divisor cannot be greater -// than 16 -#[inline] -fn into_pre_div(divisor: u32) -> Prediv { - match divisor { - 1 => Prediv::DIV1, - 2 => Prediv::DIV2, - 3 => Prediv::DIV3, - 4 => Prediv::DIV4, - 5 => Prediv::DIV5, - 6 => Prediv::DIV6, - 7 => Prediv::DIV7, - 8 => Prediv::DIV8, - 9 => Prediv::DIV9, - 10 => Prediv::DIV10, - 11 => Prediv::DIV11, - 12 => Prediv::DIV12, - 13 => Prediv::DIV13, - 14 => Prediv::DIV14, - 15 => Prediv::DIV15, - 16 => Prediv::DIV16, - _ => unreachable!(), - } -} - -// Determine GCD using Euclidean algorithm -#[inline] -fn gcd(mut a: u32, mut b: u32) -> u32 { - while b != 0 { - let r = a % b; - a = b; - b = r; - } - a + pub(crate) const PLL_IN: RangeInclusive = Hertz(1_000_000)..=Hertz(24_000_000); + pub(crate) const PLL_OUT: RangeInclusive = Hertz(16_000_000)..=Hertz(72_000_000); } diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index eaaf8071c..db0df9fac 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -4,7 +4,7 @@ use embassy_hal_internal::into_ref; use crate::gpio::sealed::AFType; use crate::gpio::Speed; -#[cfg(not(stm32f1))] +#[cfg(not(any(stm32f1, rcc_f3v1, rcc_f37)))] pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; #[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))] pub use crate::pac::rcc::vals::Mcosel as McoSource; @@ -13,10 +13,16 @@ pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; use crate::pac::RCC; use crate::{peripherals, Peripheral}; +#[cfg(any(stm32f1, rcc_f3v1, rcc_f37))] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub enum McoPrescaler { + DIV1, +} + pub(crate) mod sealed { pub trait McoInstance { type Source; - unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: super::McoPrescaler); + unsafe fn apply_clock_settings(source: Self::Source, prescaler: super::McoPrescaler); } } @@ -29,7 +35,7 @@ macro_rules! impl_peri { impl sealed::McoInstance for peripherals::$peri { type Source = $source; - unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: McoPrescaler) { + unsafe fn apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { #[cfg(not(any(stm32u5, stm32wba)))] let r = RCC.cfgr(); #[cfg(any(stm32u5, stm32wba))] @@ -37,8 +43,8 @@ macro_rules! impl_peri { r.modify(|w| { w.$set_source(source); - #[cfg(not(stm32f1))] - w.$set_prescaler(prescaler); + #[cfg(not(any(stm32f1, rcc_f3v1, rcc_f37)))] + w.$set_prescaler(_prescaler); }); } } @@ -68,16 +74,12 @@ impl<'d, T: McoInstance> Mco<'d, T> { _peri: impl Peripheral

+ 'd, pin: impl Peripheral

> + 'd, source: T::Source, - #[cfg(not(stm32f1))] prescaler: McoPrescaler, + prescaler: McoPrescaler, ) -> Self { into_ref!(pin); critical_section::with(|_| unsafe { - T::apply_clock_settings( - source, - #[cfg(not(stm32f1))] - prescaler, - ); + T::apply_clock_settings(source, prescaler); pin.set_as_af(pin.af_num(), AFType::OutputPushPull); pin.set_speed(Speed::VeryHigh); }); diff --git a/examples/stm32f3/src/bin/hello.rs b/examples/stm32f3/src/bin/hello.rs index fd54da53d..3c295612c 100644 --- a/examples/stm32f3/src/bin/hello.rs +++ b/examples/stm32f3/src/bin/hello.rs @@ -3,16 +3,13 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::time::Hertz; use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { - let mut config = Config::default(); - config.rcc.hse = Some(Hertz(8_000_000)); - config.rcc.sysclk = Some(Hertz(16_000_000)); + let config = Config::default(); let _p = embassy_stm32::init(config); loop { diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs index cf9ecedfa..ee1c43afd 100644 --- a/examples/stm32f3/src/bin/usb_serial.rs +++ b/examples/stm32f3/src/bin/usb_serial.rs @@ -21,11 +21,22 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.hse = Some(mhz(8)); - config.rcc.sysclk = Some(mhz(48)); - config.rcc.pclk1 = Some(mhz(24)); - config.rcc.pclk2 = Some(mhz(24)); - config.rcc.pll48 = true; + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: mhz(8), + mode: HseMode::Bypass, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL9, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + } let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index 063ee9dac..a9fb7f1a6 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -5,7 +5,6 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC1; -use embassy_stm32::rcc::{AdcClockSource, Adcpres}; use embassy_stm32::time::mhz; use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_time::{Delay, Timer}; @@ -18,12 +17,23 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { let mut config = Config::default(); - config.rcc.sysclk = Some(mhz(64)); - config.rcc.hclk = Some(mhz(64)); - config.rcc.pclk1 = Some(mhz(32)); - config.rcc.pclk2 = Some(mhz(64)); - config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1)); - + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: mhz(8), + mode: HseMode::Bypass, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL9, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.adc = AdcClockSource::Pll(AdcPllPrescaler::DIV1); + } let mut p = embassy_stm32::init(config); info!("create adc..."); diff --git a/examples/stm32f334/src/bin/hello.rs b/examples/stm32f334/src/bin/hello.rs index fd54da53d..3c295612c 100644 --- a/examples/stm32f334/src/bin/hello.rs +++ b/examples/stm32f334/src/bin/hello.rs @@ -3,16 +3,13 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::time::Hertz; use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { - let mut config = Config::default(); - config.rcc.hse = Some(Hertz(8_000_000)); - config.rcc.sysclk = Some(Hertz(16_000_000)); + let config = Config::default(); let _p = embassy_stm32::init(config); loop { diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index 850a0e335..6f25191be 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs @@ -6,7 +6,6 @@ use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::opamp::{OpAmp, OpAmpGain}; use embassy_stm32::peripherals::ADC2; -use embassy_stm32::rcc::{AdcClockSource, Adcpres}; use embassy_stm32::time::mhz; use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_time::{Delay, Timer}; @@ -19,12 +18,23 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { let mut config = Config::default(); - config.rcc.sysclk = Some(mhz(64)); - config.rcc.hclk = Some(mhz(64)); - config.rcc.pclk1 = Some(mhz(32)); - config.rcc.pclk2 = Some(mhz(64)); - config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1)); - + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: mhz(8), + mode: HseMode::Bypass, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL9, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.adc = AdcClockSource::Pll(AdcPllPrescaler::DIV1); + } let mut p = embassy_stm32::init(config); info!("create adc..."); diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index c149cad92..7fc1ea926 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::hrtim::*; -use embassy_stm32::rcc::HrtimClockSource; use embassy_stm32::time::{khz, mhz}; use embassy_stm32::Config; use embassy_time::Timer; @@ -12,14 +11,26 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let mut config: Config = Default::default(); - config.rcc.sysclk = Some(mhz(64)); - config.rcc.hclk = Some(mhz(64)); - config.rcc.pclk1 = Some(mhz(32)); - config.rcc.pclk2 = Some(mhz(64)); - config.rcc.hrtim = HrtimClockSource::PllClk; - + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: mhz(8), + mode: HseMode::Bypass, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL9, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.hrtim = HrtimClockSource::PllClk; + } let p = embassy_stm32::init(config); + info!("Hello World!"); let ch1 = PwmPin::new_cha(p.PA8); diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index fefe72c86..36fe8a235 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -276,6 +276,24 @@ pub fn config() -> Config { config.rcc.apb2_pre = APBPrescaler::DIV2; } + #[cfg(feature = "stm32f303ze")] + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Bypass, + }); + config.rcc.pll = Some(Pll { + src: PllSource::HSE, + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL9, + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + } + #[cfg(feature = "stm32f429zi")] { use embassy_stm32::rcc::*;