mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-26 13:39:41 +01:00
281 lines
6.2 KiB
Rust
281 lines
6.2 KiB
Rust
#![feature(asm)]
|
|
#![feature(const_fn)]
|
|
#![feature(optin_builtin_traits)]
|
|
#![feature(proc_macro)]
|
|
#![no_std]
|
|
|
|
extern crate cortex_m;
|
|
extern crate cortex_m_rtfm_macros;
|
|
extern crate static_ref;
|
|
|
|
use core::cell::UnsafeCell;
|
|
|
|
pub use cortex_m_rtfm_macros::app;
|
|
pub use cortex_m::asm::{bkpt, wfi};
|
|
pub use cortex_m::interrupt::CriticalSection;
|
|
pub use cortex_m::interrupt::free as atomic;
|
|
pub use static_ref::Static;
|
|
use cortex_m::interrupt::Nr;
|
|
#[cfg(not(armv6m))]
|
|
use cortex_m::register::{basepri_max, basepri};
|
|
|
|
#[cfg(not(armv6m))]
|
|
macro_rules! barrier {
|
|
() => {
|
|
asm!("" ::: "memory" : "volatile");
|
|
}
|
|
}
|
|
|
|
#[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
|
|
F: FnOnce(U, &mut Threshold) -> R,
|
|
G: FnOnce(T) -> U,
|
|
{
|
|
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);
|
|
barrier!();
|
|
let ret = f(g(data), &mut Threshold(ceiling));
|
|
barrier!();
|
|
basepri::write(old);
|
|
ret
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
f(g(data), t)
|
|
}
|
|
}
|
|
|
|
pub struct Peripheral<P>
|
|
where
|
|
P: 'static,
|
|
{
|
|
// 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,
|
|
peripheral: cortex_m::peripheral::Peripheral<P>,
|
|
}
|
|
|
|
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()
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub unsafe fn claim<R, F>(
|
|
&'static self,
|
|
ceiling: u8,
|
|
nvic_prio_bits: u8,
|
|
t: &mut Threshold,
|
|
f: F,
|
|
) -> R
|
|
where
|
|
F: FnOnce(&P, &mut Threshold) -> R,
|
|
{
|
|
claim(
|
|
&self.peripheral,
|
|
ceiling,
|
|
nvic_prio_bits,
|
|
t,
|
|
f,
|
|
|peripheral| &*peripheral.get(),
|
|
)
|
|
}
|
|
|
|
pub fn get(&self) -> *mut P {
|
|
self.peripheral.get()
|
|
}
|
|
}
|
|
|
|
unsafe impl<P> Sync for Peripheral<P>
|
|
where
|
|
P: Send,
|
|
{
|
|
}
|
|
|
|
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>,
|
|
}
|
|
|
|
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())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub unsafe fn claim<R, F>(
|
|
&'static self,
|
|
ceiling: u8,
|
|
nvic_prio_bits: u8,
|
|
t: &mut Threshold,
|
|
f: F,
|
|
) -> R
|
|
where
|
|
F: FnOnce(&Static<T>, &mut Threshold) -> R,
|
|
{
|
|
claim(&self.data, ceiling, nvic_prio_bits, t, f, |data| {
|
|
Static::ref_(&*data.get())
|
|
})
|
|
}
|
|
|
|
#[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())
|
|
})
|
|
}
|
|
|
|
pub fn get(&self) -> *mut T {
|
|
self.data.get()
|
|
}
|
|
}
|
|
|
|
unsafe impl<T> Sync for Resource<T>
|
|
where
|
|
T: Send,
|
|
{
|
|
}
|
|
|
|
pub struct Threshold(u8);
|
|
|
|
impl Threshold {
|
|
pub unsafe fn new(value: u8) -> Self {
|
|
Threshold(value)
|
|
}
|
|
}
|
|
|
|
impl !Send for Threshold {}
|
|
|
|
/// 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]
|
|
macro_rules! task {
|
|
($NAME:ident, $body:path) => {
|
|
#[allow(non_snake_case)]
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn $NAME() {
|
|
let f: fn($crate::Threshold, ::$NAME::Resources) = $body;
|
|
|
|
f(
|
|
$crate::Threshold::new(::$NAME::$NAME),
|
|
::$NAME::Resources::new(),
|
|
);
|
|
}
|
|
};
|
|
($NAME:ident, $body:path, $local:ident {
|
|
$($var:ident: $ty:ty = $expr:expr;)+
|
|
}) => {
|
|
struct $local {
|
|
$($var: $ty,)+
|
|
}
|
|
|
|
#[allow(non_snake_case)]
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn $NAME() {
|
|
let f: fn(
|
|
$crate::Threshold,
|
|
&mut $local,
|
|
::$NAME::Resources,
|
|
) = $body;
|
|
|
|
static mut LOCAL: $local = $local {
|
|
$($var: $expr,)+
|
|
};
|
|
|
|
f(
|
|
$crate::Threshold::new(::$NAME::$NAME),
|
|
&mut LOCAL,
|
|
::$NAME::Resources::new(),
|
|
);
|
|
}
|
|
};
|
|
}
|
|
|
|
#[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,
|
|
}
|
|
|
|
impl Exception {
|
|
#[doc(hidden)]
|
|
pub fn nr(&self) -> usize {
|
|
match *self {
|
|
Exception::SVCALL => 11,
|
|
Exception::PENDSV => 14,
|
|
Exception::SYS_TICK => 15,
|
|
}
|
|
}
|
|
}
|