use core::any::Any;
use ufmt::derive::uDebug;
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(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, RefCell};
use avr_oxide::hal::generic::timer::{TimerIsrCallback, TimerMode, TimerControl, TimerIdentity, RtcTimerCalibration, RtcSource, RtcCalibration, RtcPrescaler};
use avr_oxide::{isr_cb_invoke, v_read, v_write};
#[repr(C)]
pub struct AvrTypeBTimerControl {
pub(crate) ctrla: u8,
pub(crate) ctrlb: u8,
pub(crate) reserved: [u8; 2],
pub(crate) evctrl: u8,
pub(crate) intctrl: u8,
pub(crate) intflags: u8,
pub(crate) status: u8,
pub(crate) dbgctrl: u8,
pub(crate) temp: u8,
pub(crate) cnt: u16,
pub(crate) ccmp: u16
}
pub trait AtmelTCB {
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 AtmelTCB for AvrTypeBTimerControl {
#[inline(always)]
fn enable(&mut self) {
unsafe {
core::ptr::write_volatile(&mut self.ctrla as *mut u8, 0b01000011);
}
}
#[inline(always)]
fn disable(&mut self) {
unsafe {
core::ptr::write_volatile(&mut self.ctrla as *mut u8, 0b00000000);
}
}
#[inline(always)]
fn enable_interrupt(&mut self) {
unsafe {
core::ptr::write_volatile(&mut self.intctrl as *mut u8, 0b00000001);
}
}
#[inline(always)]
fn clear_interrupt(&mut self) {
unsafe {
core::ptr::write_volatile(&mut self.intflags as *mut u8, 0b00000001);
}
}
#[inline(always)]
fn mask_interrupt(&mut self) {
unsafe {
core::ptr::write_volatile(&mut self.intctrl as *mut u8, 0b00000000);
}
}
#[inline(always)]
fn set_top(&mut self, top: u16) {
unsafe {
core::ptr::write_volatile(&mut self.cnt as *mut u16, 0x0000);
core::ptr::write_volatile(&mut self.ccmp as *mut u16, top);
}
}
#[inline(always)]
fn set_periodic_mode(&mut self) {
unsafe {
let ctrlb_reg = &mut self.ctrlb as *mut u8;
let ctrlb = core::ptr::read_volatile(ctrlb_reg);
core::ptr::write_volatile(ctrlb_reg, ctrlb | 0b00010000);
}
}
}
pub struct AtmelTimer<T>
where
T: 'static + AtmelTCB
{
pub(crate) interrupt_handler: Cell<TimerIsrCallback>,
pub(crate) interrupt_period: u16,
pub(crate) tcb: RefCell<&'static mut T>,
pub(crate) count_max: u16,
pub(crate) mode: TimerMode
}
impl<T> TimerControl for AtmelTimer<T>
where
T: AtmelTCB
{
fn set_interrupt_period(&mut self, period: u16) {
unsafe {
core::ptr::write_volatile(&mut self.interrupt_period as *mut u16, period)
}
}
fn set_mode(&mut self, mode: TimerMode) {
self.mode = mode;
}
fn set_count_max(&mut self, max: u16) {
self.count_max = max;
}
fn start(&self, handler: TimerIsrCallback) {
let mut tcb = self.tcb.borrow_mut();
tcb.disable();
match self.mode {
TimerMode::Periodic => {
tcb.set_periodic_mode();
tcb.set_top(self.count_max);
}
};
tcb.clear_interrupt();
avr_oxide::hal::concurrency::interrupt::isolated(||{
self.interrupt_handler.replace(handler);
});
if handler.is_nop() {
tcb.mask_interrupt();
} else {
tcb.enable_interrupt();
}
tcb.enable();
}
fn stop(&self) {
let mut tcb = self.tcb.borrow_mut();
tcb.disable();
}
fn get_count(&self) -> u16 {
todo!()
}
fn reset_count(&mut self) {
todo!()
}
}
impl<T> AtmelTimer<T>
where
T: AtmelTCB
{
#[inline(always)]
pub(crate) fn call_interrupt(&mut self, source: TimerIdentity, ticks: u16) {
let continue_running = isr_cb_invoke!(self.interrupt_handler.get(), source, ticks);
if !continue_running {
self.tcb.borrow_mut().disable();
}
}
#[inline(always)]
pub(crate) fn interrupt_period(&self) -> u16 {
unsafe {
core::ptr::read_volatile(&self.interrupt_period as *const u16)
}
}
#[inline(always)]
pub(crate) fn clear_interrupt(&self) {
self.tcb.borrow_mut().clear_interrupt();
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! atmel_tcb {
($tcbref:expr, $timersrc:expr, $isr:ident) => {
use avr_oxide::hal::generic::timer::{ TimerMode, TimerIsrCallback };
use avr_oxide::hal::generic::timer::base::{ AtmelTimer, AtmelTCB, AvrTypeBTimerControl };
use avr_oxide::mut_singleton;
use core::cell::{RefCell,Cell};
pub type TimerImpl = AtmelTimer<AvrTypeBTimerControl>;
mut_singleton!(
AtmelTimer<AvrTypeBTimerControl>,
INSTANCE,
instance,
AtmelTimer {
interrupt_handler: Cell::new(TimerIsrCallback::Nop(false)),
interrupt_period: 0,
tcb: RefCell::new(core::mem::transmute($tcbref)),
count_max: 0,
mode: TimerMode::Periodic
});
#[no_mangle]
pub unsafe extern "avr-interrupt" fn $isr() {
static mut COUNT_INTS : u16 = 0;
avr_oxide::hal::concurrency::interrupt::isr(||{
let counter = core::ptr::read_volatile(&COUNT_INTS as *const u16);
match &mut INSTANCE {
None => {},
Some(atmeltimer) => {
if counter == 0 {
atmeltimer.call_interrupt($timersrc, atmeltimer.interrupt_period());
core::ptr::write_volatile(&mut COUNT_INTS as *mut u16, atmeltimer.interrupt_period())
} else {
core::ptr::write_volatile(&mut COUNT_INTS as *mut u16, counter-1);
}
atmeltimer.clear_interrupt();
}
}
})
}
}
}
#[repr(C)]
pub struct AvrRealTimeCounterControl {
pub(crate) ctrla: u8,
pub(crate) status: u8,
pub(crate) intctrl: u8,
pub(crate) intflags: u8,
pub(crate) temp: u8,
pub(crate) dbgctrl: u8,
pub(crate) calib: u8,
pub(crate) clksel: u8,
pub(crate) cnt: u16,
pub(crate) per: u16,
pub(crate) cmp: u16,
res_1: u8,
res_2: u8,
pub(crate) pitctrla: u8,
pub(crate) pitstatus: u8,
pub(crate) pitintctrl: u8,
pub(crate) pitintflags: u8,
pub(crate) pitdbgctrl: 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: RefCell<&'static mut 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,
_ => panic!()
}
}
}
impl RtcTimerCalibration for AvrRealTimeCounter {
fn set_clock_calibration(&mut self, source: RtcSource, calibration: RtcCalibration, prescaler: RtcPrescaler) {
let mut rtc = self.rtc.borrow_mut();
unsafe {
while (v_read!(u8, rtc.status) & 0x01) != 0 {}
v_write!(u8, rtc.ctrla, 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);
v_write!(u8, rtc.clksel, match source {
RtcSource::Int32k => 0x00,
RtcSource::Int1k => 0x01,
RtcSource::TOsc32k => 0x02,
RtcSource::External => 0x03
});
v_write!(u8, rtc.calib, 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) {
self.interrupt_period = period.into();
}
fn set_mode(&mut self, mode: TimerMode) {
self.mode = mode;
}
fn set_count_max(&mut self, _max: u16) {
todo!()
}
fn start(&self, handler: TimerIsrCallback) {
let mut rtc = self.rtc.borrow_mut();
unsafe {
while (v_read!(u8, rtc.status) & 0x01) != 0 {}
avr_oxide::hal::concurrency::interrupt::isolated(||{
self.interrupt_handler.replace(handler);
});
if handler.is_nop() {
v_write!(u8, rtc.pitintctrl, 0);
} else {
while (v_read!(u8, rtc.pitstatus) & 0x01) != 0 {}
v_write!(u8, rtc.pitctrla,
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);
v_write!(u8, rtc.pitintctrl, 1);
}
v_write!(u8, rtc.ctrla, v_read!(u8, rtc.ctrla) | 0b10000101);
}
}
fn stop(&self) {
let mut rtc = self.rtc.borrow_mut();
unsafe {
v_write!(u8, rtc.ctrla, v_read!(u8, rtc.ctrla) & 0b01111000);
}
}
fn get_count(&self) -> u16 {
todo!()
}
fn reset_count(&mut self) {
todo!()
}
}
impl AvrRealTimeCounter {
#[inline(always)]
pub(crate) fn call_interrupt(&self, source: TimerIdentity, ticks: u16) {
let continue_running = isr_cb_invoke!(self.interrupt_handler.get(), source, ticks);
if !continue_running {
self.stop();
}
}
#[inline(always)]
pub(crate) unsafe fn clear_interrupt(&self) {
let mut rtc = self.rtc.borrow_mut();
v_write!(u8, rtc.pitintflags, 0x01);
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! atmel_rtc {
($rtcref:expr, $timersrc:expr, $isr: ident) => {
use avr_oxide::hal::generic::timer::{ TimerMode, TimerIsrCallback };
use avr_oxide::hal::generic::timer::base::{ AvrRealTimeCounterControl, AvrRealTimeCounter, RtcPitPeriod };
use avr_oxide::mut_singleton;
use core::cell::{RefCell,Cell};
pub type TimerImpl = AvrRealTimeCounter;
mut_singleton!(
AvrRealTimeCounter,
INSTANCE,
instance,
AvrRealTimeCounter {
interrupt_handler: Cell::new(TimerIsrCallback::Nop(false)),
interrupt_period: RtcPitPeriod::Cyc4,
rtc: RefCell::new(core::mem::transmute($rtcref)),
mode: TimerMode::Periodic
});
#[no_mangle]
pub unsafe extern "avr-interrupt" fn $isr() {
avr_oxide::hal::concurrency::interrupt::isr(||{
match &mut INSTANCE {
None => {},
Some(avrrtc) => {
avrrtc.call_interrupt($timersrc, 1);
avrrtc.clear_interrupt();
}
}
})
}
}
}
}
#[cfg(not(target_arch="avr"))]
pub mod base {
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, source: TimerIdentity, ticks: u16) {
let continue_running = isr_cb_invoke!(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:ident) => {
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 instance() -> &'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,
_ => panic!()
}
}
}
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: ident) => {
use avr_oxide::hal::generic::timer::{ TimerMode, TimerIsrCallback };
use avr_oxide::hal::generic::timer::base::{ DummyRealTimeCounter, RtcPitPeriod };
use avr_oxide::mut_singleton;
pub type TimerImpl = DummyRealTimeCounter;
mut_singleton!(
DummyRealTimeCounter,
INSTANCE,
instance,
DummyRealTimeCounter {
interrupt_handler: TimerIsrCallback::Nop(false),
interrupt_period: RtcPitPeriod::Cyc4,
mode: TimerMode::Periodic
});
}
}
}