mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-29 15:04:32 +01:00
rename rtfm::critical
to rtfm::atomic
, touch up the documentation
This commit is contained in:
parent
840c32060b
commit
404dde6f2a
1 changed files with 91 additions and 43 deletions
134
src/lib.rs
134
src/lib.rs
|
@ -1,12 +1,13 @@
|
||||||
//! RTFM: Real Time For the Masses (ARM Cortex-M edition)
|
//! RTFM: Real Time For the Masses (ARM Cortex-M edition)
|
||||||
//!
|
//!
|
||||||
//! RTFM is a framework for building event-driven applications for ARM Cortex-M
|
//! `cortex-m-rtfm` is a framework for building concurrent applications for ARM
|
||||||
//! microcontrollers.
|
//! Cortex-M microcontrollers.
|
||||||
//!
|
//!
|
||||||
//! This crate is based on the RTFM framework created by [prof. Per
|
//! This crate is based on [the RTFM framework] created by [prof. Per
|
||||||
//! Lindgren][per] and uses a simplified version of the Stack Resource Policy as
|
//! Lindgren][per] and uses a simplified version of the Stack Resource Policy as
|
||||||
//! scheduling policy. Check the [references] for details.
|
//! scheduling policy (check the [references] for details).
|
||||||
//!
|
//!
|
||||||
|
//! [the RTFM framework]: http://www.rtfm-lang.org/
|
||||||
//! [per]: https://www.ltu.se/staff/p/pln-1.11258?l=en
|
//! [per]: https://www.ltu.se/staff/p/pln-1.11258?l=en
|
||||||
//! [references]: ./index.html#references
|
//! [references]: ./index.html#references
|
||||||
//!
|
//!
|
||||||
|
@ -14,13 +15,16 @@
|
||||||
//!
|
//!
|
||||||
//! - **Event triggered tasks** as the unit of concurrency.
|
//! - **Event triggered tasks** as the unit of concurrency.
|
||||||
//! - Supports prioritization of tasks and, thus, **preemptive multitasking**.
|
//! - Supports prioritization of tasks and, thus, **preemptive multitasking**.
|
||||||
//! - **Data race free memory sharing** through fine grained *non global*
|
//! - **Efficient data race free memory sharing** through fine grained *non
|
||||||
//! critical sections.
|
//! global* critical sections.
|
||||||
//! - **Deadlock free execution** guaranteed at compile time.
|
//! - **Deadlock free execution** guaranteed at compile time.
|
||||||
//! - **Minimal overhead** as the scheduler has no software component / runtime;
|
//! - **Minimal scheduling overhead** as the scheduler has no "software
|
||||||
//! the hardware does all the scheduling.
|
//! component"; the hardware does all the scheduling.
|
||||||
//! - Full support for all Cortex M3, M4 and M7 devices. M0(+) is also supported
|
//! - **Highly efficient memory usage**. All the tasks share the call stack and
|
||||||
//! but the whole API is not available (due to missing hardware features).
|
//! there's no hard dependency on a dynamic allocator.
|
||||||
|
//! - **All Cortex M3, M4 and M7 devices are fully supported**. M0(+) is
|
||||||
|
//! partially supported as the whole API is not available (due to missing
|
||||||
|
//! hardware features).
|
||||||
//! - The number of task priority levels is configurable at compile time through
|
//! - The number of task priority levels is configurable at compile time through
|
||||||
//! the `P2` (4 levels), `P3` (8 levels), etc. Cargo features. The number of
|
//! the `P2` (4 levels), `P3` (8 levels), etc. Cargo features. The number of
|
||||||
//! priority levels supported by the hardware is device specific but this
|
//! priority levels supported by the hardware is device specific but this
|
||||||
|
@ -55,6 +59,7 @@
|
||||||
//! ## Zero tasks
|
//! ## Zero tasks
|
||||||
//!
|
//!
|
||||||
//! ``` ignore
|
//! ``` ignore
|
||||||
|
//! #![feature(used)]
|
||||||
//! #![no_std]
|
//! #![no_std]
|
||||||
//!
|
//!
|
||||||
//! #[macro_use] // for the `hprintln!` macro
|
//! #[macro_use] // for the `hprintln!` macro
|
||||||
|
@ -101,7 +106,7 @@
|
||||||
//! structure into your program:
|
//! structure into your program:
|
||||||
//!
|
//!
|
||||||
//! - `init`, the initialization phase, runs first. This function is executed
|
//! - `init`, the initialization phase, runs first. This function is executed
|
||||||
//! inside a *global* critical section and can't be preempted.
|
//! "atomically", in the sense that no task / interrupt can preempt it.
|
||||||
//!
|
//!
|
||||||
//! - `idle`, a never ending function that runs after `init`.
|
//! - `idle`, a never ending function that runs after `init`.
|
||||||
//!
|
//!
|
||||||
|
@ -110,6 +115,8 @@
|
||||||
//! # One task
|
//! # One task
|
||||||
//!
|
//!
|
||||||
//! ``` ignore
|
//! ``` ignore
|
||||||
|
//! #![feature(const_fn)]
|
||||||
|
//! #![feature(used)]
|
||||||
//! #![no_std]
|
//! #![no_std]
|
||||||
//!
|
//!
|
||||||
//! extern crate cortex_m_rt;
|
//! extern crate cortex_m_rt;
|
||||||
|
@ -129,7 +136,9 @@
|
||||||
//! // IDLE LOOP
|
//! // IDLE LOOP
|
||||||
//! fn idle(_priority: P0) -> ! {
|
//! fn idle(_priority: P0) -> ! {
|
||||||
//! // Sleep
|
//! // Sleep
|
||||||
//! loop { rtfm::wfi() }
|
//! loop {
|
||||||
|
//! rtfm::wfi();
|
||||||
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! // TASKS
|
//! // TASKS
|
||||||
|
@ -173,6 +182,8 @@
|
||||||
//! # Two "serial" tasks
|
//! # Two "serial" tasks
|
||||||
//!
|
//!
|
||||||
//! ``` ignore
|
//! ``` ignore
|
||||||
|
//! #![feature(const_fn)]
|
||||||
|
//! #![feature(used)]
|
||||||
//! #![no_std]
|
//! #![no_std]
|
||||||
//!
|
//!
|
||||||
//! extern crate cortex_m_rt;
|
//! extern crate cortex_m_rt;
|
||||||
|
@ -203,6 +214,17 @@
|
||||||
//! // Data shared between tasks `t1` and `t2`
|
//! // Data shared between tasks `t1` and `t2`
|
||||||
//! static COUNTER: Resource<Cell<u32>, C1> = Resource::new(Cell::new(0));
|
//! static COUNTER: Resource<Cell<u32>, C1> = Resource::new(Cell::new(0));
|
||||||
//!
|
//!
|
||||||
|
//! fn init(priority: P0, ceiling: &C16) {
|
||||||
|
//! // ..
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn idle(priority: P0) -> ! {
|
||||||
|
//! // Sleep
|
||||||
|
//! loop {
|
||||||
|
//! rtfm::wfi();
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
//! fn t1(_task: Tim6Dacunder, priority: P1) {
|
//! fn t1(_task: Tim6Dacunder, priority: P1) {
|
||||||
//! let ceiling = priority.as_ceiling();
|
//! let ceiling = priority.as_ceiling();
|
||||||
//!
|
//!
|
||||||
|
@ -223,13 +245,13 @@
|
||||||
//! Here we declare two tasks, `t1` and `t2`; both with a priority of 1 (`P1`).
|
//! Here we declare two tasks, `t1` and `t2`; both with a priority of 1 (`P1`).
|
||||||
//! As both tasks have the same priority, we say that they are *serial* tasks in
|
//! As both tasks have the same priority, we say that they are *serial* tasks in
|
||||||
//! the sense that `t1` can only run *after* `t2` is done and vice versa; i.e.
|
//! the sense that `t1` can only run *after* `t2` is done and vice versa; i.e.
|
||||||
//! there's no preemption.
|
//! no preemption between them is possible.
|
||||||
//!
|
//!
|
||||||
//! To share data between these two tasks, we use the
|
//! To share data between these two tasks, we use the
|
||||||
//! [`Resource`](./struct.Resource.html) abstraction. As the tasks can't preempt
|
//! [`Resource`](./struct.Resource.html) abstraction. As the tasks can't preempt
|
||||||
//! each other, they can access the `COUNTER` resource using the zero cost
|
//! each other, they can access the `COUNTER` resource using the zero cost
|
||||||
//! [`access`](./struct.Resource.html#method.access) method -- no
|
//! [`access`](./struct.Resource.html#method.access) method -- no
|
||||||
//! synchronization needed.
|
//! synchronization is required.
|
||||||
//!
|
//!
|
||||||
//! `COUNTER` has an extra type parameter: `C1`. This is the *ceiling* of the
|
//! `COUNTER` has an extra type parameter: `C1`. This is the *ceiling* of the
|
||||||
//! resource. For now suffices to say that the ceiling must be the maximum of
|
//! resource. For now suffices to say that the ceiling must be the maximum of
|
||||||
|
@ -240,6 +262,8 @@
|
||||||
//! # Preemptive multitasking
|
//! # Preemptive multitasking
|
||||||
//!
|
//!
|
||||||
//! ``` ignore
|
//! ``` ignore
|
||||||
|
//! #![feature(const_fn)]
|
||||||
|
//! #![feature(used)]
|
||||||
//! #![no_std]
|
//! #![no_std]
|
||||||
//!
|
//!
|
||||||
//! extern crate cortex_m_rt;
|
//! extern crate cortex_m_rt;
|
||||||
|
@ -250,9 +274,7 @@
|
||||||
//! use core::cell::Cell;
|
//! use core::cell::Cell;
|
||||||
//!
|
//!
|
||||||
//! use stm32f30x::interrupt::{Tim6Dacunder, Tim7};
|
//! use stm32f30x::interrupt::{Tim6Dacunder, Tim7};
|
||||||
//! use rtfm::{C2, C16, P0, P1, P2, Resource};
|
//! use rtfm::{C1, C16, C2, P0, P1, P2, Resource};
|
||||||
//!
|
|
||||||
//! // omitted: `idle`, `init`
|
|
||||||
//!
|
//!
|
||||||
//! tasks!(stm32f30x, {
|
//! tasks!(stm32f30x, {
|
||||||
//! t1: Task {
|
//! t1: Task {
|
||||||
|
@ -269,16 +291,29 @@
|
||||||
//!
|
//!
|
||||||
//! static COUNTER: Resource<Cell<u32>, C2> = Resource::new(Cell::new(0));
|
//! static COUNTER: Resource<Cell<u32>, C2> = Resource::new(Cell::new(0));
|
||||||
//!
|
//!
|
||||||
|
//! fn init(priority: P0, ceiling: &C16) {
|
||||||
|
//! // ..
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn idle(priority: P0) -> ! {
|
||||||
|
//! // Sleep
|
||||||
|
//! loop {
|
||||||
|
//! rtfm::wfi();
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
//! fn t1(_task: Tim6Dacunder, priority: P1) {
|
//! fn t1(_task: Tim6Dacunder, priority: P1) {
|
||||||
//! // ..
|
//! // ..
|
||||||
//!
|
//!
|
||||||
//! let ceiling: &C1 = priority.as_ceiling();
|
//! let ceiling: &C1 = priority.as_ceiling();
|
||||||
//!
|
//!
|
||||||
//! ceiling.raise(&COUNTER, |ceiling: &C2| {
|
//! ceiling.raise(
|
||||||
//! let counter = COUNTER.access(&priority, ceiling);
|
//! &COUNTER, |ceiling: &C2| {
|
||||||
|
//! let counter = COUNTER.access(&priority, ceiling);
|
||||||
//!
|
//!
|
||||||
//! counter.set(counter.get() + 1);
|
//! counter.set(counter.get() + 1);
|
||||||
//! });
|
//! }
|
||||||
|
//! );
|
||||||
//!
|
//!
|
||||||
//! // ..
|
//! // ..
|
||||||
//! }
|
//! }
|
||||||
|
@ -300,39 +335,48 @@
|
||||||
//! To avoid data races, `t1` must modify `COUNTER` in an atomic way; i.e. `t2`
|
//! To avoid data races, `t1` must modify `COUNTER` in an atomic way; i.e. `t2`
|
||||||
//! most not preempt `t1` while `COUNTER` is being modified. This is
|
//! most not preempt `t1` while `COUNTER` is being modified. This is
|
||||||
//! accomplished by [`raise`](./struct.C.html#method.raise)-ing the `ceiling`.
|
//! accomplished by [`raise`](./struct.C.html#method.raise)-ing the `ceiling`.
|
||||||
//! This creates a critical section, denoted by a closure, for whose span
|
//! This creates a critical section, denoted by a closure; for whose execution,
|
||||||
//! `COUNTER` is accessible but `t2` is blocked from preempting `t1`.
|
//! `COUNTER` is accessible but `t2` is blocked from preempting `t1`.
|
||||||
//!
|
//!
|
||||||
//! How `t2` accesses `COUNTER` remains unchanged. Since `t1` can't preempt `t2`
|
//! How `t2` accesses `COUNTER` remains unchanged. Since `t1` can't preempt `t2`
|
||||||
//! due to the differences in priority; no critical section is needed in `t2`.
|
//! due to the differences in priority; no critical section is needed in `t2`.
|
||||||
//!
|
//!
|
||||||
//! Note that the ceiling of `COUNTER` had to change to `C2`. This is required
|
//! Note that the ceiling of `COUNTER` had to be changed to `C2`. This is
|
||||||
//! because the ceiling must be the maximum between `P1` and `P2`.
|
//! required because the ceiling must be the maximum between `P1` and `P2`.
|
||||||
//!
|
//!
|
||||||
//! Finally, it should be noted that the critical section in `t1` will only
|
//! Finally, it should be noted that the critical section in `t1` will only
|
||||||
//! block tasks with a priority of 2 or lower. This is exactly what the ceiling
|
//! block tasks with a priority of 2 or lower. This is exactly what the ceiling
|
||||||
//! represents: it's the "bar" that a task priority must pass in order to be
|
//! represents: it's the "bar" that a task priority must pass in order to be
|
||||||
//! able to preempt the current task / critical section.
|
//! able to preempt the current task / critical section. Note that a task with
|
||||||
|
//! e.g. a priority of 3 (`P3`) effectively imposes a ceiling of 3 (`C3`)
|
||||||
|
//! because only other task with a priority of 4 or greater can preempt it.
|
||||||
//!
|
//!
|
||||||
//! # Peripherals as resources
|
//! # Peripherals as resources
|
||||||
//!
|
//!
|
||||||
//! ``` ignore
|
//! ``` ignore
|
||||||
|
//! #![feature(const_fn)]
|
||||||
|
//! #![feature(used)]
|
||||||
//! #![no_std]
|
//! #![no_std]
|
||||||
//!
|
//!
|
||||||
//! extern crate cortex_m_rt;
|
//! extern crate cortex_m_rt;
|
||||||
//! #[macro_use]
|
//! #[macro_use]
|
||||||
//! extern crate cortex_m_rtfm as rtfm;
|
//! extern crate cortex_m_rtfm as rtfm;
|
||||||
//! extern crate stm32f100xx;
|
//! extern crate stm32f30x;
|
||||||
//!
|
//!
|
||||||
//! use rtfm::{C0, C16, P0, Peripheral};
|
//! use rtfm::{C0, C16, P0, Peripheral};
|
||||||
//!
|
//!
|
||||||
//! static GPIOA: Peripheral<stm32f100xx::Gpioa, C0> =
|
//! peripherals!(stm32f30x, {
|
||||||
//! unsafe { Peripheral::new(stm32f100xx::GPIOA) };
|
//! GPIOA: Peripheral {
|
||||||
|
//! register_block: Gpioa,
|
||||||
|
//! ceiling: C0,
|
||||||
|
//! },
|
||||||
|
//! RCC: Peripheral {
|
||||||
|
//! register_block: Rcc,
|
||||||
|
//! ceiling: C0,
|
||||||
|
//! },
|
||||||
|
//! });
|
||||||
//!
|
//!
|
||||||
//! static RCC: Peripheral<stm32f100xx::Rcc, C0> =
|
//! tasks!(stm32f30x, {});
|
||||||
//! unsafe { Peripheral::new(stm32f100xx::RCC) };
|
|
||||||
//!
|
|
||||||
//! tasks!(stm32f100xx, {});
|
|
||||||
//!
|
//!
|
||||||
//! fn init(priority: P0, ceiling: &C16) {
|
//! fn init(priority: P0, ceiling: &C16) {
|
||||||
//! let gpioa = GPIOA.access(&priority, &ceiling);
|
//! let gpioa = GPIOA.access(&priority, &ceiling);
|
||||||
|
@ -343,7 +387,9 @@
|
||||||
//!
|
//!
|
||||||
//! fn idle(_priority: P0) -> ! {
|
//! fn idle(_priority: P0) -> ! {
|
||||||
//! // Sleep
|
//! // Sleep
|
||||||
//! loop { rtfm::wfi() }
|
//! loop {
|
||||||
|
//! rtfm::wfi();
|
||||||
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -352,8 +398,8 @@
|
||||||
//! [`Peripheral`](./struct.Peripheral.html) abstraction.
|
//! [`Peripheral`](./struct.Peripheral.html) abstraction.
|
||||||
//!
|
//!
|
||||||
//! `Peripheral` and `Resource` has pretty much the same API except that
|
//! `Peripheral` and `Resource` has pretty much the same API except that
|
||||||
//! `Peripheral.new` is `unsafe`. Care must be taken to NOT alias peripherals;
|
//! `Peripheral` instances must be declared using the
|
||||||
//! i.e. don't create two `Peripheral`s that point to the same register block.
|
//! [`peripherals!`](./macro.peripherals.html) macro.
|
||||||
//!
|
//!
|
||||||
//! # References
|
//! # References
|
||||||
//!
|
//!
|
||||||
|
@ -537,10 +583,10 @@ impl<Periph, RC> Peripheral<Periph, C<RC>> {
|
||||||
|
|
||||||
unsafe impl<T, C> Sync for Peripheral<T, C> {}
|
unsafe impl<T, C> Sync for Peripheral<T, C> {}
|
||||||
|
|
||||||
/// Runs the closure `f` in a *global* critical section
|
/// Runs the closure `f` "atomically"
|
||||||
///
|
///
|
||||||
/// No task can preempt this critical section
|
/// No task can preempt the execution of the closure
|
||||||
pub fn critical<R, F>(f: F) -> R
|
pub fn atomic<R, F>(f: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&CMAX) -> R,
|
F: FnOnce(&CMAX) -> R,
|
||||||
{
|
{
|
||||||
|
@ -558,7 +604,7 @@ where
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disables the `task`
|
/// Disables a `task`
|
||||||
///
|
///
|
||||||
/// The task won't run even if the underlying interrupt is raised
|
/// The task won't run even if the underlying interrupt is raised
|
||||||
pub fn disable<T, TP>(_task: fn(T, P<TP>))
|
pub fn disable<T, TP>(_task: fn(T, P<TP>))
|
||||||
|
@ -572,7 +618,7 @@ where
|
||||||
unsafe { (*_NVIC.get()).disable(_task) }
|
unsafe { (*_NVIC.get()).disable(_task) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables the `task`
|
/// Enables a `task`
|
||||||
pub fn enable<T, TP>(_task: fn(T, P<TP>))
|
pub fn enable<T, TP>(_task: fn(T, P<TP>))
|
||||||
where
|
where
|
||||||
T: Context + Nr,
|
T: Context + Nr,
|
||||||
|
@ -791,7 +837,9 @@ macro_rules! peripherals {
|
||||||
///
|
///
|
||||||
/// fn idle(priority: P0) -> ! {
|
/// fn idle(priority: P0) -> ! {
|
||||||
/// // Sleep
|
/// // Sleep
|
||||||
/// loop { rtfm::wfi() }
|
/// loop {
|
||||||
|
/// rtfm::wfi();
|
||||||
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// // NOTE signature must match the tasks! declaration
|
/// // NOTE signature must match the tasks! declaration
|
||||||
|
@ -813,7 +861,7 @@ macro_rules! tasks {
|
||||||
},)*
|
},)*
|
||||||
}) => {
|
}) => {
|
||||||
fn main() {
|
fn main() {
|
||||||
$crate::critical(|cmax| {
|
$crate::atomic(|cmax| {
|
||||||
fn validate_signature(_: fn($crate::P0, &$crate::CMAX)) {}
|
fn validate_signature(_: fn($crate::P0, &$crate::CMAX)) {}
|
||||||
|
|
||||||
validate_signature(init);
|
validate_signature(init);
|
||||||
|
|
Loading…
Reference in a new issue