aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gdbinit6
-rw-r--r--.gitignore1
-rw-r--r--Cargo.toml4
-rw-r--r--README.md5
-rw-r--r--examples/full-syntax.rs1
-rw-r--r--examples/nested.rs14
-rw-r--r--examples/one-task.rs19
-rw-r--r--examples/preemption.rs8
-rw-r--r--examples/two-tasks.rs4
-rw-r--r--macros/Cargo.toml5
-rw-r--r--macros/src/check.rs4
-rw-r--r--macros/src/lib.rs144
-rw-r--r--src/examples/_1_one_task.rs19
-rw-r--r--src/examples/_2_two_tasks.rs4
-rw-r--r--src/examples/_3_preemption.rs8
-rw-r--r--src/examples/_4_nested.rs14
-rw-r--r--src/examples/_6_full_syntax.rs1
-rw-r--r--src/lib.rs32
18 files changed, 206 insertions, 87 deletions
diff --git a/.gdbinit b/.gdbinit
new file mode 100644
index 00000000..7c72d4fb
--- /dev/null
+++ b/.gdbinit
@@ -0,0 +1,6 @@
+target remote :3333
+
+monitor arm semihosting enable
+
+load
+step
diff --git a/.gitignore b/.gitignore
index 7a8e51cd..8bc31d43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
**/*.rs.bk
*.org
+.gdb_history
Cargo.lock
target/
diff --git a/Cargo.toml b/Cargo.toml
index 8ce7bdb2..f7fe92ab 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,7 @@ authors = [
"Per Lindgren <per.lindgren@ltu.se>",
]
categories = ["concurrency", "embedded", "no-std"]
-description = "Real Time For the Masses (RTFM), a framework for building concurrent applications, for ARM Cortex-M microcontrollers"
+description = "Real Time For the Masses (RTFM) framework for ARM Cortex-M microcontrollers"
documentation = "https://docs.rs/cortex-m-rtfm"
keywords = ["arm", "cortex-m"]
license = "MIT OR Apache-2.0"
@@ -14,8 +14,8 @@ version = "0.2.0"
[dependencies]
cortex-m = "0.3.1"
+rtfm-core = "0.1.0"
static-ref = "0.2.1"
-rtfm-core = { git = "https://github.com/japaric/rtfm-core" }
[dependencies.cortex-m-rtfm-macros]
path = "macros"
diff --git a/README.md b/README.md
index eb9555f6..240e2f8f 100644
--- a/README.md
+++ b/README.md
@@ -3,10 +3,9 @@
# `cortex-m-rtfm`
-> Real Time For the Masses (RTFM), a framework for building concurrent
-> applications, for ARM Cortex-M MCUs
+> Real Time For the Masses (RTFM) framework for ARM Cortex-M microcontrollers
-# [Manual](https://docs.rs/cortex-m-rtfm)
+# [Documentation](https://docs.rs/cortex-m-rtfm)
# License
diff --git a/examples/full-syntax.rs b/examples/full-syntax.rs
index 20e8dfbc..9b6b394e 100644
--- a/examples/full-syntax.rs
+++ b/examples/full-syntax.rs
@@ -1,6 +1,5 @@
//! A showcase of the `app!` macro syntax
#![deny(unsafe_code)]
-#![feature(const_fn)]
#![feature(proc_macro)]
#![no_std]
diff --git a/examples/nested.rs b/examples/nested.rs
index 70131709..1c164f86 100644
--- a/examples/nested.rs
+++ b/examples/nested.rs
@@ -3,7 +3,6 @@
//! If you run this program you'll hit the breakpoints as indicated by the
//! letters in the comments: A, then B, then C, etc.
#![deny(unsafe_code)]
-#![feature(const_fn)]
#![feature(proc_macro)]
#![no_std]
@@ -59,13 +58,14 @@ fn idle() -> ! {
}
}
-fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
+#[allow(non_snake_case)]
+fn exti0(
+ t: &mut Threshold,
+ EXTI0::Resources { mut LOW, mut HIGH }: EXTI0::Resources,
+) {
// Because this task has a priority of 1 the preemption threshold `t` also
// starts at 1
- let mut low = r.LOW;
- let mut high = r.HIGH;
-
// B
rtfm::bkpt();
@@ -73,7 +73,7 @@ fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
rtfm::set_pending(Interrupt::EXTI1); // ~> exti1
// A claim creates a critical section
- low.claim_mut(t, |_low, t| {
+ LOW.claim_mut(t, |_low, t| {
// This claim increases the preemption threshold to 2
//
// 2 is just high enough to not race with task `exti1` for access to the
@@ -94,7 +94,7 @@ fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
rtfm::bkpt();
// Claims can be nested
- high.claim_mut(t, |_high, _| {
+ HIGH.claim_mut(t, |_high, _| {
// This claim increases the preemption threshold to 3
// Now `exti2` can't preempt this task
diff --git a/examples/one-task.rs b/examples/one-task.rs
index 556177d0..e58d9fcd 100644
--- a/examples/one-task.rs
+++ b/examples/one-task.rs
@@ -1,6 +1,5 @@
//! An application with one task
#![deny(unsafe_code)]
-#![feature(const_fn)]
#![feature(proc_macro)]
#![no_std]
@@ -34,17 +33,6 @@ app! {
// Path to the task handler
path: sys_tick,
- // This is the priority of the task.
- //
- // 1 is the lowest priority a task can have, and the maximum
- // priority is determined by the number of priority bits the device
- // has. `stm32f103xx` has 4 priority bits so 16 is the maximum valid
- // value.
- //
- // You can omit this field. If you do the priority is assumed to be
- // 1.
- priority: 1,
-
// These are the resources this task has access to.
//
// A resource can be a peripheral like `GPIOC` or a static variable
@@ -54,7 +42,10 @@ app! {
}
}
-fn init(p: init::Peripherals, _r: init::Resources) {
+fn init(p: init::Peripherals, r: init::Resources) {
+ // `init` can modify all the `resources` declared in `app!`
+ r.ON;
+
// power on GPIOC
p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
@@ -81,7 +72,7 @@ fn idle() -> ! {
//
// `_t` is the preemption threshold token. We won't use it in this program.
//
-// `r` is the set of resources this task has access to. `TIMER0_A1::Resources`
+// `r` is the set of resources this task has access to. `SYS_TICK::Resources`
// has one field per resource declared in `app!`.
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
// toggle state
diff --git a/examples/preemption.rs b/examples/preemption.rs
index 256b9bdd..5fda37d5 100644
--- a/examples/preemption.rs
+++ b/examples/preemption.rs
@@ -1,6 +1,5 @@
//! Two tasks running at *different* priorities with access to the same resource
#![deny(unsafe_code)]
-#![feature(const_fn)]
#![feature(proc_macro)]
#![no_std]
@@ -58,8 +57,11 @@ fn tim2(t: &mut Threshold, mut r: TIM2::Resources) {
// As this task runs at lower priority it needs a critical section to
// prevent `sys_tick` from preempting it while it modifies this resource
// data. The critical section is required to prevent data races which can
- // lead to undefined behavior
- r.COUNTER.claim_mut(t, |counter, _t| { **counter += 1; });
+ // lead to undefined behavior.
+ r.COUNTER.claim_mut(t, |counter, _t| {
+ // `claim_mut` creates a critical section
+ **counter += 1;
+ });
// ..
}
diff --git a/examples/two-tasks.rs b/examples/two-tasks.rs
index ea059a02..2200e5ba 100644
--- a/examples/two-tasks.rs
+++ b/examples/two-tasks.rs
@@ -1,7 +1,5 @@
//! Two tasks running at the *same* priority with access to the same resource
-
#![deny(unsafe_code)]
-#![feature(const_fn)]
#![feature(proc_macro)]
#![no_std]
@@ -31,8 +29,6 @@ app! {
},
}
-// When data resources are declared in the top `resources` field, `init` will
-// have full access to them
fn init(_p: init::Peripherals, _r: init::Resources) {
// ..
}
diff --git a/macros/Cargo.toml b/macros/Cargo.toml
index 4237e21e..a62d2089 100644
--- a/macros/Cargo.toml
+++ b/macros/Cargo.toml
@@ -6,11 +6,8 @@ version = "0.1.0"
[dependencies]
error-chain = "0.10.0"
quote = "0.3.15"
+rtfm-syntax = "0.1.0"
syn = "0.11.11"
-[dependencies.rtfm-syntax]
-git = "https://github.com/japaric/rtfm-syntax"
-optional = false
-
[lib]
proc-macro = true
diff --git a/macros/src/check.rs b/macros/src/check.rs
index 42dd3c9e..3cd112ac 100644
--- a/macros/src/check.rs
+++ b/macros/src/check.rs
@@ -2,7 +2,7 @@ use std::collections::HashMap;
use syn::{Ident, Path};
use syntax::check::{self, Idle, Init};
-use syntax::{self, Idents, Statics};
+use syntax::{self, Resources, Statics};
use syntax::error::*;
@@ -51,7 +51,7 @@ pub struct Task {
pub kind: Kind,
pub path: Path,
pub priority: u8,
- pub resources: Idents,
+ pub resources: Resources,
}
pub fn app(app: check::App) -> Result<App> {
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index 8ea87fa0..2a1f72e4 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -1,5 +1,4 @@
//! Procedural macros for the RTFM framework
-
#![deny(warnings)]
#![feature(proc_macro)]
#![recursion_limit = "128"]
@@ -14,7 +13,6 @@ extern crate syn;
use proc_macro::TokenStream;
use syntax::App;
-
use syntax::error::*;
mod analyze;
@@ -23,6 +21,148 @@ mod trans;
/// The `app!` macro, a macro used to specify the tasks and resources of a
/// RTFM application.
+///
+/// The contents of this macro uses a `key: value` syntax. All the possible keys
+/// are shown below:
+///
+/// ``` text
+/// app! {
+/// device: ..,
+///
+/// resources: { .. },
+///
+/// init: { .. },
+///
+/// idle: { .. },
+///
+/// tasks: { .. },
+/// }
+/// ```
+///
+/// # `device`
+///
+/// The value of this key is a Rust path, like `foo::bar::baz`, that must point to
+/// a *device crate*, a crate generated using `svd2rust`.
+///
+/// # `resources`
+///
+/// This key is optional. Its value is a list of `static` variables. These
+/// variables are the data that can be safely accessed, modified and shared by
+/// tasks.
+///
+/// ``` text
+/// resources: {
+/// static A: bool = false;
+/// static B: i32 = 0;
+/// static C: [u8; 16] = [0; 16];
+/// static D: Thing = Thing::new(..);
+/// }
+/// ```
+///
+/// If this key is omitted its value defaults to an empty list.
+///
+/// # `init`
+///
+/// This key is optional. Its value is a set of key values. All the possible
+/// keys are shown below:
+///
+/// ``` text
+/// init: {
+/// path: ..,
+/// }
+/// ```
+///
+/// ## `init.path`
+///
+/// This key is optional. Its value is a Rust path, like `foo::bar::baz`, that
+/// points to the initialization function.
+///
+/// If the key is omitted its value defaults to `init`.
+///
+/// # `idle`
+///
+/// This key is optional. Its value is a set of key values. All the possible
+/// keys are shown below:
+///
+/// ``` text
+/// idle: {
+/// path: ..,
+/// resources: [..],
+/// }
+/// ```
+///
+/// ## `idle.path`
+///
+/// This key is optional. Its value is a Rust path, like `foo::bar::baz`, that
+/// points to the idle loop function.
+///
+/// If the key is omitted its value defaults to `idle`.
+///
+/// ## `idle.resources`
+///
+/// This key is optional. Its value is a list of resources the `idle` loop has
+/// access to. The resources in this list can refer to the resources listed in
+/// the top `resources` key. If the name doesn't match one of the resources
+/// listed in the top `resources` key the resource is assumed to be a
+/// peripheral.
+///
+/// If omitted its value defaults to an empty list.
+///
+/// # `tasks`
+///
+/// This key is optional. Its value is a list of tasks. Each task itself is a
+/// set of key value pair. The full syntax is shown below:
+///
+/// ``` text
+/// tasks: {
+/// $TASK: {
+/// enabled: ..,
+/// path: ..,
+/// priority: ..,
+/// resources: [..],
+/// },
+/// }
+/// ```
+///
+/// If this key is omitted its value is assumed to be an empty list.
+///
+/// ## `tasks.$TASK`
+///
+/// The key must be either a Cortex-M exception or a device specific interrupt.
+/// `PENDSV`, `SVCALL`, `SYS_TICK` are considered as exceptions. All other names
+/// are assumed to be interrupts.
+///
+/// ## `tasks.$TASK.enabled`
+///
+/// This key is optional for interrupts and forbidden for exceptions. Its value
+/// must be a boolean and indicates whether the interrupt will be enabled
+/// (`true`) or disabled (`false`) after `init` ends and before `idle` starts.
+///
+/// If this key is omitted its value defaults to `true`.
+///
+/// ## `tasks.$TASK.path`
+///
+/// The value of this key is a Rust path, like `foo::bar::baz`, that points to
+/// the handler of this task.
+///
+/// ## `tasks.$TASK.priority`
+///
+/// This key is optional. Its value is an integer with type `u8` that specifies
+/// the priority of this task. The minimum valid priority is 1. The maximum
+/// valid priority depends on the number of the NVIC priority bits the device
+/// has; if the device has 4 priority bits the maximum allowed value would be
+/// 16.
+///
+/// If this key is omitted its value defaults to `1`.
+///
+/// ## `tasks.$TASK.resources`
+///
+/// This key is optional. Its value is a list of resources this task has access
+/// to. The resources in this list can refer to the resources listed in the top
+/// `resources` key. If the name doesn't match one of the resources listed in
+/// the top `resources` key the resource is assumed to be a peripheral.
+///
+/// If omitted its value defaults to an empty list.
#[proc_macro]
pub fn app(ts: TokenStream) -> TokenStream {
match run(ts) {
diff --git a/src/examples/_1_one_task.rs b/src/examples/_1_one_task.rs
index 1bccc219..614db2aa 100644
--- a/src/examples/_1_one_task.rs
+++ b/src/examples/_1_one_task.rs
@@ -2,7 +2,6 @@
//!
//! ```
//! #![deny(unsafe_code)]
-//! #![feature(const_fn)]
//! #![feature(proc_macro)]
//! #![no_std]
//!
@@ -36,17 +35,6 @@
//! // Path to the task handler
//! path: sys_tick,
//!
-//! // This is the priority of the task.
-//! //
-//! // 1 is the lowest priority a task can have, and the maximum
-//! // priority is determined by the number of priority bits the device
-//! // has. `stm32f103xx` has 4 priority bits so 16 is the maximum valid
-//! // value.
-//! //
-//! // You can omit this field. If you do the priority is assumed to be
-//! // 1.
-//! priority: 1,
-//!
//! // These are the resources this task has access to.
//! //
//! // A resource can be a peripheral like `GPIOC` or a static variable
@@ -56,7 +44,10 @@
//! }
//! }
//!
-//! fn init(p: init::Peripherals, _r: init::Resources) {
+//! fn init(p: init::Peripherals, r: init::Resources) {
+//! // `init` can modify all the `resources` declared in `app!`
+//! r.ON;
+//!
//! // power on GPIOC
//! p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
//!
@@ -83,7 +74,7 @@
//! //
//! // `_t` is the preemption threshold token. We won't use it in this program.
//! //
-//! // `r` is the set of resources this task has access to. `TIMER0_A1::Resources`
+//! // `r` is the set of resources this task has access to. `SYS_TICK::Resources`
//! // has one field per resource declared in `app!`.
//! fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
//! // toggle state
diff --git a/src/examples/_2_two_tasks.rs b/src/examples/_2_two_tasks.rs
index 451293cf..5db991b0 100644
--- a/src/examples/_2_two_tasks.rs
+++ b/src/examples/_2_two_tasks.rs
@@ -1,9 +1,7 @@
//! Two tasks running at the *same* priority with access to the same resource
//!
//! ```
-//!
//! #![deny(unsafe_code)]
-//! #![feature(const_fn)]
//! #![feature(proc_macro)]
//! #![no_std]
//!
@@ -33,8 +31,6 @@
//! },
//! }
//!
-//! // When data resources are declared in the top `resources` field, `init` will
-//! // have full access to them
//! fn init(_p: init::Peripherals, _r: init::Resources) {
//! // ..
//! }
diff --git a/src/examples/_3_preemption.rs b/src/examples/_3_preemption.rs
index 1f6b244b..9dc8983b 100644
--- a/src/examples/_3_preemption.rs
+++ b/src/examples/_3_preemption.rs
@@ -2,7 +2,6 @@
//!
//! ```
//! #![deny(unsafe_code)]
-//! #![feature(const_fn)]
//! #![feature(proc_macro)]
//! #![no_std]
//!
@@ -60,8 +59,11 @@
//! // As this task runs at lower priority it needs a critical section to
//! // prevent `sys_tick` from preempting it while it modifies this resource
//! // data. The critical section is required to prevent data races which can
-//! // lead to undefined behavior
-//! r.COUNTER.claim_mut(t, |counter, _t| { **counter += 1; });
+//! // lead to undefined behavior.
+//! r.COUNTER.claim_mut(t, |counter, _t| {
+//! // `claim_mut` creates a critical section
+//! **counter += 1;
+//! });
//!
//! // ..
//! }
diff --git a/src/examples/_4_nested.rs b/src/examples/_4_nested.rs
index d0306210..94af0bee 100644
--- a/src/examples/_4_nested.rs
+++ b/src/examples/_4_nested.rs
@@ -5,7 +5,6 @@
//!
//! ```
//! #![deny(unsafe_code)]
-//! #![feature(const_fn)]
//! #![feature(proc_macro)]
//! #![no_std]
//!
@@ -61,13 +60,14 @@
//! }
//! }
//!
-//! fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
+//! #[allow(non_snake_case)]
+//! fn exti0(
+//! t: &mut Threshold,
+//! EXTI0::Resources { mut LOW, mut HIGH }: EXTI0::Resources,
+//! ) {
//! // Because this task has a priority of 1 the preemption threshold `t` also
//! // starts at 1
//!
-//! let mut low = r.LOW;
-//! let mut high = r.HIGH;
-//!
//! // B
//! rtfm::bkpt();
//!
@@ -75,7 +75,7 @@
//! rtfm::set_pending(Interrupt::EXTI1); // ~> exti1
//!
//! // A claim creates a critical section
-//! low.claim_mut(t, |_low, t| {
+//! LOW.claim_mut(t, |_low, t| {
//! // This claim increases the preemption threshold to 2
//! //
//! // 2 is just high enough to not race with task `exti1` for access to the
@@ -96,7 +96,7 @@
//! rtfm::bkpt();
//!
//! // Claims can be nested
-//! high.claim_mut(t, |_high, _| {
+//! HIGH.claim_mut(t, |_high, _| {
//! // This claim increases the preemption threshold to 3
//!
//! // Now `exti2` can't preempt this task
diff --git a/src/examples/_6_full_syntax.rs b/src/examples/_6_full_syntax.rs
index 449bee6c..80520657 100644
--- a/src/examples/_6_full_syntax.rs
+++ b/src/examples/_6_full_syntax.rs
@@ -2,7 +2,6 @@
//!
//! ```
//! #![deny(unsafe_code)]
-//! #![feature(const_fn)]
//! #![feature(proc_macro)]
//! #![no_std]
//!
diff --git a/src/lib.rs b/src/lib.rs
index dc856596..6188ed31 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,4 @@
-//! Real Time For the Masses (RTFM), a framework for building concurrent
-//! applications, for ARM Cortex-M microcontrollers
+//! Real Time For the Masses (RTFM) framework 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,
@@ -37,24 +36,24 @@
//!
//! # 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
+//! 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.
//!
//! [`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/
+//!
+//! # More documentation
+//!
+//! The `app!` macro is documented [here](../cortex_m_rtfm_macros/fn.app.html).
//!
//! # Examples
//!
-//! In increasing grade of complexity, see the [examples](./examples/index.html)
+//! 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]
@@ -74,7 +73,9 @@ use cortex_m::register::basepri;
pub mod examples;
-/// Executes the closure `f` in an interrupt free context
+/// Executes the closure `f` in a preemption free context
+///
+/// During the execution of the closure no task can preempt the current task.
pub fn atomic<R, F>(t: &mut Threshold, f: F) -> R
where
F: FnOnce(&mut Threshold) -> R,
@@ -127,11 +128,10 @@ where
}
}
-/// Sets an interrupt as pending
+/// Sets an interrupt, that is a task, 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.
+/// 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.
pub fn set_pending<I>(interrupt: I)
where
I: Nr,