Skip to content
Snippets Groups Projects
Commit e85d6e53 authored by Jorge Aparicio's avatar Jorge Aparicio
Browse files

update examples

parent 271df39b
No related branches found
No related tags found
No related merge requests found
//! 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 @@ ...@@ -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! { ...@@ -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! { ...@@ -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;
...@@ -62,6 +71,7 @@ fn idle_(t: &mut Threshold, mut r: idle::Resources) -> ! { ...@@ -62,6 +71,7 @@ fn idle_(t: &mut Threshold, mut r: idle::Resources) -> ! {
} }
} }
} }
}
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) { fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
**r.ON = !**r.ON; **r.ON = !**r.ON;
......
//! 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() -> ! { ...@@ -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 ...@@ -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);
} }
//! 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;
}
}
...@@ -2,7 +2,6 @@ ...@@ -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! { ...@@ -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() -> ! { ...@@ -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();
} }
...@@ -14,11 +14,11 @@ use rtfm::{app, Threshold}; ...@@ -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! { ...@@ -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() -> ! { ...@@ -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;
......
//! 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! { ...@@ -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() -> ! { ...@@ -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) { ...@@ -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; });
// .. // ..
......
//! 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}; ...@@ -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) {
// .. // ..
......
//! 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; ...@@ -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) { ...@@ -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();
......
//! 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 @@ ...@@ -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 @@ ...@@ -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();
......
//! 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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 {
......
//! 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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -66,8 +55,6 @@
//! // .. //! // ..
//! } //! }
//! //!
//! task!(TIM2, tim2);
//!
//! fn tim2(_t: &mut Threshold, r: TIM2::Resources) { //! fn tim2(_t: &mut Threshold, r: TIM2::Resources) {
//! // .. //! // ..
//! //!
......
//! 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 @@ ...@@ -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 @@ ...@@ -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; });
//! //!
//! // .. //! // ..
......
...@@ -4,13 +4,11 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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();
//! } //! }
//! ``` //! ```
......
//! 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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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);
//! } //! }
......
//! 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) {}
//! loop {
//! *l.COUNTER += 1;
//! //!
//! **r.OWNED != **r.OWNED; //! pub fn idle(t: &mut Threshold, mut r: ::idle::Resources) -> ! {
//! loop {
//! *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 @@ ...@@ -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;
//! } //! }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment