update examples

This commit is contained in:
Jorge Aparicio 2017-07-29 00:34:00 -05:00
parent e85d6e53c8
commit 2d80f3631b
18 changed files with 206 additions and 87 deletions

6
.gdbinit Normal file
View file

@ -0,0 +1,6 @@
target remote :3333
monitor arm semihosting enable
load
step

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
**/*.rs.bk **/*.rs.bk
*.org *.org
.gdb_history
Cargo.lock Cargo.lock
target/ target/

View file

@ -4,7 +4,7 @@ authors = [
"Per Lindgren <per.lindgren@ltu.se>", "Per Lindgren <per.lindgren@ltu.se>",
] ]
categories = ["concurrency", "embedded", "no-std"] 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" documentation = "https://docs.rs/cortex-m-rtfm"
keywords = ["arm", "cortex-m"] keywords = ["arm", "cortex-m"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -14,8 +14,8 @@ version = "0.2.0"
[dependencies] [dependencies]
cortex-m = "0.3.1" cortex-m = "0.3.1"
rtfm-core = "0.1.0"
static-ref = "0.2.1" static-ref = "0.2.1"
rtfm-core = { git = "https://github.com/japaric/rtfm-core" }
[dependencies.cortex-m-rtfm-macros] [dependencies.cortex-m-rtfm-macros]
path = "macros" path = "macros"

View file

@ -3,10 +3,9 @@
# `cortex-m-rtfm` # `cortex-m-rtfm`
> Real Time For the Masses (RTFM), a framework for building concurrent > Real Time For the Masses (RTFM) framework for ARM Cortex-M microcontrollers
> applications, for ARM Cortex-M MCUs
# [Manual](https://docs.rs/cortex-m-rtfm) # [Documentation](https://docs.rs/cortex-m-rtfm)
# License # License

View file

@ -1,6 +1,5 @@
//! A showcase of the `app!` macro syntax //! A showcase of the `app!` macro syntax
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![feature(const_fn)]
#![feature(proc_macro)] #![feature(proc_macro)]
#![no_std] #![no_std]

View file

@ -3,7 +3,6 @@
//! If you run this program you'll hit the breakpoints as indicated by the //! If you run this program you'll hit the breakpoints as indicated by the
//! letters in the comments: A, then B, then C, etc. //! letters in the comments: A, then B, then C, etc.
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![feature(const_fn)]
#![feature(proc_macro)] #![feature(proc_macro)]
#![no_std] #![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 // Because this task has a priority of 1 the preemption threshold `t` also
// starts at 1 // starts at 1
let mut low = r.LOW;
let mut high = r.HIGH;
// B // B
rtfm::bkpt(); rtfm::bkpt();
@ -73,7 +73,7 @@ fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
rtfm::set_pending(Interrupt::EXTI1); // ~> exti1 rtfm::set_pending(Interrupt::EXTI1); // ~> exti1
// A claim creates a critical section // 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 // This claim increases the preemption threshold to 2
// //
// 2 is just high enough to not race with task `exti1` for access to the // 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(); rtfm::bkpt();
// Claims can be nested // Claims can be nested
high.claim_mut(t, |_high, _| { HIGH.claim_mut(t, |_high, _| {
// This claim increases the preemption threshold to 3 // This claim increases the preemption threshold to 3
// Now `exti2` can't preempt this task // Now `exti2` can't preempt this task

View file

@ -1,6 +1,5 @@
//! An application with one task //! An application with one task
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![feature(const_fn)]
#![feature(proc_macro)] #![feature(proc_macro)]
#![no_std] #![no_std]
@ -34,17 +33,6 @@ app! {
// Path to the task handler // Path to the task handler
path: sys_tick, 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. // These are the resources this task has access to.
// //
// A resource can be a peripheral like `GPIOC` or a static variable // 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 // power on GPIOC
p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled()); 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. // `_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!`. // has one field per resource declared in `app!`.
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) { fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
// toggle state // toggle state

View file

@ -1,6 +1,5 @@
//! Two tasks running at *different* priorities with access to the same resource //! Two tasks running at *different* priorities with access to the same resource
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![feature(const_fn)]
#![feature(proc_macro)] #![feature(proc_macro)]
#![no_std] #![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 // As this task runs at lower priority it needs a critical section to
// prevent `sys_tick` from preempting it while it modifies this resource // prevent `sys_tick` from preempting it while it modifies this resource
// data. The critical section is required to prevent data races which can // data. The critical section is required to prevent data races which can
// lead to undefined behavior // lead to undefined behavior.
r.COUNTER.claim_mut(t, |counter, _t| { **counter += 1; }); r.COUNTER.claim_mut(t, |counter, _t| {
// `claim_mut` creates a critical section
**counter += 1;
});
// .. // ..
} }

View file

@ -1,7 +1,5 @@
//! Two tasks running at the *same* priority with access to the same resource //! Two tasks running at the *same* priority with access to the same resource
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![feature(const_fn)]
#![feature(proc_macro)] #![feature(proc_macro)]
#![no_std] #![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) { fn init(_p: init::Peripherals, _r: init::Resources) {
// .. // ..
} }

View file

@ -6,11 +6,8 @@ version = "0.1.0"
[dependencies] [dependencies]
error-chain = "0.10.0" error-chain = "0.10.0"
quote = "0.3.15" quote = "0.3.15"
rtfm-syntax = "0.1.0"
syn = "0.11.11" syn = "0.11.11"
[dependencies.rtfm-syntax]
git = "https://github.com/japaric/rtfm-syntax"
optional = false
[lib] [lib]
proc-macro = true proc-macro = true

View file

@ -2,7 +2,7 @@ use std::collections::HashMap;
use syn::{Ident, Path}; use syn::{Ident, Path};
use syntax::check::{self, Idle, Init}; use syntax::check::{self, Idle, Init};
use syntax::{self, Idents, Statics}; use syntax::{self, Resources, Statics};
use syntax::error::*; use syntax::error::*;
@ -51,7 +51,7 @@ pub struct Task {
pub kind: Kind, pub kind: Kind,
pub path: Path, pub path: Path,
pub priority: u8, pub priority: u8,
pub resources: Idents, pub resources: Resources,
} }
pub fn app(app: check::App) -> Result<App> { pub fn app(app: check::App) -> Result<App> {

View file

@ -1,5 +1,4 @@
//! Procedural macros for the RTFM framework //! Procedural macros for the RTFM framework
#![deny(warnings)] #![deny(warnings)]
#![feature(proc_macro)] #![feature(proc_macro)]
#![recursion_limit = "128"] #![recursion_limit = "128"]
@ -14,7 +13,6 @@ extern crate syn;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use syntax::App; use syntax::App;
use syntax::error::*; use syntax::error::*;
mod analyze; mod analyze;
@ -23,6 +21,148 @@ mod trans;
/// The `app!` macro, a macro used to specify the tasks and resources of a /// The `app!` macro, a macro used to specify the tasks and resources of a
/// RTFM application. /// 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] #[proc_macro]
pub fn app(ts: TokenStream) -> TokenStream { pub fn app(ts: TokenStream) -> TokenStream {
match run(ts) { match run(ts) {

View file

@ -2,7 +2,6 @@
//! //!
//! ``` //! ```
//! #![deny(unsafe_code)] //! #![deny(unsafe_code)]
//! #![feature(const_fn)]
//! #![feature(proc_macro)] //! #![feature(proc_macro)]
//! #![no_std] //! #![no_std]
//! //!
@ -36,17 +35,6 @@
//! // Path to the task handler //! // Path to the task handler
//! path: sys_tick, //! 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. //! // These are the resources this task has access to.
//! // //! //
//! // A resource can be a peripheral like `GPIOC` or a static variable //! // 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 //! // power on GPIOC
//! p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled()); //! 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. //! // `_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!`. //! // has one field per resource declared in `app!`.
//! fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) { //! fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
//! // toggle state //! // toggle state

View file

@ -1,9 +1,7 @@
//! Two tasks running at the *same* priority with access to the same resource //! Two tasks running at the *same* priority with access to the same resource
//! //!
//! ``` //! ```
//!
//! #![deny(unsafe_code)] //! #![deny(unsafe_code)]
//! #![feature(const_fn)]
//! #![feature(proc_macro)] //! #![feature(proc_macro)]
//! #![no_std] //! #![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) { //! fn init(_p: init::Peripherals, _r: init::Resources) {
//! // .. //! // ..
//! } //! }

View file

@ -2,7 +2,6 @@
//! //!
//! ``` //! ```
//! #![deny(unsafe_code)] //! #![deny(unsafe_code)]
//! #![feature(const_fn)]
//! #![feature(proc_macro)] //! #![feature(proc_macro)]
//! #![no_std] //! #![no_std]
//! //!
@ -60,8 +59,11 @@
//! // As this task runs at lower priority it needs a critical section to //! // As this task runs at lower priority it needs a critical section to
//! // prevent `sys_tick` from preempting it while it modifies this resource //! // prevent `sys_tick` from preempting it while it modifies this resource
//! // data. The critical section is required to prevent data races which can //! // data. The critical section is required to prevent data races which can
//! // lead to undefined behavior //! // lead to undefined behavior.
//! r.COUNTER.claim_mut(t, |counter, _t| { **counter += 1; }); //! r.COUNTER.claim_mut(t, |counter, _t| {
//! // `claim_mut` creates a critical section
//! **counter += 1;
//! });
//! //!
//! // .. //! // ..
//! } //! }

View file

@ -5,7 +5,6 @@
//! //!
//! ``` //! ```
//! #![deny(unsafe_code)] //! #![deny(unsafe_code)]
//! #![feature(const_fn)]
//! #![feature(proc_macro)] //! #![feature(proc_macro)]
//! #![no_std] //! #![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 //! // Because this task has a priority of 1 the preemption threshold `t` also
//! // starts at 1 //! // starts at 1
//! //!
//! let mut low = r.LOW;
//! let mut high = r.HIGH;
//!
//! // B //! // B
//! rtfm::bkpt(); //! rtfm::bkpt();
//! //!
@ -75,7 +75,7 @@
//! rtfm::set_pending(Interrupt::EXTI1); // ~> exti1 //! rtfm::set_pending(Interrupt::EXTI1); // ~> exti1
//! //!
//! // A claim creates a critical section //! // 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 //! // This claim increases the preemption threshold to 2
//! // //! //
//! // 2 is just high enough to not race with task `exti1` for access to the //! // 2 is just high enough to not race with task `exti1` for access to the
@ -96,7 +96,7 @@
//! rtfm::bkpt(); //! rtfm::bkpt();
//! //!
//! // Claims can be nested //! // Claims can be nested
//! high.claim_mut(t, |_high, _| { //! HIGH.claim_mut(t, |_high, _| {
//! // This claim increases the preemption threshold to 3 //! // This claim increases the preemption threshold to 3
//! //!
//! // Now `exti2` can't preempt this task //! // Now `exti2` can't preempt this task

View file

@ -2,7 +2,6 @@
//! //!
//! ``` //! ```
//! #![deny(unsafe_code)] //! #![deny(unsafe_code)]
//! #![feature(const_fn)]
//! #![feature(proc_macro)] //! #![feature(proc_macro)]
//! #![no_std] //! #![no_std]
//! //!

View file

@ -1,5 +1,4 @@
//! Real Time For the Masses (RTFM), a framework for building concurrent //! Real Time For the Masses (RTFM) framework for ARM Cortex-M microcontrollers
//! applications, for ARM Cortex-M microcontrollers
//! //!
//! This crate is based on [the RTFM framework] created by the Embedded Systems //! 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, //! group at [Luleå University of Technology][ltu], led by Prof. Per Lindgren,
@ -37,24 +36,24 @@
//! //!
//! # Dependencies //! # Dependencies
//! //!
//! - A device crate generated using [`svd2rust`] v0.11.x. The input SVD file //! The application crate must depend on a device crate generated using
//! *must* contain [`<cpu>`] information. //! [`svd2rust`] v0.11.x and the "rt" feature of that crate must be enabled. The
//! - A `start` lang time: Vanilla `main` must be supported in binary crates. //! SVD file used to generate the device crate *must* contain [`<cpu>`]
//! You can use the [`cortex-m-rt`] crate to fulfill the requirement //! information.
//! //!
//! [`svd2rust`]: https://docs.rs/svd2rust/0..0/svd2rust/ //! [`svd2rust`]: https://docs.rs/svd2rust/0..0/svd2rust/
//! [`<cpu>`]: https://www.keil.com/pack/doc/CMSIS/SVD/html/elem_cpu.html //! [`<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 //! # Examples
//! //!
//! In increasing grade of complexity, see the [examples](./examples/index.html) //! In increasing grade of complexity. See the [examples](./examples/index.html)
//! module. //! module.
#![deny(missing_docs)] #![deny(missing_docs)]
#![deny(warnings)] #![deny(warnings)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(optin_builtin_traits)]
#![feature(proc_macro)] #![feature(proc_macro)]
#![no_std] #![no_std]
@ -74,7 +73,9 @@ use cortex_m::register::basepri;
pub mod examples; 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 pub fn atomic<R, F>(t: &mut Threshold, f: F) -> R
where where
F: FnOnce(&mut Threshold) -> R, 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 /// If the task priority is high enough the task will be serviced immediately,
/// immediately, otherwise it will be serviced at some point after the current /// otherwise it will be serviced at some point after the current task ends.
/// task ends.
pub fn set_pending<I>(interrupt: I) pub fn set_pending<I>(interrupt: I)
where where
I: Nr, I: Nr,