diff --git a/boards/atsame54_xpro/examples/timer_v2.rs b/boards/atsame54_xpro/examples/timer_v2.rs index 44daf6257b5..290593a5251 100644 --- a/boards/atsame54_xpro/examples/timer_v2.rs +++ b/boards/atsame54_xpro/examples/timer_v2.rs @@ -22,18 +22,21 @@ use rtt_target::{rprintln, rtt_init_print}; type Button = ExtInt15>>; +const TIMER_HZ: u32 = 32; + #[rtic::app(device = hal::pac, peripherals = true, dispatchers = [FREQM])] mod app { use super::*; #[monotonic(binds = TC0, default = true)] - type Mono = MonotonicTimer<32, Tc0Tc1, Gclk1Id>; + type Mono = MonotonicTimer; #[shared] struct Shared {} #[local] struct Local { + countdown: CountdownTimer, button: Button, led: bsp::Led, } @@ -73,23 +76,70 @@ mod app { let tc0_clk = buses.apb.enable(tokens.apbs.tc0); let tc1_clk = buses.apb.enable(tokens.apbs.tc1); - let (tc0_tc1_pclk, _gclk1) = clock::pclk::Pclk::enable(tokens.pclks.tc0_tc1, gclk1); + let (tc0_tc1_pclk, gclk1) = clock::pclk::Pclk::enable(tokens.pclks.tc0_tc1, gclk1); - let mono = Timer::paired( + let monotonic = TimerBuilder::paired( ctx.device.TC0, tc0_clk, ctx.device.TC1, tc1_clk, tc0_tc1_pclk, ) - .into_32_bit() .into_monotonic() - .unwrap(); + .unwrap() + .enable(); + + let tc6_clk = buses.apb.enable(tokens.apbs.tc6); + let tc7_clk = buses.apb.enable(tokens.apbs.tc7); + + let (tc6_tc7_pclk, _gclk1) = clock::pclk::Pclk::enable(tokens.pclks.tc6_tc7, gclk1); + + let (_, countdown) = TimerBuilder::disjoint( + ctx.device.TC6, + tc6_clk, + ctx.device.TC7, + tc7_clk, + tc6_tc7_pclk, + ); + + // TODO: Create a PR to fugit to fix extension traits + use atsamd_hal::fugit::ExtU32; + let mut countdown = countdown + .into_8_bit() + .into_countdown() + .unwrap() + .with_saturated_period(1_u32.secs()) + .with_interrupt(); + + unsafe { + countdown + .inner_raw() + .registers() + .count8() + .ctrla + .modify(|_, w| w.prescsync().resync()); + } + + let countdown = countdown.enable(); let led: bsp::Led = bsp::pin_alias!(pins.led).into(); bump_activity_led(); - (Shared {}, Local { button, led }, init::Monotonics(mono)) + ( + Shared {}, + Local { + button, + led, + countdown, + }, + init::Monotonics(monotonic), + ) + } + #[task(binds = TC7, local = [countdown])] + fn countdown(ctx: countdown::Context) { + ctx.local.countdown.clear_interrupt_flag(); + rprintln!("Countdown timer run out!"); + bump_activity_led(); } #[task(binds = EIC_EXTINT_15, local = [button])] diff --git a/hal/src/prelude.rs b/hal/src/prelude.rs index d4a5cb86918..fe980487a34 100644 --- a/hal/src/prelude.rs +++ b/hal/src/prelude.rs @@ -4,6 +4,9 @@ pub use crate::timer_traits::InterruptDrivenTimer as _atsamd_hal_timer_traits_In pub use fugit::ExtU32 as _; pub use fugit::RateExtU32 as _; +#[cfg(feature = "thumbv7")] +pub use crate::timer::v2::prelude::*; + // embedded-hal doesn’t yet have v2 in its prelude, so we need to // export it ourselves #[cfg(feature = "unproven")] diff --git a/hal/src/thumbv7em/timer/v2.rs b/hal/src/thumbv7em/timer/v2.rs index a5fe1b8b3e5..ac952274764 100644 --- a/hal/src/thumbv7em/timer/v2.rs +++ b/hal/src/thumbv7em/timer/v2.rs @@ -25,9 +25,12 @@ //! Example of how to construct, configure and enable a timer. //! //! ```no_run -//! # use atsamd_hal::clock::v2::pclk::Pclk; -//! # use atsamd_hal::timer::v2::{Timer, TimersTupleExt, TimerPrescaler, TimerDirection}; //! # let mut pac = unsafe { atsamd_hal::pac::Peripherals::steal() }; +//! use atsamd_hal::prelude::*; +//! use atsamd_hal::clock::v2::pclk::Pclk; +//! use atsamd_hal::timer::v2 as timer; +//! use timer::{TimerBuilder, TimerPrescaler, TimerDirection, TimerInterrupt, TimerInterruptSet}; +//! //! let (mut buses, clocks, tokens) = atsamd_hal::clock::v2::clock_system_at_reset( //! pac.OSCCTRL, //! pac.OSC32KCTRL, @@ -50,36 +53,75 @@ //! let (tc0_tc1_pclk, gclk0) = Pclk::enable(tokens.pclks.tc0_tc1, gclk0); //! let (tc2_tc3_pclk, gclk0) = Pclk::enable(tokens.pclks.tc2_tc3, gclk0); //! -//! let (pri, sec) = Timer::disjoint(tc0, tc0_clk, tc1, tc1_clk, tc0_tc1_pclk) /* -> (Timer, Timer) */; -//! let (tc0, tc0_clk, tc1, tc1_clk, tc0_tc1_pclk) = (pri, sec).free(); -//! let timer = Timer::paired(tc0, tc0_clk, tc1, tc1_clk, tc0_tc1_pclk) /* -> Timer */; -//! let timer = timer -//! .with_prescaler(TimerPrescaler::DIV16) -//! .with_oneshot(true) -//! .with_direction(TimerDirection::Increment) -//! .enable(); +//! let (pri, sec) = TimerBuilder::disjoint(tc0, tc0_clk, tc1, tc1_clk, tc0_tc1_pclk); /* -> (TimerBuilder, TimerBuilder) */ +//! let pri = pri +//! .into_8_bit() +//! .with_ondemand(true) +//! .into_raw() +//! .with_interrupts(TimerInterruptSet::from_iter( +//! [ +//! TimerInterrupt::Overflow, +//! TimerInterrupt::MatchOrCaptureChannel0, +//! TimerInterrupt::Error, +//! ] +//! )) +//! .with_frequency(48.MHz()) +//! .expect("oops") +//! .enable(); +//! let (tc0, tc0_clk, tc1, tc1_clk, tc0_tc1_pclk) = (pri.disable(), sec.into_raw()).free(); +//! let timer = TimerBuilder::paired(tc0, tc0_clk, tc1, tc1_clk, tc0_tc1_pclk); /* -> TimerBuilder */ +//! let timer = timer /* -> RawTimer */ +//! .into_raw() +//! .with_interrupts(TimerInterrupt::Overflow.into()) +//! .with_prescaler(TimerPrescaler::DIV16) +//! .with_oneshot(true) +//! .with_direction(TimerDirection::Increment) +//! .enable(); //! let timer = timer.disable(); -//! let (tc0, tc0_clk, tc1, tc1_clk, tc0_tc1_pclk) = timer.free(); +//! let timer = timer +//! .reset_into_builder() +//! .into_monotonic::<48_000_000>() +//! .expect("oops") +//! .enable(); +//! let (tc0, tc0_clk, tc1, tc1_clk, tc0_tc1_pclk) = timer.disable().into_raw().free(); //! -//! let (pri, sec) = Timer::disjoint(tc2, tc2_clk, tc3, tc3_clk, tc2_tc3_pclk) /* -> (Timer, Timer) */; +//! let (pri, sec) = TimerBuilder::disjoint(tc2, tc2_clk, tc3, tc3_clk, tc2_tc3_pclk) /* -> (TimerBuilder, TimerBuilder) */; //! let (tc2, tc2_clk, tc3, tc3_clk, tc2_tc3_pclk) = (pri, sec).free(); -//! let timer = Timer::paired(tc2, tc2_clk, tc3, tc3_clk, tc2_tc3_pclk) /* -> Timer */; -//! let timer = timer.into_32_bit().enable().disable(); -//! let (tc2, tc2_clk, tc3, tc3_clk, tc2_tc3_pclk) = timer.free(); +//! let timer = TimerBuilder::paired(tc2, tc2_clk, tc3, tc3_clk, tc2_tc3_pclk) /* -> TimerBuilder */; +//! let mut timer = timer /* -> CountdownTimer */ +//! .into_8_bit() +//! .into_countdown::<32_768>() +//! .expect("oops") +//! .enable(); +//! timer.retrigger_with_period(2.secs()); +//! timer.enable_interrupt(); +//! timer.disable_interrupt(); +//! let (tc2, tc2_clk, tc3, tc3_clk, tc2_tc3_pclk) = timer.into_raw().disable().free(); //! ``` //! //! In order to use the timer as a RTIC monotonic timer, one can call //! `Timer::into_monotonic`. This requires a feature flag `rtic` being enabled. -use core::marker::PhantomData; +use core::{convert::Infallible, marker::PhantomData}; + +pub mod prelude; + +mod builder; +pub use builder::*; + +mod raw; +pub use raw::*; #[cfg(feature = "rtic")] mod mono; #[cfg(feature = "rtic")] -pub use mono::MonotonicTimer; +pub use mono::*; + +mod countdown; +pub use countdown::*; mod interrupt; -pub use interrupt::{Interrupt, InterruptSet}; +pub use interrupt::*; mod types; pub use types::*; @@ -92,272 +134,7 @@ use crate::{ time::Hertz, }; -/// General timer abstraction. WiP. -pub struct Timer { - reg: T::Reg, - pclk_freq: Hertz, - __: PhantomData<(I, S, TW)>, -} - -impl Timer { - fn new(reg: T::Reg, pclk_freq: Hertz) -> Self { - reg.count8().ctrla.modify(|_, w| w.swrst().set_bit()); - while reg.count8().syncbusy.read().swrst().bit_is_set() {} - Self { - reg, - pclk_freq, - __: PhantomData, - } - } -} - -impl Timer { - fn to(self) -> Timer { - Timer { - reg: self.reg, - pclk_freq: self.pclk_freq, - __: PhantomData, - } - } - - fn sync_ctrlbset_write(&mut self, write: impl WriteClosure) { - self.reg.count8().ctrlbset.write(write); - while self.reg.count8().syncbusy.read().ctrlb().bit_is_set() {} - } - - fn sync_ctrlbclr_write(&mut self, write: impl WriteClosure) { - self.reg.count8().ctrlbclr.write(write); - while self.reg.count8().syncbusy.read().ctrlb().bit_is_set() {} - } - - pub fn set_debug_run(&mut self, value: bool) -> &mut Self { - self.reg.count8().dbgctrl.write(|w| w.dbgrun().bit(value)); - self - } - - pub fn set_oneshot(&mut self, value: bool) -> &mut Self { - if value { - self.sync_ctrlbset_write(|w| w.oneshot().set_bit()); - } else { - self.sync_ctrlbclr_write(|w| w.oneshot().set_bit()); - } - self - } - - pub fn set_direction(&mut self, dir: TimerDirection) -> &mut Self { - match dir { - TimerDirection::Increment => self.sync_ctrlbclr_write(|w| w.dir().set_bit()), - TimerDirection::Decrement => self.sync_ctrlbset_write(|w| w.dir().set_bit()), - } - self - } - - pub fn direction(&self) -> TimerDirection { - match self.reg.count8().ctrlbset.read().dir().bit_is_set() { - true => TimerDirection::Decrement, - false => TimerDirection::Increment, - } - } - - pub fn enable_interrupts(&mut self, interrupt_set: InterruptSet) -> &mut Self { - self.reg - .count8() - .intenset - .write(|w| unsafe { w.bits(interrupt_set.0) }); - self - } - - pub fn disable_interrupts(&mut self, interrupt_set: InterruptSet) -> &mut Self { - self.reg - .count8() - .intenclr - .write(|w| unsafe { w.bits(interrupt_set.0) }); - self - } - - pub unsafe fn registers(&self) -> &T::Reg { - &self.reg - } -} - -impl Timer { - pub fn disable(self) -> Timer { - self.reg.count8().ctrla.modify(|_, w| w.enable().set_bit()); - while self.reg.count8().syncbusy.read().enable().bit_is_set() {} - self.to() - } - - fn sync_run_command(&mut self, cmd: TimerCommand) -> &mut Self { - self.sync_ctrlbset_write(|w| w.cmd().variant(cmd)); - while !self.reg.count8().ctrlbset.read().cmd().is_none() {} - self - } -} - -impl Timer { - pub fn enable(self) -> Timer { - self.reg.count8().ctrla.modify(|_, w| w.enable().set_bit()); - while self.reg.count8().syncbusy.read().enable().bit_is_set() {} - self.to() - } - - pub fn into_8_bit(self) -> Timer { - self.reg.count8().ctrla.modify(|_, w| w.mode().count8()); - self.to() - } - - pub fn into_16_bit(self) -> Timer { - self.reg.count8().ctrla.modify(|_, w| w.mode().count16()); - self.to() - } - - pub fn set_ondemand(&mut self, value: bool) -> &mut Self { - self.reg - .count8() - .ctrla - .modify(|_, w| w.ondemand().bit(value)); - self - } - - pub fn with_ondemand(mut self, value: bool) -> Self { - self.set_ondemand(value); - self - } - - pub fn set_runstdby(&mut self, value: bool) -> &mut Self { - self.reg - .count8() - .ctrla - .modify(|_, w| w.runstdby().bit(value)); - self - } - - pub fn with_runstdby(mut self, value: bool) -> Self { - self.set_runstdby(value); - self - } - - pub fn with_debug_run(mut self, value: bool) -> Self { - self.set_debug_run(value); - self - } - - pub fn with_oneshot(mut self, value: bool) -> Self { - self.set_oneshot(value); - self - } - - pub fn with_direction(mut self, dir: TimerDirection) -> Self { - self.set_direction(dir); - self - } - - pub fn with_interrupts(mut self, interrupt_set: InterruptSet) -> Self { - self.disable_interrupts(InterruptSet::full()); - self.enable_interrupts(interrupt_set); - self - } - - /// Mutually exclusive with [`Self::with_prescaler`] - pub fn with_frequency(self, frequency: Hertz) -> Result { - let input_freq = self.pclk_freq.to_Hz(); - let output_freq = frequency.to_Hz(); - let prescaler = match input_freq.checked_rem(output_freq) { - Some(0) => match input_freq / output_freq { - 1 => TimerPrescaler::DIV1, - 2 => TimerPrescaler::DIV2, - 4 => TimerPrescaler::DIV4, - 8 => TimerPrescaler::DIV8, - 16 => TimerPrescaler::DIV16, - 64 => TimerPrescaler::DIV64, - 256 => TimerPrescaler::DIV256, - 1024 => TimerPrescaler::DIV1024, - _ => { - return Err(TimerError::NoValidPrescaler( - TimerPrescalerError::InvalidPrescaler, - )) - } - }, - Some(_) => { - return Err(TimerError::NoValidPrescaler( - TimerPrescalerError::FrequenciesNotDivisible, - )) - } - None => { - return Err(TimerError::NoValidPrescaler( - TimerPrescalerError::OutputFrequencyIsZero, - )) - } - }; - Ok(self.with_prescaler(prescaler)) - } - - /// Mutually exclusive with [`Self::with_frequency`] - pub fn with_prescaler(self, prescaler: TimerPrescaler) -> Self { - self.reg - .count8() - .ctrla - .modify(|_, w| w.prescaler().variant(prescaler)); - self - } -} - -impl Timer { - pub fn into_32_bit(self) -> Timer { - self.reg.count8().ctrla.modify(|_, w| w.mode().count32()); - self.to() - } -} - -impl Timer { - pub fn compare(&self, index: TimerCompareRegister) -> TW { - TW::from_u32(self.reg.count32().cc[index as usize].read().cc().bits()) - } - - pub fn set_compare(&mut self, index: TimerCompareRegister, compare: TW) -> &mut Self { - // Writing over reserved bits for an 8/16 bit timer, o-la-la. - // Hopefully that's fine. - self.reg.count32().cc[index as usize].write(|w| unsafe { w.cc().bits(compare.as_()) }); - match index { - TimerCompareRegister::Zero => { - while self.reg.count8().syncbusy.read().cc0().bit_is_set() {} - } - TimerCompareRegister::One => { - while self.reg.count8().syncbusy.read().cc1().bit_is_set() {} - } - } - self - } - - pub fn count(&mut self) -> TW { - self.sync_run_command(TimerCommand::READSYNC); - TW::from_u32(self.reg.count32().count.read().count().bits()) - } - - pub fn set_count(&mut self, count: TW) -> &mut Self { - // Writing over reserved bits for an 8/16 bit timer, o-la-la. - // Hopefully that's fine. - self.reg - .count32() - .count - .write(|w| unsafe { w.count().bits(count.as_()) }); - while self.reg.count8().syncbusy.read().count().bit_is_set() {} - self - } - - // Clears the interrupts - pub fn interrupt_flags(&self) -> InterruptSet { - let interrupts = self.reg.count8().intflag.read().bits(); - // Clear the interrupts - self.reg - .count8() - .intflag - .write(|w| unsafe { w.bits(interrupts) }); - InterruptSet(interrupts) - } -} - -impl Timer { +impl TimerBuilder { // Create the disjoint pair of timers. They support 8-bit and 16-bit counters pub fn disjoint( primary_reg: T::Reg, @@ -365,54 +142,20 @@ impl Timer { secondary_reg: Reg>, secondary_clk: ApbClk>, common_pclk: Pclk, - ) -> (Timer, Timer, I>) { + ) -> (TimerBuilder, TimerBuilder, I>) { let _ = primary_clk; let _ = secondary_clk; let pclk_freq = common_pclk.freq(); let _ = common_pclk; ( - Timer::new(primary_reg, pclk_freq), - Timer::new(secondary_reg, pclk_freq), - ) - } -} - -pub trait TimersTupleExt { - fn free( - self, - ) -> ( - T::Reg, - ApbClk, - Reg>, - ApbClk>, - Pclk, - ); -} - -impl TimersTupleExt - for (Timer, Timer, I, TW2>) -{ - fn free( - self, - ) -> ( - T::Reg, - ApbClk, - Reg>, - ApbClk>, - Pclk, - ) { - ( - self.0.reg, - ApbClk::new(unsafe { ApbToken::new() }), - self.1.reg, - ApbClk::new(unsafe { ApbToken::new() }), - Pclk::new(unsafe { PclkToken::new() }, self.0.pclk_freq), + TimerBuilder::new(RawTimer::new(primary_reg, pclk_freq)), + TimerBuilder::new(RawTimer::new(secondary_reg, pclk_freq)), ) } } -impl Timer +impl TimerBuilder where Reg: From<(Reg, Reg>)>, { @@ -423,35 +166,14 @@ where secondary_reg: Reg>, secondary_clk: ApbClk>, common_pclk: Pclk, - ) -> Timer { + ) -> TimerBuilder { let _ = primary_clk; let _ = secondary_clk; let pclk_freq = common_pclk.freq(); let _ = common_pclk; - Timer::new((primary_reg, secondary_reg).into(), pclk_freq) - } -} - -impl Timer -where - T::Reg: Into<(Reg, Reg)>, -{ - pub fn free( - self, - ) -> ( - Reg, - ApbClk, - Reg, - ApbClk, - Pclk, - ) { - let (pri_reg, sec_reg) = self.reg.into(); - ( - pri_reg, - ApbClk::new(unsafe { ApbToken::new() }), - sec_reg, - ApbClk::new(unsafe { ApbToken::new() }), - Pclk::new(unsafe { PclkToken::new() }, self.pclk_freq), - ) + TimerBuilder::new(RawTimer::new( + (primary_reg, secondary_reg).into(), + pclk_freq, + )) } } diff --git a/hal/src/thumbv7em/timer/v2/builder.rs b/hal/src/thumbv7em/timer/v2/builder.rs new file mode 100644 index 00000000000..58d0cda282c --- /dev/null +++ b/hal/src/thumbv7em/timer/v2/builder.rs @@ -0,0 +1,84 @@ +use super::*; + +pub struct TimerBuilder(RawTimer); + +impl TimerBuilder { + pub(super) fn new(inner: RawTimer) -> Self { + Self(inner) + } + + pub fn into_8_bit(self) -> TimerBuilder { + self.0.reg.count8().ctrla.modify(|_, w| w.mode().count8()); + TimerBuilder(self.0.to()) + } + + pub fn into_16_bit(self) -> TimerBuilder { + self.0.reg.count8().ctrla.modify(|_, w| w.mode().count16()); + TimerBuilder(self.0.to()) + } + + pub fn with_ondemand(mut self, value: bool) -> Self { + self.0.set_ondemand(value); + self + } + + pub fn with_runstdby(mut self, value: bool) -> Self { + self.0.set_runstdby(value); + self + } + + pub fn with_debug_run(mut self, value: bool) -> Self { + self.0.set_debug_run(value); + self + } +} + +impl IntoRaw for TimerBuilder { + fn into_raw(self) -> RawTimer { + self.0 + } +} + +impl TimerBuilder { + pub fn into_32_bit(self) -> TimerBuilder { + self.0.reg.count8().ctrla.modify(|_, w| w.mode().count32()); + TimerBuilder(self.0.to()) + } +} + +impl FreeTimerResourcesExt + for TimerBuilder +where + T::Reg: Into<(Reg, Reg)>, +{ + fn free( + self, + ) -> ( + Reg, + ApbClk, + Reg, + ApbClk, + Pclk, + ) { + self.0.free() + } +} + +impl FreeTimerResourcesExt + for ( + TimerBuilder, + TimerBuilder, I, TW2>, + ) +{ + fn free( + self, + ) -> ( + T::Reg, + ApbClk, + Reg>, + ApbClk>, + Pclk, + ) { + (self.0 .0, self.1 .0).free() + } +} diff --git a/hal/src/thumbv7em/timer/v2/countdown.rs b/hal/src/thumbv7em/timer/v2/countdown.rs new file mode 100644 index 00000000000..e99d60b254f --- /dev/null +++ b/hal/src/thumbv7em/timer/v2/countdown.rs @@ -0,0 +1,170 @@ +use super::*; + +pub trait IntoCountdown { + fn into_countdown( + self, + ) -> Result, TimerError>; +} + +impl IntoCountdown + for TimerBuilder +{ + fn into_countdown( + self, + ) -> Result, TimerError> { + let raw = self + .into_raw() + .with_frequency(Hertz::Hz(TIMER_HZ))? + .with_mode(TimerMode::MFRQ) + .with_direction(TimerDirection::Decrement) + .with_interrupts(TimerInterruptSet::empty()); + Ok(UnreadyCountdownTimer(CountdownTimer { raw })) + } +} + +pub struct UnreadyCountdownTimer( + CountdownTimer, +); + +impl + UnreadyCountdownTimer +{ + pub fn with_period( + mut self, + period: fugit::TimerDurationU32, + ) -> Result, CountdownTimerError> { + self.0.set_period(period)?; + Ok(self.0) + } + + pub fn with_saturated_period( + mut self, + period: fugit::TimerDurationU32, + ) -> CountdownTimer { + self.0.set_saturated_period(period); + self.0 + } +} + +pub struct CountdownTimer { + raw: RawTimer, +} + +#[derive(Copy, Clone, Debug)] +pub enum CountdownTimerError { + OutOfRange, +} + +impl + CountdownTimer +{ + pub fn enable(self) -> CountdownTimer { + CountdownTimer { + raw: self.raw.enable(), + } + } + + pub fn with_oneshot(mut self, value: bool) -> Self { + self.set_oneshot(value); + self + } + + pub fn with_interrupt(mut self) -> Self { + self.enable_interrupt(); + self + } +} + +impl + CountdownTimer +{ + pub fn disable(self) -> CountdownTimer { + CountdownTimer { + raw: self.raw.disable(), + } + } + + pub fn retrigger(&mut self) -> &mut Self { + self.raw.retrigger(); + self + } + + pub fn wait(&mut self) -> nb::Result<(), Infallible> { + if self.raw.interrupt_flags().overflow() { + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } + + pub fn clear_interrupt_flag(&mut self) -> &mut Self { + let _ = self.raw.interrupt_flags(); + self + } +} + +impl + CountdownTimer +{ + // TODO: set_period -> try_set_period ? Provide guaranteed `set_period` for u32 + // timer Or maybe just set_saturating_period to avoid all that hassle + pub fn set_period( + &mut self, + period: fugit::TimerDurationU32, + ) -> Result<&mut Self, CountdownTimerError> { + match TW::from_u32(period.ticks()) { + Some(ticks) => { + self.raw.set_compare(TimerCompareRegister::Zero, ticks); + self.raw.set_count(ticks); + Ok(self) + } + None => Err(CountdownTimerError::OutOfRange), + } + } + + pub fn set_saturated_period(&mut self, period: fugit::TimerDurationU32) -> &mut Self { + let period = match TW::from_u32(period.ticks() - 1) { + Some(ticks) => ticks, + None => TW::max_value(), + }; + self.raw.set_compare(TimerCompareRegister::Zero, period); + self.raw.set_count(period); + self + } + + pub fn set_oneshot(&mut self, value: bool) -> &mut Self { + self.raw.set_oneshot(value); + self + } + + pub fn enable_interrupt(&mut self) -> &mut Self { + self.raw.enable_interrupts(TimerInterrupt::Overflow.into()); + self + } + + pub fn disable_interrupt(&mut self) -> &mut Self { + self.raw.disable_interrupts(TimerInterrupt::Overflow.into()); + self + } + + // TODO: Clean it up + /// # Safety + /// API of the `CountdownTimer` full ownership over underlying timer and + /// makes assumptions about its state + /// - direction: decrement + /// - interrupts: all but overflow should be disabled; overflow is _do not + /// care_ + /// - mode: mfrq (must wrap on CC0, NOT on TOP) + /// - frequency: matches TIMER_HZ + pub unsafe fn inner_raw(&mut self) -> &mut RawTimer { + &mut self.raw + } +} + +impl IntoRaw + for CountdownTimer +{ + fn into_raw(self) -> RawTimer { + self.raw + } +} diff --git a/hal/src/thumbv7em/timer/v2/interrupt.rs b/hal/src/thumbv7em/timer/v2/interrupt.rs index 55814bfb526..6b469c46e81 100644 --- a/hal/src/thumbv7em/timer/v2/interrupt.rs +++ b/hal/src/thumbv7em/timer/v2/interrupt.rs @@ -2,7 +2,7 @@ use num_traits::FromPrimitive; #[repr(u8)] #[derive(Copy, Clone, PartialEq, Debug, Eq, num_derive::FromPrimitive)] -pub enum Interrupt { +pub enum TimerInterrupt { MatchOrCaptureChannel1 = 1 << 5, MatchOrCaptureChannel0 = 1 << 4, Error = 1 << 1, @@ -12,7 +12,7 @@ pub enum Interrupt { bitfield::bitfield! { /// Raw userpage POD struct that exposes bitfields via methods #[derive(Copy, Clone, PartialEq, Eq)] - pub struct InterruptSet(u8); + pub struct TimerInterruptSet(u8); impl Debug; u8; pub overflow, set_overflow: 0; @@ -21,26 +21,30 @@ bitfield::bitfield! { pub match_or_capture_channel_1, set_match_or_capture_channel_1: 5; } -impl InterruptSet { +impl TimerInterruptSet { pub fn full() -> Self { Self::from_iter(Self(u8::MAX)) } + + pub fn empty() -> Self { + Self(0) + } } -impl From for InterruptSet { - fn from(value: Interrupt) -> Self { +impl From for TimerInterruptSet { + fn from(value: TimerInterrupt) -> Self { Self(value as _) } } -impl FromIterator for InterruptSet { - fn from_iter>(iter: T) -> Self { +impl FromIterator for TimerInterruptSet { + fn from_iter>(iter: T) -> Self { Self(iter.into_iter().fold(0, |l, r| l | r as u8)) } } -impl Iterator for InterruptSet { - type Item = Interrupt; +impl Iterator for TimerInterruptSet { + type Item = TimerInterrupt; fn next(&mut self) -> Option { let raw_interrupt_set = &mut self.0; @@ -49,7 +53,7 @@ impl Iterator for InterruptSet { let raw_interrupt = 1 << raw_interrupt_set.trailing_zeros(); // Clear the bit *raw_interrupt_set &= !raw_interrupt; - match Interrupt::from_u8(raw_interrupt) { + match TimerInterrupt::from_u8(raw_interrupt) { None => continue, Some(i) => return Some(i), } @@ -64,35 +68,35 @@ mod tests { #[test] fn test_full_interrupt_set() { let interrupts = [ - Interrupt::MatchOrCaptureChannel0, - Interrupt::MatchOrCaptureChannel1, - Interrupt::Error, - Interrupt::Overflow, + TimerInterrupt::MatchOrCaptureChannel0, + TimerInterrupt::MatchOrCaptureChannel1, + TimerInterrupt::Error, + TimerInterrupt::Overflow, ]; - let full_interrupt_set_from_u8_max = InterruptSet::full(); - let full_interrupt_set_from_summed_variants = InterruptSet( - Interrupt::MatchOrCaptureChannel0 as u8 - | Interrupt::MatchOrCaptureChannel1 as u8 - | Interrupt::Error as u8 - | Interrupt::Overflow as u8, + let full_interrupt_set_from_u8_max = TimerInterruptSet::full(); + let full_interrupt_set_from_summed_variants = TimerInterruptSet( + TimerInterrupt::MatchOrCaptureChannel0 as u8 + | TimerInterrupt::MatchOrCaptureChannel1 as u8 + | TimerInterrupt::Error as u8 + | TimerInterrupt::Overflow as u8, ); - let full_interrupt_set = InterruptSet::from_iter(interrupts); + let full_interrupt_set = TimerInterruptSet::from_iter(interrupts); assert_eq!(full_interrupt_set_from_u8_max, full_interrupt_set); assert_eq!(full_interrupt_set_from_summed_variants, full_interrupt_set); assert_eq!(full_interrupt_set.count(), interrupts.len()); } #[test] fn test_interrupt_set_with_single_interrupts() { - for interrupt in InterruptSet(u8::MAX) { - let is_from = InterruptSet::from(interrupt); - let is_from_iter = InterruptSet::from_iter([interrupt]); + for interrupt in TimerInterruptSet(u8::MAX) { + let is_from = TimerInterruptSet::from(interrupt); + let is_from_iter = TimerInterruptSet::from_iter([interrupt]); assert_eq!(is_from, is_from_iter); } } #[test] fn test_empty_interrupt_set() { - let interrupt_set_from_0 = InterruptSet(0); - let interrupt_set_from_empty_iterator = InterruptSet::from_iter([]); + let interrupt_set_from_0 = TimerInterruptSet(0); + let interrupt_set_from_empty_iterator = TimerInterruptSet::from_iter([]); assert_eq!(0, interrupt_set_from_0.count()); assert_eq!(interrupt_set_from_0, interrupt_set_from_empty_iterator); } diff --git a/hal/src/thumbv7em/timer/v2/mono.rs b/hal/src/thumbv7em/timer/v2/mono.rs index ce18a45d722..1738a9cdff0 100644 --- a/hal/src/thumbv7em/timer/v2/mono.rs +++ b/hal/src/thumbv7em/timer/v2/mono.rs @@ -1,38 +1,64 @@ use super::*; -impl Timer { - pub fn into_monotonic( +pub trait IntoMonotonic { + fn into_monotonic( + self, + ) -> Result, TimerError>; +} + +impl IntoMonotonic for TimerBuilder { + fn into_monotonic( self, ) -> Result, TimerError> { - MonotonicTimer::enable(self) + let raw = self + .into_32_bit() + .into_raw() + .with_frequency(Hertz::Hz(TIMER_HZ))? + .with_mode(TimerMode::NFRQ) + .with_oneshot(false) + .with_direction(TimerDirection::Increment) + .with_interrupts(TimerInterrupt::Overflow.into()); + Ok(MonotonicTimer { raw, high_bits: 0 }) } } -pub struct MonotonicTimer { - inner_timer: Timer, +pub struct MonotonicTimer { + raw: RawTimer, high_bits: u32, } impl MonotonicTimer { - fn enable(inner: Timer) -> Result { - let inner_timer = inner - .with_frequency(Hertz::Hz(TIMER_HZ))? - .with_direction(TimerDirection::Increment) - .with_interrupts(Interrupt::Overflow.into()) - .enable(); - Ok(Self { - inner_timer, - high_bits: 0, - }) + pub fn enable(self) -> MonotonicTimer { + MonotonicTimer { + raw: self.raw.enable(), + high_bits: self.high_bits, + } } +} + +impl MonotonicTimer { + pub unsafe fn inner_raw(&mut self) -> &mut RawTimer { + &mut self.raw + } + + pub fn disable(self) -> MonotonicTimer { + MonotonicTimer { + raw: self.raw.disable(), + high_bits: self.high_bits, + } + } +} - pub fn disable(self) -> Timer { - self.inner_timer.disable() +impl IntoRaw + for MonotonicTimer +{ + fn into_raw(self) -> RawTimer { + self.raw } } impl rtic_monotonic::Monotonic - for MonotonicTimer + for MonotonicTimer { const DISABLE_INTERRUPT_ON_EMPTY_QUEUE: bool = false; @@ -41,7 +67,7 @@ impl rtic_monotonic::Monotonic type Duration = fugit::TimerDurationU64; fn now(&mut self) -> Self::Instant { - let ticks = u64::from(self.high_bits) << u32::BITS | u64::from(self.inner_timer.count()); + let ticks = u64::from(self.high_bits) << u32::BITS | u64::from(self.raw.count()); Self::Instant::from_ticks(ticks) } @@ -54,20 +80,20 @@ impl rtic_monotonic::Monotonic .map_or(0, |d| d.ticks()) <= u32::MAX.into() { - let timer = &mut self.inner_timer; - timer.enable_interrupts(Interrupt::MatchOrCaptureChannel0.into()); + let timer = &mut self.raw; + timer.enable_interrupts(TimerInterrupt::MatchOrCaptureChannel0.into()); timer.set_compare(TimerCompareRegister::Zero, instant.ticks() as u32); } } fn clear_compare_flag(&mut self) { - let timer = &mut self.inner_timer; + let timer = &mut self.raw; let interrupts = timer.interrupt_flags(); for interrupt in interrupts { match interrupt { - Interrupt::Overflow => self.high_bits += 1, - Interrupt::MatchOrCaptureChannel0 => { - timer.disable_interrupts(Interrupt::MatchOrCaptureChannel0.into()); + TimerInterrupt::Overflow => self.high_bits += 1, + TimerInterrupt::MatchOrCaptureChannel0 => { + timer.disable_interrupts(TimerInterrupt::MatchOrCaptureChannel0.into()); timer.set_compare(TimerCompareRegister::Zero, 0); } _ => {} @@ -81,6 +107,6 @@ impl rtic_monotonic::Monotonic unsafe fn reset(&mut self) { self.high_bits = 0; - self.inner_timer.set_count(0); + self.raw.set_count(0); } } diff --git a/hal/src/thumbv7em/timer/v2/prelude.rs b/hal/src/thumbv7em/timer/v2/prelude.rs new file mode 100644 index 00000000000..3bdb925179b --- /dev/null +++ b/hal/src/thumbv7em/timer/v2/prelude.rs @@ -0,0 +1,5 @@ +pub use super::FreeTimerResourcesExt as _; +pub use super::IntoCountdown as _; +#[cfg(feature = "rtic")] +pub use super::IntoMonotonic as _; +pub use super::IntoRaw as _; diff --git a/hal/src/thumbv7em/timer/v2/raw.rs b/hal/src/thumbv7em/timer/v2/raw.rs new file mode 100644 index 00000000000..11c5d362685 --- /dev/null +++ b/hal/src/thumbv7em/timer/v2/raw.rs @@ -0,0 +1,335 @@ +use super::*; + +pub trait IntoRaw { + fn into_raw(self) -> RawTimer; +} + +// TODO: These `pub(super)` are somewhat smelly; especially `reg` and `to` +// Maybe `Builder` should have access to a better API inside Timer, maybe at +// least unsafe Or maybe they should not be sibling modules, if builder needs to +// access raw, then maybe builder should be just submodule of raw. + +/// General timer abstraction. WiP. +pub struct RawTimer { + pub(super) reg: T::Reg, // pub(super) for the builder + pclk_freq: Hertz, + __: PhantomData<(I, S, TW)>, +} + +impl RawTimer { + // pub(super) for the builder + pub(super) fn new(reg: T::Reg, pclk_freq: Hertz) -> Self { + reg.count8().ctrla.modify(|_, w| w.swrst().set_bit()); + while reg.count8().syncbusy.read().swrst().bit_is_set() {} + let mut s = Self { + reg, + pclk_freq, + __: PhantomData, + }; + s.set_debug_run(false); // Not controlled by SWRST, setting explicitly + s + } +} + +impl RawTimer { + // pub(super) for the builder + pub(super) fn to(self) -> RawTimer { + RawTimer { + reg: self.reg, + pclk_freq: self.pclk_freq, + __: PhantomData, + } + } + + fn sync_ctrlbset_write(&mut self, write: impl WriteClosure) { + self.reg.count8().ctrlbset.write(write); + while self.reg.count8().syncbusy.read().ctrlb().bit_is_set() {} + } + + fn sync_ctrlbclr_write(&mut self, write: impl WriteClosure) { + self.reg.count8().ctrlbclr.write(write); + while self.reg.count8().syncbusy.read().ctrlb().bit_is_set() {} + } + + pub fn set_debug_run(&mut self, value: bool) -> &mut Self { + self.reg.count8().dbgctrl.write(|w| w.dbgrun().bit(value)); + self + } + + // To re-engage the timer one must call [`Timer::retrigger`] + pub fn set_oneshot(&mut self, value: bool) -> &mut Self { + if value { + self.sync_ctrlbset_write(|w| w.oneshot().set_bit()); + } else { + self.sync_ctrlbclr_write(|w| w.oneshot().set_bit()); + } + self + } + + pub fn set_ondemand(&mut self, value: bool) -> &mut Self { + self.reg + .count8() + .ctrla + .modify(|_, w| w.ondemand().bit(value)); + self + } + + pub fn set_runstdby(&mut self, value: bool) -> &mut Self { + self.reg + .count8() + .ctrla + .modify(|_, w| w.runstdby().bit(value)); + self + } + + pub fn set_direction(&mut self, dir: TimerDirection) -> &mut Self { + match dir { + TimerDirection::Increment => self.sync_ctrlbclr_write(|w| w.dir().set_bit()), + TimerDirection::Decrement => self.sync_ctrlbset_write(|w| w.dir().set_bit()), + } + self + } + + pub fn direction(&self) -> TimerDirection { + match self.reg.count8().ctrlbset.read().dir().bit_is_set() { + true => TimerDirection::Decrement, + false => TimerDirection::Increment, + } + } + + pub fn enable_interrupts(&mut self, interrupt_set: TimerInterruptSet) -> &mut Self { + self.reg + .count8() + .intenset + .write(|w| unsafe { w.bits(interrupt_set.0) }); + self + } + + pub fn disable_interrupts(&mut self, interrupt_set: TimerInterruptSet) -> &mut Self { + self.reg + .count8() + .intenclr + .write(|w| unsafe { w.bits(interrupt_set.0) }); + self + } + + pub unsafe fn registers(&mut self) -> &T::Reg { + &self.reg + } + + fn sync_run_command(&mut self, cmd: TimerCommand) -> &mut Self { + self.sync_ctrlbset_write(|w| w.cmd().variant(cmd)); + while !self.reg.count8().ctrlbset.read().cmd().is_none() {} + self + } +} + +impl RawTimer { + // TODO: Restoring the builder is dangerous if new configuration in + // "raw" mode violated some invariant that other "specific timer" + // might have made. + pub unsafe fn into_builder(self) -> TimerBuilder { + TimerBuilder::new(self) + } + + pub fn reset_into_builder(self) -> TimerBuilder { + TimerBuilder::new(RawTimer::new(self.reg, self.pclk_freq)) + } + + pub fn enable(self) -> RawTimer { + self.reg.count8().ctrla.modify(|_, w| w.enable().set_bit()); + while self.reg.count8().syncbusy.read().enable().bit_is_set() {} + self.to() + } + + pub fn with_ondemand(mut self, value: bool) -> Self { + self.set_ondemand(value); + self + } + + pub fn with_runstdby(mut self, value: bool) -> Self { + self.set_runstdby(value); + self + } + + pub fn with_oneshot(mut self, value: bool) -> Self { + self.set_oneshot(value); + self + } + + pub fn with_direction(mut self, dir: TimerDirection) -> Self { + self.set_direction(dir); + self + } + + /// Disables all interrupts first + pub fn with_interrupts(mut self, interrupt_set: TimerInterruptSet) -> Self { + // TODO: If monotonic/countdown decays into raw then we should disable + // interrupts first so it's more idempotent But then, maybe + // monotonic/countdown should do the same? :thinking: + // self.disable_interrupts(InterruptSet::full()); + self.enable_interrupts(interrupt_set); + self + } + + /// Mutually exclusive with [`Self::with_prescaler`] + pub fn with_frequency(self, frequency: Hertz) -> Result { + let input_freq = self.pclk_freq.to_Hz(); + let output_freq = frequency.to_Hz(); + let prescaler = match input_freq.checked_rem(output_freq) { + Some(0) => match input_freq / output_freq { + 1 => TimerPrescaler::DIV1, + 2 => TimerPrescaler::DIV2, + 4 => TimerPrescaler::DIV4, + 8 => TimerPrescaler::DIV8, + 16 => TimerPrescaler::DIV16, + 64 => TimerPrescaler::DIV64, + 256 => TimerPrescaler::DIV256, + 1024 => TimerPrescaler::DIV1024, + _ => { + return Err(TimerError::NoValidPrescaler( + TimerPrescalerError::InvalidPrescaler, + )) + } + }, + Some(_) => { + return Err(TimerError::NoValidPrescaler( + TimerPrescalerError::FrequenciesNotDivisible, + )) + } + None => { + return Err(TimerError::NoValidPrescaler( + TimerPrescalerError::OutputFrequencyIsZero, + )) + } + }; + Ok(self.with_prescaler(prescaler)) + } + + /// Mutually exclusive with [`Self::with_frequency`] + pub fn with_prescaler(self, prescaler: TimerPrescaler) -> Self { + self.reg + .count8() + .ctrla + .modify(|_, w| w.prescaler().variant(prescaler)); + self + } + + pub fn with_mode(self, mode: TimerMode) -> Self { + self.reg.count8().wave.write(|w| w.wavegen().variant(mode)); + self + } +} + +impl RawTimer { + pub fn disable(self) -> RawTimer { + self.reg.count8().ctrla.modify(|_, w| w.enable().set_bit()); + while self.reg.count8().syncbusy.read().enable().bit_is_set() {} + self.to() + } + + pub fn retrigger(&mut self) { + self.sync_run_command(TimerCommand::RETRIGGER); + } + + // Clears the interrupts + #[must_use] + pub fn interrupt_flags(&mut self) -> TimerInterruptSet { + let interrupts = self.reg.count8().intflag.read().bits(); + // Clear the interrupts + self.reg + .count8() + .intflag + .write(|w| unsafe { w.bits(interrupts) }); + TimerInterruptSet(interrupts) + } +} + +// TODO: Make sure that count && CCs can be interacted with when timer is +// disabled as well as when enabled Especially if `sync_run_command` is fine +// when disabled +impl RawTimer { + pub fn compare(&self, index: TimerCompareRegister) -> TW { + // Compare register value must be <= TW::MAX, this is noop + TW::truncated_from_u32(self.reg.count32().cc[index as usize].read().cc().bits()) + } + + pub fn set_compare(&mut self, index: TimerCompareRegister, compare: TW) -> &mut Self { + // Writing over reserved bits for an 8/16 bit timer, o-la-la. + // Hopefully that's fine. + self.reg.count32().cc[index as usize].write(|w| unsafe { w.cc().bits(compare.as_()) }); + match index { + TimerCompareRegister::Zero => { + while self.reg.count8().syncbusy.read().cc0().bit_is_set() {} + } + TimerCompareRegister::One => { + while self.reg.count8().syncbusy.read().cc1().bit_is_set() {} + } + } + self + } + + pub fn count(&mut self) -> TW { + self.sync_run_command(TimerCommand::READSYNC); + // Count value must be <= TW::MAX, this is noop + TW::truncated_from_u32(self.reg.count32().count.read().count().bits()) + } + + pub fn set_count(&mut self, count: TW) -> &mut Self { + // Writing over reserved bits for an 8/16 bit timer, o-la-la. + // Hopefully that's fine. + self.reg + .count32() + .count + .write(|w| unsafe { w.count().bits(count.as_()) }); + while self.reg.count8().syncbusy.read().count().bit_is_set() {} + self + } +} + +impl FreeTimerResourcesExt + for (RawTimer, RawTimer, I, TW2>) +{ + fn free( + self, + ) -> ( + T::Reg, + ApbClk, + Reg>, + ApbClk>, + Pclk, + ) { + ( + self.0.reg, + ApbClk::new(unsafe { ApbToken::new() }), + self.1.reg, + ApbClk::new(unsafe { ApbToken::new() }), + Pclk::new(unsafe { PclkToken::new() }, self.0.pclk_freq), + ) + } +} + +impl FreeTimerResourcesExt + for RawTimer +where + T::Reg: Into<(Reg, Reg)>, +{ + fn free( + self, + ) -> ( + Reg, + ApbClk, + Reg, + ApbClk, + Pclk, + ) { + let (pri_reg, sec_reg) = self.reg.into(); + ( + pri_reg, + ApbClk::new(unsafe { ApbToken::new() }), + sec_reg, + ApbClk::new(unsafe { ApbToken::new() }), + Pclk::new(unsafe { PclkToken::new() }, self.pclk_freq), + ) + } +} diff --git a/hal/src/thumbv7em/timer/v2/types.rs b/hal/src/thumbv7em/timer/v2/types.rs index 7ea034790e7..8a93b27b32b 100644 --- a/hal/src/thumbv7em/timer/v2/types.rs +++ b/hal/src/thumbv7em/timer/v2/types.rs @@ -1,7 +1,7 @@ use core::ops::Deref; -use crate::clock::v2::apb::ApbId; -use crate::clock::v2::pclk::PclkId; +use crate::clock::v2::apb::{ApbClk, ApbId}; +use crate::clock::v2::pclk::{Pclk, PclkId, PclkSourceId}; use crate::clock::v2::types; use crate::pac; @@ -143,28 +143,29 @@ pub mod state { } pub mod timer_width { - pub trait TimerWidth: Copy + Clone + num_traits::AsPrimitive { - fn from_u32(v: u32) -> Self; + use num_traits::*; + pub trait TimerWidth: Copy + Clone + AsPrimitive + FromPrimitive + Bounded { + fn truncated_from_u32(v: u32) -> Self; } - impl TimerWidth for u8 { - fn from_u32(v: u32) -> Self { - v as Self - } - } - impl TimerWidth for u16 { - fn from_u32(v: u32) -> Self { - v as Self - } - } - impl TimerWidth for u32 { - fn from_u32(v: u32) -> Self { - v as Self + macro_rules! impl_timer_width_for { + ( + $($t:ty),+ + ) => { + $( + impl TimerWidth for $t { + fn truncated_from_u32(v: u32) -> Self { + v as Self + } + } + )+ } } + + impl_timer_width_for!(u8, u16, u32); } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum TimerDirection { Increment, Decrement, @@ -172,6 +173,8 @@ pub enum TimerDirection { pub type TimerPrescaler = crate::pac::tc0::count8::ctrla::PRESCALER_A; +pub type TimerMode = crate::pac::tc0::count8::wave::WAVEGEN_A; + #[derive(Copy, Clone, Debug)] pub enum TimerError { NoValidPrescaler(TimerPrescalerError), @@ -210,3 +213,15 @@ pub enum TimerCompareRegister { pub(super) type SecondaryTimer = <::CombinedTimer as CombinedTimerId>::SecondaryTimer; pub(super) type Reg = ::Reg; + +pub trait FreeTimerResourcesExt { + fn free( + self, + ) -> ( + T::Reg, + ApbClk, + Reg>, + ApbClk>, + Pclk, + ); +}