diff --git a/src/timer.rs b/src/timer.rs index 6560e8244..9b9b98ba8 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -11,6 +11,8 @@ //! [examples/adc.rs]: https://github.com/stm32-rs/stm32f3xx-hal/blob/v0.9.0/examples/adc.rs use core::convert::{From, TryFrom}; +use core::marker::PhantomData; +use core::ops::Deref; use crate::pac::{DCB, DWT}; #[cfg(feature = "enumset")] @@ -102,6 +104,8 @@ pub struct Timer { pub enum Event { /// Timer timed out / count down ended Update, + // CounterUnderflow, + // CounterOverflow, } impl Timer @@ -109,6 +113,7 @@ where TIM: Instance, { /// Configures a TIM peripheral as a periodic count down timer + // TODO: CHange clocks to be a global variable pub fn new(tim: TIM, clocks: Clocks, apb: &mut ::Bus) -> Self { TIM::enable(apb); TIM::reset(apb); @@ -119,7 +124,10 @@ where /// Stops the timer #[inline] pub fn stop(&mut self) { - self.tim.set_cr1_cen(false); + self.tim + .as_basic_timer_mut() + .cr1 + .modify(|_, w| w.cen().disabled()); } /// Enable or disable the interrupt for the specified [`Event`]. @@ -161,7 +169,11 @@ where #[inline] pub fn configure_interrupt(&mut self, event: Event, enable: bool) { match event { - Event::Update => self.tim.set_dier_uie(enable), + Event::Update => self + .tim + .as_basic_timer_mut() + .dier + .modify(|_, w| w.uie().bit(enable)), } } @@ -185,7 +197,7 @@ where #[inline] pub fn is_interrupt_configured(&self, event: Event) -> bool { match event { - Event::Update => self.tim.is_dier_uie_set(), + Event::Update => self.tim.as_basic_timer().dier.read().uie().bit(), } } @@ -209,7 +221,13 @@ where /// Check if an interrupt event happened. pub fn is_event_triggered(&self, event: Event) -> bool { match event { - Event::Update => self.tim.is_sr_uief_set(), + Event::Update => self + .tim + .as_basic_timer() + .sr + .read() + .uif() + .is_update_pending(), } } @@ -232,14 +250,22 @@ where #[inline] pub fn clear_event(&mut self, event: Event) { match event { - Event::Update => self.tim.clear_sr_uief(), + Event::Update => self + .tim + .as_basic_timer_mut() + .sr + .modify(|_, w| w.uif().clear()), } } /// Clear **all** interrupt events. #[inline] pub fn clear_events(&mut self) { - self.tim.clear_sr(); + // SAFETY: This atomic write clears all flags and ignores the reserverd bit fields. + self.tim + .as_basic_timer_mut() + .sr + .write(|w| unsafe { w.bits(0) }); } /// Get access to the underlying register block. @@ -283,10 +309,19 @@ where let ticks = clock.integer() * *timeout.scaling_factor() * timeout.integer(); let psc = crate::unwrap!(u16::try_from((ticks - 1) / (1 << 16)).ok()); - self.tim.set_psc(psc); + // NOTE(write): uses all bits in this register. + self.tim + .as_basic_timer_mut() + .psc + .write(|w| w.psc().bits(psc)); let arr = crate::unwrap!(u16::try_from(ticks / u32::from(psc + 1)).ok()); - self.tim.set_arr(arr); + // TODO(Sh3Rm4n): + // self.tim.arr.write(|w| { w.arr().bits(arr) }); + self.tim + .as_basic_timer_mut() + .arr + .write(|w| unsafe { w.bits(u32::from(arr)) }); // Ensure that the below procedure does not create an unexpected interrupt. let is_update_interrupt_active = self.is_interrupt_configured(Event::Update); @@ -296,7 +331,7 @@ where // Trigger an update event to load the prescaler value to the clock The above line raises // an update event which will indicate that the timer is already finished. - self.tim.set_egr_ug(); + self.tim.as_basic_timer_mut().egr.write(|w| w.ug().update()); // Since this is not the case, it should be cleared. self.clear_event(Event::Update); @@ -305,13 +340,23 @@ where } // start counter - self.tim.set_cr1_cen(true); + self.tim + .as_basic_timer_mut() + .cr1 + .modify(|_, w| w.cen().bit(true)); } /// Wait until [`Event::Update`] / the timer has elapsed /// and than clear the event. fn wait(&mut self) -> nb::Result<(), Void> { - if !self.tim.is_sr_uief_set() { + if !self + .tim + .as_basic_timer() + .sr + .read() + .uif() + .is_update_pending() + { Err(nb::Error::WouldBlock) } else { self.clear_event(Event::Update); @@ -332,7 +377,7 @@ where type Error = AlreadyCancled; fn cancel(&mut self) -> Result<(), Self::Error> { // If timer is already stopped. - if !self.tim.is_cr1_cen_set() { + if !self.tim.as_basic_timer().cr1.read().cen().bit() { return Err(AlreadyCancled); } self.stop(); @@ -344,6 +389,9 @@ where /// based on [`crate::pac::tim6::RegisterBlock`]. /// /// This is not meant to be used outside of this crate. +// TODO: Maybe use transmute to create a real basic common register block +// (e.g. pac::tim6::ReigsterBlock), as all blocks should be compatible to +// each other ... (hopefully). pub trait CommonRegisterBlock: crate::private::Sealed { #[doc(hidden)] fn set_cr1_cen(&mut self, enable: bool); @@ -369,7 +417,7 @@ pub trait CommonRegisterBlock: crate::private::Sealed { /// Associated clocks with timers pub trait Instance: - CommonRegisterBlock + AsBasicTimer + crate::interrupts::InterruptNumber + crate::private::Sealed + rcc::Enable @@ -381,6 +429,28 @@ pub trait Instance: macro_rules! timer { ($TIMX:ident) => { + // TODO: This must be associated, so that Into trait works? + impl From for BasicTimer { + fn from(tim: crate::pac::$TIMX) -> Self { + Self { + // TODO: Check if TIM6 is really common ground for all timer. + _ptr: unsafe { pac::TIM6::ptr() as _ }, + real_timer: tim, + } + } + } + + impl AsBasicTimer for crate::pac::$TIMX { + fn as_basic_timer(&self) -> &pac::tim6::RegisterBlock { + unsafe { &*(crate::pac::$TIMX::ptr() as *const pac::tim6::RegisterBlock) } + // unsafe { &*(self._ptr as *const Self::Target) } + } + + fn as_basic_timer_mut(&mut self) -> &mut pac::tim6::RegisterBlock { + unsafe { &mut *(crate::pac::$TIMX::ptr() as *mut pac::tim6::RegisterBlock) } + } + } + impl CommonRegisterBlock for crate::pac::$TIMX { #[inline] fn set_cr1_cen(&mut self, enable: bool) { @@ -444,7 +514,7 @@ macro_rules! timer { macro_rules! timer_var_clock { ($($TIMX:ident, $timXsw:ident),+) => { $( - impl Instance for crate::pac::$TIMX { + impl Instance for crate::pac::$TIMX { #[inline] fn clock(clocks: &Clocks) -> Hertz { // SAFETY: Atomic read with no side-effects. @@ -582,3 +652,60 @@ cfg_if::cfg_if! { timer_var_clock!(1); } } + +fn test(tim: pac::TIM16) { + let tim6: *const pac::tim6::RegisterBlock = unsafe { core::mem::transmute(pac::TIM16::ptr()) }; +} + +// TODO: Rename BasicTimer to BasicTimerPeripheral or similar to not be confusing +// by the actual Timer??? or in general, this could replace the Timer implementation? +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct BasicTimer { + _ptr: usize, + real_timer: T, +} + +impl Deref for BasicTimer { + type Target = pac::tim6::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*(self._ptr as *const Self::Target) } + } +} +// +// impl From for BasicTimer { +// fn from(tim: pac::TIM6) -> Self { +// Self { +// _ptr: unsafe { pac::TIM6::ptr() as _ }, +// real_timer: tim, +// } +// } +// } + +// impl BasicTimer { +// pub fn free(self) -> T { +// self.real_timer +// } +// } + +// TODO: Is that trait needed, when we already have Into? +pub trait BasicTimerInstance: Deref {} +impl BasicTimerInstance for BasicTimer {} + +// TODO: +pub trait AsBasicTimer { + fn as_basic_timer(&self) -> &pac::tim6::RegisterBlock; + + fn as_basic_timer_mut(&mut self) -> &mut pac::tim6::RegisterBlock; +} + +fn test2(tim: impl Into>) { + let tim: BasicTimer = tim.into(); + tim.cr1.read(); +} + +fn test3(tim: pac::TIM6) { + test2(tim); +}