rtic/src/lib.rs

275 lines
6.1 KiB
Rust
Raw Normal View History

2017-03-05 06:26:14 +01:00
#![feature(asm)]
#![feature(const_fn)]
#![feature(optin_builtin_traits)]
2017-07-12 06:44:54 +02:00
#![feature(proc_macro)]
2017-03-05 06:26:14 +01:00
#![no_std]
extern crate cortex_m;
2017-07-12 06:44:54 +02:00
extern crate cortex_m_rtfm_macros;
extern crate static_ref;
2017-03-05 06:26:14 +01:00
2017-04-10 05:42:17 +02:00
use core::cell::UnsafeCell;
pub use cortex_m_rtfm_macros::app;
2017-04-14 17:05:24 +02:00
pub use cortex_m::asm::{bkpt, wfi};
2017-07-04 18:26:11 +02:00
pub use cortex_m::interrupt::CriticalSection;
pub use cortex_m::interrupt::free as atomic;
pub use static_ref::Static;
use cortex_m::interrupt::Nr;
2017-07-04 18:26:11 +02:00
#[cfg(not(armv6m))]
use cortex_m::register::{basepri_max, basepri};
2017-07-04 18:26:11 +02:00
#[inline(always)]
unsafe fn claim<T, U, R, F, G>(
data: T,
ceiling: u8,
nvic_prio_bits: u8,
t: &mut Threshold,
f: F,
g: G,
) -> R
where
2017-07-04 18:26:11 +02:00
F: FnOnce(U, &mut Threshold) -> R,
G: FnOnce(T) -> U,
{
2017-07-04 18:26:11 +02:00
let max_priority = 1 << nvic_prio_bits;
if ceiling > t.0 {
match () {
#[cfg(armv6m)]
() => {
atomic(|_| f(g(data), &mut Threshold::new(max_priority)))
}
#[cfg(not(armv6m))]
() => {
if ceiling == max_priority {
atomic(|_| f(g(data), &mut Threshold::new(max_priority)))
} else {
let old = basepri::read();
let hw = (max_priority - ceiling) << (8 - nvic_prio_bits);
basepri_max::write(hw);
let ret = f(g(data), &mut Threshold(ceiling));
basepri::write(old);
ret
}
}
2017-03-05 06:26:14 +01:00
}
2017-07-04 18:26:11 +02:00
} else {
f(g(data), t)
2017-03-05 06:26:14 +01:00
}
2017-03-10 05:59:50 +01:00
}
2017-03-05 06:26:14 +01:00
2017-07-04 18:26:11 +02:00
pub struct Peripheral<P>
2017-04-17 18:59:56 +02:00
where
P: 'static,
2017-04-10 05:42:17 +02:00
{
2017-07-04 18:26:11 +02:00
// FIXME(rustc/LLVM bug?) storing the ceiling in the resource de-optimizes
// claims (the ceiling value gets loaded at runtime rather than inlined)
// ceiling: u8,
2017-04-10 05:42:17 +02:00
peripheral: cortex_m::peripheral::Peripheral<P>,
2017-03-10 05:59:50 +01:00
}
2017-03-05 06:26:14 +01:00
2017-07-04 18:26:11 +02:00
impl<P> Peripheral<P> {
pub const fn new(peripheral: cortex_m::peripheral::Peripheral<P>) -> Self {
Peripheral { peripheral }
}
#[inline(always)]
pub unsafe fn borrow<'cs>(
&'static self,
_cs: &'cs CriticalSection,
) -> &'cs P {
&*self.peripheral.get()
}
2017-07-04 18:26:11 +02:00
#[inline(always)]
pub unsafe fn claim<R, F>(
2017-04-17 18:59:56 +02:00
&'static self,
2017-07-04 18:26:11 +02:00
ceiling: u8,
nvic_prio_bits: u8,
t: &mut Threshold,
f: F,
) -> R
2017-04-17 18:59:56 +02:00
where
2017-07-04 18:26:11 +02:00
F: FnOnce(&P, &mut Threshold) -> R,
{
2017-07-04 18:26:11 +02:00
claim(
&self.peripheral,
ceiling,
nvic_prio_bits,
t,
f,
|peripheral| &*peripheral.get(),
)
}
2017-07-04 18:26:11 +02:00
pub fn get(&self) -> *mut P {
self.peripheral.get()
}
}
2017-07-04 18:26:11 +02:00
unsafe impl<P> Sync for Peripheral<P>
where
2017-07-04 18:26:11 +02:00
P: Send,
{
}
2017-07-04 18:26:11 +02:00
pub struct Resource<T> {
// FIXME(rustc/LLVM bug?) storing the ceiling in the resource de-optimizes
// claims (the ceiling value gets loaded at runtime rather than inlined)
// ceiling: u8,
data: UnsafeCell<T>,
}
2017-07-04 18:26:11 +02:00
impl<T> Resource<T> {
pub const fn new(value: T) -> Self {
Resource {
data: UnsafeCell::new(value),
}
}
#[inline(always)]
pub unsafe fn borrow<'cs>(
&'static self,
_cs: &'cs CriticalSection,
) -> &'cs Static<T> {
Static::ref_(&*self.data.get())
}
#[inline(always)]
pub unsafe fn borrow_mut<'cs>(
&'static self,
_cs: &'cs CriticalSection,
) -> &'cs mut Static<T> {
Static::ref_mut(&mut *self.data.get())
2017-04-10 05:42:17 +02:00
}
2017-03-05 06:26:14 +01:00
2017-07-04 18:26:11 +02:00
#[inline(always)]
pub unsafe fn claim<R, F>(
&'static self,
ceiling: u8,
nvic_prio_bits: u8,
t: &mut Threshold,
f: F,
) -> R
2017-04-21 22:41:03 +02:00
where
2017-07-04 18:26:11 +02:00
F: FnOnce(&Static<T>, &mut Threshold) -> R,
2017-04-21 22:41:03 +02:00
{
2017-07-04 18:26:11 +02:00
claim(&self.data, ceiling, nvic_prio_bits, t, f, |data| {
Static::ref_(&*data.get())
})
2017-04-21 22:41:03 +02:00
}
2017-07-04 18:26:11 +02:00
#[inline(always)]
pub unsafe fn claim_mut<R, F>(
&'static self,
ceiling: u8,
nvic_prio_bits: u8,
t: &mut Threshold,
f: F,
) -> R
where
F: FnOnce(&mut Static<T>, &mut Threshold) -> R,
{
claim(&self.data, ceiling, nvic_prio_bits, t, f, |data| {
Static::ref_mut(&mut *data.get())
})
}
2017-07-04 18:26:11 +02:00
pub fn get(&self) -> *mut T {
self.data.get()
}
2017-03-05 06:26:14 +01:00
}
2017-03-10 05:59:50 +01:00
2017-07-04 18:26:11 +02:00
unsafe impl<T> Sync for Resource<T>
2017-04-17 18:59:56 +02:00
where
2017-07-04 18:26:11 +02:00
T: Send,
2017-04-04 23:37:01 +02:00
{
2017-04-04 22:36:23 +02:00
}
2017-07-04 18:26:11 +02:00
pub struct Threshold(u8);
2017-07-04 18:26:11 +02:00
impl Threshold {
pub unsafe fn new(value: u8) -> Self {
Threshold(value)
}
}
2017-07-04 18:26:11 +02:00
impl !Send for Threshold {}
2017-04-10 05:42:17 +02:00
/// Sets an interrupt as pending
pub fn set_pending<I>(interrupt: I)
where
I: Nr,
{
// NOTE(safe) atomic write
let nvic = unsafe { &*cortex_m::peripheral::NVIC.get() };
nvic.set_pending(interrupt);
}
#[macro_export]
2017-07-04 18:26:11 +02:00
macro_rules! task {
($NAME:ident, $body:path) => {
#[allow(non_snake_case)]
#[allow(unsafe_code)]
2017-07-04 18:26:11 +02:00
#[no_mangle]
pub unsafe extern "C" fn $NAME() {
let f: fn(&mut $crate::Threshold, ::$NAME::Resources) = $body;
2017-07-04 18:26:11 +02:00
f(
&mut $crate::Threshold::new(::$NAME::$NAME),
2017-07-04 18:26:11 +02:00
::$NAME::Resources::new(),
);
}
};
2017-07-04 18:26:11 +02:00
($NAME:ident, $body:path, $local:ident {
$($var:ident: $ty:ty = $expr:expr;)+
2017-04-10 05:42:17 +02:00
}) => {
2017-07-04 18:26:11 +02:00
struct $local {
$($var: $ty,)+
}
2017-07-04 18:26:11 +02:00
#[allow(non_snake_case)]
#[allow(unsafe_code)]
2017-07-04 18:26:11 +02:00
#[no_mangle]
pub unsafe extern "C" fn $NAME() {
let f: fn(
&mut $crate::Threshold,
2017-07-04 18:26:11 +02:00
&mut $local,
::$NAME::Resources,
) = $body;
static mut LOCAL: $local = $local {
$($var: $expr,)+
};
f(
&mut $crate::Threshold::new(::$NAME::$NAME),
2017-07-04 18:26:11 +02:00
&mut LOCAL,
::$NAME::Resources::new(),
);
}
};
}
2017-07-04 18:26:11 +02:00
#[allow(non_camel_case_types)]
#[doc(hidden)]
pub enum Exception {
/// System service call via SWI instruction
SVCALL,
/// Pendable request for system service
PENDSV,
/// System tick timer
SYS_TICK,
}
2017-04-10 05:42:17 +02:00
2017-07-04 18:26:11 +02:00
impl Exception {
#[doc(hidden)]
pub fn nr(&self) -> usize {
match *self {
Exception::SVCALL => 11,
Exception::PENDSV => 14,
Exception::SYS_TICK => 15,
}
}
}