diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index fa10b7f7..5b6b22ea 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -5,7 +5,8 @@ use std::{env, fs}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; -use stm32_metapac::metadata::{MemoryRegionKind, METADATA}; +use stm32_metapac::metadata::ir::{BlockItemInner, Enum}; +use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, METADATA}; fn main() { let target = env::var("TARGET").unwrap(); @@ -387,6 +388,51 @@ fn main() { }); } + // ======== + // Generate rcc fieldset and enum maps + let rcc_enum_map: HashMap<&str, HashMap<&str, &Enum>> = { + let rcc_registers = METADATA + .peripherals + .iter() + .filter_map(|p| p.registers.as_ref()) + .find(|r| r.kind == "rcc") + .unwrap() + .ir; + + let rcc_blocks = rcc_registers.blocks.iter().find(|b| b.name == "Rcc").unwrap().items; + + let rcc_block_item_map: HashMap<&str, &str> = rcc_blocks + .iter() + .filter_map(|b| match &b.inner { + BlockItemInner::Register(register) => register.fieldset.map(|f| (f, b.name)), + _ => None, + }) + .collect(); + + let rcc_enum_map: HashMap<&str, &Enum> = rcc_registers.enums.iter().map(|e| (e.name, e)).collect(); + + rcc_registers + .fieldsets + .iter() + .filter_map(|f| { + rcc_block_item_map.get(f.name).map(|b| { + ( + *b, + f.fields + .iter() + .filter_map(|f| { + let enumm = f.enumm?; + let enumm = rcc_enum_map.get(enumm)?; + + Some((f.name, *enumm)) + }) + .collect(), + ) + }) + }) + .collect() + }; + // ======== // Generate RccPeripheral impls @@ -454,10 +500,61 @@ fn main() { (TokenStream::new(), TokenStream::new()) }; + let mux_for = |mux: Option<&'static PeripheralRccRegister>| { + // temporary hack to restrict the scope of the implementation to h5 + if !&chip_name.starts_with("stm32h5") { + return None; + } + + let mux = mux?; + let fieldset = rcc_enum_map.get(mux.register)?; + let enumm = fieldset.get(mux.field)?; + + Some((mux, *enumm)) + }; + + let clock_frequency = match mux_for(rcc.mux.as_ref()) { + Some((mux, rcc_enumm)) => { + let fieldset_name = format_ident!("{}", mux.register); + let field_name = format_ident!("{}", mux.field); + let enum_name = format_ident!("{}", rcc_enumm.name); + + let match_arms: TokenStream = rcc_enumm + .variants + .iter() + .filter(|v| v.name != "DISABLE") + .map(|v| { + let variant_name = format_ident!("{}", v.name); + + // temporary hack to restrict the scope of the implementation until clock names can be stabilized + let clock_name = format_ident!("mux_{}", 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!(), + } + } + } + None => quote! { + unsafe { crate::rcc::get_freqs().#clk } + }, + }; + g.extend(quote! { impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { fn frequency() -> crate::time::Hertz { - unsafe { crate::rcc::get_freqs().#clk } + #clock_frequency } fn enable() { critical_section::with(|_cs| { @@ -486,12 +583,14 @@ fn main() { } } - let mut refcount_mod = TokenStream::new(); - for refcount_static in refcount_statics { - refcount_mod.extend(quote! { - pub(crate) static mut #refcount_static: u8 = 0; - }); - } + let refcount_mod: TokenStream = refcount_statics + .iter() + .map(|refcount_static| { + quote! { + pub(crate) static mut #refcount_static: u8 = 0; + } + }) + .collect(); g.extend(quote! { mod refcount_statics { diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 7236d82f..d37dd45d 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -388,7 +388,7 @@ pub(crate) unsafe fn init(config: Config) { 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 pll3 = init_pll(2, config.pll3, &pll_input); // Configure sysclk let (sys, sw) = match config.sys { @@ -447,7 +447,7 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h7)] let adc = match config.adc_clock_source { AdcClockSource::PLL2_P => pll2.p, - AdcClockSource::PLL3_R => _pll3.r, + AdcClockSource::PLL3_R => pll3.r, AdcClockSource::PER => _per_ck, _ => unreachable!(), }; @@ -545,6 +545,53 @@ pub(crate) unsafe fn init(config: Config) { apb2_tim, adc, rtc, + + #[cfg(stm32h5)] + mux_rcc_pclk1: Some(apb1), + #[cfg(stm32h5)] + mux_pll2_q: None, + #[cfg(stm32h5)] + mux_pll3_q: None, + #[cfg(stm32h5)] + mux_hsi_ker: None, + #[cfg(stm32h5)] + mux_csi_ker: None, + #[cfg(stm32h5)] + mux_lse: None, + #[cfg(stm32h5)] + mux_pll1_q: pll1.q, + #[cfg(stm32h5)] + mux_pll2_p: pll2.p, + #[cfg(rcc_h5)] + mux_pll3_p: pll3.p, + #[cfg(stm32h5)] + mux_audioclk: None, + #[cfg(stm32h5)] + mux_per: None, + + #[cfg(rcc_h5)] + mux_pll3_r: pll3.r, + #[cfg(all(not(rcc_h5), stm32h5))] + mux_pll3_r: None, + #[cfg(stm32h5)] + mux_rcc_pclk3: Some(apb3), + #[cfg(stm32h5)] + mux_pll3_1: None, + #[cfg(stm32h5)] + mux_hsi48_ker: None, + #[cfg(stm32h5)] + mux_lsi_ker: None, + #[cfg(stm32h5)] + mux_pll2_r: pll2.r, + #[cfg(stm32h5)] + mux_rcc_pclk2: Some(apb2), + #[cfg(stm32h5)] + mux_rcc_pclk4: None, + #[cfg(stm32h5)] + mux_hse: hse, + + #[cfg(stm32h5)] + mux_hsi48: None, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index abb53fd1..695d4158 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -134,6 +134,52 @@ pub struct Clocks { pub hrtim: Option, pub rtc: Option, + + #[cfg(stm32h5)] + pub mux_rcc_pclk1: Option, + #[cfg(stm32h5)] + pub mux_pll2_q: Option, + #[cfg(stm32h5)] + pub mux_pll3_q: Option, + #[cfg(stm32h5)] + pub mux_hsi_ker: Option, + #[cfg(stm32h5)] + pub mux_csi_ker: Option, + #[cfg(stm32h5)] + pub mux_lse: Option, + + #[cfg(stm32h5)] + pub mux_pll1_q: Option, + #[cfg(stm32h5)] + pub mux_pll2_p: Option, + #[cfg(rcc_h5)] + pub mux_pll3_p: Option, + #[cfg(stm32h5)] + pub mux_audioclk: Option, + #[cfg(stm32h5)] + pub mux_per: Option, + + #[cfg(stm32h5)] + pub mux_pll3_r: Option, + #[cfg(stm32h5)] + pub mux_rcc_pclk3: Option, + #[cfg(stm32h5)] + pub mux_pll3_1: Option, + #[cfg(stm32h5)] + pub mux_hsi48_ker: Option, + #[cfg(stm32h5)] + pub mux_lsi_ker: Option, + #[cfg(stm32h5)] + pub mux_pll2_r: Option, + #[cfg(stm32h5)] + pub mux_rcc_pclk2: Option, + #[cfg(stm32h5)] + pub mux_rcc_pclk4: Option, + #[cfg(stm32h5)] + pub mux_hse: Option, + + #[cfg(stm32h5)] + pub mux_hsi48: Option, } #[cfg(feature = "low-power")]