#![macro_use]
use core::marker::PhantomData;
use embassy_hal_internal::{Peri, PeripheralType};
use crate::pac;
use crate::pac::timer::vals;
use crate::ppi::{Event, Task};
pub(crate) trait SealedInstance {
const CCS: usize;
fn regs() -> pac::timer::Timer;
}
#[allow(private_bounds)]
pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
type Interrupt: crate::interrupt::typelevel::Interrupt;
}
pub trait ExtendedInstance: Instance {}
macro_rules! impl_timer {
($type:ident, $pac_type:ident, $irq:ident, $ccs:literal) => {
impl crate::timer::SealedInstance for peripherals::$type {
const CCS: usize = $ccs;
fn regs() -> pac::timer::Timer {
unsafe { pac::timer::Timer::from_ptr(pac::$pac_type.as_ptr()) }
}
}
impl crate::timer::Instance for peripherals::$type {
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
($type:ident, $pac_type:ident, $irq:ident) => {
impl_timer!($type, $pac_type, $irq, 4);
};
($type:ident, $pac_type:ident, $irq:ident, extended) => {
impl_timer!($type, $pac_type, $irq, 6);
impl crate::timer::ExtendedInstance for peripherals::$type {}
};
}
#[repr(u8)]
pub enum Frequency {
F16MHz = 0,
F8MHz = 1,
F4MHz = 2,
F2MHz = 3,
F1MHz = 4,
F500kHz = 5,
F250kHz = 6,
F125kHz = 7,
F62500Hz = 8,
F31250Hz = 9,
}
pub struct Timer<'d> {
r: pac::timer::Timer,
ccs: usize,
_p: PhantomData<&'d ()>,
}
impl<'d> Timer<'d> {
pub fn new<T: Instance>(timer: Peri<'d, T>) -> Self {
Self::new_inner(timer, false)
}
pub fn new_counter<T: Instance>(timer: Peri<'d, T>) -> Self {
Self::new_inner(timer, true)
}
fn new_inner<T: Instance>(_timer: Peri<'d, T>, is_counter: bool) -> Self {
let regs = T::regs();
let this = Self {
r: regs,
ccs: T::CCS,
_p: PhantomData,
};
this.stop();
regs.mode().write(|w| {
w.set_mode(match is_counter {
#[cfg(not(feature = "_nrf51"))]
true => vals::Mode::LOW_POWER_COUNTER,
#[cfg(feature = "_nrf51")]
true => vals::Mode::COUNTER,
false => vals::Mode::TIMER,
})
});
regs.bitmode().write(|w| w.set_bitmode(vals::Bitmode::_32BIT));
this.clear();
this.set_frequency(Frequency::F1MHz);
for n in 0..this.ccs {
let cc = this.cc(n);
cc.unshort_compare_clear();
cc.unshort_compare_stop();
cc.write(0);
}
this
}
#[cfg(feature = "unstable-pac")]
#[inline]
pub fn regs(&mut self) -> pac::timer::Timer {
self.r
}
pub fn start(&self) {
self.r.tasks_start().write_value(1)
}
pub fn stop(&self) {
self.r.tasks_stop().write_value(1)
}
pub fn clear(&self) {
self.r.tasks_clear().write_value(1)
}
pub fn task_start(&self) -> Task<'d> {
Task::from_reg(self.r.tasks_start())
}
pub fn task_stop(&self) -> Task<'d> {
Task::from_reg(self.r.tasks_stop())
}
pub fn task_clear(&self) -> Task<'d> {
Task::from_reg(self.r.tasks_clear())
}
pub fn task_count(&self) -> Task<'d> {
Task::from_reg(self.r.tasks_count())
}
pub fn set_frequency(&self, frequency: Frequency) {
self.stop();
self.r
.prescaler()
.write(|w| w.set_prescaler(frequency as u8))
}
pub fn cc(&self, n: usize) -> Cc<'d> {
if n >= self.ccs {
panic!("Cannot get CC register {} of timer with {} CC registers.", n, self.ccs);
}
Cc {
n,
r: self.r,
_p: PhantomData,
}
}
}
impl Timer<'static> {
pub fn persist(self) {
core::mem::forget(self);
}
}
impl<'d> Drop for Timer<'d> {
fn drop(&mut self) {
self.stop();
}
}
pub struct Cc<'d> {
n: usize,
r: pac::timer::Timer,
_p: PhantomData<&'d ()>,
}
impl<'d> Cc<'d> {
pub fn read(&self) -> u32 {
self.r.cc(self.n).read()
}
pub fn write(&self, value: u32) {
self.r.cc(self.n).write_value(value);
}
pub fn capture(&self) -> u32 {
self.r.tasks_capture(self.n).write_value(1);
self.read()
}
pub fn task_capture(&self) -> Task<'d> {
Task::from_reg(self.r.tasks_capture(self.n))
}
pub fn event_compare(&self) -> Event<'d> {
Event::from_reg(self.r.events_compare(self.n))
}
#[inline]
pub fn clear_events(&self) {
self.r.events_compare(self.n).write_value(0);
}
pub fn short_compare_clear(&self) {
self.r.shorts().modify(|w| w.set_compare_clear(self.n, true))
}
pub fn unshort_compare_clear(&self) {
self.r.shorts().modify(|w| w.set_compare_clear(self.n, false))
}
pub fn short_compare_stop(&self) {
self.r.shorts().modify(|w| w.set_compare_stop(self.n, true))
}
pub fn unshort_compare_stop(&self) {
self.r.shorts().modify(|w| w.set_compare_stop(self.n, false))
}
}