update examples

This commit is contained in:
Jorge Aparicio 2017-07-27 22:40:47 -05:00
parent 271df39bdb
commit e85d6e53c8
15 changed files with 198 additions and 294 deletions

View file

@ -1,5 +1,4 @@
//! A showcase of the `app!` macro syntax //! A showcase of the `app!` macro syntax
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![feature(const_fn)] #![feature(const_fn)]
#![feature(proc_macro)] #![feature(proc_macro)]
@ -8,7 +7,7 @@
extern crate cortex_m_rtfm as rtfm; extern crate cortex_m_rtfm as rtfm;
extern crate stm32f103xx; extern crate stm32f103xx;
use rtfm::{app, Resource, Threshold}; use rtfm::{app, Threshold};
app! { app! {
device: stm32f103xx, device: stm32f103xx,
@ -21,23 +20,30 @@ app! {
}, },
init: { init: {
path: init_, // this is a path to the "init" function // This is the path to the `init` function
//
// `init` doesn't necessarily has to be in the root of the crate
path: main::init,
}, },
idle: { idle: {
path: idle_, // this is a path to the "idle" function // This is a path to the `idle` function
//
// `idle` doesn't necessarily has to be in the root of the crate
path: main::idle,
resources: [OWNED, SHARED], resources: [OWNED, SHARED],
}, },
tasks: { tasks: {
SYS_TICK: { SYS_TICK: {
path: sys_tick, path: sys_tick,
priority: 1, // If omitted priority is assumed to be 1
// priority: 1,
resources: [CO_OWNED, ON, SHARED], resources: [CO_OWNED, ON, SHARED],
}, },
TIM2: { TIM2: {
// tasks are enabled, between `init` and `idle`, by default but they // Tasks are enabled, between `init` and `idle`, by default but they
// can start disabled if `false` is specified here // can start disabled if `false` is specified here
enabled: false, enabled: false,
path: tim2, path: tim2,
@ -47,9 +53,12 @@ app! {
}, },
} }
fn init_(_p: init::Peripherals, _r: init::Resources) {} mod main {
use rtfm::{self, Resource, Threshold};
fn idle_(t: &mut Threshold, mut r: idle::Resources) -> ! { pub fn init(_p: ::init::Peripherals, _r: ::init::Resources) {}
pub fn idle(t: &mut Threshold, mut r: ::idle::Resources) -> ! {
loop { loop {
*r.OWNED != *r.OWNED; *r.OWNED != *r.OWNED;
@ -61,6 +70,7 @@ fn idle_(t: &mut Threshold, mut r: idle::Resources) -> ! {
r.SHARED.claim_mut(t, |shared, _| **shared = !**shared); r.SHARED.claim_mut(t, |shared, _| **shared = !**shared);
} }
} }
}
} }
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) { fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {

View file

@ -1,5 +1,4 @@
//! Working with resources in a generic fashion //! Working with resources in a generic fashion
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![feature(proc_macro)] #![feature(proc_macro)]
#![no_std] #![no_std]
@ -36,7 +35,7 @@ fn idle() -> ! {
} }
} }
// a generic function to use resources in any task (regardless of its priority) // A generic function that uses some resources
fn work<G, S>(t: &mut Threshold, gpioa: &G, spi1: &S) fn work<G, S>(t: &mut Threshold, gpioa: &G, spi1: &S)
where where
G: Resource<Data = GPIOA>, G: Resource<Data = GPIOA>,
@ -53,12 +52,12 @@ where
}); });
} }
// this task needs critical sections to access the resources // This task needs critical sections to access the resources
fn exti0(t: &mut Threshold, r: EXTI0::Resources) { fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
work(t, &r.GPIOA, &r.SPI1); work(t, &r.GPIOA, &r.SPI1);
} }
// this task has direct access to the resources // This task has direct access to the resources
fn exti1(t: &mut Threshold, r: EXTI1::Resources) { fn exti1(t: &mut Threshold, r: EXTI1::Resources) {
work(t, r.GPIOA, r.SPI1); work(t, r.GPIOA, r.SPI1);
} }

View file

@ -1,76 +0,0 @@
//! Using paths and modules
#![deny(unsafe_code)]
#![feature(const_fn)]
#![feature(proc_macro)]
#![no_std]
extern crate cortex_m_rtfm as rtfm;
extern crate stm32f103xx;
use rtfm::app;
app! {
device: stm32f103xx,
resources: {
static CO_OWNED: u32 = 0;
static ON: bool = false;
static OWNED: bool = false;
static SHARED: bool = false;
},
init: {
path: main::init,
},
idle: {
path: main::idle,
resources: [OWNED, SHARED],
},
tasks: {
SYS_TICK: {
path: tasks::sys_tick,
resources: [CO_OWNED, ON, SHARED],
},
TIM2: {
path: tasks::tim2,
resources: [CO_OWNED],
},
},
}
mod main {
use rtfm::{self, Resource, Threshold};
pub fn init(_p: ::init::Peripherals, _r: ::init::Resources) {}
pub fn idle(t: &mut Threshold, mut r: ::idle::Resources) -> ! {
loop {
*r.OWNED != *r.OWNED;
if *r.OWNED {
if r.SHARED.claim(t, |shared, _| **shared) {
rtfm::wfi();
}
} else {
r.SHARED.claim_mut(t, |shared, _| **shared = !**shared);
}
}
}
}
pub mod tasks {
use rtfm::Threshold;
pub fn sys_tick(_t: &mut Threshold, r: ::SYS_TICK::Resources) {
**r.ON = !**r.ON;
**r.CO_OWNED += 1;
}
pub fn tim2(_t: &mut Threshold, r: ::TIM2::Resources) {
**r.CO_OWNED += 1;
}
}

View file

@ -2,7 +2,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(const_fn)]
#![feature(proc_macro)] #![feature(proc_macro)]
@ -46,9 +45,12 @@ app! {
fn init(_p: init::Peripherals, _r: init::Resources) {} fn init(_p: init::Peripherals, _r: init::Resources) {}
fn idle() -> ! { fn idle() -> ! {
// sets task `exti0` as pending // A
rtfm::bkpt();
// Sets task `exti0` as pending
// //
// because `exti0` has higher priority than `idle` it will be executed // Because `exti0` has higher priority than `idle` it will be executed
// immediately // immediately
rtfm::set_pending(Interrupt::EXTI0); // ~> exti0 rtfm::set_pending(Interrupt::EXTI0); // ~> exti0
@ -58,64 +60,66 @@ fn idle() -> ! {
} }
fn exti0(t: &mut Threshold, r: EXTI0::Resources) { fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
// because this task has a priority of 1 the preemption threshold is also 1 // Because this task has a priority of 1 the preemption threshold `t` also
// starts at 1
let mut low = r.LOW; let mut low = r.LOW;
let mut high = r.HIGH; let mut high = r.HIGH;
// A // B
rtfm::bkpt(); rtfm::bkpt();
// because `exti1` has higher priority than `exti0` it can preempt it // Because `exti1` has higher priority than `exti0` it can preempt it
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
// 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
// `LOW` resource // `LOW` resource
// C // D
rtfm::bkpt(); rtfm::bkpt();
// now `exti1` can't preempt this task because its priority is equal to // Now `exti1` can't preempt this task because its priority is equal to
// the current preemption threshold // the current preemption threshold
rtfm::set_pending(Interrupt::EXTI1); rtfm::set_pending(Interrupt::EXTI1);
// but `exti2` can, because its priority is higher than the current // But `exti2` can, because its priority is higher than the current
// preemption threshold // preemption threshold
rtfm::set_pending(Interrupt::EXTI2); // ~> exti2 rtfm::set_pending(Interrupt::EXTI2); // ~> exti2
// E // F
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
rtfm::set_pending(Interrupt::EXTI2); rtfm::set_pending(Interrupt::EXTI2);
// F // G
rtfm::bkpt(); rtfm::bkpt();
}); });
// upon leaving the critical section the preemption threshold drops to 2 // Upon leaving the critical section the preemption threshold drops back
// and `exti2` immediately preempts this task // to 2 and `exti2` immediately preempts this task
// ~> exti2 // ~> exti2
}); });
// once again the preemption threshold drops to 1 // Once again the preemption threshold drops but this time to 1. Now the
// now the pending `exti1` can preempt this task // pending `exti1` task can preempt this task
// ~> exti1 // ~> exti1
} }
fn exti1(_t: &mut Threshold, _r: EXTI1::Resources) { fn exti1(_t: &mut Threshold, _r: EXTI1::Resources) {
// B, H // C, I
rtfm::bkpt(); rtfm::bkpt();
} }
fn exti2(_t: &mut Threshold, _r: EXTI2::Resources) { fn exti2(_t: &mut Threshold, _r: EXTI2::Resources) {
// D, G // E, H
rtfm::bkpt(); rtfm::bkpt();
} }

View file

@ -14,11 +14,11 @@ use rtfm::{app, Threshold};
app! { app! {
device: stm32f103xx, device: stm32f103xx,
// Here resources are declared // Here data resources are declared
// //
// Resources are static variables that are safe to share across tasks // Data resources are static variables that are safe to share across tasks
resources: { resources: {
// declaration of resources looks exactly like declaration of static // Declaration of resources looks exactly like declaration of static
// variables // variables
static ON: bool = false; static ON: bool = false;
}, },
@ -31,20 +31,24 @@ app! {
tasks: { tasks: {
// Here we declare that we'll use the SYS_TICK exception as a task // Here we declare that we'll use the SYS_TICK exception as a task
SYS_TICK: { SYS_TICK: {
// Path to the task *handler* // Path to the task handler
path: sys_tick, path: sys_tick,
// This is the priority of the task. // This is the priority of the task.
// //
// 1 is the lowest priority a task can have. // 1 is the lowest priority a task can have, and the maximum
// The maximum priority is determined by the number of priority bits // priority is determined by the number of priority bits the device
// the device has. This device has 4 priority bits so 16 is the // has. `stm32f103xx` has 4 priority bits so 16 is the maximum valid
// maximum value. // value.
//
// You can omit this field. If you do the priority is assumed to be
// 1.
priority: 1, priority: 1,
// These are the *resources* associated with this task // These are the resources this task has access to.
// //
// The peripherals that the task needs can be listed here // A resource can be a peripheral like `GPIOC` or a static variable
// like `ON`
resources: [GPIOC, ON], resources: [GPIOC, ON],
}, },
} }
@ -75,8 +79,10 @@ fn idle() -> ! {
// This is the task handler of the SYS_TICK exception // This is the task handler of the SYS_TICK exception
// //
// `r` is the resources this task has access to. `SYS_TICK::Resources` has one // `_t` is the preemption threshold token. We won't use it in this program.
// field per every resource declared in `app!`. //
// `r` is the set of resources this task has access to. `TIMER0_A1::Resources`
// 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
**r.ON = !**r.ON; **r.ON = !**r.ON;

View file

@ -1,4 +1,4 @@
//! 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(const_fn)]
#![feature(proc_macro)] #![feature(proc_macro)]
@ -17,7 +17,7 @@ app! {
}, },
tasks: { tasks: {
// the task `SYS_TICK` has higher priority than `TIM2` // The `SYS_TICK` task has higher priority than `TIM2`
SYS_TICK: { SYS_TICK: {
path: sys_tick, path: sys_tick,
priority: 2, priority: 2,
@ -45,7 +45,7 @@ fn idle() -> ! {
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) { fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
// .. // ..
// this task can't be preempted by `tim2` so it has direct access to the // This task can't be preempted by `tim2` so it has direct access to the
// resource data // resource data
**r.COUNTER += 1; **r.COUNTER += 1;
@ -55,10 +55,10 @@ fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
fn tim2(t: &mut Threshold, mut r: TIM2::Resources) { 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 data corruption or data loss // lead to undefined behavior
r.COUNTER.claim_mut(t, |counter, _t| { **counter += 1; }); r.COUNTER.claim_mut(t, |counter, _t| { **counter += 1; });
// .. // ..

View file

@ -1,4 +1,4 @@
//! 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(const_fn)]
@ -13,34 +13,25 @@ use rtfm::{app, Threshold};
app! { app! {
device: stm32f103xx, device: stm32f103xx,
// Resources that are plain data, not peripherals
resources: { resources: {
// Declaration of resources looks like the declaration of `static`
// variables
static COUNTER: u64 = 0; static COUNTER: u64 = 0;
}, },
// Both SYS_TICK and TIM2 have access to the `COUNTER` data
tasks: { tasks: {
SYS_TICK: { SYS_TICK: {
path: sys_tick, path: sys_tick,
priority: 1,
// Both this task and TIM2 have access to the `COUNTER` resource
resources: [COUNTER], resources: [COUNTER],
}, },
// An interrupt as a task
TIM2: { TIM2: {
// For interrupts the `enabled` field must be specified. It
// indicates if the interrupt will be enabled or disabled once
// `idle` starts
path: tim2, path: tim2,
priority: 1,
resources: [COUNTER], resources: [COUNTER],
}, },
}, },
} }
// when data resources are declared in the top `resources` field, `init` will // When data resources are declared in the top `resources` field, `init` will
// have full access to them // have full access to them
fn init(_p: init::Peripherals, _r: init::Resources) { fn init(_p: init::Peripherals, _r: init::Resources) {
// .. // ..

View file

@ -1,7 +1,7 @@
//! Minimal example with zero tasks //! Minimal example with zero tasks
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![feature(proc_macro)] // IMPORTANT always include this feature gate // IMPORTANT always include this feature gate
#![feature(proc_macro)]
#![no_std] #![no_std]
extern crate cortex_m_rtfm as rtfm; // IMPORTANT always do this rename extern crate cortex_m_rtfm as rtfm; // IMPORTANT always do this rename
@ -15,7 +15,7 @@ use rtfm::app;
// This macro will expand to a `main` function so you don't need to supply // This macro will expand to a `main` function so you don't need to supply
// `main` yourself. // `main` yourself.
app! { app! {
// this is a path to the device crate // this is the path to the device crate
device: stm32f103xx, device: stm32f103xx,
} }
@ -28,20 +28,14 @@ fn init(p: init::Peripherals) {
p.GPIOA; p.GPIOA;
p.RCC; p.RCC;
// .. // ..
// You'll hit this breakpoint first
rtfm::bkpt();
} }
// The idle loop. // The idle loop.
// //
// This runs afterwards and has a priority of 0. All tasks can preempt this // This runs after `init` and has a priority of 0. All tasks can preempt this
// function. This function can never return so it must contain some sort of // function. This function can never return so it must contain some sort of
// endless loop. // endless loop.
fn idle() -> ! { fn idle() -> ! {
// And then this breakpoint
rtfm::bkpt();
loop { loop {
// This puts the processor to sleep until there's a task to service // This puts the processor to sleep until there's a task to service
rtfm::wfi(); rtfm::wfi();

View file

@ -1,9 +1,9 @@
//! Minimal example with zero tasks //! Minimal example with zero tasks
//! //!
//! ``` //! ```
//!
//! #![deny(unsafe_code)] //! #![deny(unsafe_code)]
//! #![feature(proc_macro)] // IMPORTANT always include this feature gate //! // IMPORTANT always include this feature gate
//! #![feature(proc_macro)]
//! #![no_std] //! #![no_std]
//! //!
//! extern crate cortex_m_rtfm as rtfm; // IMPORTANT always do this rename //! extern crate cortex_m_rtfm as rtfm; // IMPORTANT always do this rename
@ -17,7 +17,7 @@
//! // This macro will expand to a `main` function so you don't need to supply //! // This macro will expand to a `main` function so you don't need to supply
//! // `main` yourself. //! // `main` yourself.
//! app! { //! app! {
//! // this is a path to the device crate //! // this is the path to the device crate
//! device: stm32f103xx, //! device: stm32f103xx,
//! } //! }
//! //!
@ -30,20 +30,14 @@
//! p.GPIOA; //! p.GPIOA;
//! p.RCC; //! p.RCC;
//! // .. //! // ..
//!
//! // You'll hit this breakpoint first
//! rtfm::bkpt();
//! } //! }
//! //!
//! // The idle loop. //! // The idle loop.
//! // //! //
//! // This runs afterwards and has a priority of 0. All tasks can preempt this //! // This runs after `init` and has a priority of 0. All tasks can preempt this
//! // function. This function can never return so it must contain some sort of //! // function. This function can never return so it must contain some sort of
//! // endless loop. //! // endless loop.
//! fn idle() -> ! { //! fn idle() -> ! {
//! // And then this breakpoint
//! rtfm::bkpt();
//!
//! loop { //! loop {
//! // This puts the processor to sleep until there's a task to service //! // This puts the processor to sleep until there's a task to service
//! rtfm::wfi(); //! rtfm::wfi();

View file

@ -1,14 +1,12 @@
//! An application with one task //! An application with one task
//! //!
//! ``` //! ```
//!
//! #![deny(unsafe_code)] //! #![deny(unsafe_code)]
//! #![feature(const_fn)] //! #![feature(const_fn)]
//! #![feature(proc_macro)] //! #![feature(proc_macro)]
//! #![no_std] //! #![no_std]
//! //!
//! extern crate cortex_m; //! extern crate cortex_m;
//! #[macro_use(task)]
//! extern crate cortex_m_rtfm as rtfm; //! extern crate cortex_m_rtfm as rtfm;
//! extern crate stm32f103xx; //! extern crate stm32f103xx;
//! //!
@ -18,6 +16,15 @@
//! app! { //! app! {
//! device: stm32f103xx, //! device: stm32f103xx,
//! //!
//! // Here data resources are declared
//! //
//! // Data resources are static variables that are safe to share across tasks
//! resources: {
//! // Declaration of resources looks exactly like declaration of static
//! // variables
//! static ON: bool = false;
//! },
//!
//! // Here tasks are declared //! // Here tasks are declared
//! // //! //
//! // Each task corresponds to an interrupt or an exception. Every time the //! // Each task corresponds to an interrupt or an exception. Every time the
@ -26,22 +33,30 @@
//! tasks: { //! tasks: {
//! // Here we declare that we'll use the SYS_TICK exception as a task //! // Here we declare that we'll use the SYS_TICK exception as a task
//! SYS_TICK: { //! SYS_TICK: {
//! // Path to the task handler
//! path: sys_tick,
//!
//! // This is the priority of the task. //! // This is the priority of the task.
//! // 1 is the lowest priority a task can have. //! //
//! // The maximum priority is determined by the number of priority bits //! // 1 is the lowest priority a task can have, and the maximum
//! // the device has. This device has 4 priority bits so 16 is the //! // priority is determined by the number of priority bits the device
//! // maximum value. //! // 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, //! priority: 1,
//! //!
//! // These are the *resources* associated with this task //! // These are the resources this task has access to.
//! // //! //
//! // The peripherals that the task needs can be listed here //! // A resource can be a peripheral like `GPIOC` or a static variable
//! resources: [GPIOC], //! // like `ON`
//! resources: [GPIOC, ON],
//! }, //! },
//! } //! }
//! } //! }
//! //!
//! fn init(p: init::Peripherals) { //! fn init(p: init::Peripherals, _r: init::Resources) {
//! // power on GPIOC //! // power on GPIOC
//! p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled()); //! p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
//! //!
@ -64,26 +79,17 @@
//! } //! }
//! } //! }
//! //!
//! // This binds the `sys_tick` handler to the `SYS_TICK` task
//! //
//! // This particular handler has local state associated to it. The value of the
//! // `STATE` variable will be preserved across invocations of this handler
//! task!(SYS_TICK, sys_tick, Locals {
//! static STATE: bool = false;
//! });
//!
//! // This is the task handler of the SYS_TICK exception //! // This is the task handler of the SYS_TICK exception
//! // //! //
//! // `t` is the preemption threshold token. We won't use it this time. //! // `_t` is the preemption threshold token. We won't use it in this program.
//! // `l` is the data local to this task. The type here must match the one declared //! //
//! // in `task!`. //! // `r` is the set of resources this task has access to. `TIMER0_A1::Resources`
//! // `r` is the resources this task has access to. `SYS_TICK::Resources` has one //! // has one field per resource declared in `app!`.
//! // field per resource declared in `app!`. //! fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
//! fn sys_tick(_t: &mut Threshold, l: &mut Locals, r: SYS_TICK::Resources) {
//! // toggle state //! // toggle state
//! *l.STATE = !*l.STATE; //! **r.ON = !**r.ON;
//! //!
//! if *l.STATE { //! if **r.ON {
//! // set the pin PC13 high //! // set the pin PC13 high
//! r.GPIOC.bsrr.write(|w| w.bs13().set()); //! r.GPIOC.bsrr.write(|w| w.bs13().set());
//! } else { //! } else {

View file

@ -1,4 +1,4 @@
//! 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
//! //!
//! ``` //! ```
//! //!
@ -7,7 +7,6 @@
//! #![feature(proc_macro)] //! #![feature(proc_macro)]
//! #![no_std] //! #![no_std]
//! //!
//! #[macro_use(task)]
//! extern crate cortex_m_rtfm as rtfm; //! extern crate cortex_m_rtfm as rtfm;
//! extern crate stm32f103xx; //! extern crate stm32f103xx;
//! //!
@ -16,33 +15,25 @@
//! app! { //! app! {
//! device: stm32f103xx, //! device: stm32f103xx,
//! //!
//! // Resources that are plain data, not peripherals
//! resources: { //! resources: {
//! // Declaration of resources looks like the declaration of `static`
//! // variables
//! static COUNTER: u64 = 0; //! static COUNTER: u64 = 0;
//! }, //! },
//! //!
//! // Both SYS_TICK and TIM2 have access to the `COUNTER` data
//! tasks: { //! tasks: {
//! SYS_TICK: { //! SYS_TICK: {
//! priority: 1, //! path: sys_tick,
//! // Both this task and TIM2 have access to the `COUNTER` resource
//! resources: [COUNTER], //! resources: [COUNTER],
//! }, //! },
//! //!
//! // An interrupt as a task
//! TIM2: { //! TIM2: {
//! // For interrupts the `enabled` field must be specified. It //! path: tim2,
//! // indicates if the interrupt will be enabled or disabled once
//! // `idle` starts
//! enabled: true,
//! priority: 1,
//! resources: [COUNTER], //! resources: [COUNTER],
//! }, //! },
//! }, //! },
//! } //! }
//! //!
//! // when data resources are declared in the top `resources` field, `init` will //! // When data resources are declared in the top `resources` field, `init` will
//! // have full access to them //! // have full access to them
//! fn init(_p: init::Peripherals, _r: init::Resources) { //! fn init(_p: init::Peripherals, _r: init::Resources) {
//! // .. //! // ..
@ -54,8 +45,6 @@
//! } //! }
//! } //! }
//! //!
//! task!(SYS_TICK, sys_tick);
//!
//! // As both tasks are running at the same priority one can't preempt the other. //! // As both tasks are running at the same priority one can't preempt the other.
//! // Thus both tasks have direct access to the resource //! // Thus both tasks have direct access to the resource
//! fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) { //! fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
@ -66,8 +55,6 @@
//! // .. //! // ..
//! } //! }
//! //!
//! task!(TIM2, tim2);
//!
//! fn tim2(_t: &mut Threshold, r: TIM2::Resources) { //! fn tim2(_t: &mut Threshold, r: TIM2::Resources) {
//! // .. //! // ..
//! //!

View file

@ -1,13 +1,11 @@
//! 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(const_fn)]
//! #![feature(proc_macro)] //! #![feature(proc_macro)]
//! #![no_std] //! #![no_std]
//! //!
//! #[macro_use(task)]
//! extern crate cortex_m_rtfm as rtfm; //! extern crate cortex_m_rtfm as rtfm;
//! extern crate stm32f103xx; //! extern crate stm32f103xx;
//! //!
@ -21,14 +19,15 @@
//! }, //! },
//! //!
//! tasks: { //! tasks: {
//! // the task `SYS_TICK` has higher priority than `TIM2` //! // The `SYS_TICK` task has higher priority than `TIM2`
//! SYS_TICK: { //! SYS_TICK: {
//! path: sys_tick,
//! priority: 2, //! priority: 2,
//! resources: [COUNTER], //! resources: [COUNTER],
//! }, //! },
//! //!
//! TIM2: { //! TIM2: {
//! enabled: true, //! path: tim2,
//! priority: 1, //! priority: 1,
//! resources: [COUNTER], //! resources: [COUNTER],
//! }, //! },
@ -45,27 +44,23 @@
//! } //! }
//! } //! }
//! //!
//! task!(SYS_TICK, sys_tick);
//!
//! fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) { //! fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
//! // .. //! // ..
//! //!
//! // this task can't be preempted by `tim2` so it has direct access to the //! // This task can't be preempted by `tim2` so it has direct access to the
//! // resource data //! // resource data
//! **r.COUNTER += 1; //! **r.COUNTER += 1;
//! //!
//! // .. //! // ..
//! } //! }
//! //!
//! task!(TIM2, tim2);
//!
//! fn tim2(t: &mut Threshold, mut r: TIM2::Resources) { //! 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 data corruption or data loss //! // lead to undefined behavior
//! r.COUNTER.claim_mut(t, |counter, _t| { **counter += 1; }); //! r.COUNTER.claim_mut(t, |counter, _t| { **counter += 1; });
//! //!
//! // .. //! // ..

View file

@ -4,13 +4,11 @@
//! 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(const_fn)]
//! #![feature(proc_macro)] //! #![feature(proc_macro)]
//! #![no_std] //! #![no_std]
//! //!
//! #[macro_use(task)]
//! extern crate cortex_m_rtfm as rtfm; //! extern crate cortex_m_rtfm as rtfm;
//! extern crate stm32f103xx; //! extern crate stm32f103xx;
//! //!
@ -27,19 +25,19 @@
//! //!
//! tasks: { //! tasks: {
//! EXTI0: { //! EXTI0: {
//! enabled: true, //! path: exti0,
//! priority: 1, //! priority: 1,
//! resources: [LOW, HIGH], //! resources: [LOW, HIGH],
//! }, //! },
//! //!
//! EXTI1: { //! EXTI1: {
//! enabled: true, //! path: exti1,
//! priority: 2, //! priority: 2,
//! resources: [LOW], //! resources: [LOW],
//! }, //! },
//! //!
//! EXTI2: { //! EXTI2: {
//! enabled: true, //! path: exti2,
//! priority: 3, //! priority: 3,
//! resources: [HIGH], //! resources: [HIGH],
//! }, //! },
@ -49,9 +47,12 @@
//! fn init(_p: init::Peripherals, _r: init::Resources) {} //! fn init(_p: init::Peripherals, _r: init::Resources) {}
//! //!
//! fn idle() -> ! { //! fn idle() -> ! {
//! // sets task `exti0` as pending //! // A
//! rtfm::bkpt();
//!
//! // Sets task `exti0` as pending
//! // //! //
//! // because `exti0` has higher priority than `idle` it will be executed //! // Because `exti0` has higher priority than `idle` it will be executed
//! // immediately //! // immediately
//! rtfm::set_pending(Interrupt::EXTI0); // ~> exti0 //! rtfm::set_pending(Interrupt::EXTI0); // ~> exti0
//! //!
@ -60,72 +61,68 @@
//! } //! }
//! } //! }
//! //!
//! task!(EXTI0, exti0);
//!
//! fn exti0(t: &mut Threshold, r: EXTI0::Resources) { //! fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
//! // because this task has a priority of 1 the preemption threshold is also 1 //! // Because this task has a priority of 1 the preemption threshold `t` also
//! // starts at 1
//! //!
//! let mut low = r.LOW; //! let mut low = r.LOW;
//! let mut high = r.HIGH; //! let mut high = r.HIGH;
//! //!
//! // A //! // B
//! rtfm::bkpt(); //! rtfm::bkpt();
//! //!
//! // because `exti1` has higher priority than `exti0` it can preempt it //! // Because `exti1` has higher priority than `exti0` it can preempt it
//! 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
//! // 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
//! // `LOW` resource //! // `LOW` resource
//! //!
//! // C //! // D
//! rtfm::bkpt(); //! rtfm::bkpt();
//! //!
//! // now `exti1` can't preempt this task because its priority is equal to //! // Now `exti1` can't preempt this task because its priority is equal to
//! // the current preemption threshold //! // the current preemption threshold
//! rtfm::set_pending(Interrupt::EXTI1); //! rtfm::set_pending(Interrupt::EXTI1);
//! //!
//! // but `exti2` can, because its priority is higher than the current //! // But `exti2` can, because its priority is higher than the current
//! // preemption threshold //! // preemption threshold
//! rtfm::set_pending(Interrupt::EXTI2); // ~> exti2 //! rtfm::set_pending(Interrupt::EXTI2); // ~> exti2
//! //!
//! // E //! // F
//! 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
//! rtfm::set_pending(Interrupt::EXTI2); //! rtfm::set_pending(Interrupt::EXTI2);
//! //!
//! // F //! // G
//! rtfm::bkpt(); //! rtfm::bkpt();
//! }); //! });
//! //!
//! // upon leaving the critical section the preemption threshold drops to 2 //! // Upon leaving the critical section the preemption threshold drops back
//! // and `exti2` immediately preempts this task //! // to 2 and `exti2` immediately preempts this task
//! // ~> exti2 //! // ~> exti2
//! }); //! });
//! //!
//! // once again the preemption threshold drops to 1 //! // Once again the preemption threshold drops but this time to 1. Now the
//! // now the pending `exti1` can preempt this task //! // pending `exti1` task can preempt this task
//! // ~> exti1 //! // ~> exti1
//! } //! }
//! //!
//! task!(EXTI1, exti1);
//!
//! fn exti1(_t: &mut Threshold, _r: EXTI1::Resources) { //! fn exti1(_t: &mut Threshold, _r: EXTI1::Resources) {
//! // B, H //! // C, I
//! rtfm::bkpt(); //! rtfm::bkpt();
//! } //! }
//! //!
//! task!(EXTI2, exti2);
//!
//! fn exti2(_t: &mut Threshold, _r: EXTI2::Resources) { //! fn exti2(_t: &mut Threshold, _r: EXTI2::Resources) {
//! // D, G //! // E, H
//! rtfm::bkpt(); //! rtfm::bkpt();
//! } //! }
//! ``` //! ```

View file

@ -1,12 +1,10 @@
//! Working with resources in a generic fashion //! Working with resources in a generic fashion
//! //!
//! ``` //! ```
//!
//! #![deny(unsafe_code)] //! #![deny(unsafe_code)]
//! #![feature(proc_macro)] //! #![feature(proc_macro)]
//! #![no_std] //! #![no_std]
//! //!
//! #[macro_use(task)]
//! extern crate cortex_m_rtfm as rtfm; //! extern crate cortex_m_rtfm as rtfm;
//! extern crate stm32f103xx; //! extern crate stm32f103xx;
//! //!
@ -18,13 +16,13 @@
//! //!
//! tasks: { //! tasks: {
//! EXTI0: { //! EXTI0: {
//! enabled: true, //! path: exti0,
//! priority: 1, //! priority: 1,
//! resources: [GPIOA, SPI1], //! resources: [GPIOA, SPI1],
//! }, //! },
//! //!
//! EXTI1: { //! EXTI1: {
//! enabled: true, //! path: exti1,
//! priority: 2, //! priority: 2,
//! resources: [GPIOA, SPI1], //! resources: [GPIOA, SPI1],
//! }, //! },
@ -39,7 +37,7 @@
//! } //! }
//! } //! }
//! //!
//! // a generic function to use resources in any task (regardless of its priority) //! // A generic function that uses some resources
//! fn work<G, S>(t: &mut Threshold, gpioa: &G, spi1: &S) //! fn work<G, S>(t: &mut Threshold, gpioa: &G, spi1: &S)
//! where //! where
//! G: Resource<Data = GPIOA>, //! G: Resource<Data = GPIOA>,
@ -56,16 +54,12 @@
//! }); //! });
//! } //! }
//! //!
//! task!(EXTI0, exti0); //! // This task needs critical sections to access the resources
//!
//! // this task needs critical sections to access the resources
//! fn exti0(t: &mut Threshold, r: EXTI0::Resources) { //! fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
//! work(t, &r.GPIOA, &r.SPI1); //! work(t, &r.GPIOA, &r.SPI1);
//! } //! }
//! //!
//! task!(EXTI1, exti1); //! // This task has direct access to the resources
//!
//! // this task has direct access to the resources
//! fn exti1(t: &mut Threshold, r: EXTI1::Resources) { //! fn exti1(t: &mut Threshold, r: EXTI1::Resources) {
//! work(t, r.GPIOA, r.SPI1); //! work(t, r.GPIOA, r.SPI1);
//! } //! }

View file

@ -1,62 +1,70 @@
//! A showcase of the `app!` macro syntax //! A showcase of the `app!` macro syntax
//! //!
//! ``` //! ```
//!
//! #![deny(unsafe_code)] //! #![deny(unsafe_code)]
//! #![feature(const_fn)] //! #![feature(const_fn)]
//! #![feature(proc_macro)] //! #![feature(proc_macro)]
//! #![no_std] //! #![no_std]
//! //!
//! #[macro_use(task)]
//! extern crate cortex_m_rtfm as rtfm; //! extern crate cortex_m_rtfm as rtfm;
//! extern crate stm32f103xx; //! extern crate stm32f103xx;
//! //!
//! use rtfm::{app, Resource, Threshold}; //! use rtfm::{app, Threshold};
//! //!
//! app! { //! app! {
//! device: stm32f103xx, //! device: stm32f103xx,
//! //!
//! resources: { //! resources: {
//! static CO_OWNED: u32 = 0; //! static CO_OWNED: u32 = 0;
//! static ON: bool = false;
//! static OWNED: bool = false; //! static OWNED: bool = false;
//! static SHARED: bool = false; //! static SHARED: bool = false;
//! }, //! },
//! //!
//! init: { //! init: {
//! path: init_, // this is a path to the "init" function //! // This is the path to the `init` function
//! //
//! // `init` doesn't necessarily has to be in the root of the crate
//! path: main::init,
//! }, //! },
//! //!
//! idle: { //! idle: {
//! locals: { //! // This is a path to the `idle` function
//! static COUNTER: u32 = 0; //! //
//! }, //! // `idle` doesn't necessarily has to be in the root of the crate
//! path: idle_, // this is a path to the "idle" function //! path: main::idle,
//! resources: [OWNED, SHARED], //! resources: [OWNED, SHARED],
//! }, //! },
//! //!
//! tasks: { //! tasks: {
//! SYS_TICK: { //! SYS_TICK: {
//! priority: 1, //! path: sys_tick,
//! resources: [CO_OWNED, SHARED], //! // If omitted priority is assumed to be 1
//! // priority: 1,
//! resources: [CO_OWNED, ON, SHARED],
//! }, //! },
//! //!
//! TIM2: { //! TIM2: {
//! enabled: true, //! // Tasks are enabled, between `init` and `idle`, by default but they
//! // can start disabled if `false` is specified here
//! enabled: false,
//! path: tim2,
//! priority: 1, //! priority: 1,
//! resources: [CO_OWNED], //! resources: [CO_OWNED],
//! }, //! },
//! }, //! },
//! } //! }
//! //!
//! fn init_(_p: init::Peripherals, _r: init::Resources) {} //! mod main {
//! use rtfm::{self, Resource, Threshold};
//! //!
//! fn idle_(t: &mut Threshold, l: &mut idle::Locals, mut r: idle::Resources) -> ! { //! pub fn init(_p: ::init::Peripherals, _r: ::init::Resources) {}
//!
//! pub fn idle(t: &mut Threshold, mut r: ::idle::Resources) -> ! {
//! loop { //! loop {
//! *l.COUNTER += 1; //! *r.OWNED != *r.OWNED;
//! //!
//! **r.OWNED != **r.OWNED; //! if *r.OWNED {
//!
//! if **r.OWNED {
//! if r.SHARED.claim(t, |shared, _| **shared) { //! if r.SHARED.claim(t, |shared, _| **shared) {
//! rtfm::wfi(); //! rtfm::wfi();
//! } //! }
@ -65,19 +73,14 @@
//! } //! }
//! } //! }
//! } //! }
//! }
//! //!
//! task!(SYS_TICK, sys_tick, Local { //! fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
//! static STATE: bool = true; //! **r.ON = !**r.ON;
//! });
//!
//! fn sys_tick(_t: &mut Threshold, l: &mut Local, r: SYS_TICK::Resources) {
//! *l.STATE = !*l.STATE;
//! //!
//! **r.CO_OWNED += 1; //! **r.CO_OWNED += 1;
//! } //! }
//! //!
//! task!(TIM2, tim2);
//!
//! fn tim2(_t: &mut Threshold, r: TIM2::Resources) { //! fn tim2(_t: &mut Threshold, r: TIM2::Resources) {
//! **r.CO_OWNED += 1; //! **r.CO_OWNED += 1;
//! } //! }