avr-oxide 0.0.2

An extremely simply Rusty operating system for AVR microcontrollers
/* timer.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! ATmega4809 specific implementation of the TimerControl traits for the
//! device TCBs.

// Imports ===================================================================


// Declarations ==============================================================


// Code ======================================================================
#[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) {
          // Flags == Run in standby, divide clock by 2, enable
          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;
        }
      }
    }

    // Clear the interrupt request
    (*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;
        }
      }
    }

    // Clear the interrupt request
    (*tcb1).intflags.write(|w| w.capt().set_bit());
  }
}

// Tests =====================================================================