aboutsummaryrefslogtreecommitdiff
path: root/src/examples
diff options
context:
space:
mode:
Diffstat (limited to 'src/examples')
-rw-r--r--src/examples/_0_zero_tasks.rs53
-rw-r--r--src/examples/_1_one_task.rs95
-rw-r--r--src/examples/_2_two_tasks.rs79
-rw-r--r--src/examples/_3_preemption.rs74
-rw-r--r--src/examples/_4_nested.rs129
-rw-r--r--src/examples/_5_generics.rs73
-rw-r--r--src/examples/_6_full_syntax.rs85
-rw-r--r--src/examples/mod.rs9
8 files changed, 597 insertions, 0 deletions
diff --git a/src/examples/_0_zero_tasks.rs b/src/examples/_0_zero_tasks.rs
new file mode 100644
index 00000000..15231818
--- /dev/null
+++ b/src/examples/_0_zero_tasks.rs
@@ -0,0 +1,53 @@
+//! Minimal example with zero tasks
+//!
+//! ```
+//!
+//! #![deny(unsafe_code)]
+//! #![feature(proc_macro)] // IMPORTANT always include this feature gate
+//! #![no_std]
+//!
+//! extern crate cortex_m_rtfm as rtfm; // IMPORTANT always do this rename
+//! extern crate stm32f103xx; // the device crate
+//!
+//! // import the procedural macro
+//! use rtfm::app;
+//!
+//! // This macro call indicates that this is a RTFM application
+//! //
+//! // This macro will expand to a `main` function so you don't need to supply
+//! // `main` yourself.
+//! app! {
+//! // this is a path to the device crate
+//! device: stm32f103xx,
+//! }
+//!
+//! // The initialization phase.
+//! //
+//! // This runs first and within a *global* critical section. Nothing can preempt
+//! // this function.
+//! fn init(p: init::Peripherals) {
+//! // This function has access to all the peripherals of the device
+//! p.GPIOA;
+//! p.RCC;
+//! // ..
+//!
+//! // You'll hit this breakpoint first
+//! rtfm::bkpt();
+//! }
+//!
+//! // The idle loop.
+//! //
+//! // This runs afterwards and has a priority of 0. All tasks can preempt this
+//! // function. This function can never return so it must contain some sort of
+//! // endless loop.
+//! fn idle() -> ! {
+//! // And then this breakpoint
+//! rtfm::bkpt();
+//!
+//! loop {
+//! // This puts the processor to sleep until there's a task to service
+//! rtfm::wfi();
+//! }
+//! }
+//! ```
+// Auto-generated. Do not modify.
diff --git a/src/examples/_1_one_task.rs b/src/examples/_1_one_task.rs
new file mode 100644
index 00000000..33e8bf7f
--- /dev/null
+++ b/src/examples/_1_one_task.rs
@@ -0,0 +1,95 @@
+//! An application with one task
+//!
+//! ```
+//!
+//! #![deny(unsafe_code)]
+//! #![feature(const_fn)]
+//! #![feature(proc_macro)]
+//! #![no_std]
+//!
+//! extern crate cortex_m;
+//! #[macro_use(task)]
+//! extern crate cortex_m_rtfm as rtfm;
+//! extern crate stm32f103xx;
+//!
+//! use cortex_m::peripheral::SystClkSource;
+//! use rtfm::{app, Threshold};
+//!
+//! app! {
+//! device: stm32f103xx,
+//!
+//! // Here tasks are declared
+//! //
+//! // Each task corresponds to an interrupt or an exception. Every time the
+//! // interrupt or exception becomes *pending* the corresponding task handler
+//! // will be executed.
+//! tasks: {
+//! // Here we declare that we'll use the SYS_TICK exception as a task
+//! SYS_TICK: {
+//! // 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
+//! // the device has. This device has 4 priority bits so 16 is the
+//! // maximum value.
+//! priority: 1,
+//!
+//! // These are the *resources* associated with this task
+//! //
+//! // The peripherals that the task needs can be listed here
+//! resources: [GPIOC],
+//! },
+//! }
+//! }
+//!
+//! fn init(p: init::Peripherals) {
+//! // power on GPIOC
+//! p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
+//!
+//! // configure PC13 as output
+//! p.GPIOC.bsrr.write(|w| w.bs13().set());
+//! p.GPIOC
+//! .crh
+//! .modify(|_, w| w.mode13().output().cnf13().push());
+//!
+//! // configure the system timer to generate one interrupt every second
+//! p.SYST.set_clock_source(SystClkSource::Core);
+//! p.SYST.set_reload(8_000_000); // 1s
+//! p.SYST.enable_interrupt();
+//! p.SYST.enable_counter();
+//! }
+//!
+//! fn idle() -> ! {
+//! loop {
+//! rtfm::wfi();
+//! }
+//! }
+//!
+//! // 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
+//! //
+//! // `t` is the preemption threshold token. We won't use it this time.
+//! // `l` is the data local to this task. The type here must match the one declared
+//! // in `task!`.
+//! // `r` is the resources this task has access to. `SYS_TICK::Resources` has one
+//! // field per resource declared in `app!`.
+//! fn sys_tick(_t: &mut Threshold, l: &mut Locals, r: SYS_TICK::Resources) {
+//! // toggle state
+//! *l.STATE = !*l.STATE;
+//!
+//! if *l.STATE {
+//! // set the pin PC13 high
+//! r.GPIOC.bsrr.write(|w| w.bs13().set());
+//! } else {
+//! // set the pin PC13 low
+//! r.GPIOC.bsrr.write(|w| w.br13().reset());
+//! }
+//! }
+//! ```
+// Auto-generated. Do not modify.
diff --git a/src/examples/_2_two_tasks.rs b/src/examples/_2_two_tasks.rs
new file mode 100644
index 00000000..9eb61b18
--- /dev/null
+++ b/src/examples/_2_two_tasks.rs
@@ -0,0 +1,79 @@
+//! Two tasks running at the same priority with access to the same resource
+//!
+//! ```
+//!
+//! #![deny(unsafe_code)]
+//! #![feature(const_fn)]
+//! #![feature(proc_macro)]
+//! #![no_std]
+//!
+//! #[macro_use(task)]
+//! extern crate cortex_m_rtfm as rtfm;
+//! extern crate stm32f103xx;
+//!
+//! use rtfm::{app, Threshold};
+//!
+//! app! {
+//! device: stm32f103xx,
+//!
+//! // Resources that are plain data, not peripherals
+//! resources: {
+//! // Declaration of resources looks like the declaration of `static`
+//! // variables
+//! static COUNTER: u64 = 0;
+//! },
+//!
+//! tasks: {
+//! SYS_TICK: {
+//! priority: 1,
+//! // Both this task and TIM2 have access to the `COUNTER` resource
+//! resources: [COUNTER],
+//! },
+//!
+//! // An interrupt as a task
+//! TIM2: {
+//! // For interrupts the `enabled` field must be specified. It
+//! // indicates if the interrupt will be enabled or disabled once
+//! // `idle` starts
+//! enabled: true,
+//! priority: 1,
+//! resources: [COUNTER],
+//! },
+//! },
+//! }
+//!
+//! // 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 idle() -> ! {
+//! loop {
+//! rtfm::wfi();
+//! }
+//! }
+//!
+//! task!(SYS_TICK, sys_tick);
+//!
+//! // As both tasks are running at the same priority one can't preempt the other.
+//! // Thus both tasks have direct access to the resource
+//! fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
+//! // ..
+//!
+//! **r.COUNTER += 1;
+//!
+//! // ..
+//! }
+//!
+//! task!(TIM2, tim2);
+//!
+//! fn tim2(_t: &mut Threshold, r: TIM2::Resources) {
+//! // ..
+//!
+//! **r.COUNTER += 1;
+//!
+//! // ..
+//! }
+//! ```
+// Auto-generated. Do not modify.
diff --git a/src/examples/_3_preemption.rs b/src/examples/_3_preemption.rs
new file mode 100644
index 00000000..b93ec086
--- /dev/null
+++ b/src/examples/_3_preemption.rs
@@ -0,0 +1,74 @@
+//! Two tasks running at different priorities with access to the same resource
+//!
+//! ```
+//!
+//! #![deny(unsafe_code)]
+//! #![feature(const_fn)]
+//! #![feature(proc_macro)]
+//! #![no_std]
+//!
+//! #[macro_use(task)]
+//! extern crate cortex_m_rtfm as rtfm;
+//! extern crate stm32f103xx;
+//!
+//! use rtfm::{app, Resource, Threshold};
+//!
+//! app! {
+//! device: stm32f103xx,
+//!
+//! resources: {
+//! static COUNTER: u64 = 0;
+//! },
+//!
+//! tasks: {
+//! // the task `SYS_TICK` has higher priority than `TIM2`
+//! SYS_TICK: {
+//! priority: 2,
+//! resources: [COUNTER],
+//! },
+//!
+//! TIM2: {
+//! enabled: true,
+//! priority: 1,
+//! resources: [COUNTER],
+//! },
+//! },
+//! }
+//!
+//! fn init(_p: init::Peripherals, _r: init::Resources) {
+//! // ..
+//! }
+//!
+//! fn idle() -> ! {
+//! loop {
+//! rtfm::wfi();
+//! }
+//! }
+//!
+//! task!(SYS_TICK, sys_tick);
+//!
+//! 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
+//! // resource data
+//! **r.COUNTER += 1;
+//!
+//! // ..
+//! }
+//!
+//! task!(TIM2, tim2);
+//!
+//! fn tim2(t: &mut Threshold, mut r: TIM2::Resources) {
+//! // ..
+//!
+//! // as this task runs at lower priority it needs a critical section to
+//! // prevent `sys_tick` from preempting it while it modifies this resource
+//! // data. The critical section is required to prevent data races which can
+//! // lead to data corruption or data loss
+//! r.COUNTER.claim_mut(t, |counter, _t| { **counter += 1; });
+//!
+//! // ..
+//! }
+//! ```
+// Auto-generated. Do not modify.
diff --git a/src/examples/_4_nested.rs b/src/examples/_4_nested.rs
new file mode 100644
index 00000000..718710d7
--- /dev/null
+++ b/src/examples/_4_nested.rs
@@ -0,0 +1,129 @@
+//! Nesting claims and how the preemption threshold works
+//!
+//! If you run this program you'll hit the breakpoints as indicated by the
+//! letters in the comments: A, then B, then C, etc.
+//!
+//! ```
+//!
+//! #![deny(unsafe_code)]
+//! #![feature(const_fn)]
+//! #![feature(proc_macro)]
+//! #![no_std]
+//!
+//! #[macro_use(task)]
+//! extern crate cortex_m_rtfm as rtfm;
+//! extern crate stm32f103xx;
+//!
+//! use stm32f103xx::Interrupt;
+//! use rtfm::{app, Resource, Threshold};
+//!
+//! app! {
+//! device: stm32f103xx,
+//!
+//! resources: {
+//! static LOW: u64 = 0;
+//! static HIGH: u64 = 0;
+//! },
+//!
+//! tasks: {
+//! EXTI0: {
+//! enabled: true,
+//! priority: 1,
+//! resources: [LOW, HIGH],
+//! },
+//!
+//! EXTI1: {
+//! enabled: true,
+//! priority: 2,
+//! resources: [LOW],
+//! },
+//!
+//! EXTI2: {
+//! enabled: true,
+//! priority: 3,
+//! resources: [HIGH],
+//! },
+//! },
+//! }
+//!
+//! fn init(_p: init::Peripherals, _r: init::Resources) {}
+//!
+//! fn idle() -> ! {
+//! // sets task `exti0` as pending
+//! //
+//! // because `exti0` has higher priority than `idle` it will be executed
+//! // immediately
+//! rtfm::set_pending(Interrupt::EXTI0); // ~> exti0
+//!
+//! loop {
+//! rtfm::wfi();
+//! }
+//! }
+//!
+//! task!(EXTI0, exti0);
+//!
+//! fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
+//! // because this task has a priority of 1 the preemption threshold is also 1
+//!
+//! // A
+//! rtfm::bkpt();
+//!
+//! // because `exti1` has higher priority than `exti0` it can preempt it
+//! rtfm::set_pending(Interrupt::EXTI1); // ~> exti1
+//!
+//! // a claim creates a critical section
+//! r.LOW.claim_mut(t, |_low, t| {
+//! // this claim increases the preemption threshold to 2
+//! // just high enough to not race with task `exti1` for access to the
+//! // `LOW` resource
+//!
+//! // C
+//! rtfm::bkpt();
+//!
+//! // now `exti1` can't preempt this task because its priority is equal to
+//! // the current preemption threshold
+//! rtfm::set_pending(Interrupt::EXTI1);
+//!
+//! // but `exti2` can, because its priority is higher than the current
+//! // preemption threshold
+//! rtfm::set_pending(Interrupt::EXTI2); // ~> exti2
+//!
+//! // E
+//! rtfm::bkpt();
+//!
+//! // claims can be nested
+//! r.HIGH.claim_mut(t, |_high, _| {
+//! // This claim increases the preemption threshold to 3
+//!
+//! // now `exti2` can't preempt this task
+//! rtfm::set_pending(Interrupt::EXTI2);
+//!
+//! // F
+//! rtfm::bkpt();
+//! });
+//!
+//! // upon leaving the critical section the preemption threshold drops to 2
+//! // and `exti2` immediately preempts this task
+//! // ~> exti2
+//! });
+//!
+//! // once again the preemption threshold drops to 1
+//! // now the pending `exti1` can preempt this task
+//! // ~> exti1
+//! }
+//!
+//! task!(EXTI1, exti1);
+//!
+//! fn exti1(_t: &mut Threshold, _r: EXTI1::Resources) {
+//! // B, H
+//! rtfm::bkpt();
+//! }
+//!
+//! task!(EXTI2, exti2);
+//!
+//! fn exti2(_t: &mut Threshold, _r: EXTI2::Resources) {
+//! // D, G
+//! rtfm::bkpt();
+//! }
+//! ```
+// Auto-generated. Do not modify.
diff --git a/src/examples/_5_generics.rs b/src/examples/_5_generics.rs
new file mode 100644
index 00000000..a8f42cdf
--- /dev/null
+++ b/src/examples/_5_generics.rs
@@ -0,0 +1,73 @@
+//! Working with resources in a generic fashion
+//!
+//! ```
+//!
+//! #![deny(unsafe_code)]
+//! #![feature(proc_macro)]
+//! #![no_std]
+//!
+//! #[macro_use(task)]
+//! extern crate cortex_m_rtfm as rtfm;
+//! extern crate stm32f103xx;
+//!
+//! use rtfm::{app, Resource, Threshold};
+//! use stm32f103xx::{SPI1, GPIOA};
+//!
+//! app! {
+//! device: stm32f103xx,
+//!
+//! tasks: {
+//! EXTI0: {
+//! enabled: true,
+//! priority: 1,
+//! resources: [GPIOA, SPI1],
+//! },
+//!
+//! EXTI1: {
+//! enabled: true,
+//! priority: 2,
+//! resources: [GPIOA, SPI1],
+//! },
+//! },
+//! }
+//!
+//! fn init(_p: init::Peripherals) {}
+//!
+//! fn idle() -> ! {
+//! loop {
+//! rtfm::wfi();
+//! }
+//! }
+//!
+//! // a generic function to use resources in any task (regardless of its priority)
+//! fn work<G, S>(t: &mut Threshold, gpioa: &G, spi1: &S)
+//! where
+//! G: Resource<Data = GPIOA>,
+//! S: Resource<Data = SPI1>,
+//! {
+//! gpioa.claim(t, |_gpioa, t| {
+//! // drive NSS low
+//!
+//! spi1.claim(t, |_spi1, _| {
+//! // transfer data
+//! });
+//!
+//! // drive NSS high
+//! });
+//! }
+//!
+//! task!(EXTI0, exti0);
+//!
+//! // this task needs critical sections to access the resources
+//! fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
+//! work(t, &r.GPIOA, &r.SPI1);
+//! }
+//!
+//! task!(EXTI1, exti1);
+//!
+//! // this task has direct access to the resources
+//! fn exti1(t: &mut Threshold, r: EXTI1::Resources) {
+//! work(t, r.GPIOA, r.SPI1);
+//! }
+//! ```
+// Auto-generated. Do not modify.
diff --git a/src/examples/_6_full_syntax.rs b/src/examples/_6_full_syntax.rs
new file mode 100644
index 00000000..9e932436
--- /dev/null
+++ b/src/examples/_6_full_syntax.rs
@@ -0,0 +1,85 @@
+//! A showcase of the `app!` macro syntax
+//!
+//! ```
+//!
+//! #![deny(unsafe_code)]
+//! #![feature(const_fn)]
+//! #![feature(proc_macro)]
+//! #![no_std]
+//!
+//! #[macro_use(task)]
+//! extern crate cortex_m_rtfm as rtfm;
+//! extern crate stm32f103xx;
+//!
+//! use rtfm::{app, Resource, Threshold};
+//!
+//! app! {
+//! device: stm32f103xx,
+//!
+//! resources: {
+//! static CO_OWNED: u32 = 0;
+//! static OWNED: bool = false;
+//! static SHARED: bool = false;
+//! },
+//!
+//! init: {
+//! path: init_, // this is a path to the "init" function
+//! },
+//!
+//! idle: {
+//! locals: {
+//! static COUNTER: u32 = 0;
+//! },
+//! path: idle_, // this is a path to the "idle" function
+//! resources: [OWNED, SHARED],
+//! },
+//!
+//! tasks: {
+//! SYS_TICK: {
+//! priority: 1,
+//! resources: [CO_OWNED, SHARED],
+//! },
+//!
+//! TIM2: {
+//! enabled: true,
+//! priority: 1,
+//! resources: [CO_OWNED],
+//! },
+//! },
+//! }
+//!
+//! fn init_(_p: init::Peripherals, _r: init::Resources) {}
+//!
+//! fn idle_(t: &mut Threshold, l: &mut idle::Locals, mut r: idle::Resources) -> ! {
+//! loop {
+//! *l.COUNTER += 1;
+//!
+//! **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);
+//! }
+//! }
+//! }
+//!
+//! task!(SYS_TICK, sys_tick, Local {
+//! static STATE: bool = true;
+//! });
+//!
+//! fn sys_tick(_t: &mut Threshold, l: &mut Local, r: SYS_TICK::Resources) {
+//! *l.STATE = !*l.STATE;
+//!
+//! **r.CO_OWNED += 1;
+//! }
+//!
+//! task!(TIM2, tim2);
+//!
+//! fn tim2(_t: &mut Threshold, r: TIM2::Resources) {
+//! **r.CO_OWNED += 1;
+//! }
+//! ```
+// Auto-generated. Do not modify.
diff --git a/src/examples/mod.rs b/src/examples/mod.rs
new file mode 100644
index 00000000..e0be5a6f
--- /dev/null
+++ b/src/examples/mod.rs
@@ -0,0 +1,9 @@
+//! Examples
+// Auto-generated. Do not modify.
+pub mod _0_zero_tasks;
+pub mod _1_one_task;
+pub mod _2_two_tasks;
+pub mod _3_preemption;
+pub mod _4_nested;
+pub mod _5_generics;
+pub mod _6_full_syntax;