1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
//! 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
//!
//! In increasing grade of complexity, see the [examples](./examples/index.html)
//! module.
#![deny(missing_docs)]
#![deny(warnings)]
#![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 rtfm_core;
extern crate static_ref;
use core::u8;
pub use rtfm_core::{Resource, Static, Threshold};
pub use cortex_m::asm::{bkpt, wfi};
pub use cortex_m_rtfm_macros::app;
use cortex_m::interrupt::{self, Nr};
#[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)]
pub unsafe fn claim<T, R, F>(
data: T,
ceiling: u8,
nvic_prio_bits: u8,
t: &mut Threshold,
f: F,
) -> R
where
F: FnOnce(T, &mut Threshold) -> R,
{
let max_priority = 1 << nvic_prio_bits;
if ceiling > t.value() {
match () {
#[cfg(armv6m)]
() => atomic(t, |t| f(data, t)),
#[cfg(not(armv6m))]
() => {
if ceiling == max_priority {
atomic(t, |t| f(data, t))
} else {
let old = basepri::read();
let hw = (max_priority - ceiling) << (8 - nvic_prio_bits);
basepri::write(hw);
let ret = f(data, &mut Threshold::new(ceiling));
basepri::write(old);
ret
}
}
}
} else {
f(data, t)
}
}
/// 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);
}
#[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,
}
}
}
|