avr-oxide 0.2.2

An extremely simple Rusty operating system for AVR microcontrollers
/* cpu.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! ATmega328P-specific CPU control block implementation

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

use avr_oxide::hal::generic::cpu::private::{PermitIdleToken, PermitStandbyToken};
use avr_oxide::hal::generic::cpu::{ClockControl, ConfigurationChange, Cpu, SleepControl};
use avr_oxide::{mut_singleton, v_read, v_write};
use avr_oxide::hal::atmega328p::{ADDR_CLKPR, ADDR_CPU};

// Declarations ==============================================================
#[repr(C)]
pub struct Atmega328PControlRegisters {
  pub(crate) sp: u16,
  pub(crate) sreg: u8
}

#[repr(C)]
pub struct Atmega328PClockPrescaleRegister {
  pub(crate) clkpr: u8
}

pub struct NullSleepController;


// Code ======================================================================
impl Cpu for Atmega328PControlRegisters {
  unsafe fn write_protected(&mut self, change: ConfigurationChange, register: &mut u8, value: u8) {
    // The 328P doesn't have a register protection mechanism, so we JFDI
    *register = value;
  }

  fn read_sp(&self) -> u16 {
    unsafe {
      v_read!(u16,self.sp) & 0b0000_0111_1111_1111
    }
  }

  unsafe fn write_sp(&mut self, sp: u16) {
    v_write!(u16,self.sp,sp)
  }

  fn read_sreg(&self) -> u8 {
    unsafe {
      v_read!(u8,self.sreg)
    }
  }

  unsafe fn write_sreg(&mut self, sreg: u8) {
    v_write!(u8,self.sreg,sreg)
  }

  fn interrupts_enabled(&self) -> bool {
    (self.read_sreg() & 0b1000_0000) > 0
  }
}

#[inline(always)]
pub fn instance() -> &'static mut Atmega328PControlRegisters {
  unsafe {
    core::mem::transmute(ADDR_CPU)
  }
}

pub fn clock() -> &'static mut Atmega328PClockPrescaleRegister {
  unsafe {
    core::mem::transmute(ADDR_CLKPR)
  }
}

impl ClockControl for Atmega328PClockPrescaleRegister {
  unsafe fn clk_per_prescaler(&mut self, scaler: u8) {
    extern "C" {
      fn ccp_clkper_write(ioaddr: *mut u8, value: u8);
    }


    let clkps_val = match scaler {
      1 => 0x00,
      2 => 0x01,
      4 => 0x02,
      8 => 0x03,
      16 => 0x04,
      32 => 0x05,
      64 => 0x06,
      128 => 0x07,
      _ => panic!()
    };
    ccp_clkper_write(&mut self.clkpr as *mut u8, clkps_val);
  }
}


#[macro_export]
macro_rules! cpu {
  () => {
    avr_oxide::hal::atmega328p::cpu::instance()
  }
}


impl SleepControl for NullSleepController {
  unsafe fn reset(&mut self) {
  }

  fn inhibit_standby(&mut self) -> PermitStandbyToken {
    PermitStandbyToken
  }

  fn permit_standby(&mut self, token: PermitStandbyToken) {
  }

  fn standby_permitted(&self) -> bool {
    false
  }

  fn inhibit_idle(&mut self) -> PermitIdleToken {
    PermitIdleToken
  }

  fn permit_idle(&mut self, token: PermitIdleToken) {
  }

  fn idle_permitted(&self) -> bool {
    false
  }
}

mut_singleton!(
  NullSleepController,
  SLEEPCTRLINSTANCE,
  sleepctrl,
  NullSleepController {
  });

/**
 * Obtain a references to the Sleep controller instance
 */
#[macro_export]
macro_rules! sleepctrl {
  () => {
    avr_oxide::hal::atmega328p::cpu::sleepctrl()
  }
}