diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 460184920..4bbd43c47 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -70,7 +70,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-d7462d805ef05892531a83cd9ad60c9cba568d54" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -94,7 +94,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-d7462d805ef05892531a83cd9ad60c9cba568d54", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 08c051956..84e8be25d 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -5,7 +5,9 @@ use std::{env, fs}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; -use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccKernelClock, StopMode, METADATA}; +use stm32_metapac::metadata::{ + MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA, +}; fn main() { let target = env::var("TARGET").unwrap(); @@ -374,12 +376,130 @@ fn main() { } } - let force_refcount = HashSet::from(["usart"]); - let mut refcount_statics = BTreeSet::new(); + struct ClockGen<'a> { + rcc_registers: &'a PeripheralRegisters, + chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>, + force_refcount: HashSet<&'a str>, - let mut clock_names = BTreeSet::new(); + refcount_statics: BTreeSet, + clock_names: BTreeSet, + muxes: BTreeSet<(Ident, Ident, Ident)>, + } - let mut rcc_cfgr_regs = BTreeSet::new(); + let mut clock_gen = ClockGen { + rcc_registers, + chained_muxes: HashMap::new(), + force_refcount: HashSet::from(["usart"]), + + refcount_statics: BTreeSet::new(), + clock_names: BTreeSet::new(), + muxes: BTreeSet::new(), + }; + if chip_name.starts_with("stm32h5") { + clock_gen.chained_muxes.insert( + "PER", + &PeripheralRccRegister { + register: "CCIPR5", + field: "PERSEL", + }, + ); + } + if chip_name.starts_with("stm32h7") { + clock_gen.chained_muxes.insert( + "PER", + &PeripheralRccRegister { + register: "D1CCIPR", + field: "PERSEL", + }, + ); + } + if chip_name.starts_with("stm32u5") { + clock_gen.chained_muxes.insert( + "ICLK", + &PeripheralRccRegister { + register: "CCIPR1", + field: "ICLKSEL", + }, + ); + } + if chip_name.starts_with("stm32wb") && !chip_name.starts_with("stm32wba") { + clock_gen.chained_muxes.insert( + "CLK48", + &PeripheralRccRegister { + register: "CCIPR", + field: "CLK48SEL", + }, + ); + } + if chip_name.starts_with("stm32f7") { + clock_gen.chained_muxes.insert( + "CLK48", + &PeripheralRccRegister { + register: "DCKCFGR2", + field: "CLK48SEL", + }, + ); + } + if chip_name.starts_with("stm32f4") && !chip_name.starts_with("stm32f410") { + clock_gen.chained_muxes.insert( + "CLK48", + &PeripheralRccRegister { + register: "DCKCFGR", + field: "CLK48SEL", + }, + ); + } + + impl<'a> ClockGen<'a> { + fn gen_clock(&mut self, name: &str) -> TokenStream { + let clock_name = format_ident!("{}", name.to_ascii_lowercase()); + self.clock_names.insert(name.to_ascii_lowercase()); + quote!( unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } ) + } + + fn gen_mux(&mut self, mux: &PeripheralRccRegister) -> TokenStream { + let ir = &self.rcc_registers.ir; + let fieldset_name = mux.register.to_ascii_lowercase(); + let fieldset = ir + .fieldsets + .iter() + .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name)) + .unwrap(); + let field_name = mux.field.to_ascii_lowercase(); + let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap(); + let enum_name = field.enumm.unwrap(); + let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap(); + + let fieldset_name = format_ident!("{}", fieldset_name); + let field_name = format_ident!("{}", field_name); + let enum_name = format_ident!("{}", enum_name); + + self.muxes + .insert((fieldset_name.clone(), field_name.clone(), enum_name.clone())); + + let mut match_arms = TokenStream::new(); + + for v in enumm.variants.iter().filter(|v| v.name != "DISABLE") { + let variant_name = format_ident!("{}", v.name); + let expr = if let Some(mux) = self.chained_muxes.get(&v.name) { + self.gen_mux(mux) + } else { + self.gen_clock(&v.name) + }; + match_arms.extend(quote! { + crate::pac::rcc::vals::#enum_name::#variant_name => #expr, + }); + } + + quote! { + match crate::pac::RCC.#fieldset_name().read().#field_name() { + #match_arms + #[allow(unreachable_patterns)] + _ => unreachable!(), + } + } + } + } for p in METADATA.peripherals { if !singletons.contains(&p.name.to_string()) { @@ -416,12 +536,12 @@ fn main() { let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); let refcount = - force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; + clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; let (before_enable, before_disable) = if refcount { let refcount_static = format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); - refcount_statics.insert(refcount_static.clone()); + clock_gen.refcount_statics.insert(refcount_static.clone()); ( quote! { @@ -442,63 +562,12 @@ fn main() { }; let clock_frequency = match &rcc.kernel_clock { - PeripheralRccKernelClock::Mux(mux) => { - let ir = &rcc_registers.ir; - let fieldset_name = mux.register.to_ascii_lowercase(); - let fieldset = ir - .fieldsets - .iter() - .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name)) - .unwrap(); - let field_name = mux.field.to_ascii_lowercase(); - let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap(); - let enum_name = field.enumm.unwrap(); - let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap(); - - let fieldset_name = format_ident!("{}", fieldset_name); - let field_name = format_ident!("{}", field_name); - let enum_name = format_ident!("{}", enum_name); - - rcc_cfgr_regs.insert((fieldset_name.clone(), field_name.clone(), enum_name.clone())); - - let match_arms: TokenStream = enumm - .variants - .iter() - .filter(|v| v.name != "DISABLE") - .map(|v| { - let variant_name = format_ident!("{}", v.name); - let clock_name = format_ident!("{}", v.name.to_ascii_lowercase()); - clock_names.insert(v.name.to_ascii_lowercase()); - quote! { - #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }, - } - }) - .collect(); - - quote! { - use crate::pac::rcc::vals::#enum_name; - - #[allow(unreachable_patterns)] - match crate::pac::RCC.#fieldset_name().read().#field_name() { - #match_arms - _ => unreachable!(), - } - } - } - PeripheralRccKernelClock::Clock(clock) => { - let clock = clock.to_ascii_lowercase(); - let clock_name = format_ident!("{}", clock); - clock_names.insert(clock.to_string()); - quote! { - unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } - } - } + PeripheralRccKernelClock::Mux(mux) => clock_gen.gen_mux(mux), + PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(clock), }; - /* - A refcount leak can result if the same field is shared by peripherals with different stop modes - This condition should be checked in stm32-data - */ + // A refcount leak can result if the same field is shared by peripherals with different stop modes + // This condition should be checked in stm32-data let stop_refcount = match rcc.stop_mode { StopMode::Standby => None, StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }), @@ -543,74 +612,79 @@ fn main() { } } - if !rcc_cfgr_regs.is_empty() { - println!("cargo:rustc-cfg=clock_mux"); + let struct_fields: Vec<_> = clock_gen + .muxes + .iter() + .map(|(_fieldset, fieldname, enum_name)| { + quote! { + pub #fieldname: #enum_name + } + }) + .collect(); - let struct_fields: Vec<_> = rcc_cfgr_regs + let mut inits = TokenStream::new(); + for fieldset in clock_gen + .muxes + .iter() + .map(|(f, _, _)| f) + .collect::>() + .into_iter() + { + let setters: Vec<_> = clock_gen + .muxes .iter() - .map(|(_fieldset, fieldname, enum_name)| { - quote! { - pub #fieldname: Option<#enum_name> - } - }) - .collect(); - - let field_names: Vec<_> = rcc_cfgr_regs - .iter() - .map(|(_fieldset, fieldname, _enum_name)| fieldname) - .collect(); - - let inits: Vec<_> = rcc_cfgr_regs - .iter() - .map(|(fieldset, fieldname, _enum_name)| { + .filter(|(f, _, _)| f == fieldset) + .map(|(_, fieldname, _)| { let setter = format_ident!("set_{}", fieldname); quote! { - match self.#fieldname { - None => {} - Some(val) => { - crate::pac::RCC.#fieldset() - .modify(|w| w.#setter(val)); - } - }; + w.#setter(self.#fieldname); } }) .collect(); - let enum_names: BTreeSet<_> = rcc_cfgr_regs - .iter() - .map(|(_fieldset, _fieldname, enum_name)| enum_name) - .collect(); - - g.extend(quote! { - pub mod mux { - #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )* - - #[derive(Clone, Copy)] - pub struct ClockMux { - #( #struct_fields, )* - } - - impl Default for ClockMux { - fn default() -> Self { - Self { - #( #field_names: None, )* - } - } - } - - impl ClockMux { - pub fn init(self) { - #( #inits )* - } - } - } - }); + inits.extend(quote! { + crate::pac::RCC.#fieldset().modify(|w| { + #(#setters)* + }); + }) } + let enum_names: BTreeSet<_> = clock_gen.muxes.iter().map(|(_, _, enum_name)| enum_name).collect(); + + g.extend(quote! { + pub mod mux { + #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )* + + #[derive(Clone, Copy)] + pub struct ClockMux { + #( #struct_fields, )* + } + + impl ClockMux { + pub(crate) const fn default() -> Self { + // safety: zero value is valid for all PAC enums. + unsafe { ::core::mem::zeroed() } + } + } + + impl Default for ClockMux { + fn default() -> Self { + Self::default() + } + } + + impl ClockMux { + pub(crate) fn init(&self) { + #inits + } + } + } + }); + // Generate RCC - clock_names.insert("sys".to_string()); - clock_names.insert("rtc".to_string()); - let clock_idents: Vec<_> = clock_names.iter().map(|n| format_ident!("{}", n)).collect(); + clock_gen.clock_names.insert("sys".to_string()); + clock_gen.clock_names.insert("rtc".to_string()); + let clock_idents: Vec<_> = clock_gen.clock_names.iter().map(|n| format_ident!("{}", n)).collect(); g.extend(quote! { #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -640,7 +714,8 @@ fn main() { } ); - let refcount_mod: TokenStream = refcount_statics + let refcount_mod: TokenStream = clock_gen + .refcount_statics .iter() .map(|refcount_static| { quote! { diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 663a7f59d..523719bb9 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -7,7 +7,6 @@ use core::task::Poll; use self::sealed::Instance; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; -use crate::pac::rcc::vals::{Lptim1sel, Lptim2sel}; use crate::peripherals::IPCC; use crate::rcc::sealed::RccPeripheral; @@ -105,7 +104,8 @@ impl Ipcc { IPCC::enable_and_reset(); IPCC::set_cpu2(true); - _configure_pwr(); + // set RF wake-up clock = LSE + crate::pac::RCC.csr().modify(|w| w.set_rfwkpsel(0b01)); let regs = IPCC::regs(); @@ -271,18 +271,3 @@ pub(crate) mod sealed { fn state() -> &'static State; } } - -fn _configure_pwr() { - // TODO: move the rest of this to rcc - let rcc = crate::pac::RCC; - - // TODO: required - // set RF wake-up clock = LSE - rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); - - // set LPTIM1 & LPTIM2 clock source - rcc.ccipr().modify(|w| { - w.set_lptim1sel(Lptim1sel::PCLK1); - w.set_lptim2sel(Lptim2sel::PCLK1); - }); -} diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index ec6ec34e8..1946c5a15 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -21,6 +21,9 @@ pub struct Config { pub ahb_pre: AHBPrescaler, pub apb_pre: APBPrescaler, pub ls: super::LsConfig, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -31,6 +34,7 @@ impl Default for Config { ahb_pre: AHBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1, ls: Default::default(), + mux: Default::default(), } } } @@ -97,28 +101,25 @@ pub(crate) unsafe fn init(config: Config) { if !set_flash_latency_after { // Spin until the effective flash latency is compatible with the clock change - while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {} + while FLASH.acr().read().latency() < target_flash_latency {} } // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once - let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre); RCC.cfgr().modify(|w| { w.set_sw(sw); - w.set_hpre(hpre); - w.set_ppre(ppre); + w.set_hpre(config.ahb_pre); + w.set_ppre(config.apb_pre); }); - - if set_flash_latency_after { - // We can make the flash require fewer wait states - // Spin until the SYSCLK changes have taken effect - loop { - let cfgr = RCC.cfgr().read(); - if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre { - break; - } + // Spin until the SYSCLK changes have taken effect + loop { + let cfgr = RCC.cfgr().read(); + if cfgr.sw() == sw && cfgr.hpre() == config.ahb_pre && cfgr.ppre() == config.apb_pre { + break; } + } - // Set the flash latency to require fewer wait states + // Set the flash latency to require fewer wait states + if set_flash_latency_after { FLASH.acr().modify(|w| w.set_latency(target_flash_latency)); } @@ -132,6 +133,11 @@ pub(crate) unsafe fn init(config: Config) { } }; + config.mux.init(); + + // without this, the ringbuffered uart test fails. + cortex_m::asm::dsb(); + set_clocks!( hsi: None, lse: None, diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 5046f0a3a..215f8a3d2 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -98,8 +98,8 @@ pub struct Config { #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] pub adc34: AdcClockSource, - #[cfg(clock_mux)] - pub mux: crate::rcc::mux::ClockMux, + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, pub ls: super::LsConfig, } @@ -128,7 +128,6 @@ impl Default for Config { #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), - #[cfg(clock_mux)] mux: Default::default(), } } @@ -370,7 +369,6 @@ pub(crate) unsafe fn init(config: Config) { }; */ - #[cfg(clock_mux)] config.mux.init(); set_clocks!( diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 343d075cd..7b252870c 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -95,6 +95,9 @@ pub struct Config { pub ls: super::LsConfig, + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, + #[cfg(stm32f2)] pub voltage: VoltageScale, } @@ -120,6 +123,7 @@ impl Default for Config { #[cfg(stm32f2)] voltage: VoltageScale::Range3, + mux: Default::default(), } } } @@ -256,6 +260,8 @@ pub(crate) unsafe fn init(config: Config) { }); while RCC.cfgr().read().sws() != config.sys {} + config.mux.init(); + set_clocks!( hsi: hsi, hse: hse, @@ -286,7 +292,9 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] pllsai1_r: pllsai.r, - clk48: pll.q, + // TODO workaround until f4 rcc is fixed in stm32-data + #[cfg(not(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7)))] + pllsai1_q: None, hsi_div488: hsi.map(|hsi| hsi/488u32), hsi_hse: None, diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index ae502dd9c..5cfe9953b 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -71,22 +71,6 @@ pub enum PllSource { HSE(Hertz, HseMode), } -/// Sets the source for the 48MHz clock to the USB peripheral. -#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] -pub enum UsbSrc { - /// Use the High Speed Internal Oscillator. The CRS must be used to calibrate the - /// oscillator to comply with the USB specification for oscillator tolerance. - #[cfg(any(stm32g0b1, stm32g0c1))] - Hsi48(super::Hsi48Config), - /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. The - /// PLL needs to be using the HSE source to comply with the USB specification for oscillator - /// tolerance. - PllQ, - /// Use the HSE source directly. The HSE must be a 48MHz source. The HSE source must comply - /// with the USB specification for oscillator tolerance. - HSE, -} - /// Clocks configutation pub struct Config { pub sys: Sysclk, @@ -94,8 +78,10 @@ pub struct Config { pub apb_pre: APBPrescaler, pub low_power_run: bool, pub ls: super::LsConfig, - #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] - pub usb_src: Option, + #[cfg(crs)] + pub hsi48: Option, + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -107,8 +93,9 @@ impl Default for Config { apb_pre: APBPrescaler::DIV1, low_power_run: false, ls: Default::default(), - #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] - usb_src: None, + #[cfg(crs)] + hsi48: Some(Default::default()), + mux: Default::default(), } } } @@ -322,34 +309,12 @@ pub(crate) unsafe fn init(config: Config) { let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ); let hse_freq = (sw == Sw::HSE).then_some(sys_clk); - #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] - let hsi48_freq = config.usb_src.and_then(|config| { - match config { - UsbSrc::PllQ => { - // Make sure the PLLQ is enabled and running at 48Mhz - assert!(pll1_q_freq.is_some() && pll1_q_freq.unwrap().0 == 48_000_000); - RCC.ccipr2() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::PLL1_Q)); - None - } - UsbSrc::HSE => { - // Make sure the HSE is enabled and running at 48Mhz - assert!(hse_freq.is_some() && hse_freq.unwrap().0 == 48_000_000); - RCC.ccipr2() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSE)); - None - } - #[cfg(any(stm32g0b1, stm32g0c1))] - UsbSrc::Hsi48(config) => { - let freq = super::init_hsi48(config); - RCC.ccipr2() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)); - Some(freq) - } - } - }); - #[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))] - let hsi48_freq: Option = None; + #[cfg(crs)] + let hsi48 = config.hsi48.map(super::init_hsi48); + #[cfg(not(crs))] + let hsi48: Option = None; + + config.mux.init(); set_clocks!( sys: Some(sys_clk), @@ -357,7 +322,7 @@ pub(crate) unsafe fn init(config: Config) { pclk1: Some(apb_freq), pclk1_tim: Some(apb_tim_freq), hsi: hsi_freq, - hsi48: hsi48_freq, + hsi48: hsi48, hsi_div_8: hsi_div_8_freq, hse: hse_freq, lse: lse_freq, diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 6ed266284..79bdbeb77 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -1,11 +1,10 @@ use stm32_metapac::flash::vals::Latency; -use stm32_metapac::rcc::vals::{Adcsel, Sw}; +use stm32_metapac::rcc::vals::Sw; use stm32_metapac::FLASH; pub use crate::pac::rcc::vals::{ - Adcsel as AdcClockSource, Clk48sel as Clk48Src, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, - Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, Ppre as APBPrescaler, - Sw as Sysclk, + Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, + Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::{PWR, RCC}; use crate::time::Hertz; @@ -82,24 +81,15 @@ pub struct Config { pub low_power_run: bool, - /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. - pub clk48_src: Clk48Src, - /// Low-Speed Clock Configuration pub ls: super::LsConfig, - /// Clock Source for ADCs 1 and 2 - pub adc12_clock_source: AdcClockSource, - - /// Clock Source for ADCs 3, 4 and 5 - pub adc345_clock_source: AdcClockSource, - - /// Clock Source for FDCAN - pub fdcan_clock_source: FdCanClockSource, - /// Enable range1 boost mode /// Recommended when the SYSCLK frequency is greater than 150MHz. pub boost: bool, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -115,12 +105,9 @@ impl Default for Config { apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, low_power_run: false, - clk48_src: Clk48Src::HSI48, ls: Default::default(), - adc12_clock_source: Adcsel::DISABLE, - adc345_clock_source: Adcsel::DISABLE, - fdcan_clock_source: FdCanClockSource::PCLK1, boost: false, + mux: Default::default(), } } } @@ -165,9 +152,7 @@ pub(crate) unsafe fn init(config: Config) { }; // Configure HSI48 if required - if let Some(hsi48_config) = config.hsi48 { - super::init_hsi48(hsi48_config); - } + let hsi48 = config.hsi48.map(super::init_hsi48); let pll_freq = config.pll.map(|pll_config| { let src_freq = match pll_config.source { @@ -176,13 +161,13 @@ pub(crate) unsafe fn init(config: Config) { _ => unreachable!(), }; - assert!(max::PLL_IN.contains(&src_freq)); - // Disable PLL before configuration RCC.cr().modify(|w| w.set_pllon(false)); while RCC.cr().read().pllrdy() {} - let internal_freq = src_freq / pll_config.prediv * pll_config.mul; + let in_freq = src_freq / pll_config.prediv; + assert!(max::PLL_IN.contains(&in_freq)); + let internal_freq = in_freq * pll_config.mul; assert!(max::PLL_VCO.contains(&internal_freq)); @@ -301,42 +286,6 @@ pub(crate) unsafe fn init(config: Config) { let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre); let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre); - // Configure the 48MHz clock source for USB and RNG peripherals. - RCC.ccipr().modify(|w| { - w.set_clk48sel(match config.clk48_src { - Clk48Src::PLL1_Q => { - // Not checking that PLL1_Q is 48MHz here so as not to require the user to have a 48MHz clock. - // Peripherals which require one (USB, RNG) should check that they‘re driven by a valid 48MHz - // clock at init. - crate::pac::rcc::vals::Clk48sel::PLL1_Q - } - Clk48Src::HSI48 => { - // Make sure HSI48 is enabled - assert!(config.hsi48.is_some()); - crate::pac::rcc::vals::Clk48sel::HSI48 - } - _ => unreachable!(), - }) - }); - - RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source)); - RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); - RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source)); - - let adc12_ck = match config.adc12_clock_source { - AdcClockSource::DISABLE => None, - AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p, - AdcClockSource::SYS => Some(sys_clk), - _ => unreachable!(), - }; - - let adc345_ck = match config.adc345_clock_source { - AdcClockSource::DISABLE => None, - AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p, - AdcClockSource::SYS => Some(sys_clk), - _ => unreachable!(), - }; - if config.low_power_run { assert!(sys_clk <= Hertz(2_000_000)); PWR.cr1().modify(|w| w.set_lpr(true)); @@ -344,6 +293,8 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); + config.mux.init(); + set_clocks!( sys: Some(sys_clk), hclk1: Some(hclk), @@ -353,12 +304,11 @@ pub(crate) unsafe fn init(config: Config) { pclk1_tim: Some(apb1_tim_freq), pclk2: Some(apb2_freq), pclk2_tim: Some(apb2_tim_freq), - adc: adc12_ck, - adc34: adc345_ck, pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p), pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q), pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r), hse: hse, + hsi48: hsi48, rtc: rtc, ); } diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 7b2255cc6..bab8bb19e 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -2,15 +2,10 @@ 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, Fdcansel as FdCanClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, - Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk, + 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::rcc::vals::{Pllrge, Pllvcosel, Timpre}; use crate::pac::{FLASH, PWR, RCC}; use crate::time::Hertz; @@ -194,16 +189,15 @@ pub struct Config { #[cfg(stm32h7)] pub apb4_pre: APBPrescaler, - pub per_clock_source: PerClockSource, - pub adc_clock_source: AdcClockSource, - pub fdcan_clock_source: FdCanClockSource, - pub timer_prescaler: TimerPrescaler, pub voltage_scale: VoltageScale, pub ls: super::LsConfig, #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] pub supply_config: SupplyConfig, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -227,21 +221,14 @@ impl Default for Config { #[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, - - fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE - timer_prescaler: TimerPrescaler::DefaultX2, voltage_scale: VoltageScale::Scale0, ls: Default::default(), #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] supply_config: SupplyConfig::Default, + + mux: Default::default(), } } } @@ -504,31 +491,6 @@ pub(crate) unsafe fn init(config: Config) { #[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(); @@ -550,16 +512,6 @@ pub(crate) unsafe fn init(config: Config) { 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); - }); - RCC.d2ccip1r().modify(|w| { - w.set_fdcansel(config.fdcan_clock_source); - }); } #[cfg(stm32h5)] { @@ -573,12 +525,6 @@ pub(crate) unsafe fn init(config: Config) { 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); - w.set_fdcan12sel(config.fdcan_clock_source) - }); } RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into())); @@ -601,6 +547,8 @@ pub(crate) unsafe fn init(config: Config) { while !pac::SYSCFG.cccsr().read().ready() {} } + config.mux.init(); + set_clocks!( sys: Some(sys), hclk1: Some(hclk), @@ -614,7 +562,6 @@ pub(crate) unsafe fn init(config: Config) { pclk4: Some(apb4), pclk1_tim: Some(apb1_tim), pclk2_tim: Some(apb2_tim), - adc: adc, rtc: rtc, hsi: hsi, @@ -646,7 +593,6 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h5)] audioclk: None, - per: None, i2s_ckin: None, ); } diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index aa4245d4e..9079ddd41 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -1,10 +1,6 @@ #[cfg(any(stm32l0, stm32l1))] pub use crate::pac::pwr::vals::Vos as VoltageScale; use crate::pac::rcc::regs::Cfgr; -#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] -pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; -#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] -pub use crate::pac::rcc::vals::Clk48sel as Clk48Src; #[cfg(any(stm32wb, stm32wl))] pub use crate::pac::rcc::vals::Hsepre as HsePrescaler; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk}; @@ -59,18 +55,14 @@ pub struct Config { #[cfg(any(stm32wl, stm32wb))] pub shared_ahb_pre: AHBPrescaler, - // muxes - #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] - pub clk48_src: Clk48Src, - // low speed LSI/LSE/RTC pub ls: super::LsConfig, - #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] - pub adc_clock_source: AdcClockSource, - #[cfg(any(stm32l0, stm32l1))] pub voltage_scale: VoltageScale, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -95,13 +87,10 @@ impl Default for Config { pllsai2: None, #[cfg(crs)] hsi48: Some(Default::default()), - #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] - clk48_src: Clk48Src::HSI48, ls: Default::default(), - #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] - adc_clock_source: AdcClockSource::SYS, #[cfg(any(stm32l0, stm32l1))] voltage_scale: VoltageScale::RANGE1, + mux: Default::default(), } } } @@ -118,7 +107,6 @@ pub const WPAN_DEFAULT: Config = Config { hsi48: Some(super::Hsi48Config { sync_from_usb: false }), msi: None, hsi: false, - clk48_src: Clk48Src::PLL1_Q, ls: super::LsConfig::default_lse(), @@ -137,7 +125,8 @@ pub const WPAN_DEFAULT: Config = Config { shared_ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, - adc_clock_source: AdcClockSource::SYS, + + mux: super::mux::ClockMux::default(), }; fn msi_enable(range: MSIRange) { @@ -267,21 +256,6 @@ pub(crate) unsafe fn init(config: Config) { Sysclk::PLL1_R => pll.r.unwrap(), }; - #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] - RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src)); - #[cfg(any(rcc_l0_v2))] - let clk48 = match config.clk48_src { - Clk48Src::HSI48 => hsi48, - Clk48Src::PLL1_VCO_DIV_2 => pll.clk48, - }; - #[cfg(any(stm32l4, stm32l5, stm32wb))] - let clk48 = match config.clk48_src { - Clk48Src::HSI48 => hsi48, - Clk48Src::MSI => msi, - Clk48Src::PLLSAI1_Q => pllsai1.q, - Clk48Src::PLL1_Q => pll.q, - }; - #[cfg(rcc_l4plus)] assert!(sys_clk.0 <= 120_000_000); #[cfg(all(stm32l4, not(rcc_l4plus)))] @@ -357,9 +331,6 @@ pub(crate) unsafe fn init(config: Config) { }); while RCC.cfgr().read().sws() != config.sys {} - #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] - RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source)); - #[cfg(any(stm32wl, stm32wb))] { RCC.extcfgr().modify(|w| { @@ -372,6 +343,8 @@ pub(crate) unsafe fn init(config: Config) { while !RCC.extcfgr().read().c2hpref() {} } + config.mux.init(); + set_clocks!( sys: Some(sys_clk), hclk1: Some(hclk1), @@ -388,10 +361,11 @@ pub(crate) unsafe fn init(config: Config) { hsi: hsi, hse: hse, msi: msi, - #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] - clk48: clk48, hsi48: hsi48, + #[cfg(any(stm32l0, stm32l1))] + pll1_vco_div_2: pll.vco.map(|c| c/2u32), + #[cfg(not(any(stm32l0, stm32l1)))] pll1_p: pll.p, #[cfg(not(any(stm32l0, stm32l1)))] @@ -511,7 +485,7 @@ mod pll { #[derive(Default)] pub(super) struct PllOutput { pub r: Option, - pub clk48: Option, + pub vco: Option, } pub(super) fn init_pll(instance: PllInstance, config: Option, input: &PllInput) -> PllOutput { @@ -528,7 +502,6 @@ mod pll { let vco_freq = pll_src * pll.mul; let r = vco_freq / pll.div; - let clk48 = (vco_freq == Hertz(96_000_000)).then_some(Hertz(48_000_000)); assert!(r <= Hertz(32_000_000)); @@ -541,7 +514,10 @@ mod pll { // Enable PLL pll_enable(instance, true); - PllOutput { r: Some(r), clk48 } + PllOutput { + r: Some(r), + vco: Some(vco_freq), + } } } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index c8ca713de..910ebe205 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -31,9 +31,7 @@ mod _version; pub use _version::*; -#[cfg(clock_mux)] -pub use crate::_generated::mux; -pub use crate::_generated::Clocks; +pub use crate::_generated::{mux, Clocks}; #[cfg(feature = "low-power")] /// Must be written within a critical section diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index c8814ed69..9533e16c4 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -85,6 +85,9 @@ pub struct Config { /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits. pub voltage_range: VoltageScale, pub ls: super::LsConfig, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -104,6 +107,7 @@ impl Default for Config { apb3_pre: APBPrescaler::DIV1, voltage_range: VoltageScale::RANGE1, ls: Default::default(), + mux: Default::default(), } } } @@ -259,6 +263,8 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); + config.mux.init(); + set_clocks!( sys: Some(sys_clk), hclk1: Some(hclk), @@ -289,7 +295,6 @@ pub(crate) unsafe fn init(config: Config) { lse: None, lsi: None, msik: None, - iclk: None, shsi: None, shsi_div_2: None, ); diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 9d5dcfc4b..8e1779d7c 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -1,8 +1,6 @@ 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 Sysclk, -}; +pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; @@ -32,9 +30,10 @@ pub struct Config { // low speed LSI/LSE/RTC pub ls: super::LsConfig, - pub adc_clock_source: AdcClockSource, - pub voltage_scale: VoltageScale, + + /// Per-peripheral kernel clock selection muxes + pub mux: super::mux::ClockMux, } impl Default for Config { @@ -49,8 +48,8 @@ impl Default for Config { apb2_pre: APBPrescaler::DIV1, apb7_pre: APBPrescaler::DIV1, ls: Default::default(), - adc_clock_source: AdcClockSource::HCLK4, voltage_scale: VoltageScale::RANGE2, + mux: Default::default(), } } } @@ -152,7 +151,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre2(config.apb2_pre); }); - RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source)); + config.mux.init(); set_clocks!( sys: Some(sys_clk), diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index 190fb274f..373697ec8 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -606,13 +606,6 @@ impl<'d, T: Instance> Bus<'d, T> { // Wait for USB power to stabilize while !crate::pac::PWR.cr3().read().usb33rdy() {} - // Use internal 48MHz HSI clock. Should be enabled in RCC by default. - critical_section::with(|_| { - crate::pac::RCC - .d2ccip2r() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)) - }); - // Enable ULPI clock if external PHY is used let ulpien = !self.phy_type.internal(); critical_section::with(|_| { @@ -645,13 +638,6 @@ impl<'d, T: Instance> Bus<'d, T> { // Wait for USB power to stabilize while !crate::pac::PWR.svmsr().read().vddusbrdy() {} - - // Select HSI48 as USB clock source. - critical_section::with(|_| { - crate::pac::RCC.ccipr1().modify(|w| { - w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); - }) - }); } ::enable_and_reset(); diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 7c6d6cd71..e6d1a6c02 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb1_pre = APBPrescaler::DIV2; config.rcc.apb2_pre = APBPrescaler::DIV1; - config.rcc.mux.hrtim1sw = Some(embassy_stm32::rcc::mux::Timsw::PLL1_P); + config.rcc.mux.hrtim1sw = embassy_stm32::rcc::mux::Timsw::PLL1_P; } let p = embassy_stm32::init(config); diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs index 3f63d0dfd..647ff0419 100644 --- a/examples/stm32g0/src/bin/hf_timer.rs +++ b/examples/stm32g0/src/bin/hf_timer.rs @@ -4,37 +4,35 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; -use embassy_stm32::pac::rcc::vals::Tim1sel; -use embassy_stm32::rcc::{Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr, Sysclk}; use embassy_stm32::time::khz; use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; use embassy_stm32::timer::simple_pwm::PwmPin; use embassy_stm32::timer::Channel; -use embassy_stm32::{pac, Config as PeripheralConfig}; +use embassy_stm32::Config as PeripheralConfig; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let mut rcc_config = RccConfig::default(); - rcc_config.sys = Sysclk::PLL(PllConfig { - source: PllSource::HSI, - m: Pllm::DIV1, - n: Plln::MUL16, - r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) - q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) - p: None, - }); + let mut config = PeripheralConfig::default(); + { + use embassy_stm32::rcc::*; - let mut peripheral_config = PeripheralConfig::default(); - peripheral_config.rcc = rcc_config; + config.rcc.sys = Sysclk::PLL(PllConfig { + source: PllSource::HSI, + m: Pllm::DIV1, + n: Plln::MUL16, + r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) + q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) + p: None, + }); - let p = embassy_stm32::init(peripheral_config); - - // configure TIM1 mux to select PLLQ as clock source - // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf - // RM0444 page 210 - // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1 - pac::RCC.ccipr().modify(|w| w.set_tim1sel(Tim1sel::PLL1_Q)); + // configure TIM1 mux to select PLLQ as clock source + // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + // RM0444 page 210 + // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1 + config.rcc.mux.tim1sel = embassy_stm32::rcc::mux::Tim1sel::PLL1_Q; + } + let p = embassy_stm32::init(config); let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull); diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs index f5aaa5624..8b9915626 100644 --- a/examples/stm32g0/src/bin/usb_serial.rs +++ b/examples/stm32g0/src/bin/usb_serial.rs @@ -4,7 +4,6 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_stm32::rcc::{Hsi48Config, UsbSrc}; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; @@ -19,10 +18,11 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.usb_src = Some(UsbSrc::Hsi48(Hsi48Config { - sync_from_usb: true, - ..Default::default() - })); + { + use embassy_stm32::rcc::*; + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); + config.rcc.mux.usbsel = mux::Usbsel::HSI48; + } let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index 6c6de1ffe..f81335f93 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; -use embassy_stm32::rcc::{AdcClockSource, Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk}; use embassy_stm32::Config; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -12,20 +11,20 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - - config.rcc.pll = Some(Pll { - source: Pllsrc::HSI, - prediv: PllPreDiv::DIV4, - mul: PllMul::MUL85, - divp: None, - divq: None, - // Main system clock at 170 MHz - divr: Some(PllRDiv::DIV2), - }); - - config.rcc.adc12_clock_source = AdcClockSource::SYS; - config.rcc.sys = Sysclk::PLL1_R; - + { + use embassy_stm32::rcc::*; + config.rcc.pll = Some(Pll { + source: Pllsrc::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, + // Main system clock at 170 MHz + divr: Some(PllRDiv::DIV2), + }); + config.rcc.mux.adc12sel = mux::Adcsel::SYS; + config.rcc.sys = Sysclk::PLL1_R; + } let mut p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index a41f765c1..7551b2a55 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -3,6 +3,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; +use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, can, Config}; use embassy_time::Timer; use static_cell::StaticCell; @@ -15,8 +16,24 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - let config = Config::default(); - + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(24_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll = Some(Pll { + source: Pllsrc::HSE, + prediv: PllPreDiv::DIV6, + mul: PllMul::MUL85, + divp: None, + divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan. + divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz + }); + config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q; + config.rcc.sys = Sysclk::PLL1_R; + } let peripherals = embassy_stm32::init(config); let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs index 5274de79d..2609abfa2 100644 --- a/examples/stm32g4/src/bin/pll.rs +++ b/examples/stm32g4/src/bin/pll.rs @@ -12,6 +12,7 @@ use {defmt_rtt as _, panic_probe as _}; async fn main(_spawner: Spawner) { let mut config = Config::default(); + config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: Pllsrc::HSI, prediv: PllPreDiv::DIV4, diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index 989fef5b0..90caaae14 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -3,9 +3,6 @@ use defmt::{panic, *}; use embassy_executor::Spawner; -use embassy_stm32::rcc::{ - Clk48Src, Hse, HseMode, Hsi48Config, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, Pllsrc, Sysclk, -}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{self, Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, Config}; @@ -22,38 +19,27 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - - // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE. - const USE_HSI48: bool = true; - - let plldivq = if USE_HSI48 { None } else { Some(PllQDiv::DIV6) }; - - config.rcc.hse = Some(Hse { - freq: Hertz(8_000_000), - mode: HseMode::Oscillator, - }); - - config.rcc.pll = Some(Pll { - source: Pllsrc::HSE, - prediv: PllPreDiv::DIV2, - mul: PllMul::MUL72, - divp: None, - divq: plldivq, - // Main system clock at 144 MHz - divr: Some(PllRDiv::DIV2), - }); - - config.rcc.sys = Sysclk::PLL1_R; - config.rcc.boost = true; // BOOST! - - if USE_HSI48 { + { + use embassy_stm32::rcc::*; // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); - config.rcc.clk48_src = Clk48Src::HSI48; - } else { - config.rcc.clk48_src = Clk48Src::PLL1_Q; + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll = Some(Pll { + source: Pllsrc::HSE, + prediv: PllPreDiv::DIV2, + mul: PllMul::MUL72, + divp: None, + divq: Some(PllQDiv::DIV6), // 48mhz + divr: Some(PllRDiv::DIV2), // Main system clock at 144 MHz + }); + config.rcc.sys = Sysclk::PLL1_R; + config.rcc.boost = true; // BOOST! + config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; + //config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; // uncomment to use PLL1_Q instead. } - let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index e5ccfe4f7..643df27f9 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs @@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) { freq: embassy_stm32::time::Hertz(25_000_000), mode: rcc::HseMode::Oscillator, }); - config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + config.rcc.mux.fdcan12sel = rcc::mux::Fdcansel::HSE; let peripherals = embassy_stm32::init(config); diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index 208493d8c..83477c8fa 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -5,7 +5,7 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; @@ -41,15 +41,12 @@ async fn main(_spawner: Spawner) { config.rcc.apb3_pre = APBPrescaler::DIV4; config.rcc.sys = Sysclk::PLL1_P; config.rcc.voltage_scale = VoltageScale::Scale0; + config.rcc.mux.usbsel = mux::Usbsel::HSI48; } let p = embassy_stm32::init(config); info!("Hello World!"); - pac::RCC.ccipr4().write(|w| { - w.set_usbsel(pac::rcc::vals::Usbsel::HSI48); - }); - // Create the driver, from the HAL. let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index f0278239f..a5594d10c 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs @@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; } let mut p = embassy_stm32::init(config); diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index e5ccfe4f7..13a6a5051 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs @@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) { freq: embassy_stm32::time::Hertz(25_000_000), mode: rcc::HseMode::Oscillator, }); - config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; let peripherals = embassy_stm32::init(config); diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs index a9bf46de0..a6f969aba 100644 --- a/examples/stm32h7/src/bin/dac.rs +++ b/examples/stm32h7/src/bin/dac.rs @@ -40,7 +40,7 @@ fn main() -> ! { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; } let p = embassy_stm32::init(config); diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index d88bd838f..feec28993 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -42,7 +42,7 @@ async fn main(spawner: Spawner) { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; } // Initialize the board and obtain a Peripherals instance diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index 910944673..a9f4604aa 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_stm32::adc::{Adc, Resolution}; -use embassy_stm32::pac; +use embassy_stm32::Config; use embassy_time::Delay; use {defmt_rtt as _, panic_probe as _}; @@ -11,12 +11,12 @@ use {defmt_rtt as _, panic_probe as _}; fn main() -> ! { info!("Hello World!"); - pac::RCC.ccipr().modify(|w| { - w.set_adcsel(pac::rcc::vals::Adcsel::SYS); - }); - pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); - - let p = embassy_stm32::init(Default::default()); + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.mux.adcsel = mux::Adcsel::SYS; + } + let p = embassy_stm32::init(config); let mut adc = Adc::new(p.ADC1, &mut Delay); //adc.enable_vref(); diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index f21aa797c..dd78d7fb3 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -33,7 +33,7 @@ fn options() -> TestOptions { freq: embassy_stm32::time::Hertz(25_000_000), mode: rcc::HseMode::Oscillator, }); - c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; TestOptions { config: c, max_latency: Duration::from_micros(1200), @@ -50,7 +50,7 @@ fn options() -> TestOptions { freq: embassy_stm32::time::Hertz(25_000_000), mode: rcc::HseMode::Oscillator, }); - c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; + c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; TestOptions { config: c, max_latency: Duration::from_micros(1200), diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 7b9585afd..cf3e04a4b 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -2,6 +2,8 @@ pub use defmt::*; #[allow(unused)] +use embassy_stm32::rcc::*; +#[allow(unused)] use embassy_stm32::time::Hertz; use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; @@ -265,7 +267,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f091rc")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Bypass, @@ -281,7 +282,6 @@ pub fn config() -> Config { } #[cfg(feature = "stm32f103c8")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Oscillator, @@ -298,7 +298,6 @@ pub fn config() -> Config { } #[cfg(feature = "stm32f207zg")] { - use embassy_stm32::rcc::*; // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), @@ -327,7 +326,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f303ze")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Bypass, @@ -345,7 +343,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f429zi")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Bypass, @@ -366,7 +363,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f446re")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Oscillator, @@ -387,7 +383,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32f767zi")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(8_000_000), mode: HseMode::Bypass, @@ -408,7 +403,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32h563zi")] { - use embassy_stm32::rcc::*; config.rcc.hsi = None; config.rcc.hsi48 = Some(Default::default()); // needed for RNG config.rcc.hse = Some(Hse { @@ -433,7 +427,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32h503rb")] { - use embassy_stm32::rcc::*; config.rcc.hsi = None; config.rcc.hsi48 = Some(Default::default()); // needed for RNG config.rcc.hse = Some(Hse { @@ -456,9 +449,26 @@ pub fn config() -> Config { config.rcc.voltage_scale = VoltageScale::Scale0; } + #[cfg(feature = "stm32g491re")] + { + config.rcc.hse = Some(Hse { + freq: Hertz(24_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll = Some(Pll { + source: Pllsrc::HSE, + prediv: PllPreDiv::DIV6, + mul: PllMul::MUL85, + divp: None, + divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan. + divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz + }); + config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q; + config.rcc.sys = Sysclk::PLL1_R; + } + #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.csi = true; config.rcc.hsi48 = Some(Default::default()); // needed for RNG @@ -485,7 +495,7 @@ pub fn config() -> Config { config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.voltage_scale = VoltageScale::Scale1; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; #[cfg(any(feature = "stm32h755zi"))] { config.rcc.supply_config = SupplyConfig::DirectSMPS; @@ -494,7 +504,6 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32h7a3zi"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.csi = true; config.rcc.hsi48 = Some(Default::default()); // needed for RNG @@ -521,12 +530,11 @@ pub fn config() -> Config { config.rcc.apb3_pre = APBPrescaler::DIV2; // 140 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 140 Mhz config.rcc.voltage_scale = VoltageScale::Scale0; - config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; } #[cfg(any(feature = "stm32l496zg", feature = "stm32l4a6zg", feature = "stm32l4r5zi"))] { - use embassy_stm32::rcc::*; config.rcc.sys = Sysclk::PLL1_R; config.rcc.hsi = true; config.rcc.pll = Some(Pll { @@ -541,7 +549,6 @@ pub fn config() -> Config { #[cfg(feature = "stm32wl55jc")] { - use embassy_stm32::rcc::*; config.rcc.hse = Some(Hse { freq: Hertz(32_000_000), mode: HseMode::Bypass, @@ -560,7 +567,6 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32l552ze"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.sys = Sysclk::PLL1_R; config.rcc.pll = Some(Pll { @@ -576,7 +582,6 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.pll1 = Some(Pll { source: PllSource::HSI, // 16 MHz @@ -593,17 +598,12 @@ pub fn config() -> Config { #[cfg(feature = "stm32wba52cg")] { - use embassy_stm32::rcc::*; config.rcc.sys = Sysclk::HSI; - - embassy_stm32::pac::RCC.ccipr2().write(|w| { - w.set_rngsel(embassy_stm32::pac::rcc::vals::Rngsel::HSI); - }); + config.rcc.mux.rngsel = mux::Rngsel::HSI; } #[cfg(feature = "stm32l073rz")] { - use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: PllSource::HSI, @@ -615,7 +615,6 @@ pub fn config() -> Config { #[cfg(any(feature = "stm32l152re"))] { - use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: PllSource::HSI,