use core::cell::UnsafeCell;
use core::marker::PhantomData;
use core::ptr;
use volatile_register::{RO, RW, WO};
use interrupt::{CriticalSection, Nr};
#[cfg(test)]
mod test;
pub const CPUID: Peripheral<Cpuid> = unsafe { Peripheral::new(0xE000_ED00) };
pub const DCB: Peripheral<Dcb> = unsafe { Peripheral::new(0xE000_EDF0) };
pub const DWT: Peripheral<Dwt> = unsafe { Peripheral::new(0xE000_1000) };
pub const FPB: Peripheral<Fpb> = unsafe { Peripheral::new(0xE000_2000) };
pub const FPU: Peripheral<Fpu> = unsafe { Peripheral::new(0xE000_EF30) };
pub const ITM: Peripheral<Itm> = unsafe { Peripheral::new(0xE000_0000) };
pub const MPU: Peripheral<Mpu> = unsafe { Peripheral::new(0xE000_ED90) };
pub const NVIC: Peripheral<Nvic> = unsafe { Peripheral::new(0xE000_E100) };
pub const SCB: Peripheral<Scb> = unsafe { Peripheral::new(0xE000_ED04) };
pub const SYST: Peripheral<Syst> = unsafe { Peripheral::new(0xE000_E010) };
pub const TPIU: Peripheral<Tpiu> = unsafe { Peripheral::new(0xE004_0000) };
pub struct Peripheral<T>
where
T: 'static,
{
address: usize,
_marker: PhantomData<&'static mut T>,
}
impl<T> Peripheral<T> {
pub const unsafe fn new(address: usize) -> Self {
Peripheral {
address: address,
_marker: PhantomData,
}
}
pub fn borrow<'cs>(&self, _ctxt: &'cs CriticalSection) -> &'cs T {
unsafe { &*self.get() }
}
pub fn get(&self) -> *mut T {
self.address as *mut T
}
}
#[repr(C)]
pub struct Cpuid {
pub base: RO<u32>,
reserved0: [u32; 15],
pub pfr: [RO<u32>; 2],
pub dfr: RO<u32>,
pub afr: RO<u32>,
pub mmfr: [RO<u32>; 4],
pub isar: [RO<u32>; 5],
reserved1: u32,
pub clidr: RO<u32>,
pub ctr: RO<u32>,
pub ccsidr: RO<u32>,
pub csselr: RO<u32>,
}
#[repr(C)]
pub struct Dcb {
pub dhcsr: RW<u32>,
pub dcrsr: WO<u32>,
pub dcrdr: RW<u32>,
pub demcr: RW<u32>,
}
#[repr(C)]
pub struct Dwt {
pub ctrl: RW<u32>,
pub cyccnt: RW<u32>,
pub cpicnt: RW<u32>,
pub exccnt: RW<u32>,
pub sleepcnt: RW<u32>,
pub lsucnt: RW<u32>,
pub foldcnt: RW<u32>,
pub pcsr: RO<u32>,
pub c: [Comparator; 16],
reserved: [u32; 932],
pub lar: WO<u32>,
pub lsr: RO<u32>,
}
#[repr(C)]
pub struct Comparator {
pub comp: RW<u32>,
pub mask: RW<u32>,
pub function: RW<u32>,
reserved: u32,
}
#[repr(C)]
pub struct Fpb {
pub ctrl: RW<u32>,
pub remap: RW<u32>,
pub comp: [RW<u32>; 127],
reserved: [u32; 875],
pub lar: WO<u32>,
pub lsr: RO<u32>,
}
#[repr(C)]
pub struct Fpu {
reserved: u32,
pub fpccr: RW<u32>,
pub fpcar: RW<u32>,
pub fpdscr: RW<u32>,
pub mvfr: [RO<u32>; 3],
}
#[repr(C)]
pub struct Itm {
pub stim: [Stim; 256],
reserved0: [u32; 640],
pub ter: [RW<u32>; 8],
reserved1: [u32; 8],
pub tpr: RW<u32>,
reserved2: [u32; 15],
pub tcr: RW<u32>,
reserved3: [u32; 75],
pub lar: WO<u32>,
pub lsr: RO<u32>,
}
pub struct Stim {
register: UnsafeCell<u32>,
}
impl Stim {
pub fn write_u8(&self, value: u8) {
unsafe { ptr::write_volatile(self.register.get() as *mut u8, value) }
}
pub fn write_u16(&self, value: u16) {
unsafe { ptr::write_volatile(self.register.get() as *mut u16, value) }
}
pub fn write_u32(&self, value: u32) {
unsafe { ptr::write_volatile(self.register.get(), value) }
}
pub fn is_fifo_ready(&self) -> bool {
unsafe { ptr::read_volatile(self.register.get()) == 1 }
}
}
#[repr(C)]
pub struct Mpu {
pub _type: RO<u32>,
pub ctrl: RW<u32>,
pub rnr: RW<u32>,
pub rbar: RW<u32>,
pub rasr: RW<u32>,
pub rbar_a1: RW<u32>,
pub rsar_a1: RW<u32>,
pub rbar_a2: RW<u32>,
pub rsar_a2: RW<u32>,
pub rbar_a3: RW<u32>,
pub rsar_a3: RW<u32>,
}
#[repr(C)]
pub struct Nvic {
pub iser: [RW<u32>; 8],
reserved0: [u32; 24],
pub icer: [RW<u32>; 8],
reserved1: [u32; 24],
pub ispr: [RW<u32>; 8],
reserved2: [u32; 24],
pub icpr: [RW<u32>; 8],
reserved3: [u32; 24],
pub iabr: [RO<u32>; 8],
reserved4: [u32; 56],
pub ipr: [RW<u8>; 240],
}
impl Nvic {
pub fn clear_pending<I>(&self, interrupt: I)
where
I: Nr,
{
let nr = interrupt.nr();
unsafe { self.icpr[usize::from(nr / 32)].write(1 << (nr % 32)) }
}
pub fn disable<I>(&self, interrupt: I)
where
I: Nr,
{
let nr = interrupt.nr();
unsafe { self.icer[usize::from(nr / 32)].write(1 << (nr % 32)) }
}
pub fn enable<I>(&self, interrupt: I)
where
I: Nr,
{
let nr = interrupt.nr();
unsafe { self.iser[usize::from(nr / 32)].write(1 << (nr % 32)) }
}
pub fn get_priority<I>(&self, interrupt: I) -> u8
where
I: Nr,
{
let nr = interrupt.nr();
self.ipr[usize::from(nr)].read()
}
pub fn is_active<I>(&self, interrupt: I) -> bool
where
I: Nr,
{
let nr = interrupt.nr();
let mask = 1 << (nr % 32);
(self.iabr[usize::from(nr / 32)].read() & mask) == mask
}
pub fn is_enabled<I>(&self, interrupt: I) -> bool
where
I: Nr,
{
let nr = interrupt.nr();
let mask = 1 << (nr % 32);
(self.iser[usize::from(nr / 32)].read() & mask) == mask
}
pub fn is_pending<I>(&self, interrupt: I) -> bool
where
I: Nr,
{
let nr = interrupt.nr();
let mask = 1 << (nr % 32);
(self.ispr[usize::from(nr / 32)].read() & mask) == mask
}
pub fn set_pending<I>(&self, interrupt: I)
where
I: Nr,
{
let nr = interrupt.nr();
unsafe { self.ispr[usize::from(nr / 32)].write(1 << (nr % 32)) }
}
pub unsafe fn set_priority<I>(&self, interrupt: I, prio: u8)
where
I: Nr,
{
let nr = interrupt.nr();
self.ipr[usize::from(nr)].write(prio)
}
}
#[repr(C)]
pub struct Scb {
pub icsr: RW<u32>,
pub vtor: RW<u32>,
pub aircr: RW<u32>,
pub scr: RW<u32>,
pub ccr: RW<u32>,
pub shpr: [RW<u8>; 12],
pub shpcrs: RW<u32>,
pub cfsr: RW<u32>,
pub hfsr: RW<u32>,
pub dfsr: RW<u32>,
pub mmar: RW<u32>,
pub bfar: RW<u32>,
pub afsr: RW<u32>,
reserved: [u32; 18],
pub cpacr: RW<u32>,
}
#[repr(C)]
pub struct Syst {
pub csr: RW<u32>,
pub rvr: RW<u32>,
pub cvr: RW<u32>,
pub calib: RO<u32>,
}
#[repr(C)]
pub struct Tpiu {
pub sspsr: RO<u32>,
pub cspsr: RW<u32>,
reserved0: [u32; 2],
pub acpr: RW<u32>,
reserved1: [u32; 55],
pub sppr: RW<u32>,
reserved2: [u32; 943],
pub lar: WO<u32>,
pub lsr: RO<u32>,
reserved3: [u32; 4],
pub _type: RO<u32>,
}