diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 3f85d9e6..a25b5708 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::{Enum, Field}; +use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, METADATA}; fn main() { let chip_name = match env::vars() @@ -361,6 +362,32 @@ fn main() { }); } + // ======== + // Generate rcc fieldset and enum maps + let rcc_registers = METADATA + .peripherals + .iter() + .filter_map(|p| p.registers.as_ref()) + .find(|r| r.kind == "rcc") + .unwrap() + .ir; + + let rcc_fieldset_map: HashMap> = rcc_registers + .fieldsets + .iter() + .map(|f| { + ( + f.name.to_ascii_uppercase(), + f.fields.iter().map(|f| (f.name.to_ascii_uppercase(), f)).collect(), + ) + }) + .collect(); + let rcc_enum_map: HashMap = rcc_registers + .enums + .iter() + .map(|e| (e.name.to_ascii_uppercase(), e)) + .collect(); + // ======== // Generate RccPeripheral impls @@ -428,10 +455,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_fieldset_map.get(mux.register)?; + let field = fieldset.get(mux.field)?; + let enum_name = field.enumm?; + let enumm = rcc_enum_map.get(enum_name.to_ascii_uppercase().as_str())?; + + Some((mux, enumm)) + }; + + let clock_frequency = match mux_for(rcc.mux.as_ref()) { + Some((mux, rcc_enumm)) => { + let fieldset_name = format_ident!("{}", mux.register.to_ascii_lowercase()); + let field_name = format_ident!("{}", mux.field.to_ascii_lowercase()); + let enum_name = format_ident!("{}", rcc_enumm.name); + + let match_arms: TokenStream = rcc_enumm + .variants + .iter() + .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; + + 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(|_| { diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 5f9cc1c8..b9c8e7bd 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -577,6 +577,53 @@ pub(crate) unsafe fn init(config: Config) { rtc: rtc_clk, #[cfg(stm32h7)] rtc_hse: None, + + #[cfg(stm32h5)] + mux_rcc_pclk1: None, + #[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: None, + #[cfg(stm32h5)] + mux_pll2_p: None, + #[cfg(stm32h5)] + mux_pll3_p: None, + #[cfg(stm32h5)] + mux_audioclk: None, + #[cfg(stm32h5)] + mux_per: None, + + #[cfg(stm32h5)] + mux_pll3_r: None, + #[cfg(stm32h5)] + mux_rcc_pclk3: None, + #[cfg(stm32h5)] + mux_pll3_1: None, + #[cfg(stm32h5)] + mux_hsi48_ker: None, + #[cfg(stm32h5)] + mux_lsi_ker: None, + #[cfg(stm32h5)] + mux_pll2_r: None, + #[cfg(stm32h5)] + mux_rcc_pclk2: None, + #[cfg(stm32h5)] + mux_rcc_pclk4: None, + #[cfg(stm32h5)] + mux_hse: None, + + #[cfg(stm32h5)] + mux_disable: None, + #[cfg(stm32h5)] + mux_hsi48: None, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index a3299089..0d2d672f 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -141,6 +141,54 @@ pub struct Clocks { #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_h7, rcc_h7rm0433, rcc_h7ab))] /// Set if the hse is configured, indicates stop is not supported pub rtc_hse: 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(stm32h5)] + 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_disable: Option, + #[cfg(stm32h5)] + pub mux_hsi48: Option, } #[cfg(feature = "low-power")]