rtic/src/lib.rs

164 lines
4.8 KiB
Rust
Raw Normal View History

//! Real Time For the Masses (RTFM), a framework for building concurrent
//! applications, for ARM Cortex-M microcontrollers
//!
//! This crate is based on [the RTFM framework] created by the Embedded Systems
//! group at [Luleå University of Technology][ltu], led by Prof. Per Lindgren,
//! and uses a simplified version of the Stack Resource Policy as scheduling
//! policy (check the [references] for details).
//!
//! [the RTFM framework]: http://www.rtfm-lang.org/
//! [ltu]: https://www.ltu.se/?l=en
//! [per]: https://www.ltu.se/staff/p/pln-1.11258?l=en
//! [references]: ./index.html#references
//!
//! # Features
//!
//! - **Event triggered tasks** as the unit of concurrency.
//! - Support for prioritization of tasks and, thus, **preemptive
//! multitasking**.
//! - **Efficient and data race free memory sharing** through fine grained *non
//! global* critical sections.
//! - **Deadlock free execution** guaranteed at compile time.
//! - **Minimal scheduling overhead** as the scheduler has no "software
//! component": the hardware does all the scheduling.
//! - **Highly efficient memory usage**: All the tasks share a single call stack
//! and there's no hard dependency on a dynamic memory allocator.
//! - **All Cortex M devices are fully supported**.
//! - This task model is amenable to known WCET (Worst Case Execution Time)
//! analysis and scheduling analysis techniques. (Though we haven't yet
//! developed Rust friendly tooling for that.)
//!
//! # Constraints
//!
//! - Tasks must run to completion. That's it, tasks can't contain endless
//! loops. However, you can run an endless event loop in the `idle` function.
//!
//! - Task priorities must remain constant at runtime.
//!
//! # Dependencies
//!
//! - A device crate generated using [`svd2rust`] v0.11.x. The input SVD file
//! *must* contain [`<cpu>`] information.
//! - A `start` lang time: Vanilla `main` must be supported in binary crates.
//! You can use the [`cortex-m-rt`] crate to fulfill the requirement
//!
//! [`svd2rust`]: https://docs.rs/svd2rust/0..0/svd2rust/
//! [`<cpu>`]: https://www.keil.com/pack/doc/CMSIS/SVD/html/elem_cpu.html
//! [`cortex-m-rt`]: https://docs.rs/cortex-m-rt/0.3.0/cortex_m_rt/
//!
//! # Examples
//!
2017-07-21 06:14:41 +02:00
//! In increasing grade of complexity, see the [examples](./examples/index.html)
//! module.
#![deny(missing_docs)]
#![deny(warnings)]
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 rtfm_core;
extern crate static_ref;
2017-03-05 06:26:14 +01:00
use core::u8;
pub use rtfm_core::{Resource, Static, Threshold};
2017-04-14 17:05:24 +02:00
pub use cortex_m::asm::{bkpt, wfi};
2017-07-21 06:14:41 +02:00
pub use cortex_m_rtfm_macros::app;
use cortex_m::interrupt::{self, Nr};
2017-07-04 18:26:11 +02:00
#[cfg(not(armv6m))]
use cortex_m::register::basepri;
pub mod examples;
/// Executes the closure `f` in an interrupt free context
pub fn atomic<R, F>(t: &mut Threshold, f: F) -> R
where
F: FnOnce(&mut Threshold) -> R,
{
if t.value() == u8::MAX {
f(t)
} else {
interrupt::disable();
let r = f(&mut unsafe { Threshold::max() });
unsafe { interrupt::enable() };
r
}
}
#[inline]
#[doc(hidden)]
2017-07-24 03:51:37 +02:00
pub unsafe fn claim<T, R, F>(
data: T,
2017-07-04 18:26:11 +02:00
ceiling: u8,
nvic_prio_bits: u8,
t: &mut Threshold,
f: F,
) -> R
where
2017-07-24 03:51:37 +02:00
F: FnOnce(T, &mut Threshold) -> R,
{
2017-07-04 18:26:11 +02:00
let max_priority = 1 << nvic_prio_bits;
if ceiling > t.value() {
2017-07-04 18:26:11 +02:00
match () {
#[cfg(armv6m)]
() => atomic(t, |t| f(data, t)),
2017-07-04 18:26:11 +02:00
#[cfg(not(armv6m))]
() => {
if ceiling == max_priority {
atomic(t, |t| f(data, t))
2017-07-04 18:26:11 +02:00
} else {
let old = basepri::read();
let hw = (max_priority - ceiling) << (8 - nvic_prio_bits);
basepri::write(hw);
2017-07-24 03:51:37 +02:00
let ret = f(data, &mut Threshold::new(ceiling));
2017-07-04 18:26:11 +02:00
basepri::write(old);
ret
}
}
2017-03-05 06:26:14 +01:00
}
2017-07-04 18:26:11 +02:00
} else {
2017-07-24 03:51:37 +02:00
f(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
/// Sets an interrupt as pending
///
/// If the interrupt priority is high enough the interrupt will be serviced
/// immediately, otherwise it will be serviced at some point after the current
/// task ends.
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);
}
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,
}
}
}