use core::any::Any;
use ufmt::derive::uDebug;
use avr_oxide::concurrency::Isolated;
use oxide_macros::Persist;
use avr_oxide::hal::generic::callback::IsrCallback;
#[derive(Clone,Copy)]
pub enum TimerMode {
Periodic
}
#[derive(Clone,Copy,PartialEq,Eq,uDebug,Persist)]
pub enum TimerIdentity {
Tcb0,
Tcb1,
Tcb2,
Tcb3,
Rtc
}
pub type TimerIsrFunction = fn(Isolated, TimerIdentity, u16, Option<*const dyn Any>) ->bool;
pub type TimerIsrCallback = IsrCallback<TimerIsrFunction,bool>;
pub trait TimerControl {
fn set_interrupt_period(&mut self, period: u16);
fn set_mode(&mut self, mode: TimerMode);
fn set_count_max(&mut self, max: u16);
fn start(&self, handler: TimerIsrCallback);
fn stop(&self);
fn get_count(&self) -> u16;
fn reset_count(&mut self);
}
#[derive(Copy,Clone)]
pub enum RtcSource {
Int32k,
Int1k,
TOsc32k,
External
}
#[derive(Copy,Clone)]
pub enum RtcCalibration {
Fast(u8),
Slow(u8)
}
#[derive(Copy,Clone)]
pub enum RtcPrescaler {
Div1,
Div2,
Div4,
Div8,
Div16,
Div32,
Div64,
Div128,
Div256,
Div512,
Div1024,
Div2048,
Div4096,
Div8192,
Div16384,
Div32768
}
pub trait RtcTimerCalibration {
fn set_clock_calibration(&mut self, source: RtcSource, calibration: RtcCalibration, prescaler: RtcPrescaler);
}
#[cfg(target_arch="avr")]
pub mod base {
use core::cell::{Cell};
use avr_oxide::hal::generic::timer::{TimerIsrCallback, TimerMode, TimerControl, TimerIdentity, RtcTimerCalibration, RtcSource, RtcCalibration, RtcPrescaler};
use avr_oxide::{isr_cb_invoke};
use avr_oxide::concurrency::{interrupt, Isolated};
use avr_oxide::hal::generic::MutDeviceRef;
use avr_oxide::util::datatypes::{BitFieldAccess, BitIndex, Volatile, VolatileBitField};
#[repr(C)]
pub struct AvrTypeBTimerControl {
pub(crate) ctrla: Volatile<u8>,
pub(crate) ctrlb: VolatileBitField,
pub(crate) reserved: [u8; 2],
pub(crate) evctrl: Volatile<u8>,
pub(crate) intctrl: VolatileBitField,
pub(crate) intflags: VolatileBitField,
pub(crate) status: Volatile<u8>,
pub(crate) dbgctrl: Volatile<u8>,
pub(crate) temp: Volatile<u8>,
pub(crate) cnt: Volatile<u16>,
pub(crate) ccmp: Volatile<u16>
}
pub trait AtmelTCB {
fn enable(&mut self, isotoken: interrupt::token::Isolated);
fn disable(&mut self, isotoken: interrupt::token::Isolated);
fn enable_interrupt(&mut self, isotoken: interrupt::token::Isolated);
fn clear_interrupt(&mut self, isotoken: interrupt::token::Isolated);
fn mask_interrupt(&mut self, isotoken: interrupt::token::Isolated);
fn set_top(&mut self, isotoken: interrupt::token::Isolated, top: u16);
fn set_periodic_mode(&mut self, isotoken: interrupt::token::Isolated);
}
impl AtmelTCB for AvrTypeBTimerControl {
fn enable(&mut self, _isotoken: interrupt::token::Isolated) {
self.ctrla.write(0b01000011);
}
fn disable(&mut self, _isotoken: interrupt::token::Isolated) {
self.ctrla.write(0b00000000);
}
fn enable_interrupt(&mut self, isotoken: interrupt::token::Isolated) {
self.intctrl.set_isolated(isotoken, BitIndex::bit_c(0));
}
fn clear_interrupt(&mut self, isotoken: interrupt::token::Isolated) {
self.intflags.set_isolated(isotoken, BitIndex::bit_c(0));
}
fn mask_interrupt(&mut self, isotoken: interrupt::token::Isolated) {
self.intctrl.clr_isolated(isotoken, BitIndex::bit_c(0));
}
fn set_top(&mut self, isotoken: interrupt::token::Isolated, top: u16) {
self.cnt.write_isolated(isotoken,0x0000);
self.ccmp.write_isolated(isotoken,top);
}
fn set_periodic_mode(&mut self, isotoken: interrupt::token::Isolated) {
self.ctrlb.set_isolated(isotoken, BitIndex::bit_c(4));
}
}
pub struct AtmelTimer<T>
where
T: 'static + AtmelTCB
{
pub(crate) interrupt_handler: Cell<TimerIsrCallback>,
pub(crate) interrupt_period: Volatile<u16>,
pub(crate) tcb: MutDeviceRef<T>,
pub(crate) count_max: Volatile<u16>,
pub(crate) mode: TimerMode
}
impl<T> TimerControl for AtmelTimer<T>
where
T: AtmelTCB
{
fn set_interrupt_period(&mut self, period: u16) {
self.interrupt_period.write(period);
}
fn set_mode(&mut self, mode: TimerMode) {
self.mode = mode;
}
fn set_count_max(&mut self, max: u16) {
self.count_max.write(max);
}
fn start(&self, handler: TimerIsrCallback) {
avr_oxide::concurrency::interrupt::isolated(|isotoken|{
let tcb = self.tcb.borrow_mut(isotoken);
tcb.disable(isotoken);
match self.mode {
TimerMode::Periodic => {
tcb.set_periodic_mode(isotoken);
tcb.set_top(isotoken, self.count_max.read());
}
};
tcb.clear_interrupt(isotoken);
self.interrupt_handler.replace(handler);
if handler.is_nop() {
tcb.mask_interrupt(isotoken);
} else {
tcb.enable_interrupt(isotoken);
}
tcb.enable(isotoken);
});
}
fn stop(&self) {
avr_oxide::concurrency::interrupt::isolated(|isotoken|{
let tcb = self.tcb.borrow_mut(isotoken);
tcb.disable(isotoken);
});
}
fn get_count(&self) -> u16 {
todo!()
}
fn reset_count(&mut self) {
todo!()
}
}
impl<T> AtmelTimer<T>
where
T: AtmelTCB
{
pub(crate) fn call_interrupt(&mut self, isotoken: Isolated, source: TimerIdentity, ticks: u16) {
let continue_running = isr_cb_invoke!(isotoken, self.interrupt_handler.get(), source, ticks);
if !continue_running {
self.tcb.borrow_mut(isotoken).disable(isotoken);
}
}
pub(crate) fn interrupt_period(&self, _isotoken: Isolated) -> u16 {
self.interrupt_period.read()
}
pub(crate) fn clear_interrupt(&self, isotoken: Isolated) {
self.tcb.borrow_mut(isotoken).clear_interrupt(isotoken);
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! atmel_tcb {
($tcbref:expr, $timersrc:expr, $isr:expr) => {
use avr_oxide::hal::generic::timer::{ TimerMode, TimerIsrCallback };
use avr_oxide::hal::generic::timer::base::{ AtmelTimer, AtmelTCB, AvrTypeBTimerControl };
use avr_oxide::util::datatypes::Volatile;
use avr_oxide::mut_singleton_explicit_init;
use avr_oxide::hal::generic::MutDeviceRef;
use core::cell::Cell;
pub type TimerImpl = AtmelTimer<AvrTypeBTimerControl>;
mut_singleton_explicit_init!(
AtmelTimer<AvrTypeBTimerControl>,
__INSTANCE,
initialise, instance, instance_isolated,
AtmelTimer {
interrupt_handler: Cell::new(TimerIsrCallback::Nop(false)),
interrupt_period: Volatile::<u16>::zero(),
tcb: MutDeviceRef::new($tcbref),
count_max: Volatile::<u16>::zero(),
mode: TimerMode::Periodic
});
#[oxide_macros::interrupt(isr=$isr)]
fn usart_timer_interrupt(isotoken: avr_oxide::concurrency::Isolated) {
static mut COUNT_INTS : Volatile<u16> = Volatile::<u16>::zero();
let counter = COUNT_INTS.read();
let atmeltimer = instance_isolated(isotoken);
if counter > atmeltimer.interrupt_period(isotoken) {
atmeltimer.call_interrupt(isotoken, $timersrc, atmeltimer.interrupt_period(isotoken));
COUNT_INTS.write_isolated(isotoken, 0u16);
} else {
COUNT_INTS.write_isolated(isotoken, counter+1);
}
atmeltimer.clear_interrupt(isotoken);
}
}
}
#[repr(C)]
pub struct AvrRealTimeCounterControl {
pub(crate) ctrla: Volatile<u8>,
pub(crate) status: VolatileBitField,
pub(crate) intctrl: VolatileBitField,
pub(crate) intflags: VolatileBitField,
pub(crate) temp: Volatile<u8>,
pub(crate) dbgctrl: Volatile<u8>,
pub(crate) calib: Volatile<u8>,
pub(crate) clksel: Volatile<u8>,
pub(crate) cnt: Volatile<u16>,
pub(crate) per: Volatile<u16>,
pub(crate) cmp: Volatile<u16>,
res_1: u8,
res_2: u8,
pub(crate) pitctrla: Volatile<u8>,
pub(crate) pitstatus: VolatileBitField,
pub(crate) pitintctrl: VolatileBitField,
pub(crate) pitintflags: VolatileBitField,
pub(crate) pitdbgctrl: Volatile<u8>
}
pub enum RtcPitPeriod {
Cyc4,
Cyc8,
Cyc16,
Cyc32,
Cyc64,
Cyc128,
Cyc256,
Cyc512,
Cyc1024,
Cyc2048,
Cyc4096,
Cyc8192,
Cyc16384,
Cyc32768
}
pub struct AvrRealTimeCounter {
pub(crate) interrupt_handler: Cell<TimerIsrCallback>,
pub(crate) interrupt_period: RtcPitPeriod,
pub(crate) rtc: MutDeviceRef<AvrRealTimeCounterControl>,
pub(crate) mode: TimerMode
}
impl From<u16> for RtcPitPeriod {
fn from(val: u16) -> Self {
match val {
4 => RtcPitPeriod::Cyc4,
8 => RtcPitPeriod::Cyc8,
16 => RtcPitPeriod::Cyc16,
32 => RtcPitPeriod::Cyc32,
64 => RtcPitPeriod::Cyc64,
128 => RtcPitPeriod::Cyc128,
256 => RtcPitPeriod::Cyc256,
512 => RtcPitPeriod::Cyc512,
1024 => RtcPitPeriod::Cyc1024,
2048 => RtcPitPeriod::Cyc2048,
4096 => RtcPitPeriod::Cyc4096,
8192 => RtcPitPeriod::Cyc8192,
16384 => RtcPitPeriod::Cyc16384,
32768 => RtcPitPeriod::Cyc32768,
_ => avr_oxide::oserror::halt(avr_oxide::oserror::OsError::BadParams)
}
}
}
impl RtcTimerCalibration for AvrRealTimeCounter {
fn set_clock_calibration(&mut self, source: RtcSource, calibration: RtcCalibration, prescaler: RtcPrescaler) {
interrupt::isolated(|isotoken|{
let rtc = self.rtc.borrow_mut(isotoken);
while rtc.status.is_set(BitIndex::bit_c(0)) {}
rtc.ctrla.write(match prescaler {
RtcPrescaler::Div1 => 0x00,
RtcPrescaler::Div2 => 0x01,
RtcPrescaler::Div4 => 0x02,
RtcPrescaler::Div8 => 0x03,
RtcPrescaler::Div16 => 0x04,
RtcPrescaler::Div32 => 0x05,
RtcPrescaler::Div64 => 0x06,
RtcPrescaler::Div128 => 0x07,
RtcPrescaler::Div256 => 0x08,
RtcPrescaler::Div512 => 0x09,
RtcPrescaler::Div1024 => 0x0a,
RtcPrescaler::Div2048 => 0x0b,
RtcPrescaler::Div4096 => 0x0c,
RtcPrescaler::Div8192 => 0x0d,
RtcPrescaler::Div16384 => 0x0e,
RtcPrescaler::Div32768 => 0x0f,
} << 3);
rtc.clksel.write(match source {
RtcSource::Int32k => 0x00,
RtcSource::Int1k => 0x01,
RtcSource::TOsc32k => 0x02,
RtcSource::External => 0x03
});
rtc.calib.write(match calibration {
RtcCalibration::Fast(val) => {
val & 0b01111111
},
RtcCalibration::Slow(val) => {
0b10000000 | (val & 0b01111111)
}
});
});
}
}
impl TimerControl for AvrRealTimeCounter {
fn set_interrupt_period(&mut self, period: u16) {
interrupt::isolated(|_isotoken|{
self.interrupt_period = period.into();
});
}
fn set_mode(&mut self, mode: TimerMode) {
interrupt::isolated(|_isotoken|{
self.mode = mode;
});
}
fn set_count_max(&mut self, _max: u16) {
todo!()
}
fn start(&self, handler: TimerIsrCallback) {
interrupt::isolated(|isotoken|{
let rtc = self.rtc.borrow_mut(isotoken);
while rtc.status.is_set(BitIndex::bit_c(0)) {}
self.interrupt_handler.replace(handler);
if handler.is_nop() {
rtc.pitintctrl.clr_all();
} else {
while rtc.pitstatus.is_set(BitIndex::bit_c(0)) {}
rtc.pitctrla.write(match self.interrupt_period {
RtcPitPeriod::Cyc4 => 0x01,
RtcPitPeriod::Cyc8 => 0x02,
RtcPitPeriod::Cyc16 => 0x03,
RtcPitPeriod::Cyc32 => 0x04,
RtcPitPeriod::Cyc64 => 0x05,
RtcPitPeriod::Cyc128 => 0x06,
RtcPitPeriod::Cyc256 => 0x07,
RtcPitPeriod::Cyc512 => 0x08,
RtcPitPeriod::Cyc1024 => 0x09,
RtcPitPeriod::Cyc2048 => 0x0a,
RtcPitPeriod::Cyc4096 => 0x0b,
RtcPitPeriod::Cyc8192 => 0x0c,
RtcPitPeriod::Cyc16384 => 0x0d,
RtcPitPeriod::Cyc32768 => 0x0e,
} << 3 | 0x01);
rtc.pitintctrl.exc_set(BitIndex::bit_c(0));
}
rtc.ctrla |= 0b10000101;
});
}
fn stop(&self) {
interrupt::isolated(|isotoken|{
let rtc = self.rtc.borrow_mut(isotoken);
rtc.ctrla &= 0b01111000;
});
}
fn get_count(&self) -> u16 {
todo!()
}
fn reset_count(&mut self) {
todo!()
}
}
impl AvrRealTimeCounter {
pub(crate) fn call_interrupt(&self, isotoken: Isolated, source: TimerIdentity, ticks: u16) {
let continue_running = isr_cb_invoke!(isotoken, self.interrupt_handler.get(), source, ticks);
if !continue_running {
self.stop();
}
}
pub(crate) unsafe fn clear_interrupt(&self, isotoken: Isolated) {
let rtc = self.rtc.borrow_mut(isotoken);
rtc.pitintflags.exc_set(BitIndex::bit_c(0));
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! atmel_rtc {
($rtcref:expr, $timersrc:expr, $isr:expr) => {
use avr_oxide::hal::generic::timer::{ TimerMode, TimerIsrCallback };
use avr_oxide::hal::generic::timer::base::{ AvrRealTimeCounterControl, AvrRealTimeCounter, RtcPitPeriod };
use avr_oxide::hal::generic::MutDeviceRef;
use avr_oxide::mut_singleton_explicit_init;
use core::cell::Cell;
pub type TimerImpl = AvrRealTimeCounter;
mut_singleton_explicit_init!(
AvrRealTimeCounter,
__INSTANCE,
initialise, instance, instance_isolated,
AvrRealTimeCounter {
interrupt_handler: Cell::new(TimerIsrCallback::Nop(false)),
interrupt_period: RtcPitPeriod::Cyc4,
rtc: MutDeviceRef::new($rtcref),
mode: TimerMode::Periodic
});
#[oxide_macros::interrupt(isr=$isr)]
fn usart_timer_interrupt(isotoken: avr_oxide::concurrency::Isolated) {
let avrrtc = instance_isolated(isotoken);
avrrtc.call_interrupt(isotoken, $timersrc, 1);
avrrtc.clear_interrupt(isotoken);
}
}
}
}
#[cfg(not(target_arch="avr"))]
pub mod base {
use crate::concurrency::Isolated;
use avr_oxide::hal::generic::timer::{TimerIsrCallback, TimerMode, TimerControl, TimerIdentity, RtcTimerCalibration, RtcSource, RtcCalibration, RtcPrescaler};
use avr_oxide::isr_cb_invoke;
#[repr(C)]
pub struct DummyTypeBTimerControl {
}
pub trait DummyTCB {
fn enable(&mut self);
fn disable(&mut self);
fn enable_interrupt(&mut self);
fn clear_interrupt(&mut self);
fn mask_interrupt(&mut self);
fn set_top(&mut self, top: u16);
fn set_periodic_mode(&mut self);
}
impl DummyTCB for DummyTypeBTimerControl {
fn enable(&mut self) {
println!("*** TCB: Enabled");
}
fn disable(&mut self) {
println!("*** TCB: Disabled");
}
fn enable_interrupt(&mut self) {
println!("*** TCB: Interrupts enabled");
}
fn clear_interrupt(&mut self) {
println!("*** TCB: Interrupts cleared");
}
fn mask_interrupt(&mut self) {
println!("*** TCB: Interrupts masked");
}
fn set_top(&mut self, top: u16) {
println!("*** TCB: Counter top set to {}", top);
}
#[inline(always)]
fn set_periodic_mode(&mut self) {
println!("*** TCB: Set to periodic mode");
}
}
#[allow(dead_code)]
pub struct DummyTimer<T>
where
T: 'static + DummyTCB
{
pub(crate) interrupt_handler: TimerIsrCallback,
pub(crate) interrupt_period: u16,
pub(crate) tcb: T,
pub(crate) count_max: u16,
pub(crate) mode: TimerMode
}
impl<T> TimerControl for DummyTimer<T>
where
T: DummyTCB
{
fn set_interrupt_period(&mut self, period: u16) {
println!("*** TCB: Set to interrupt every {} cycles", period);
}
fn set_mode(&mut self, _mode: TimerMode) {
println!("*** TCB: Set timer mode");
}
fn set_count_max(&mut self, max: u16) {
println!("*** TCB: Set count_max to {}", max);
}
fn start(&self, handler: TimerIsrCallback) {
println!("*** TCB: Set handler to {:?}", handler);
}
fn stop(&self) {
println!("*** TCB: Stop interrupts");
}
fn get_count(&self) -> u16 {
todo!()
}
fn reset_count(&mut self) {
todo!()
}
}
impl<T> DummyTimer<T>
where
T: DummyTCB
{
#[allow(dead_code)]
pub(crate) fn call_interrupt(&mut self, isotoken: Isolated, source: TimerIdentity, ticks: u16) {
let continue_running = isr_cb_invoke!(isotoken, self.interrupt_handler, source, ticks);
if !continue_running {
self.tcb.disable();
}
}
#[allow(dead_code)]
pub(crate) fn interrupt_period(&self) -> u16 {
self.interrupt_period
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! atmel_tcb {
($tcbref:expr, $timersrc:expr, $isr:expr) => {
use avr_oxide::hal::generic::timer::{ TimerMode, TimerIsrCallback };
use avr_oxide::hal::generic::timer::base::{ DummyTimer, DummyTypeBTimerControl };
pub type TimerImpl = DummyTimer<DummyTypeBTimerControl>;
static mut INSTANCE: DummyTimer<DummyTypeBTimerControl> = DummyTimer {
interrupt_handler: TimerIsrCallback::Nop(false),
interrupt_period: 0,
tcb: DummyTypeBTimerControl {},
count_max: 0,
mode: TimerMode::Periodic
};
pub fn initialise(){
}
pub fn instance() -> &'static mut TimerImpl {
unsafe {
&mut INSTANCE
}
}
pub fn instance_isolated(_isotoken: avr_oxide::concurrency::Isolated) -> &'static mut TimerImpl {
unsafe {
&mut INSTANCE
}
}
}
}
pub enum RtcPitPeriod {
Cyc4,
Cyc8,
Cyc16,
Cyc32,
Cyc64,
Cyc128,
Cyc256,
Cyc512,
Cyc1024,
Cyc2048,
Cyc4096,
Cyc8192,
Cyc16384,
Cyc32768
}
pub struct DummyRealTimeCounter {
pub(crate) interrupt_handler: TimerIsrCallback,
pub(crate) interrupt_period: RtcPitPeriod,
pub(crate) mode: TimerMode
}
impl From<u16> for RtcPitPeriod {
fn from(val: u16) -> Self {
match val {
4 => RtcPitPeriod::Cyc4,
8 => RtcPitPeriod::Cyc8,
16 => RtcPitPeriod::Cyc16,
32 => RtcPitPeriod::Cyc32,
64 => RtcPitPeriod::Cyc64,
128 => RtcPitPeriod::Cyc128,
256 => RtcPitPeriod::Cyc256,
512 => RtcPitPeriod::Cyc512,
1024 => RtcPitPeriod::Cyc1024,
2048 => RtcPitPeriod::Cyc2048,
4096 => RtcPitPeriod::Cyc4096,
8192 => RtcPitPeriod::Cyc8192,
16384 => RtcPitPeriod::Cyc16384,
32768 => RtcPitPeriod::Cyc32768,
_ => avr_oxide::oserror::halt(avr_oxide::oserror::OsError::BadParams)
}
}
}
impl RtcTimerCalibration for DummyRealTimeCounter {
fn set_clock_calibration(&mut self, source: RtcSource, calibration: RtcCalibration, prescaler: RtcPrescaler) {
println!("RTC calibration set");
}
}
impl TimerControl for DummyRealTimeCounter {
fn set_interrupt_period(&mut self, period: u16) {
let rtcperiod : RtcPitPeriod = period.into();
println!("*** RTC: Set to interrupt every {} cycles", period);
}
fn set_mode(&mut self, mode: TimerMode) {
println!("*** TCB: Set time mode");
}
fn set_count_max(&mut self, _max: u16) {
todo!()
}
fn start(&self, handler: TimerIsrCallback) {
println!("*** RTC: Set handler to {:?}", handler);
}
fn stop(&self) {
println!("*** RTC: stop()");
}
fn get_count(&self) -> u16 {
todo!()
}
fn reset_count(&mut self) {
todo!()
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! atmel_rtc {
($rtcref:expr, $timersrc:expr, $isr:expr) => {
use avr_oxide::hal::generic::timer::{ TimerMode, TimerIsrCallback };
use avr_oxide::hal::generic::timer::base::{ DummyRealTimeCounter, RtcPitPeriod };
use avr_oxide::mut_singleton_explicit_init;
pub type TimerImpl = DummyRealTimeCounter;
mut_singleton_explicit_init!(
DummyRealTimeCounter,
__INSTANCE,
initialise, instance, instance_isolated,
DummyRealTimeCounter {
interrupt_handler: TimerIsrCallback::Nop(false),
interrupt_period: RtcPitPeriod::Cyc4,
mode: TimerMode::Periodic
});
}
}
}