2017-07-29 07:34:00 +02:00
|
|
|
//! Real Time For the Masses (RTFM) framework for ARM Cortex-M microcontrollers
|
2017-07-21 05:53:44 +02:00
|
|
|
//!
|
|
|
|
//! 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
|
2017-07-29 08:16:11 +02:00
|
|
|
//! loops. However, you can run an endless event loop in the `idle` *loop*.
|
2017-07-21 05:53:44 +02:00
|
|
|
//!
|
|
|
|
//! - Task priorities must remain constant at runtime.
|
|
|
|
//!
|
|
|
|
//! # Dependencies
|
|
|
|
//!
|
2017-07-29 07:34:00 +02:00
|
|
|
//! The application crate must depend on a device crate generated using
|
|
|
|
//! [`svd2rust`] v0.11.x and the "rt" feature of that crate must be enabled. The
|
|
|
|
//! SVD file used to generate the device crate *must* contain [`<cpu>`]
|
|
|
|
//! information.
|
2017-07-21 05:53:44 +02:00
|
|
|
//!
|
|
|
|
//! [`svd2rust`]: https://docs.rs/svd2rust/0..0/svd2rust/
|
|
|
|
//! [`<cpu>`]: https://www.keil.com/pack/doc/CMSIS/SVD/html/elem_cpu.html
|
2017-07-29 07:34:00 +02:00
|
|
|
//!
|
2017-07-29 08:16:11 +02:00
|
|
|
//! # `app!`
|
2017-07-29 07:34:00 +02:00
|
|
|
//!
|
2017-07-29 08:50:04 +02:00
|
|
|
//! The `app!` macro is documented [here].
|
|
|
|
//!
|
|
|
|
//! [here]: https://docs.rs/cortex-m-rtfm-macros/0.2.0/cortex_m_rtfm_macros/fn.app.html
|
2017-07-21 05:53:44 +02:00
|
|
|
//!
|
|
|
|
//! # Examples
|
|
|
|
//!
|
2017-07-29 07:34:00 +02:00
|
|
|
//! In increasing grade of complexity. See the [examples](./examples/index.html)
|
2017-07-21 06:14:41 +02:00
|
|
|
//! module.
|
2017-07-29 08:16:11 +02:00
|
|
|
//!
|
|
|
|
//! # References
|
|
|
|
//!
|
|
|
|
//! - Baker, T. P. (1991). Stack-based scheduling of realtime processes.
|
|
|
|
//! *Real-Time Systems*, 3(1), 67-99.
|
|
|
|
//!
|
|
|
|
//! > The original Stack Resource Policy paper. [PDF][srp].
|
|
|
|
//!
|
|
|
|
//! [srp]: http://www.cs.fsu.edu/~baker/papers/mstacks3.pdf
|
|
|
|
//!
|
|
|
|
//! - Eriksson, J., Häggström, F., Aittamaa, S., Kruglyak, A., & Lindgren, P.
|
|
|
|
//! (2013, June). Real-time for the masses, step 1: Programming API and static
|
|
|
|
//! priority SRP kernel primitives. In Industrial Embedded Systems (SIES),
|
|
|
|
//! 2013 8th IEEE International Symposium on (pp. 110-113). IEEE.
|
|
|
|
//!
|
|
|
|
//! > A description of the RTFM task and resource model. [PDF][rtfm]
|
|
|
|
//!
|
|
|
|
//! [rtfm]: http://www.diva-portal.org/smash/get/diva2:1005680/FULLTEXT01.pdf
|
2017-07-21 05:53:44 +02:00
|
|
|
#![deny(missing_docs)]
|
|
|
|
#![deny(warnings)]
|
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;
|
2017-07-27 18:37:58 +02:00
|
|
|
extern crate rtfm_core;
|
2017-03-05 06:26:14 +01:00
|
|
|
|
2017-07-27 18:37:58 +02:00
|
|
|
use core::u8;
|
|
|
|
|
2017-09-03 18:05:48 +02:00
|
|
|
pub use rtfm_core::{Resource, LateResource, 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;
|
2017-07-27 18:37:58 +02:00
|
|
|
use cortex_m::interrupt::{self, Nr};
|
2017-07-04 18:26:11 +02:00
|
|
|
#[cfg(not(armv6m))]
|
2017-07-27 18:37:58 +02:00
|
|
|
use cortex_m::register::basepri;
|
2017-07-21 05:53:44 +02:00
|
|
|
|
|
|
|
pub mod examples;
|
|
|
|
|
2017-07-29 07:34:00 +02:00
|
|
|
/// Executes the closure `f` in a preemption free context
|
|
|
|
///
|
|
|
|
/// During the execution of the closure no task can preempt the current task.
|
2017-07-27 18:37:58 +02:00
|
|
|
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
|
2017-07-21 05:53:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-26 05:30:41 +02:00
|
|
|
#[inline]
|
2017-07-21 05:53:44 +02:00
|
|
|
#[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,
|
2017-07-27 22:15:19 +02:00
|
|
|
_nvic_prio_bits: u8,
|
2017-07-04 18:26:11 +02:00
|
|
|
t: &mut Threshold,
|
|
|
|
f: F,
|
|
|
|
) -> R
|
2017-04-21 07:24:54 +02:00
|
|
|
where
|
2017-07-24 03:51:37 +02:00
|
|
|
F: FnOnce(T, &mut Threshold) -> R,
|
2017-04-21 07:24:54 +02:00
|
|
|
{
|
2017-07-27 18:37:58 +02:00
|
|
|
if ceiling > t.value() {
|
2017-07-04 18:26:11 +02:00
|
|
|
match () {
|
|
|
|
#[cfg(armv6m)]
|
2017-07-27 18:37:58 +02:00
|
|
|
() => atomic(t, |t| f(data, t)),
|
|
|
|
|
2017-07-04 18:26:11 +02:00
|
|
|
#[cfg(not(armv6m))]
|
|
|
|
() => {
|
2017-07-27 22:15:19 +02:00
|
|
|
let max_priority = 1 << _nvic_prio_bits;
|
2017-07-27 21:59:31 +02:00
|
|
|
|
2017-07-04 18:26:11 +02:00
|
|
|
if ceiling == max_priority {
|
2017-07-27 18:37:58 +02:00
|
|
|
atomic(t, |t| f(data, t))
|
2017-07-04 18:26:11 +02:00
|
|
|
} else {
|
|
|
|
let old = basepri::read();
|
2017-07-27 22:15:19 +02:00
|
|
|
let hw = (max_priority - ceiling) << (8 - _nvic_prio_bits);
|
2017-07-27 18:37:58 +02:00
|
|
|
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
|
|
|
|
2017-07-29 07:34:00 +02:00
|
|
|
/// Sets an interrupt, that is a task, as pending
|
2017-07-25 05:46:29 +02:00
|
|
|
///
|
2017-07-29 07:34:00 +02:00
|
|
|
/// If the task priority is high enough the task will be serviced immediately,
|
|
|
|
/// otherwise it will be serviced at some point after the current task ends.
|
2017-07-07 06:25:29 +02:00
|
|
|
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);
|
|
|
|
}
|