From e799d6c8956ed3ea5ced65d58c3065a22927ad10 Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 14 Nov 2025 17:29:31 +0100 Subject: More work on examples --- src/adc.rs | 73 ++++++++++++++++++---------- src/clocks/mod.rs | 12 ++++- src/clocks/periph_helpers.rs | 8 ++++ src/lib.rs | 1 - src/lpuart/mod.rs | 2 +- src/ostimer.rs | 62 ++++++++++++++---------- src/reset.rs | 112 ------------------------------------------- 7 files changed, 102 insertions(+), 168 deletions(-) delete mode 100644 src/reset.rs (limited to 'src') diff --git a/src/adc.rs b/src/adc.rs index 655bf934f..b5ec5983f 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -1,6 +1,10 @@ //! ADC driver use core::sync::atomic::{AtomicBool, Ordering}; +use embassy_hal_internal::{Peri, PeripheralType}; + +use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; +use crate::clocks::{enable_and_reset, Gate, PoweredClock}; use crate::pac; use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; @@ -12,7 +16,7 @@ type Regs = pac::adc1::RegisterBlock; static INTERRUPT_TRIGGERED: AtomicBool = AtomicBool::new(false); // Token-based instance pattern like embassy-imxrt -pub trait Instance { +pub trait Instance: Gate + PeripheralType { fn ptr() -> *const Regs; } @@ -26,12 +30,12 @@ impl Instance for crate::peripherals::ADC1 { } // Also implement Instance for the Peri wrapper type -impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::ADC1> { - #[inline(always)] - fn ptr() -> *const Regs { - pac::Adc1::ptr() - } -} +// impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::ADC1> { +// #[inline(always)] +// fn ptr() -> *const Regs { +// pac::Adc1::ptr() +// } +// } #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] @@ -60,6 +64,29 @@ pub struct LpadcConfig { pub enable_conv_pause: bool, pub conv_pause_delay: u16, pub fifo_watermark: u8, + pub power: PoweredClock, + pub source: AdcClockSel, + pub div: Div4, +} + +impl Default for LpadcConfig { + fn default() -> Self { + LpadcConfig { + enable_in_doze_mode: true, + conversion_average_mode: CalAvgs::NoAverage, + enable_analog_preliminary: false, + power_up_delay: 0x80, + reference_voltage_source: Refsel::Option1, + power_level_mode: Pwrsel::Lowest, + trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, + enable_conv_pause: false, + conv_pause_delay: 0, + fifo_watermark: 0, + power: PoweredClock::NormalEnabledDeepSleepDisabled, + source: AdcClockSel::FroLfDiv, + div: Div4::no_div(), + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -94,15 +121,24 @@ pub struct ConvResult { pub conv_value: u16, } -pub struct Adc { - _inst: core::marker::PhantomData, +pub struct Adc<'a, I: Instance> { + _inst: core::marker::PhantomData<&'a mut I>, } -impl Adc { +impl<'a, I: Instance> Adc<'a, I> { /// initialize ADC - pub fn new(_inst: impl Instance, config: LpadcConfig) -> Self { + pub fn new(_inst: Peri<'a, I>, config: LpadcConfig) -> Self { let adc = unsafe { &*I::ptr() }; + let _clock_freq = unsafe { + enable_and_reset::(&AdcConfig { + power: config.power, + source: config.source, + div: config.div, + }) + .expect("Adc Init should not fail") + }; + /* Reset the module. */ adc.ctrl().modify(|_, w| w.rst().held_in_reset()); adc.ctrl().modify(|_, w| w.rst().released_from_reset()); @@ -194,21 +230,6 @@ impl Adc { adc.ctrl().modify(|_, w| w.adcen().disabled()); } - pub fn get_default_config() -> LpadcConfig { - LpadcConfig { - enable_in_doze_mode: true, - conversion_average_mode: CalAvgs::NoAverage, - enable_analog_preliminary: false, - power_up_delay: 0x80, - reference_voltage_source: Refsel::Option1, - power_level_mode: Pwrsel::Lowest, - trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, - enable_conv_pause: false, - conv_pause_delay: 0, - fifo_watermark: 0, - } - } - pub fn do_offset_calibration(&self) { let adc = unsafe { &*I::ptr() }; // Enable calibration mode diff --git a/src/clocks/mod.rs b/src/clocks/mod.rs index 24e118e38..e04f63b8e 100644 --- a/src/clocks/mod.rs +++ b/src/clocks/mod.rs @@ -79,6 +79,11 @@ pub unsafe fn assert_reset() { G::assert_reset(); } +#[inline] +pub unsafe fn is_reset_released() -> bool { + G::is_reset_released() +} + /// Pulse a reset line (assert then release) with a short delay. #[inline] pub unsafe fn pulse_reset() { @@ -150,12 +155,15 @@ pub mod gate { use super::periph_helpers::{AdcConfig, LpuartConfig, OsTimerConfig}; use super::*; + // These peripherals have no additional upstream clocks or configuration required + // other than enabling through the MRCC gate. impl_cc_gate!(PORT1, mrcc_glb_cc1, port1, NoConfig); impl_cc_gate!(PORT2, mrcc_glb_cc1, port2, NoConfig); impl_cc_gate!(PORT3, mrcc_glb_cc1, port3, NoConfig); + impl_cc_gate!(GPIO3, mrcc_glb_cc2, gpio3, NoConfig); + impl_cc_gate!(OSTIMER0, mrcc_glb_cc1, ostimer0, OsTimerConfig); impl_cc_gate!(LPUART2, mrcc_glb_cc0, lpuart2, LpuartConfig); - impl_cc_gate!(GPIO3, mrcc_glb_cc2, gpio3, NoConfig); impl_cc_gate!(ADC1, mrcc_glb_cc1, adc1, AdcConfig); } @@ -276,7 +284,7 @@ pub struct Clock { pub power: PoweredClock, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PoweredClock { NormalEnabledDeepSleepDisabled, AlwaysEnabled, diff --git a/src/clocks/periph_helpers.rs b/src/clocks/periph_helpers.rs index de767ef87..1657bd7eb 100644 --- a/src/clocks/periph_helpers.rs +++ b/src/clocks/periph_helpers.rs @@ -18,6 +18,11 @@ pub trait SPConfHelper { pub struct Div4(pub(super) u8); impl Div4 { + /// Divide by one, or no division + pub const fn no_div() -> Self { + Self(0) + } + /// Store a "raw" divisor value that will divide the source by /// `(n + 1)`, e.g. `Div4::from_raw(0)` will divide the source /// by 1, and `Div4::from_raw(15)` will divide the source by @@ -81,6 +86,7 @@ pub enum LpuartClockSel { None, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum LpuartInstance { Lpuart0, Lpuart1, @@ -102,6 +108,7 @@ pub struct LpuartConfig { pub(crate) instance: LpuartInstance, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum OstimerClockSel { /// 16k clock, sourced from FRO16K (Vdd Core) Clk16kVddCore, @@ -116,6 +123,7 @@ pub struct OsTimerConfig { pub source: OstimerClockSel, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum AdcClockSel { FroLfDiv, FroHf, diff --git a/src/lib.rs b/src/lib.rs index fd7d3cd07..4120c1e84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,6 @@ pub mod clocks; // still provide clock helpers pub mod gpio; pub mod pins; // pin mux helpers -pub mod reset; // reset control helpers pub mod adc; pub mod config; diff --git a/src/lpuart/mod.rs b/src/lpuart/mod.rs index be69372a2..9e8b25ff6 100644 --- a/src/lpuart/mod.rs +++ b/src/lpuart/mod.rs @@ -545,7 +545,7 @@ impl Default for Config { swap_txd_rxd: false, power: PoweredClock::NormalEnabledDeepSleepDisabled, source: LpuartClockSel::FroLfDiv, - div: const { Div4::from_divisor(1).unwrap() }, + div: Div4::no_div(), } } } diff --git a/src/ostimer.rs b/src/ostimer.rs index 8bc68389a..efa534194 100644 --- a/src/ostimer.rs +++ b/src/ostimer.rs @@ -29,8 +29,13 @@ use core::sync::atomic::{AtomicBool, Ordering}; +use embassy_hal_internal::{Peri, PeripheralType}; + +use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel}; +use crate::clocks::{assert_reset, enable_and_reset, is_reset_released, release_reset, Gate, PoweredClock}; use crate::interrupt::InterruptExt; use crate::pac; +use crate::peripherals::OSTIMER0; // PAC defines the shared RegisterBlock under `ostimer0`. type Regs = pac::ostimer0::RegisterBlock; @@ -197,16 +202,16 @@ impl<'d> Alarm<'d> { pub struct Config { /// Initialize MATCH registers to their max values and mask/clear the interrupt flag. pub init_match_max: bool, - /// OSTIMER clock frequency in Hz (must match the actual hardware clock) - pub clock_frequency_hz: u64, + pub power: PoweredClock, + pub source: OstimerClockSel, } impl Default for Config { fn default() -> Self { Self { init_match_max: true, - // Default to 1MHz - user should override this with actual frequency - clock_frequency_hz: 1_000_000, + power: PoweredClock::NormalEnabledDeepSleepDisabled, + source: OstimerClockSel::Clk1M, } } } @@ -222,8 +227,16 @@ impl<'d, I: Instance> Ostimer<'d, I> { /// Construct OSTIMER handle. /// Requires clocks for the instance to be enabled by the board before calling. /// Does not enable NVIC or INTENA; use time_driver::init() for async operation. - pub fn new(_inst: impl Instance, cfg: Config, _p: &'d crate::pac::Peripherals) -> Self { - assert!(cfg.clock_frequency_hz > 0, "OSTIMER frequency must be greater than 0"); + pub fn new(_inst: Peri<'d, I>, cfg: Config) -> Self { + let clock_freq = unsafe { + enable_and_reset::(&OsTimerConfig { + power: cfg.power, + source: cfg.source, + }) + .expect("Enabling OsTimer clock should not fail") + }; + + assert!(clock_freq > 0, "OSTIMER frequency must be greater than 0"); if cfg.init_match_max { let r: &Regs = unsafe { &*I::ptr() }; @@ -233,7 +246,7 @@ impl<'d, I: Instance> Ostimer<'d, I> { Self { _inst: core::marker::PhantomData, - clock_frequency_hz: cfg.clock_frequency_hz, + clock_frequency_hz: clock_freq as u64, _phantom: core::marker::PhantomData, } } @@ -260,7 +273,7 @@ impl<'d, I: Instance> Ostimer<'d, I> { /// # Safety /// This operation will reset the entire OSTIMER peripheral. Any active alarms /// or time_driver operations will be disrupted. Use with caution. - pub fn reset(&self, peripherals: &crate::pac::Peripherals) { + pub fn reset(&self, _peripherals: &crate::pac::Peripherals) { critical_section::with(|_| { let r: &Regs = unsafe { &*I::ptr() }; @@ -270,19 +283,17 @@ impl<'d, I: Instance> Ostimer<'d, I> { .write(|w| w.ostimer_intrflag().clear_bit_by_one().ostimer_intena().clear_bit()); unsafe { - crate::reset::assert::(peripherals); - } + assert_reset::(); - for _ in 0..RESET_STABILIZE_SPINS { - cortex_m::asm::nop(); - } + for _ in 0..RESET_STABILIZE_SPINS { + cortex_m::asm::nop(); + } - unsafe { - crate::reset::release::(peripherals); - } + release_reset::(); - while !::is_released(&peripherals.mrcc0) { - cortex_m::asm::nop(); + while !is_reset_released::() { + cortex_m::asm::nop(); + } } for _ in 0..RESET_STABILIZE_SPINS { @@ -469,14 +480,13 @@ fn now_ticks_read() -> u64 { // Read high then low to minimize incoherent snapshots let hi = (r.evtimerh().read().evtimer_count_value().bits() as u64) & (EVTIMER_HI_MASK as u64); let lo = r.evtimerl().read().evtimer_count_value().bits() as u64; - // Combine and convert from Gray code to binary let gray = lo | (hi << EVTIMER_HI_SHIFT); gray_to_bin(gray) } // Instance trait like other drivers, providing a PAC pointer for this OSTIMER instance -pub trait Instance { +pub trait Instance: Gate + PeripheralType { fn ptr() -> *const Regs; } @@ -491,12 +501,12 @@ impl Instance for crate::peripherals::OSTIMER0 { } // Also implement Instance for the Peri wrapper type -impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::OSTIMER0> { - #[inline(always)] - fn ptr() -> *const Regs { - pac::Ostimer0::ptr() - } -} +// impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::OSTIMER0> { +// #[inline(always)] +// fn ptr() -> *const Regs { +// pac::Ostimer0::ptr() +// } +// } #[inline(always)] fn bin_to_gray(x: u64) -> u64 { diff --git a/src/reset.rs b/src/reset.rs deleted file mode 100644 index 1c131d1cc..000000000 --- a/src/reset.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! Reset control helpers built on PAC field writers. -use crate::pac; - -/// Trait describing a reset line that can be asserted/deasserted. -pub trait ResetLine { - /// Drive the peripheral out of reset. - unsafe fn release(mrcc: &pac::mrcc0::RegisterBlock); - - /// Drive the peripheral into reset. - unsafe fn assert(mrcc: &pac::mrcc0::RegisterBlock); - - /// Check whether the peripheral is currently released. - fn is_released(mrcc: &pac::mrcc0::RegisterBlock) -> bool; -} - -/// Release a reset line for the given peripheral set. -#[inline] -pub unsafe fn release(peripherals: &pac::Peripherals) { - R::release(&peripherals.mrcc0); -} - -/// Assert a reset line for the given peripheral set. -#[inline] -pub unsafe fn assert(peripherals: &pac::Peripherals) { - R::assert(&peripherals.mrcc0); -} - -/// Pulse a reset line (assert then release) with a short delay. -#[inline] -pub unsafe fn pulse(peripherals: &pac::Peripherals) { - let mrcc = &peripherals.mrcc0; - R::assert(mrcc); - cortex_m::asm::nop(); - cortex_m::asm::nop(); - R::release(mrcc); -} - -macro_rules! impl_reset_line { - ($name:ident, $reg:ident, $field:ident) => { - pub struct $name; - - impl ResetLine for $name { - #[inline] - unsafe fn release(mrcc: &pac::mrcc0::RegisterBlock) { - mrcc.$reg().modify(|_, w| w.$field().enabled()); - } - - #[inline] - unsafe fn assert(mrcc: &pac::mrcc0::RegisterBlock) { - mrcc.$reg().modify(|_, w| w.$field().disabled()); - } - - #[inline] - fn is_released(mrcc: &pac::mrcc0::RegisterBlock) -> bool { - mrcc.$reg().read().$field().is_enabled() - } - } - }; -} - -pub mod line { - use super::*; - - impl_reset_line!(Port2, mrcc_glb_rst1, port2); - impl_reset_line!(Port3, mrcc_glb_rst1, port3); - impl_reset_line!(Gpio3, mrcc_glb_rst2, gpio3); - impl_reset_line!(Lpuart2, mrcc_glb_rst0, lpuart2); - impl_reset_line!(Ostimer0, mrcc_glb_rst1, ostimer0); - impl_reset_line!(Port1, mrcc_glb_rst1, port1); - impl_reset_line!(Adc1, mrcc_glb_rst1, adc1); -} - -#[inline] -pub unsafe fn release_reset_port2(peripherals: &pac::Peripherals) { - release::(peripherals); -} - -#[inline] -pub unsafe fn release_reset_port3(peripherals: &pac::Peripherals) { - release::(peripherals); -} - -#[inline] -pub unsafe fn release_reset_gpio3(peripherals: &pac::Peripherals) { - release::(peripherals); -} - -#[inline] -pub unsafe fn release_reset_lpuart2(peripherals: &pac::Peripherals) { - release::(peripherals); -} - -#[inline] -pub unsafe fn release_reset_ostimer0(peripherals: &pac::Peripherals) { - release::(peripherals); -} - -/// Convenience shim retained for existing call sites. -#[inline] -pub unsafe fn reset_ostimer0(peripherals: &pac::Peripherals) { - pulse::(peripherals); -} - -#[inline] -pub unsafe fn release_reset_port1(peripherals: &pac::Peripherals) { - release::(peripherals); -} - -#[inline] -pub unsafe fn release_reset_adc1(peripherals: &pac::Peripherals) { - release::(peripherals); -} -- cgit