mod console;
mod serial_console;
mod peripherals;
+mod timer;
mod mpu;
mod task;
mod svcall;
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()
use atsam3xa_hal::prelude::*;
use crate::serial_console::SerialConsole;
use crate::mpu::{self, MemoryRegion, MemoryPermission};
+use crate::timer;
use crate::video;
pub struct 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 {
+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();
+ });
+}