diff options
Diffstat (limited to 'src/examples')
-rw-r--r-- | src/examples/_0_zero_tasks.rs | 53 | ||||
-rw-r--r-- | src/examples/_1_one_task.rs | 95 | ||||
-rw-r--r-- | src/examples/_2_two_tasks.rs | 79 | ||||
-rw-r--r-- | src/examples/_3_preemption.rs | 74 | ||||
-rw-r--r-- | src/examples/_4_nested.rs | 129 | ||||
-rw-r--r-- | src/examples/_5_generics.rs | 73 | ||||
-rw-r--r-- | src/examples/_6_full_syntax.rs | 85 | ||||
-rw-r--r-- | src/examples/mod.rs | 9 |
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; |