#[macro_use]
pub mod base {
use crate::hal::generic::timer::{TimerInterruptHandler, TimerMode, TimerControl};
pub trait AtmelTCB {
fn enable(&self);
fn disable(&self);
fn enable_interrupt(&self);
fn clear_interrupt(&self);
fn mask_interrupt(&self);
fn set_top(&self, top: u16);
fn set_periodic_mode(&self);
}
pub struct AtmelTimer<T>
where
T: 'static + AtmelTCB
{
pub(in super) interrupt_handler: Option<TimerInterruptHandler>,
pub(in super) interrupt_period: u16,
pub(in super) tcb: &'static T,
pub(in super) count_max: u16,
pub(in super) mode: TimerMode
}
impl<T> TimerControl for AtmelTimer<T>
where
T: AtmelTCB
{
fn interrupting(&mut self, period: u16) -> &mut Self {
self.interrupt_period = period;
self
}
fn mode(&mut self, mode: TimerMode) -> &mut Self {
self.mode = mode;
self
}
fn count_max(&mut self, max: u16) -> &mut Self {
self.count_max = max;
self
}
fn start(&mut self, handler: Option<TimerInterruptHandler>) {
self.tcb.disable();
match self.mode {
TimerMode::Periodic => {
self.tcb.set_periodic_mode();
self.tcb.set_top(self.count_max.clone());
}
};
self.tcb.clear_interrupt();
match handler {
None => {
self.tcb.mask_interrupt();
},
Some(handler) => {
self.interrupt_handler = Some(handler);
self.tcb.enable_interrupt();
}
}
self.tcb.enable();
}
fn stop(&mut self) {
self.tcb.disable();
}
fn get_count(&self) -> u16 {
todo!()
}
fn reset_count(&mut self) {
todo!()
}
}
impl<T> AtmelTimer<T>
where
T: AtmelTCB
{
#[inline(always)]
pub(in super) fn call_interrupt(&self, ticks: u16) {
match self.interrupt_handler {
Some(handler) => {
match handler(ticks) {
true => {},
false => self.tcb.disable()
}
},
None => {}
}
}
#[inline(always)]
pub(in super) fn interrupt_period(&self) -> u16 {
self.interrupt_period.clone()
}
}
#[macro_export]
macro_rules! atmel_tcb {
($tcb:ty) => {
impl AtmelTCB for $tcb {
#[inline(always)]
fn enable(&self) {
self.ctrla.write(|w| unsafe { w.bits(0b01000011)});
}
#[inline(always)]
fn disable(&self) {
self.ctrla.write(|w| unsafe { w.bits(0b00000000)});
}
#[inline(always)]
fn enable_interrupt(&self) {
self.intctrl.write(|w| w.capt().set_bit());
}
#[inline(always)]
fn clear_interrupt(&self) {
self.intflags.write(|w| w.capt().set_bit());
}
#[inline(always)]
fn mask_interrupt(&self) {
self.intctrl.write(|w| w.capt().clear_bit());
}
#[inline(always)]
fn set_top(&self, top: u16) {
unsafe {
self.cnt.write(|w| w.bits(0x0000));
self.ccmp.write(|w| w.bits(top));
}
}
#[inline(always)]
fn set_periodic_mode(&self) {
unsafe {
self.ctrlb.write(|w|w.bits(1 << 4));
}
}
}
}
}
}
pub mod tcb0 {
extern crate avr_device_snowgoons as avr_device;
use crate::hal::generic::timer::TimerMode;
use crate::hal::atmega4809::timer::base::{ AtmelTimer, AtmelTCB};
use crate::mut_singleton;
pub type TimerImpl = AtmelTimer<avr_device::atmega4809::tcb0::RegisterBlock>;
mut_singleton!(
AtmelTimer<avr_device::atmega4809::tcb0::RegisterBlock>,
INSTANCE,
instance,
AtmelTimer {
interrupt_handler: None,
interrupt_period: 0,
tcb: & *avr_device::atmega4809::TCB0::ptr(),
count_max: 0,
mode: TimerMode::Periodic
});
atmel_tcb!(avr_device::atmega4809::tcb0::RegisterBlock);
#[no_mangle]
pub unsafe extern "avr-interrupt" fn _ivr_tcb0_int() {
static mut COUNT_INTS : u16 = 0;
if COUNT_INTS < u16::MAX {
COUNT_INTS += 1;
}
let tcb0 = avr_device::atmega4809::TCB0::ptr();
match &mut INSTANCE {
None => {},
Some(atmeltimer) => {
if COUNT_INTS >= atmeltimer.interrupt_period() {
atmeltimer.call_interrupt(COUNT_INTS.clone());
COUNT_INTS = 0;
}
}
}
(*tcb0).intflags.write(|w| w.capt().set_bit());
}
}
pub mod tcb1 {
extern crate avr_device_snowgoons as avr_device;
use crate::hal::generic::timer::TimerMode;
use crate::hal::atmega4809::timer::base::{ AtmelTimer, AtmelTCB};
use crate::mut_singleton;
pub type TimerImpl = AtmelTimer<avr_device::atmega4809::tcb1::RegisterBlock>;
mut_singleton!(
AtmelTimer<avr_device::atmega4809::tcb1::RegisterBlock>,
INSTANCE,
instance,
AtmelTimer {
interrupt_handler: None,
interrupt_period: 0,
tcb: & *avr_device::atmega4809::TCB1::ptr(),
count_max: 0,
mode: TimerMode::Periodic
});
atmel_tcb!(avr_device::atmega4809::tcb1::RegisterBlock);
#[no_mangle]
pub unsafe extern "avr-interrupt" fn _ivr_tcb1_int() {
static mut COUNT_INTS : u16 = 0;
if COUNT_INTS < u16::MAX {
COUNT_INTS += 1;
}
let tcb1 = avr_device::atmega4809::TCB1::ptr();
match &mut INSTANCE {
None => {},
Some(atmeltimer) => {
if COUNT_INTS >= atmeltimer.interrupt_period() {
atmeltimer.call_interrupt(COUNT_INTS.clone());
COUNT_INTS = 0;
}
}
}
(*tcb1).intflags.write(|w| w.capt().set_bit());
}
}