use crate::hal::timer::{CountDown, Periodic};
use crate::BorrowUnchecked;
use core::marker::PhantomData;
use cortex_m::{interrupt, peripheral::DWT};
use fugit::{
HertzU32 as Hertz, RateExtU32, TimerDurationU32 as TimerDuration, TimerRateU32 as TimerRate,
};
use void::Void;
use crate::pac::TC0;
#[cfg(any(feature = "atsam4e_e", feature = "atsam4n_c", feature = "atsam4s_c"))]
use crate::pac::TC1;
#[cfg(feature = "atsam4e_e")]
use crate::pac::TC2;
use crate::clock::{Enabled, Tc0Clock, Tc1Clock, Tc2Clock};
#[cfg(any(feature = "atsam4e_e", feature = "atsam4n_c", feature = "atsam4s_c"))]
use crate::clock::{Tc3Clock, Tc4Clock, Tc5Clock};
#[cfg(feature = "atsam4e_e")]
use crate::clock::{Tc6Clock, Tc7Clock, Tc8Clock};
#[derive(Clone, Copy, Debug, PartialEq, Eq, defmt::Format)]
pub enum ClockSource {
MckDiv2 = 0,
MckDiv8 = 1,
MckDiv32 = 2,
MckDiv128 = 3,
Slck32768Hz = 4,
}
impl ClockSource {
pub const fn div(&self) -> u32 {
match self {
ClockSource::MckDiv2 => 2,
ClockSource::MckDiv8 => 8,
ClockSource::MckDiv32 => 32,
ClockSource::MckDiv128 => 128,
ClockSource::Slck32768Hz => {
panic!("Invalid, must set frequency manually");
}
}
}
}
pub struct TimerCounter<TC> {
_tc: TC,
}
pub struct TimerCounterChannels<
TC,
CLK1,
CLK2,
CLK3,
const FREQ1: u32,
const FREQ2: u32,
const FREQ3: u32,
> {
pub ch0: TimerCounterChannel<TC, CLK1, 0, FREQ1>,
pub ch1: TimerCounterChannel<TC, CLK2, 1, FREQ2>,
pub ch2: TimerCounterChannel<TC, CLK3, 2, FREQ3>,
}
pub struct TimerCounterChannel<TC, CLK, const CH: u8, const FREQ: u32> {
freq: Hertz,
source: ClockSource,
_clock: PhantomData<CLK>,
_mode: PhantomData<TC>,
}
macro_rules! tc {
($($TYPE:ident: ($TC:ident, $clock1:ident, $clock2:ident, $clock3:ident),)+) => {
$(
pub type $TYPE = TimerCounter<$TC>;
impl TimerCounter<$TC>
{
/// Configure this timer counter block.
/// Each TC block has 3 channels
/// The clock is obtained from the `ClockController` instance
/// and its frequency impacts the resolution and maximum range of
/// the timeout values that can be passed to the `start` method.
///
/// Example
/// ```
/// let clocks = ClockController::new(
/// cx.device.PMC,
/// &cx.device.SUPC,
/// &cx.device.EFC0,
/// MainClock::Crystal12Mhz,
/// SlowClock::RcOscillator32Khz,
/// );
pub fn new(tc: $TC) -> Self {
unsafe {
tc.wpmr.write_with_zero(|w| w.wpkey().passwd().wpen().clear_bit());
tc.ccr0.write_with_zero(|w| w.clkdis().set_bit());
tc.ccr1.write_with_zero(|w| w.clkdis().set_bit());
tc.ccr2.write_with_zero(|w| w.clkdis().set_bit());
}
Self {
_tc: tc,
}
}
pub fn split<const FREQ1: u32, const FREQ2: u32, const FREQ3: u32>(self, clock1: $clock1<Enabled>, _clock2: $clock2<Enabled>, _clock3: $clock3<Enabled>) -> TimerCounterChannels<$TC, $clock1<Enabled>, $clock2<Enabled>, $clock3<Enabled>, FREQ1, FREQ2, FREQ3> {
let freq = clock1.frequency();
let source = ClockSource::MckDiv2;
TimerCounterChannels::<$TC, $clock1<Enabled>, $clock2<Enabled>, $clock3<Enabled>, FREQ1, FREQ2, FREQ3> {
ch0: TimerCounterChannel { _clock: PhantomData, freq, source, _mode: PhantomData },
ch1: TimerCounterChannel { _clock: PhantomData, freq, source, _mode: PhantomData },
ch2: TimerCounterChannel { _clock: PhantomData, freq, source, _mode: PhantomData },
}
}
}
impl<CLK, const CH: u8, const FREQ: u32> TimerCounterChannel<$TC, CLK, CH, FREQ> {
pub fn clock_input(&mut self, source: ClockSource) {
self.source = source;
match CH {
0 => $TC::borrow_unchecked(|tc| tc.cmr0().modify(|_, w| w.tcclks().bits(source as u8))),
1 => $TC::borrow_unchecked(|tc| tc.cmr1().modify(|_, w| w.tcclks().bits(source as u8))),
2 => $TC::borrow_unchecked(|tc| tc.cmr2().modify(|_, w| w.tcclks().bits(source as u8))),
_ => panic!("Invalid TimerCounterChannel: {}", CH),
}
}
pub fn enable_interrupt(&mut self) {
match CH {
0 => $TC::borrow_unchecked(|tc| unsafe { tc.ier0.write_with_zero(|w| w.cpcs().set_bit())}),
1 => $TC::borrow_unchecked(|tc| unsafe { tc.ier1.write_with_zero(|w| w.cpcs().set_bit())}),
2 => $TC::borrow_unchecked(|tc| unsafe { tc.ier2.write_with_zero(|w| w.cpcs().set_bit())}),
_ => panic!("Invalid TimerCounterChannel: {}", CH),
}
}
pub fn disable_interrupt(&mut self) {
match CH {
0 => $TC::borrow_unchecked(|tc| unsafe { tc.idr0.write_with_zero(|w| w.cpcs().set_bit())}),
1 => $TC::borrow_unchecked(|tc| unsafe { tc.idr1.write_with_zero(|w| w.cpcs().set_bit())}),
2 => $TC::borrow_unchecked(|tc| unsafe { tc.idr2.write_with_zero(|w| w.cpcs().set_bit())}),
_ => panic!("Invalid TimerCounterChannel: {}", CH),
}
}
pub fn clear_interrupt_flags(&mut self) -> bool {
match CH {
0 => $TC::borrow_unchecked(|tc| tc.sr0.read().cpcs().bit()),
1 => $TC::borrow_unchecked(|tc| tc.sr1.read().cpcs().bit()),
2 => $TC::borrow_unchecked(|tc| tc.sr2.read().cpcs().bit()),
_ => panic!("Invalid TimerCounterChannel: {}", CH),
}
}
}
impl<CLK, const CH: u8, const FREQ: u32> Periodic for TimerCounterChannel<$TC, CLK, CH, FREQ> {}
impl<CLK, const CH: u8, const FREQ: u32> CountDown for TimerCounterChannel<$TC, CLK, CH, FREQ> {
type Time = TimerDuration<FREQ>;
fn start<T>(&mut self, timeout: T)
where
T: Into<Self::Time>,
{
let timeout: TimerDuration<FREQ> = timeout.into();
let rate: Hertz = timeout.into_rate();
let freq: TimerRate<FREQ> = FREQ.Hz();
match self.source {
ClockSource::MckDiv2 => {
let div_freq = self.freq / 2;
assert_eq!(freq, div_freq, "FREQ({}) != self.freq / 2 ({})", freq, div_freq);
}
ClockSource::MckDiv8 => {
let div_freq = self.freq / 8;
assert_eq!(freq, div_freq, "FREQ({}) != self.freq / 8 ({})", freq, div_freq);
}
ClockSource::MckDiv32 => {
let div_freq = self.freq / 32;
assert_eq!(freq, div_freq, "FREQ({}) != self.freq / 32 ({})", freq, div_freq);
}
ClockSource::MckDiv128 => {
let div_freq = self.freq / 128;
assert_eq!(freq, div_freq, "FREQ({}) != self.freq / 128 ({})", freq, div_freq);
}
ClockSource::Slck32768Hz => {
let div_freq = 32768_u32.Hz::<1, 1>();
assert_eq!(freq, div_freq, "FREQ({}) != {}", freq, div_freq);
}
}
if rate > freq {
panic!("{} is too fast. Max {}", rate, freq);
}
#[cfg(feature = "atsam4e")]
let max_counter = u32::max_value();
#[cfg(any(feature = "atsam4n", feature = "atsam4s"))]
let max_counter: u32 = u16::max_value() as u32;
let cycles = freq / rate;
if cycles > max_counter.into() {
let min_freq: TimerRate<FREQ> = freq / max_counter;
panic!("{} Hz is too slow. Min {} Hz.", rate, min_freq);
}
defmt::trace!("{}->{} Cycles:{} ClockSource:{}", core::stringify!($TC), CH, cycles, self.source);
match CH {
0 => $TC::borrow_unchecked(|tc| tc.cmr0().modify(|_, w| w.tcclks().bits(self.source as u8).cpctrg().set_bit())),
1 => $TC::borrow_unchecked(|tc| tc.cmr1().modify(|_, w| w.tcclks().bits(self.source as u8).cpctrg().set_bit())),
2 => $TC::borrow_unchecked(|tc| tc.cmr2().modify(|_, w| w.tcclks().bits(self.source as u8).cpctrg().set_bit())),
_ => panic!("Invalid TimerCounterChannel: {}", CH),
}
match CH {
0 => $TC::borrow_unchecked(|tc| unsafe { tc.rc0.write_with_zero(|w| w.rc().bits(cycles) )}),
1 => $TC::borrow_unchecked(|tc| unsafe { tc.rc1.write_with_zero(|w| w.rc().bits(cycles) )}),
2 => $TC::borrow_unchecked(|tc| unsafe { tc.rc2.write_with_zero(|w| w.rc().bits(cycles) )}),
_ => panic!("Invalid TimerCounterChannel: {}", CH),
}
self.clear_interrupt_flags();
match CH {
0 => $TC::borrow_unchecked(|tc| unsafe { tc.ccr0.write_with_zero(|w| w.clken().set_bit().swtrg().set_bit())}),
1 => $TC::borrow_unchecked(|tc| unsafe { tc.ccr1.write_with_zero(|w| w.clken().set_bit().swtrg().set_bit())}),
2 => $TC::borrow_unchecked(|tc| unsafe { tc.ccr2.write_with_zero(|w| w.clken().set_bit().swtrg().set_bit())}),
_ => panic!("Invalid TimerCounterChannel: {}", CH),
}
}
fn wait(&mut self) -> nb::Result<(), Void> {
if match CH {
0 => $TC::borrow_unchecked(|tc| tc.sr0.read().cpcs().bit()),
1 => $TC::borrow_unchecked(|tc| tc.sr1.read().cpcs().bit()),
2 => $TC::borrow_unchecked(|tc| tc.sr2.read().cpcs().bit()),
_ => panic!("Invalid TimerCounterChannel: {}", CH),
} {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
)+
}
}
tc! {
TimerCounter0: (TC0, Tc0Clock, Tc1Clock, Tc2Clock),
}
#[cfg(any(feature = "atsam4e_e", feature = "atsam4n_c", feature = "atsam4s_c"))]
tc! {
TimerCounter1: (TC1, Tc3Clock, Tc4Clock, Tc5Clock),
}
#[cfg(feature = "atsam4e_e")]
tc! {
TimerCounter2: (TC2, Tc6Clock, Tc7Clock, Tc8Clock),
}
pub struct DwtTimer<const TIMER_HZ: u32> {
end_time: Option<fugit::TimerInstantU32<TIMER_HZ>>,
}
impl<const TIMER_HZ: u32> DwtTimer<TIMER_HZ> {
pub fn new() -> Self {
Self { end_time: None }
}
pub fn now() -> u64 {
static mut DWT_OVERFLOWS: u32 = 0;
static mut OLD_DWT: u32 = 0;
interrupt::free(|_| {
let (overflows, last_cnt) = unsafe { (&mut DWT_OVERFLOWS, &mut OLD_DWT) };
let cyccnt = DWT::cycle_count();
if cyccnt <= *last_cnt {
*overflows += 1;
}
let ticks = (*overflows as u64) << 32 | (cyccnt as u64);
*last_cnt = cyccnt;
ticks
})
}
}
impl<const TIMER_HZ: u32> Default for DwtTimer<TIMER_HZ> {
fn default() -> Self {
Self::new()
}
}
impl<const TIMER_HZ: u32> fugit_timer::Timer<TIMER_HZ> for DwtTimer<TIMER_HZ> {
type Error = core::convert::Infallible;
fn now(&mut self) -> fugit::TimerInstantU32<TIMER_HZ> {
fugit::TimerInstantU32::from_ticks(Self::now() as u32)
}
fn start(&mut self, duration: fugit::TimerDurationU32<TIMER_HZ>) -> Result<(), Self::Error> {
let end = self.now() + duration;
self.end_time.replace(end);
Ok(())
}
fn cancel(&mut self) -> Result<(), Self::Error> {
self.end_time.take();
Ok(())
}
fn wait(&mut self) -> nb::Result<(), Self::Error> {
let now = self.now();
match self.end_time {
Some(end) if end <= now => Ok(()),
_ => Err(nb::Error::WouldBlock),
}
}
}