diff --git a/.helix/languages.toml b/.helix/languages.toml deleted file mode 100644 index d34df4b248..0000000000 --- a/.helix/languages.toml +++ /dev/null @@ -1,11 +0,0 @@ -[language-server.rust-analyzer.config.cargo] -allTargets = false -noDefaultFeatures = true -target = "thumbv8m.main-none-eabihf" -features = ["stm32n657x0", "time-driver-any", "unstable-pac", "exti"] - -[language-server.rust-analyzer.config.check] -allTargets = false -noDefaultFeatures = true -target = "thumbv8m.main-none-eabihf" -features = ["stm32n657x0", "time-driver-any", "unstable-pac", "exti"] diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs index 3a49ef6f57..560692807b 100644 --- a/embassy-mspm0/build.rs +++ b/embassy-mspm0/build.rs @@ -90,6 +90,26 @@ fn get_chip_cfgs(chip_name: &str) -> Vec { cfgs.push("mspm0c1105_c1106".to_string()); } + if chip_name.starts_with("mspm0g") { + // G-series + cfgs.push("mspm0g".to_string()); + } + + if chip_name.starts_with("mspm0l") { + // L-series + cfgs.push("mspm0l".to_string()); + } + + if chip_name.starts_with("mspm0c") { + // C-series + cfgs.push("mspm0c".to_string()); + } + + if chip_name.starts_with("mspm0h") { + // H-series + cfgs.push("mspm0h".to_string()); + } + // Family ranges (temporary until int groups are generated) // // TODO: Remove this once int group stuff is generated. @@ -582,8 +602,14 @@ fn generate_timers() -> TokenStream { quote! { Bits32 } }; + let prescaler = if timer.prescaler { + quote! { Bits8 } + } else { + quote! { None } + }; + quote! { - impl_timer!(#name, #bits); + impl_timer!(#name, #bits, #prescaler); } }); diff --git a/embassy-mspm0/src/clocks.rs b/embassy-mspm0/src/clocks.rs new file mode 100644 index 0000000000..77c428cc9b --- /dev/null +++ b/embassy-mspm0/src/clocks.rs @@ -0,0 +1,273 @@ +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; + +use mspm0_metapac::sysctl::vals::FcccmdKey; + +use crate::pac; + +pub(crate) struct Clocks { + /// PLL, SYSOSC, or HFXT + pub m_clk: AtomicU32, + /// LFOSC or LFXT + pub rtc_clk: AtomicU32, + /// ULPCLK + #[cfg(mspm0g)] + pub ulp_clk: AtomicU32, + /// MFCLK + pub mf_clk: AtomicU32, + /// SYSOSC + pub sys_osc: AtomicU32, + // HFCLK + // pub hf_clk: AtomicU32, +} + +pub(crate) static CLOCKS: Clocks = Clocks { + m_clk: AtomicU32::new(0), + rtc_clk: AtomicU32::new(0), + #[cfg(mspm0g)] + ulp_clk: AtomicU32::new(0), + mf_clk: AtomicU32::new(0), + sys_osc: AtomicU32::new(0), + // hf_clk: AtomicU32::new(0), +}; + +#[cfg(mspm0g)] +#[derive(Clone)] +pub struct PllConfig { + pub pdiv: u8, + pub qdiv: u8, + pub rdiv2x: u8, +} + +#[derive(Clone)] +pub enum SysOscSpeed { + HighSpeed, + // UserTrim, + LowSpeed, +} + +impl SysOscSpeed { + pub fn frequency(&self) -> u32 { + match self { + #[cfg(any(mspm0g, mspm0l, mspm0h))] + SysOscSpeed::HighSpeed => 32_000_000, + // NOTE: TRM is not clear about limit also specifying 32MHz possible + #[cfg(any(mspm0c))] + SysOscSpeed::HighSpeed => 24_000_000, + // SysOscSpeed::UserTrim => unimplemented!(), + SysOscSpeed::LowSpeed => 4_000_000, + } + } +} + +#[derive(Clone)] +pub struct SysOscConfig { + pub fcl_enabled: bool, + pub speed: SysOscSpeed, +} + +#[derive(Clone)] +pub enum MClkSource { + #[cfg(mspm0g)] + PLL, + SYSOSC, + LFCLK, + HFCLK, +} + +#[derive(Clone)] +pub struct ClockConfig { + #[cfg(mspm0g)] + pub pll_config: Option, + + pub sysosc_config: SysOscConfig, + + pub mclk_source: MClkSource, +} + +impl Default for ClockConfig { + fn default() -> Self { + Self { + #[cfg(mspm0g)] + pll_config: Some(PllConfig { + pdiv: 0, + qdiv: 1, + rdiv2x: 0, + }), + sysosc_config: SysOscConfig { + fcl_enabled: true, + speed: SysOscSpeed::HighSpeed, + }, + #[cfg(mspm0g)] + mclk_source: MClkSource::PLL, + #[cfg(not(mspm0g))] + mclk_source: MClkSource::SYSOSC, + } + } +} + +// TODO: Debug utils; to be moved +pub fn start_measure_frequency() { + pac::SYSCTL.genclkcfg().modify(|w| { + w.set_fccselclk(mspm0_metapac::sysctl::vals::Fccselclk::SYSPLLCLK0); + w.set_fcclvltrig(mspm0_metapac::sysctl::vals::Fcclvltrig::RISE2RISE); + w.set_fcctrigsrc(mspm0_metapac::sysctl::vals::Fcctrigsrc::LFCLK); + w.set_fcctrigcnt(0x1F); + }); + + compiler_fence(Ordering::SeqCst); + + pac::SYSCTL.fcccmd().write(|w| { + w.set_go(true); + w.set_key(FcccmdKey::KEY); + }) +} + +pub fn frequency() -> Option { + let status = pac::SYSCTL.clkstatus().read(); + #[cfg(feature = "defmt")] + defmt::warn!( + "PLL status off={}, good={}; hsclkoff={}, hsclkgood={}, sysosc_freq={}", + status.sysplloff(), + status.syspllgood(), + status.hsclksoff(), + status.hsclkgood(), + status.sysoscfreq() as u8 + ); + + if status.fccdone() { + Some(pac::SYSCTL.fcc().read().data() * 32768 / 0x20) + } else { + None + } +} + +// TODO: create extensive ClockConfig +pub(crate) unsafe fn init(config: ClockConfig) { + // TODO: Further clock configuration + + CLOCKS.m_clk.store( + match config.mclk_source { + #[cfg(mspm0g)] + MClkSource::PLL => 80_000_000, // TODO: calculate + MClkSource::SYSOSC => config.sysosc_config.speed.frequency(), + MClkSource::LFCLK => unimplemented!("LFCLK is not supported yet"), + MClkSource::HFCLK => unimplemented!("HFCLK is not supported yet"), + }, + Ordering::Relaxed, + ); + + CLOCKS.rtc_clk.store(32_000, Ordering::Relaxed); + CLOCKS.mf_clk.store(4_000_000, Ordering::Relaxed); + CLOCKS + .sys_osc + .store(config.sysosc_config.speed.frequency(), Ordering::Relaxed); + + // TODO: this can deviate in case HF/PLL is not running at max freq + #[cfg(mspm0g)] + CLOCKS.ulp_clk.store(40_000_000, Ordering::Relaxed); + + pac::SYSCTL.sysosccfg().modify(|w| { + w.set_freq(match config.sysosc_config.speed { + SysOscSpeed::HighSpeed => mspm0_metapac::sysctl::vals::SysosccfgFreq::SYSOSCBASE, + SysOscSpeed::LowSpeed => mspm0_metapac::sysctl::vals::SysosccfgFreq::SYSOSC4M, + }); + }); + + // Enable MFCLK for peripheral use + // + // NOTE: Only used for DAC peripheral + pac::SYSCTL.genclken().modify(|w| { + w.set_mfpclken(true); + }); + + if config.sysosc_config.fcl_enabled { + pac::SYSCTL.sysoscfclctl().write(|w| { + w.set_setusefcl(config.sysosc_config.fcl_enabled); + // FIXME: this should exist for mspm0c/mspm0l + #[cfg(not(any(mspm0c, mspm0l, mspm0h)))] + w.set_setuseexres(config.sysosc_config.fcl_enabled); + }); + } + + #[cfg(mspm0g)] + if let Some(pll_config) = config.pll_config { + // TODO: assert this requires sys_osc.speed == HighSpeed + + pac::SYSCTL.syspllcfg0().modify(|w| { + w.set_syspllref(mspm0_metapac::sysctl::vals::Syspllref::SYSOSC); + w.set_enableclk2x(true); + w.set_enableclk1(true); + w.set_enableclk0(true); // FIXME: this probably isn't needed + w.set_mclk2xvco(false); + w.set_rdivclk1(mspm0_metapac::sysctl::vals::Rdivclk1::CLK1DIV2); + w.set_rdivclk2x(mspm0_metapac::sysctl::vals::Rdivclk2x::from_bits(pll_config.rdiv2x)); + }); + + // let divs = crate::common::hillclimb([0u32, 1u32, 0u32], |divs| { + // if divs[0] > 3 || !(1..127).contains(&divs[1]) || divs[2] > 15 { + // return i32::MAX; + // } + + // let pdiv = 1 << divs[0]; + // let qdiv = divs[1] + 1; + // let rdiv = divs[2] + 1; + // target_freq as i32 - (((2 * common::get_mclk_frequency() * qdiv) / pdiv) / rdiv) as i32 + // }); + + // Load PLL params from factory region (16-32MHz) + let pll_params_0 = core::ptr::read_volatile(0x41C4001C as *const u32); + let pll_params_1 = core::ptr::read_volatile(0x41C40020 as *const u32); + (pac::SYSCTL.syspllparam0().as_ptr() as *mut u32).write_volatile(pll_params_0); + (pac::SYSCTL.syspllparam1().as_ptr() as *mut u32).write_volatile(pll_params_1); + + pac::SYSCTL.syspllcfg1().modify(|w| { + w.set_pdiv(mspm0_metapac::sysctl::vals::Pdiv::from_bits(pll_config.pdiv)); + w.set_qdiv(mspm0_metapac::sysctl::vals::Qdiv(pll_config.qdiv)); + }); + + pac::SYSCTL.hsclken().modify(|w| { + w.set_syspllen(true); + }); + pac::SYSCTL.hsclkcfg().modify(|w| { + // For now PLL is assumed + w.set_hsclksel(mspm0_metapac::sysctl::vals::Hsclksel::SYSPLL); + }); + pac::SYSCTL + .genclkcfg() + .modify(|w| w.set_canclksrc(mspm0_metapac::sysctl::vals::Canclksrc::SYSPLLOUT1)); + + cortex_m::asm::delay(2_000_000); // Wait a bit for PLL to catch up + } + + // FIXME: this should exist for mpsm0c/mspm0l + #[cfg(not(any(mspm0c, mspm0l, mspm0h)))] + pac::SYSCTL.hsclkcfg().modify(|w| match config.mclk_source { + #[cfg(mspm0g)] + MClkSource::PLL => w.set_hsclksel(mspm0_metapac::sysctl::vals::Hsclksel::SYSPLL), + MClkSource::HFCLK => w.set_hsclksel(mspm0_metapac::sysctl::vals::Hsclksel::HFCLKCLK), + _ => {} + }); + + pac::SYSCTL.mclkcfg().modify(|w| { + match config.mclk_source { + MClkSource::SYSOSC => { + w.set_usemftick(true); + w.set_mdiv(0); + } + #[cfg(mspm0g)] + MClkSource::PLL => { + w.set_flashwait(mspm0_metapac::sysctl::vals::Flashwait::WAIT2); + w.set_usehsclk(true); + } + MClkSource::HFCLK => { + // FIXME: this should exist for MSPM0L + w.set_flashwait(mspm0_metapac::sysctl::vals::Flashwait::WAIT2); + #[cfg(not(mspm0l))] + w.set_usehsclk(true); + } + MClkSource::LFCLK => { + w.set_uselfclk(true); + } + } + }); +} diff --git a/embassy-mspm0/src/common.rs b/embassy-mspm0/src/common.rs new file mode 100644 index 0000000000..92c1e7ad87 --- /dev/null +++ b/embassy-mspm0/src/common.rs @@ -0,0 +1,60 @@ +/// Naive hill-climbing algorithm +/// +/// NOTE: this doesn't typically give optimal results as there is no lookahead +pub fn hillclimb i32>(mut initial_state: [u32; C], derivate_fn: F) -> [u32; C] { + let mut last_error = derivate_fn(&initial_state); + + // Check each axis to find best incline + loop { + let mut best_error: i32 = i32::MAX; + let mut best_delta: (usize, bool) = (usize::MAX, false); + for i in 0..C { + let mut test_state = initial_state.clone(); + test_state[i] = test_state[i].saturating_add(1); + let add_error = derivate_fn(&test_state).abs(); + if add_error < best_error { + best_delta = (i, false); + best_error = add_error; + } + test_state[i] = test_state[i].saturating_sub(2); + let sub_error = derivate_fn(&test_state).abs(); + if sub_error < best_error { + best_delta = (i, true); + best_error = sub_error; + } + + #[cfg(feature = "defmt")] + defmt::trace!("Evaluated axis {}, best_error {}", i, best_error); + } + + // Surrounding errors are higher than current + if best_error >= last_error.abs() { + break; + } + + last_error = best_error; + + if best_delta.1 { + initial_state[best_delta.0] -= 1; + } else { + initial_state[best_delta.0] += 1; + } + } + + initial_state +} + +#[cfg(test)] +mod tests { + use crate::common::hillclimb; + + #[test] + fn simple_optimization() { + let target = [8u32, 32u32]; + let val = hillclimb([0u32; 2], |x| { + (x[0] as i32 - target[0] as i32).abs() + (x[1] as i32 - target[1] as i32) + }); + + assert_eq!(target, val); + } +} diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index 200334c852..d615c2a3eb 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -13,6 +13,8 @@ pub(crate) mod fmt; mod macros; pub mod adc; +pub mod clocks; +mod common; pub mod dma; pub mod gpio; // TODO: I2C unicomm @@ -71,6 +73,7 @@ pub use mspm0_metapac as pac; pub(crate) use mspm0_metapac as pac; pub use crate::_generated::interrupt; +use crate::clocks::ClockConfig; /// Macro to bind interrupts to handlers. /// @@ -148,9 +151,10 @@ macro_rules! bind_interrupts { /// `embassy-mspm0` global configuration. #[non_exhaustive] -#[derive(Clone, Copy)] +#[derive(Clone)] pub struct Config { - // TODO: OSC configuration. + pub clock_config: ClockConfig, + /// The size of DMA block transfer burst. /// /// If this is set to a value @@ -167,6 +171,7 @@ pub struct Config { impl Default for Config { fn default() -> Self { Self { + clock_config: ClockConfig::default(), dma_burst_size: dma::BurstSize::Complete, dma_round_robin: false, } @@ -177,21 +182,7 @@ pub fn init(config: Config) -> Peripherals { critical_section::with(|cs| { let peripherals = Peripherals::take_with_cs(cs); - // TODO: Further clock configuration - - pac::SYSCTL.mclkcfg().modify(|w| { - // Enable MFCLK - w.set_usemftick(true); - // MDIV must be disabled if MFCLK is enabled. - w.set_mdiv(0); - }); - - // Enable MFCLK for peripheral use - // - // TODO: Optional? - pac::SYSCTL.genclken().modify(|w| { - w.set_mfpclken(true); - }); + unsafe { crate::clocks::init(config.clock_config) }; pac::SYSCTL.borthreshold().modify(|w| { w.set_level(0); diff --git a/embassy-mspm0/src/time_driver.rs b/embassy-mspm0/src/time_driver.rs index bbf7d744a7..07b8b1283f 100644 --- a/embassy-mspm0/src/time_driver.rs +++ b/embassy-mspm0/src/time_driver.rs @@ -6,7 +6,6 @@ use critical_section::{CriticalSection, Mutex}; use embassy_time_driver::Driver; use embassy_time_queue_utils::Queue; use mspm0_metapac::interrupt; -use mspm0_metapac::tim::Tim; use mspm0_metapac::tim::vals::{Cm, Cvae, CxC, EvtCfg, PwrenKey, Repeat, ResetKey}; use crate::peripherals; @@ -51,10 +50,6 @@ type T = peripherals::TIMA1; // TODO: RTC -fn regs() -> Tim { - unsafe { Tim::from_ptr(T::regs()) } -} - /// Clock timekeeping works with something we call "periods", which are time intervals /// of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods. fn calc_now(period: u32, counter: u16) -> u64 { @@ -87,7 +82,7 @@ impl TimxDriver { fn init(&'static self, _cs: CriticalSection) { // Clock config // TODO: Configurable tick rate up to 4 MHz (32 kHz for now) - let regs = regs(); + let regs = T::regs(); // Reset timer regs.gprcm(0).rstctl().write(|w| { @@ -176,7 +171,7 @@ impl TimxDriver { #[inline(never)] fn next_period(&self) { - let r = regs(); + let r = T::regs(); // We only modify the period from the timer interrupt, so we know this can't race. let period = self.period.load(Ordering::Relaxed) + 1; @@ -198,7 +193,7 @@ impl TimxDriver { #[inline(never)] fn on_interrupt(&self) { - let r = regs(); + let r = T::regs(); critical_section::with(|cs| { let mis = r.cpu_int(0).mis().read(); @@ -239,7 +234,7 @@ impl TimxDriver { } fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { - let r = regs(); + let r = T::regs(); self.alarm.borrow(cs).set(timestamp); @@ -286,7 +281,7 @@ impl TimxDriver { impl Driver for TimxDriver { fn now(&self) -> u64 { - let regs = regs(); + let regs = T::regs(); let period = self.period.load(Ordering::Relaxed); // Ensure the compiler does not read the counter before the period. diff --git a/embassy-mspm0/src/timer.rs b/embassy-mspm0/src/timer.rs index 4441e56408..b26baf874f 100644 --- a/embassy-mspm0/src/timer.rs +++ b/embassy-mspm0/src/timer.rs @@ -1,5 +1,9 @@ #![macro_use] +use embassy_hal_internal::{Peri, PeripheralType}; + +use crate::common::hillclimb; + /// Amount of bits of a timer. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -10,28 +14,179 @@ pub enum TimerBits { Bits32, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TimerPrescaler { + /// 8 bits. + Bits8, + // No prescaler + None, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TimerClockSource { + /// Bus Clock; typically 24-80MHz + BusClock, + // Middle Frequency; Fixed 4MHz clock + MFClock, + // Low Frequency; 32kHz + LFClock, +} + #[allow(private_bounds)] -pub trait Timer: SealedTimer + 'static { +pub trait Timer: PeripheralType + SealedTimer + 'static { /// Amount of bits this timer has. const BITS: TimerBits; + + /// Availability & Size of prescaler + const PRESCALER: TimerPrescaler; } pub(crate) trait SealedTimer { /// Registers for this timer. /// - /// This is a raw pointer to the register block. The actual register block layout varies depending on the - /// timer type. - fn regs() -> *mut (); + /// This is a raw pointer to the register block. The actual available registers will depends on the timer type. + fn regs() -> crate::pac::tim::Tim; /// Enable the interrupt corresponding to this timer. unsafe fn enable_interrupt(); } +/// Basic low-lever interface into a timer +pub struct LLTimer<'d, T: Timer> { + #[allow(unused)] + inner: Peri<'d, T>, +} + +impl<'d, T: Timer> LLTimer<'d, T> { + pub fn new(tim: Peri<'d, T>) -> Self { + Self { inner: tim } + } + + pub fn set_clk_source(&self, src: TimerClockSource) { + let regs = T::regs(); + regs.clksel().write_value(mspm0_metapac::tim::regs::Clksel(match src { + TimerClockSource::BusClock => 0b1000, + TimerClockSource::MFClock => 0b0100, + TimerClockSource::LFClock => 0b0010, + })); + } + + pub fn set_clk_enable(&self, enable: bool) { + let regs = T::regs(); + regs.commonregs(0).cclkctl().write(|w| { + w.set_clken(enable); + }) + } + + // Automatically configures clock frequency & tmr.load to give a periodic interrupt + // Frequency is at best-effort basis, actual frequency is returned + // + // This uses the ZeroEvent + // + // SAFETY: this requires the user to setup an interrupt handler which clears the zero interrupt + // failure to do so will block the CPU + pub unsafe fn start_periodic_timer(&self, freq: u32) -> u32 { + let regs = T::regs(); + + // Reset timer regs + regs.gprcm(0).rstctl().write(|w| { + w.set_resetassert(true); + w.set_key(mspm0_metapac::tim::vals::ResetKey::KEY); + w.set_resetstkyclr(true); + }); + regs.gprcm(0).pwren().modify(|w| { + w.set_enable(true); + w.set_key(mspm0_metapac::tim::vals::PwrenKey::KEY); + }); + // FIXME: assuming busclk for now + regs.clksel().modify(|w| w.set_busclk_sel(true)); + + let ctr = regs.counterregs(0); + + // Frequency guess + let actual_freq = self.set_clk_freq(freq * 100); + let load = actual_freq.div_ceil(freq).min(u16::MAX as u32); + + #[cfg(feature = "defmt")] + defmt::trace!("Timer LOAD={}", load); + + ctr.load().write_value(load); + ctr.ctr().write_value(load); + ctr.ctrctl().write(|w| { + w.set_cm(mspm0_metapac::tim::vals::Cm::DOWN); + w.set_repeat(mspm0_metapac::tim::vals::Repeat::REPEAT_1); + w.set_cvae(mspm0_metapac::tim::vals::Cvae::LDVAL); + w.set_en(true); + }); + + regs.cpu_int(0).imask().write(|w| { + w.set_l(true); + }); + + regs.commonregs(0).cclkctl().modify(|w| { + w.set_clken(true); + }); + + unsafe { T::enable_interrupt() }; + + actual_freq / load + } + + pub fn stop_timer(&self) { + let regs = T::regs(); + regs.counterregs(0).ctrctl().write(|w| { + w.set_en(false); + }) + } + + // Set clock rate (*not interrupt-rate*) at best-effort + // + // WARN: currently assumes BusClock with MCLK source + pub fn set_clk_freq(&self, frequency: u32) -> u32 { + let regs = T::regs(); + // Frequency is chip-specific & based on power-domain; + + // FIXME: usually BusClock is MCLK, but e.g. TIMG0 on G310x is PD0->ULPCLK, currently there is no way to distinguish + let clk_freq = crate::clocks::CLOCKS.m_clk.load(core::sync::atomic::Ordering::Relaxed); + + // TODO: use mathacl for div? + // NOTE: could also use `FEATUREVER` to find the available features + if matches!(T::PRESCALER, TimerPrescaler::Bits8) { + let div_range = 0..8u32; + // Should be optimal value for this clock + let divs = hillclimb([0u32; 2], |divs| { + if !div_range.contains(&divs[0]) || !(0..0xff).contains(&divs[1]) { + i32::MAX + } else { + clk_freq as i32 - (frequency * (divs[0] + 1) * (divs[1] + 1)) as i32 + } + }); + regs.clkdiv().write_value(mspm0_metapac::tim::regs::Clkdiv(divs[0])); + regs.commonregs(0) + .cps() + .write_value(mspm0_metapac::tim::regs::Cps(divs[1])); + + #[cfg(feature = "defmt")] + defmt::trace!("clk={}, divs[0]={} divs[1]={}", clk_freq, divs[0], divs[1]); + clk_freq / ((divs[0] + 1) * (divs[1] + 1)) + } else { + let divider = (frequency / clk_freq).saturating_sub(1); + let actual_div = divider.min(7); + regs.clkdiv().write_value(mspm0_metapac::tim::regs::Clkdiv(actual_div)); + regs.commonregs(0).cps().write_value(mspm0_metapac::tim::regs::Cps(0)); + + clk_freq / (actual_div + 1) + } + } +} + macro_rules! impl_timer { - ($name: ident, $bits: ident) => { + ($name: ident, $bits: ident, $prescaler: ident) => { impl crate::timer::SealedTimer for crate::peripherals::$name { - fn regs() -> *mut () { - crate::pac::$name.as_ptr() + fn regs() -> crate::pac::tim::Tim { + unsafe { crate::pac::tim::Tim::from_ptr(crate::pac::$name.as_ptr()) } } unsafe fn enable_interrupt() { @@ -43,6 +198,7 @@ macro_rules! impl_timer { impl crate::timer::Timer for crate::peripherals::$name { const BITS: crate::timer::TimerBits = crate::timer::TimerBits::$bits; + const PRESCALER: crate::timer::TimerPrescaler = crate::timer::TimerPrescaler::$prescaler; } }; } diff --git a/embassy-mspm0/src/trng.rs b/embassy-mspm0/src/trng.rs index 61dc1437b7..281f563fd5 100644 --- a/embassy-mspm0/src/trng.rs +++ b/embassy-mspm0/src/trng.rs @@ -2,6 +2,7 @@ use core::fmt::Display; use core::future::poll_fn; use core::marker::PhantomData; +use core::sync::atomic::Ordering; use core::task::Poll; use cortex_m::asm; @@ -280,21 +281,6 @@ impl TryRngCore for Trng<'_, D> { impl TryCryptoRng for Trng<'_, Crypto> {} -// TODO: Replace this when the MCLK rate can be adjusted. -#[cfg(any(mspm0c110x, mspm0c1105_c1106))] -fn get_mclk_frequency() -> u32 { - 24_000_000 -} - -// TODO: Replace this when the MCLK rate can be adjusted. -#[cfg(any( - mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0h321x, mspm0l110x, mspm0l122x, - mspm0l130x, mspm0l134x, mspm0l222x -))] -fn get_mclk_frequency() -> u32 { - 32_000_000 -} - // Inner TRNG driver implementation. Used to reduce monomorphization bloat. struct TrngInner<'d> { decim_rate: vals::DecimRate, @@ -356,7 +342,7 @@ impl TrngInner<'_> { fn set_div(&mut self) { // L-series TRM 13.2.2: The TRNG is derived from MCLK. Datasheets specify 9.5-20 MHz range. - let freq = get_mclk_frequency(); + let freq = crate::clocks::CLOCKS.m_clk.load(Ordering::Relaxed); let ratio = if freq > 160_000_000 { panic!("MCLK frequency {} > 160 MHz is not compatible with the TRNG", freq) } else if freq >= 80_000_000 {