commit:15557c76487d6920696aba4015198728efabd705
author:Chip
committer:Chip
date:Fri Mar 8 23:09:06 2019 -0600
parents:1050ccbc750cf8c4799e6f68f8a871cb6904be31
Add timer
diff --git a/src/main.rs b/src/main.rs
line changes: +2/-1
index 90229e4..603ab36
--- a/src/main.rs
+++ b/src/main.rs
@@ -17,6 +17,7 @@ mod util;
 mod console;
 mod serial_console;
 mod peripherals;
+mod timer;
 mod mpu;
 mod task;
 mod svcall;
@@ -102,7 +103,7 @@ fn main() -> ! {
 
     peripherals.watchdog.disable();
 
-    serial_console::get_global_console().write("Kernel initialized!\r\n");
+    serial_console::get_global_console().write("Kernel initialized!\n");
 
     let t = Task::default_layout_full(shell_main);
     t.run()

diff --git a/src/peripherals.rs b/src/peripherals.rs
line changes: +5/-0
index 4d15f99..0a360bd
--- a/src/peripherals.rs
+++ b/src/peripherals.rs
@@ -2,6 +2,7 @@ use cortex_m::peripheral::MPU;
 use atsam3xa_hal::prelude::*;
 use crate::serial_console::SerialConsole;
 use crate::mpu::{self, MemoryRegion, MemoryPermission};
+use crate::timer;
 use crate::video;
 
 pub struct Peripherals {
@@ -41,6 +42,10 @@ impl Peripherals {
 
         Self::mpu_setup(mp.MPU);
 
+        timer::start(atsam3xa_hal::timer::Timer::syst(mp.SYST));
+
+        // Only enable video gen on release - debug mode code is too slow
+        #[cfg(release)]
         video::gen::start(pp.TC0, &mut mp.NVIC, &pmc, &pio_b);
 
         Peripherals {

diff --git a/src/timer.rs b/src/timer.rs
line changes: +112/-0
index 0000000..a3a341a
--- /dev/null
+++ b/src/timer.rs
@@ -0,0 +1,112 @@
+use core::cmp::Ordering;
+use cortex_m::interrupt;
+use cortex_m::peripheral::SYST;
+use cortex_m_rt::exception;
+use atsam3xa_hal::timer::Ms;
+use embedded_hal::timer::CountDown;
+
+type TimeValue = u32;
+
+#[derive(Clone, Copy, Eq)]
+struct TimerCallback {
+    tt: TimeValue,
+    f: fn(),
+}
+
+impl Ord for TimerCallback {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.tt.cmp(&other.tt)
+    }
+}
+
+impl PartialOrd for TimerCallback {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl PartialEq for TimerCallback {
+    fn eq(&self, other: &Self) -> bool {
+        self.tt == other.tt
+    }
+}
+
+struct Timer {
+    systick: atsam3xa_hal::timer::Timer<SYST>,
+    t: TimeValue,
+    callbacks: [Option<TimerCallback>; 10],
+}
+
+impl Timer {
+    fn new(mut systick: atsam3xa_hal::timer::Timer<SYST>) -> Timer {
+        systick.enable_interrupt();
+        Timer {
+            systick,
+            t: 0,
+            callbacks: [None; 10],
+        }
+    }
+
+    fn add_callback(&mut self, dt: TimeValue, f: fn()) {
+        let new_index = match self.callbacks.iter().position(|&x| x.is_none()) {
+            Some(i) => i,
+            None => panic!("Cannot schedule timer callback; too many callbacks in flight"),
+        };
+
+        let tt = self.t + dt;
+        self.callbacks[new_index] = Some(TimerCallback { tt, f });
+        self.recalculate();
+    }
+
+    fn recalculate(&mut self) {
+        self.callbacks.sort_by(|&a, &b| {
+            match (a, b) {
+                (Some(i), Some(j)) => i.cmp(&j),
+                (Some(_), None) => Ordering::Less,
+                (None, Some(_)) => Ordering::Greater,
+                (None, None) => Ordering::Equal,
+            }
+        });
+        if let Some(tc) = self.callbacks[0] {
+            let dt = tc.tt - self.t;
+            self.systick.start(dt as Ms);
+        } else {
+            self.systick.stop();
+            self.t = 0;
+        }
+    }
+
+    fn execute_next(&mut self) {
+        if !self.callbacks[0].is_none() {
+            let tc = self.callbacks[0].take().unwrap();
+            unsafe {
+                (tc.f)();
+            }
+            self.t = tc.tt;
+            self.recalculate();
+        }
+    }
+}
+
+static mut TIMER: Option<Timer> = None;
+
+pub fn start(systick: atsam3xa_hal::timer::Timer<SYST>) {
+    interrupt::free(|_| unsafe {
+        TIMER = Some(Timer::new(systick));
+    });
+}
+
+pub fn schedule(d: TimeValue, f: fn()) {
+    interrupt::free(|_| unsafe {
+        let timer = TIMER.as_mut().expect("Timer not yet initialized");
+        timer.add_callback(d, f);
+    });
+}
+
+#[exception]
+fn SysTick() {
+    interrupt::free(|_| unsafe {
+        let timer = TIMER.as_mut().expect("Timer not yet initialized");
+        timer.execute_next();
+    });
+}