diff options
Diffstat (limited to 'examples')
41 files changed, 1303 insertions, 440 deletions
diff --git a/examples/baseline.rs b/examples/baseline.rs index fdf3683..3ab40db 100644 --- a/examples/baseline.rs +++ b/examples/baseline.rs @@ -5,47 +5,52 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; use lm3s6965::Interrupt; -use rtfm::app; +use panic_semihosting as _; // NOTE: does NOT properly work on QEMU -#[app(device = lm3s6965)] -const APP: () = { +#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] +mod app { #[init(spawn = [foo])] - fn init() { - hprintln!("init(baseline = {:?})", start).unwrap(); + fn init(cx: init::Context) -> init::LateResources { + // omitted: initialization of `CYCCNT` + + hprintln!("init(baseline = {:?})", cx.start).unwrap(); // `foo` inherits the baseline of `init`: `Instant(0)` - spawn.foo().unwrap(); + cx.spawn.foo().unwrap(); + + init::LateResources {} } #[task(schedule = [foo])] - fn foo() { + fn foo(cx: foo::Context) { static mut ONCE: bool = true; - hprintln!("foo(baseline = {:?})", scheduled).unwrap(); + hprintln!("foo(baseline = {:?})", cx.scheduled).unwrap(); if *ONCE { *ONCE = false; - rtfm::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART0); } else { debug::exit(debug::EXIT_SUCCESS); } } - #[interrupt(spawn = [foo])] - fn UART0() { - hprintln!("UART0(baseline = {:?})", start).unwrap(); + #[task(binds = UART0, spawn = [foo])] + fn uart0(cx: uart0::Context) { + hprintln!("UART0(baseline = {:?})", cx.start).unwrap(); // `foo` inherits the baseline of `UART0`: its `start` time - spawn.foo().unwrap(); + cx.spawn.foo().unwrap(); } + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. extern "C" { - fn UART1(); + fn SSI0(); } -}; +} diff --git a/examples/binds.rs b/examples/binds.rs index a8b386f..42010ae 100644 --- a/examples/binds.rs +++ b/examples/binds.rs @@ -5,35 +5,37 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; use lm3s6965::Interrupt; -use rtfm::app; +use panic_semihosting as _; // `examples/interrupt.rs` rewritten to use `binds` -#[app(device = lm3s6965)] -const APP: () = { +#[rtic::app(device = lm3s6965)] +mod app { #[init] - fn init() { - rtfm::pend(Interrupt::UART0); + fn init(_: init::Context) -> init::LateResources { + rtic::pend(Interrupt::UART0); hprintln!("init").unwrap(); + + init::LateResources {} } #[idle] - fn idle() -> ! { + fn idle(_: idle::Context) -> ! { hprintln!("idle").unwrap(); - rtfm::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART0); debug::exit(debug::EXIT_SUCCESS); - loop {} + loop { + cortex_m::asm::nop(); + } } - #[interrupt(binds = UART0)] - fn foo() { + #[task(binds = UART0)] + fn foo(_: foo::Context) { static mut TIMES: u32 = 0; *TIMES += 1; @@ -45,4 +47,4 @@ const APP: () = { ) .unwrap(); } -}; +} diff --git a/examples/capacity.rs b/examples/capacity.rs index a7132ba..ba8b15b 100644 --- a/examples/capacity.rs +++ b/examples/capacity.rs @@ -5,43 +5,45 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; use lm3s6965::Interrupt; -use rtfm::app; +use panic_semihosting as _; -#[app(device = lm3s6965)] -const APP: () = { +#[rtic::app(device = lm3s6965)] +mod app { #[init] - fn init() { - rtfm::pend(Interrupt::UART0); + fn init(_: init::Context) -> init::LateResources { + rtic::pend(Interrupt::UART0); + + init::LateResources {} } - #[interrupt(spawn = [foo, bar])] - fn UART0() { - spawn.foo(0).unwrap(); - spawn.foo(1).unwrap(); - spawn.foo(2).unwrap(); - spawn.foo(3).unwrap(); + #[task(binds = UART0, spawn = [foo, bar])] + fn uart0(c: uart0::Context) { + c.spawn.foo(0).unwrap(); + c.spawn.foo(1).unwrap(); + c.spawn.foo(2).unwrap(); + c.spawn.foo(3).unwrap(); - spawn.bar().unwrap(); + c.spawn.bar().unwrap(); } #[task(capacity = 4)] - fn foo(x: u32) { + fn foo(_: foo::Context, x: u32) { hprintln!("foo({})", x).unwrap(); } #[task] - fn bar() { + fn bar(_: bar::Context) { hprintln!("bar").unwrap(); debug::exit(debug::EXIT_SUCCESS); } - // Interrupt handlers used to dispatch software tasks + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. extern "C" { - fn UART1(); + fn SSI0(); } -}; +} diff --git a/examples/cfg.rs b/examples/cfg.rs index 3f4ca90..d49f54c 100644 --- a/examples/cfg.rs +++ b/examples/cfg.rs @@ -5,40 +5,55 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - +use cortex_m_semihosting::debug; #[cfg(debug_assertions)] use cortex_m_semihosting::hprintln; -use rtfm::app; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[resources] + struct Resources { + #[cfg(debug_assertions)] // <- `true` when using the `dev` profile + #[init(0)] + count: u32, + } -#[app(device = lm3s6965)] -const APP: () = { - #[cfg(debug_assertions)] // <- `true` when using the `dev` profile - static mut COUNT: u32 = 0; + #[init(spawn = [foo])] + fn init(cx: init::Context) -> init::LateResources { + cx.spawn.foo().unwrap(); + cx.spawn.foo().unwrap(); - #[init] - fn init() { - // .. + init::LateResources {} + } + + #[idle] + fn idle(_: idle::Context) -> ! { + debug::exit(debug::EXIT_SUCCESS); + + loop { + cortex_m::asm::nop(); + } } - #[task(priority = 3, resources = [COUNT], spawn = [log])] - fn foo() { + #[task(capacity = 2, resources = [count], spawn = [log])] + fn foo(_cx: foo::Context) { #[cfg(debug_assertions)] { - *resources.COUNT += 1; + *_cx.resources.count += 1; - spawn.log(*resources.COUNT).ok(); + _cx.spawn.log(*_cx.resources.count).unwrap(); } // this wouldn't compile in `release` mode - // *resources.COUNT += 1; + // *_cx.resources.count += 1; // .. } #[cfg(debug_assertions)] - #[task] - fn log(n: u32) { + #[task(capacity = 2)] + fn log(_: log::Context, n: u32) { hprintln!( "foo has been called {} time{}", n, @@ -47,8 +62,11 @@ const APP: () = { .ok(); } + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. extern "C" { - fn UART0(); - fn UART1(); + fn SSI0(); + fn QEI0(); } -}; +} diff --git a/examples/destructure.rs b/examples/destructure.rs new file mode 100644 index 0000000..e7c5323 --- /dev/null +++ b/examples/destructure.rs @@ -0,0 +1,50 @@ +//! examples/destructure.rs + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m_semihosting::hprintln; +use lm3s6965::Interrupt; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[resources] + struct Resources { + // Some resources to work with + #[init(0)] + a: u32, + #[init(0)] + b: u32, + #[init(0)] + c: u32, + } + + #[init] + fn init(_: init::Context) -> init::LateResources { + rtic::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART1); + + init::LateResources {} + } + + // Direct destructure + #[task(binds = UART0, resources = [a, b, c])] + fn uart0(cx: uart0::Context) { + let a = cx.resources.a; + let b = cx.resources.b; + let c = cx.resources.c; + + hprintln!("UART0: a = {}, b = {}, c = {}", a, b, c).unwrap(); + } + + // De-structure-ing syntax + #[task(binds = UART1, resources = [a, b, c])] + fn uart1(cx: uart1::Context) { + let uart1::Resources { a, b, c } = cx.resources; + + hprintln!("UART0: a = {}, b = {}, c = {}", a, b, c).unwrap(); + } +} diff --git a/examples/double_schedule.rs b/examples/double_schedule.rs new file mode 100644 index 0000000..b1b78b8 --- /dev/null +++ b/examples/double_schedule.rs @@ -0,0 +1,39 @@ +//! examples/double_schedule.rs + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use panic_semihosting as _; +use rtic::cyccnt::U32Ext; + +#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] +mod app { + + #[resources] + struct Resources { + nothing: (), + } + + #[init(spawn = [task1])] + fn init(cx: init::Context) -> init::LateResources { + cx.spawn.task1().ok(); + + init::LateResources { nothing: () } + } + + #[task(schedule = [task2])] + fn task1(_cx: task1::Context) { + _cx.schedule.task2(_cx.scheduled + 100.cycles()).ok(); + } + + #[task(schedule = [task1])] + fn task2(_cx: task2::Context) { + _cx.schedule.task1(_cx.scheduled + 100.cycles()).ok(); + } + + extern "C" { + fn SSI0(); + } +} diff --git a/examples/generics.rs b/examples/generics.rs index c8ce839..3107dd1 100644 --- a/examples/generics.rs +++ b/examples/generics.rs @@ -5,58 +5,64 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; use lm3s6965::Interrupt; -use rtfm::{app, Mutex}; - -#[app(device = lm3s6965)] -const APP: () = { - static mut SHARED: u32 = 0; +use panic_semihosting as _; +use rtic::{Exclusive, Mutex}; + +#[rtic::app(device = lm3s6965)] +mod app { + #[resources] + struct Resources { + #[init(0)] + shared: u32, + } #[init] - fn init() { - rtfm::pend(Interrupt::UART0); - rtfm::pend(Interrupt::UART1); + fn init(_: init::Context) -> init::LateResources { + rtic::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART1); + + init::LateResources {} } - #[interrupt(resources = [SHARED])] - fn UART0() { + #[task(binds = UART0, resources = [shared])] + fn uart0(c: uart0::Context) { static mut STATE: u32 = 0; hprintln!("UART0(STATE = {})", *STATE).unwrap(); - advance(STATE, resources.SHARED); + // second argument has type `resources::shared` + advance(STATE, c.resources.shared); - rtfm::pend(Interrupt::UART1); + rtic::pend(Interrupt::UART1); debug::exit(debug::EXIT_SUCCESS); } - #[interrupt(priority = 2, resources = [SHARED])] - fn UART1() { + #[task(binds = UART1, priority = 2, resources = [shared])] + fn uart1(c: uart1::Context) { static mut STATE: u32 = 0; hprintln!("UART1(STATE = {})", *STATE).unwrap(); - // just to show that `SHARED` can be accessed directly and .. - *resources.SHARED += 0; - // .. also through a (no-op) `lock` - resources.SHARED.lock(|shared| *shared += 0); + // just to show that `shared` can be accessed directly + *c.resources.shared += 0; - advance(STATE, resources.SHARED); + // second argument has type `Exclusive<u32>` + advance(STATE, Exclusive(c.resources.shared)); } -}; +} +// the second parameter is generic: it can be any type that implements the `Mutex` trait fn advance(state: &mut u32, mut shared: impl Mutex<T = u32>) { *state += 1; - let (old, new) = shared.lock(|shared| { + let (old, new) = shared.lock(|shared: &mut u32| { let old = *shared; *shared += *state; (old, *shared) }); - hprintln!("SHARED: {} -> {}", old, new).unwrap(); + hprintln!("shared: {} -> {}", old, new).unwrap(); } diff --git a/examples/interrupt.rs b/examples/hardware.rs index 3c669d9..f6a2d37 100644 --- a/examples/interrupt.rs +++ b/examples/hardware.rs @@ -1,42 +1,44 @@ -//! examples/interrupt.rs +//! examples/hardware.rs #![deny(unsafe_code)] #![deny(warnings)] #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; use lm3s6965::Interrupt; -use rtfm::app; +use panic_semihosting as _; -#[app(device = lm3s6965)] -const APP: () = { +#[rtic::app(device = lm3s6965)] +mod app { #[init] - fn init() { + fn init(_: init::Context) -> init::LateResources { // Pends the UART0 interrupt but its handler won't run until *after* // `init` returns because interrupts are disabled - rtfm::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART0); // equivalent to NVIC::pend hprintln!("init").unwrap(); + + init::LateResources {} } #[idle] - fn idle() -> ! { + fn idle(_: idle::Context) -> ! { // interrupts are enabled again; the `UART0` handler runs at this point hprintln!("idle").unwrap(); - rtfm::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART0); debug::exit(debug::EXIT_SUCCESS); - loop {} + loop { + cortex_m::asm::nop(); + } } - #[interrupt] - fn UART0() { + #[task(binds = UART0)] + fn uart0(_: uart0::Context) { static mut TIMES: u32 = 0; // Safe access to local `static mut` variable @@ -49,4 +51,4 @@ const APP: () = { ) .unwrap(); } -}; +} diff --git a/examples/idle.rs b/examples/idle.rs index 1f21a37..58c3c87 100644 --- a/examples/idle.rs +++ b/examples/idle.rs @@ -5,20 +5,20 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; -use rtfm::app; +use panic_semihosting as _; -#[app(device = lm3s6965)] -const APP: () = { +#[rtic::app(device = lm3s6965)] +mod app { #[init] - fn init() { + fn init(_: init::Context) -> init::LateResources { hprintln!("init").unwrap(); + + init::LateResources {} } #[idle] - fn idle() -> ! { + fn idle(_: idle::Context) -> ! { static mut X: u32 = 0; // Safe access to local `static mut` variable @@ -28,6 +28,8 @@ const APP: () = { debug::exit(debug::EXIT_SUCCESS); - loop {} + loop { + cortex_m::asm::nop(); + } } -}; +} diff --git a/examples/init.rs b/examples/init.rs index be6cfe3..6ac284a 100644 --- a/examples/init.rs +++ b/examples/init.rs @@ -5,28 +5,32 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; -use rtfm::app; +use panic_semihosting as _; -#[app(device = lm3s6965)] -const APP: () = { +#[rtic::app(device = lm3s6965, peripherals = true)] +mod app { #[init] - fn init() { + fn init(cx: init::Context) -> init::LateResources { static mut X: u32 = 0; // Cortex-M peripherals - let _core: rtfm::Peripherals = core; + let _core: cortex_m::Peripherals = cx.core; // Device specific peripherals - let _device: lm3s6965::Peripherals = device; + let _device: lm3s6965::Peripherals = cx.device; // Safe access to local `static mut` variable let _x: &'static mut u32 = X; + // Access to the critical section token, + // to indicate that this is a critical seciton + let _cs_token: bare_metal::CriticalSection = cx.cs; + hprintln!("init").unwrap(); debug::exit(debug::EXIT_SUCCESS); + + init::LateResources {} } -}; +} diff --git a/examples/late.rs b/examples/late.rs index 622008a..761c68f 100644 --- a/examples/late.rs +++ b/examples/late.rs @@ -5,50 +5,53 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; use heapless::{ consts::*, + i, spsc::{Consumer, Producer, Queue}, }; use lm3s6965::Interrupt; -use rtfm::app; - -#[app(device = lm3s6965)] -const APP: () = { +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use heapless::{ + consts::*, + spsc::{Consumer, Producer}, + }; // Late resources - static mut P: Producer<'static, u32, U4> = (); - static mut C: Consumer<'static, u32, U4> = (); + #[resources] + struct Resources { + p: Producer<'static, u32, U4>, + c: Consumer<'static, u32, U4>, + } #[init] - fn init() -> init::LateResources { - // NOTE: we use `Option` here to work around the lack of - // a stable `const` constructor - static mut Q: Option<Queue<u32, U4>> = None; + fn init(_: init::Context) -> init::LateResources { + static mut Q: Queue<u32, U4> = Queue(i::Queue::new()); - *Q = Some(Queue::new()); - let (p, c) = Q.as_mut().unwrap().split(); + let (p, c) = Q.split(); // Initialization of late resources - init::LateResources { P: p, C: c } + init::LateResources { p, c } } - #[idle(resources = [C])] - fn idle() -> ! { + #[idle(resources = [c])] + fn idle(c: idle::Context) -> ! { loop { - if let Some(byte) = resources.C.dequeue() { + if let Some(byte) = c.resources.c.dequeue() { hprintln!("received message: {}", byte).unwrap(); debug::exit(debug::EXIT_SUCCESS); } else { - rtfm::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART0); } } } - #[interrupt(resources = [P])] - fn UART0() { - resources.P.enqueue(42).unwrap(); + #[task(binds = UART0, resources = [p])] + fn uart0(c: uart0::Context) { + c.resources.p.enqueue(42).unwrap(); } -}; +} diff --git a/examples/lock.rs b/examples/lock.rs index 4ca862e..669b1ae 100644 --- a/examples/lock.rs +++ b/examples/lock.rs @@ -5,38 +5,42 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; use lm3s6965::Interrupt; -use rtfm::app; - -#[app(device = lm3s6965)] -const APP: () = { - static mut SHARED: u32 = 0; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[resources] + struct Resources { + #[init(0)] + shared: u32, + } #[init] - fn init() { - rtfm::pend(Interrupt::GPIOA); + fn init(_: init::Context) -> init::LateResources { + rtic::pend(Interrupt::GPIOA); + + init::LateResources {} } // when omitted priority is assumed to be `1` - #[interrupt(resources = [SHARED])] - fn GPIOA() { + #[task(binds = GPIOA, resources = [shared])] + fn gpioa(mut c: gpioa::Context) { hprintln!("A").unwrap(); // the lower priority task requires a critical section to access the data - resources.SHARED.lock(|shared| { + c.resources.shared.lock(|shared| { // data can only be modified within this critical section (closure) *shared += 1; // GPIOB will *not* run right now due to the critical section - rtfm::pend(Interrupt::GPIOB); + rtic::pend(Interrupt::GPIOB); - hprintln!("B - SHARED = {}", *shared).unwrap(); + hprintln!("B - shared = {}", *shared).unwrap(); - // GPIOC does not contend for `SHARED` so it's allowed to run now - rtfm::pend(Interrupt::GPIOC); + // GPIOC does not contend for `shared` so it's allowed to run now + rtic::pend(Interrupt::GPIOC); }); // critical section is over: GPIOB can now start @@ -46,16 +50,16 @@ const APP: () = { debug::exit(debug::EXIT_SUCCESS); } - #[interrupt(priority = 2, resources = [SHARED])] - fn GPIOB() { + #[task(binds = GPIOB, priority = 2, resources = [shared])] + fn gpiob(c: gpiob::Context) { // the higher priority task does *not* need a critical section - *resources.SHARED += 1; + *c.resources.shared += 1; - hprintln!("D - SHARED = {}", *resources.SHARED).unwrap(); + hprintln!("D - shared = {}", *c.resources.shared).unwrap(); } - #[interrupt(priority = 3)] - fn GPIOC() { + #[task(binds = GPIOC, priority = 3)] + fn gpioc(_: gpioc::Context) { hprintln!("C").unwrap(); } -}; +} diff --git a/examples/message.rs b/examples/message.rs index b5d68a6..f973672 100644 --- a/examples/message.rs +++ b/examples/message.rs @@ -5,47 +5,50 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; -use rtfm::app; +use panic_semihosting as _; -#[app(device = lm3s6965)] -const APP: () = { +#[rtic::app(device = lm3s6965)] +mod app { #[init(spawn = [foo])] - fn init() { - spawn.foo(/* no message */).unwrap(); + fn init(c: init::Context) -> init::LateResources { + c.spawn.foo(/* no message */).unwrap(); + + init::LateResources {} } #[task(spawn = [bar])] - fn foo() { + fn foo(c: foo::Context) { static mut COUNT: u32 = 0; hprintln!("foo").unwrap(); - spawn.bar(*COUNT).unwrap(); + c.spawn.bar(*COUNT).unwrap(); *COUNT += 1; } #[task(spawn = [baz])] - fn bar(x: u32) { + fn bar(c: bar::Context, x: u32) { hprintln!("bar({})", x).unwrap(); - spawn.baz(x + 1, x + 2).unwrap(); + c.spawn.baz(x + 1, x + 2).unwrap(); } #[task(spawn = [foo])] - fn baz(x: u32, y: u32) { + fn baz(c: baz::Context, x: u32, y: u32) { hprintln!("baz({}, {})", x, y).unwrap(); if x + y > 4 { debug::exit(debug::EXIT_SUCCESS); } - spawn.foo().unwrap(); + c.spawn.foo().unwrap(); } + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. extern "C" { - fn UART0(); + fn SSI0(); } -}; +} diff --git a/examples/not-send.rs b/examples/not-send.rs index be78c33..18071fc 100644 --- a/examples/not-send.rs +++ b/examples/not-send.rs @@ -5,54 +5,64 @@ #![no_main] #![no_std] -extern crate panic_halt; - use core::marker::PhantomData; use cortex_m_semihosting::debug; -use rtfm::app; +use panic_halt as _; +use rtic::app; pub struct NotSend { _0: PhantomData<*const ()>, } #[app(device = lm3s6965)] -const APP: () = { - static mut SHARED: Option<NotSend> = None; +mod app { + use super::NotSend; + + #[resources] + struct Resources { + #[init(None)] + shared: Option<NotSend>, + } #[init(spawn = [baz, quux])] - fn init() { - spawn.baz().unwrap(); - spawn.quux().unwrap(); + fn init(c: init::Context) -> init::LateResources { + c.spawn.baz().unwrap(); + c.spawn.quux().unwrap(); + + init::LateResources {} } #[task(spawn = [bar])] - fn foo() { + fn foo(c: foo::Context) { // scenario 1: message passed to task that runs at the same priority - spawn.bar(NotSend { _0: PhantomData }).ok(); + c.spawn.bar(NotSend { _0: PhantomData }).ok(); } #[task] - fn bar(_x: NotSend) { + fn bar(_: bar::Context, _x: NotSend) { // scenario 1 } - #[task(priority = 2, resources = [SHARED])] - fn baz() { + #[task(priority = 2, resources = [shared])] + fn baz(c: baz::Context) { // scenario 2: resource shared between tasks that run at the same priority - *resources.SHARED = Some(NotSend { _0: PhantomData }); + *c.resources.shared = Some(NotSend { _0: PhantomData }); } - #[task(priority = 2, resources = [SHARED])] - fn quux() { + #[task(priority = 2, resources = [shared])] + fn quux(c: quux::Context) { // scenario 2 - let _not_send = resources.SHARED.take().unwrap(); + let _not_send = c.resources.shared.take().unwrap(); debug::exit(debug::EXIT_SUCCESS); } + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. extern "C" { - fn UART0(); - fn UART1(); + fn SSI0(); + fn QEI0(); } -}; +} diff --git a/examples/not-sync.rs b/examples/not-sync.rs index d94e0a0..75412e6 100644 --- a/examples/not-sync.rs +++ b/examples/not-sync.rs @@ -5,37 +5,47 @@ #![no_main] #![no_std] -extern crate panic_halt; - use core::marker::PhantomData; use cortex_m_semihosting::debug; -use rtfm::app; +use panic_halt as _; pub struct NotSync { _0: PhantomData<*const ()>, } -#[app(device = lm3s6965)] -const APP: () = { - static SHARED: NotSync = NotSync { _0: PhantomData }; +#[rtic::app(device = lm3s6965)] +mod app { + use super::NotSync; + use core::marker::PhantomData; + + #[resources] + struct Resources { + #[init(NotSync { _0: PhantomData })] + shared: NotSync, + } #[init] - fn init() { + fn init(_: init::Context) -> init::LateResources { debug::exit(debug::EXIT_SUCCESS); + + init::LateResources {} } - #[task(resources = [SHARED])] - fn foo() { - let _: &NotSync = resources.SHARED; + #[task(resources = [&shared])] + fn foo(c: foo::Context) { + let _: &NotSync = c.resources.shared; } - #[task(resources = [SHARED])] - fn bar() { - let _: &NotSync = resources.SHARED; + #[task(resources = [&shared])] + fn bar(c: bar::Context) { + let _: &NotSync = c.resources.shared; } + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. extern "C" { - fn UART0(); + fn SSI0(); } -}; +} diff --git a/examples/only-shared-access.rs b/examples/only-shared-access.rs new file mode 100644 index 0000000..91d0b7a --- /dev/null +++ b/examples/only-shared-access.rs @@ -0,0 +1,39 @@ +//! examples/static.rs + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m_semihosting::{debug, hprintln}; +use lm3s6965::Interrupt; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[resources] + struct Resources { + key: u32, + } + + #[init] + fn init(_: init::Context) -> init::LateResources { + rtic::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART1); + + init::LateResources { key: 0xdeadbeef } + } + + #[task(binds = UART0, resources = [&key])] + fn uart0(cx: uart0::Context) { + let key: &u32 = cx.resources.key; + hprintln!("UART0(key = {:#x})", key).unwrap(); + + debug::exit(debug::EXIT_SUCCESS); + } + + #[task(binds = UART1, priority = 2, resources = [&key])] + fn uart1(cx: uart1::Context) { + hprintln!("UART1(key = {:#x})", cx.resources.key).unwrap(); + } +} diff --git a/examples/periodic.rs b/examples/periodic.rs index ba2b493..d3aedd3 100644 --- a/examples/periodic.rs +++ b/examples/periodic.rs @@ -5,30 +5,37 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::hprintln; -use rtfm::{app, Instant}; +use panic_semihosting as _; +use rtic::cyccnt::{Instant, U32Ext}; const PERIOD: u32 = 8_000_000; // NOTE: does NOT work on QEMU! -#[app(device = lm3s6965)] -const APP: () = { +#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] +mod app { + #[init(schedule = [foo])] - fn init() { - schedule.foo(Instant::now() + PERIOD.cycles()).unwrap(); + fn init(cx: init::Context) -> init::LateResources { + // omitted: initialization of `CYCCNT` + + cx.schedule.foo(cx.start + PERIOD.cycles()).unwrap(); + + init::LateResources {} } #[task(schedule = [foo])] - fn foo() { + fn foo(cx: foo::Context) { let now = Instant::now(); - hprintln!("foo(scheduled = {:?}, now = {:?})", scheduled, now).unwrap(); + hprintln!("foo(scheduled = {:?}, now = {:?})", cx.scheduled, now).unwrap(); - schedule.foo(scheduled + PERIOD.cycles()).unwrap(); + cx.schedule.foo(cx.scheduled + PERIOD.cycles()).unwrap(); } + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. extern "C" { - fn UART0(); + fn SSI0(); } -}; +} diff --git a/examples/peripherals-taken.rs b/examples/peripherals-taken.rs new file mode 100644 index 0000000..09f9242 --- /dev/null +++ b/examples/peripherals-taken.rs @@ -0,0 +1,18 @@ +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m_semihosting::debug; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[init] + fn init(_: init::Context) -> init::LateResources { + assert!(cortex_m::Peripherals::take().is_none()); + debug::exit(debug::EXIT_SUCCESS); + + init::LateResources {} + } +} diff --git a/examples/pool.rs b/examples/pool.rs new file mode 100644 index 0000000..cdbabca --- /dev/null +++ b/examples/pool.rs @@ -0,0 +1,76 @@ +//! examples/pool.rs + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m_semihosting::{debug, hprintln}; +use heapless::{ + pool, + pool::singleton::{Box, Pool}, +}; +use lm3s6965::Interrupt; +use panic_semihosting as _; +use rtic::app; + +// Declare a pool of 128-byte memory blocks +pool!(P: [u8; 128]); + +#[app(device = lm3s6965)] +mod app { + use crate::Box; + + // Import the memory pool into scope + use super::P; + + #[init] + fn init(_: init::Context) -> init::LateResources { + static mut MEMORY: [u8; 512] = [0; 512]; + + // Increase the capacity of the memory pool by ~4 + P::grow(MEMORY); + + rtic::pend(Interrupt::I2C0); + + init::LateResources {} + } + + #[task(binds = I2C0, priority = 2, spawn = [foo, bar])] + fn i2c0(c: i2c0::Context) { + // claim a memory block, leave it uninitialized and .. + let x = P::alloc().unwrap().freeze(); + + // .. send it to the `foo` task + c.spawn.foo(x).ok().unwrap(); + + // send another block to the task `bar` + c.spawn.bar(P::alloc().unwrap().freeze()).ok().unwrap(); + } + + #[task] + fn foo(_: foo::Context, x: Box<P>) { + hprintln!("foo({:?})", x.as_ptr()).unwrap(); + + // explicitly return the block to the pool + drop(x); + + debug::exit(debug::EXIT_SUCCESS); + } + + #[task(priority = 2)] + fn bar(_: bar::Context, x: Box<P>) { + hprintln!("bar({:?})", x.as_ptr()).unwrap(); + + // this is done automatically so we can omit the call to `drop` + // drop(x); + } + + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. + extern "C" { + fn SSI0(); + fn QEI0(); + } +} diff --git a/examples/preempt.rs b/examples/preempt.rs new file mode 100644 index 0000000..f6fc4b0 --- /dev/null +++ b/examples/preempt.rs @@ -0,0 +1,39 @@ +//! examples/preempt.rs + +#![no_main] +#![no_std] + +use cortex_m_semihosting::{debug, hprintln}; +use lm3s6965::Interrupt; +use panic_semihosting as _; +use rtic::app; + +#[app(device = lm3s6965)] +mod app { + #[init] + fn init(_: init::Context) -> init::LateResources { + rtic::pend(Interrupt::GPIOA); + + init::LateResources {} + } + + #[task(binds = GPIOA, priority = 1)] + fn gpioa(_: gpioa::Context) { + hprintln!("GPIOA - start").unwrap(); + rtic::pend(Interrupt::GPIOC); + hprintln!("GPIOA - end").unwrap(); + debug::exit(debug::EXIT_SUCCESS); + } + + #[task(binds = GPIOB, priority = 2)] + fn gpiob(_: gpiob::Context) { + hprintln!(" GPIOB").unwrap(); + } + + #[task(binds = GPIOC, priority = 2)] + fn gpioc(_: gpioc::Context) { + hprintln!(" GPIOC - start").unwrap(); + rtic::pend(Interrupt::GPIOB); + hprintln!(" GPIOC - end").unwrap(); + } +} diff --git a/examples/ramfunc.rs b/examples/ramfunc.rs index 37ea82a..5ff167a 100644 --- a/examples/ramfunc.rs +++ b/examples/ramfunc.rs @@ -5,21 +5,21 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; -use rtfm::app; +use panic_semihosting as _; -#[app(device = lm3s6965)] -const APP: () = { +#[rtic::app(device = lm3s6965)] +mod app { #[init(spawn = [bar])] - fn init() { - spawn.bar().unwrap(); + fn init(c: init::Context) -> init::LateResources { + c.spawn.bar().unwrap(); + + init::LateResources {} } #[inline(never)] #[task] - fn foo() { + fn foo(_: foo::Context) { hprintln!("foo").unwrap(); debug::exit(debug::EXIT_SUCCESS); @@ -29,8 +29,8 @@ const APP: () = { #[inline(never)] #[link_section = ".data.bar"] #[task(priority = 2, spawn = [foo])] - fn bar() { - spawn.foo().unwrap(); + fn bar(c: bar::Context) { + c.spawn.foo().unwrap(); } extern "C" { @@ -40,4 +40,4 @@ const APP: () = { #[link_section = ".data.UART1"] fn UART1(); } -}; +} diff --git a/examples/resource-user-struct.rs b/examples/resource-user-struct.rs new file mode 100644 index 0000000..a5bd0dd --- /dev/null +++ b/examples/resource-user-struct.rs @@ -0,0 +1,63 @@ +//! examples/resource.rs + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m_semihosting::{debug, hprintln}; +use lm3s6965::Interrupt; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[resources] + struct Resources { + // A resource + #[init(0)] + shared: u32, + } + + // Should not collide with the struct above + #[allow(dead_code)] + struct Resources2 { + // A resource + shared: u32, + } + + #[init] + fn init(_: init::Context) -> init::LateResources { + rtic::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART1); + + init::LateResources {} + } + + // `shared` cannot be accessed from this context + #[idle] + fn idle(_cx: idle::Context) -> ! { + debug::exit(debug::EXIT_SUCCESS); + + // error: no `resources` field in `idle::Context` + // _cx.resources.shared += 1; + + loop {} + } + + // `shared` can be accessed from this context + #[task(binds = UART0, resources = [shared])] + fn uart0(cx: uart0::Context) { + let shared: &mut u32 = cx.resources.shared; + *shared += 1; + + hprintln!("UART0: shared = {}", shared).unwrap(); + } + + // `shared` can be accessed from this context + #[task(binds = UART1, resources = [shared])] + fn uart1(cx: uart1::Context) { + *cx.resources.shared += 1; + + hprintln!("UART1: shared = {}", cx.resources.shared).unwrap(); + } +} diff --git a/examples/resource.rs b/examples/resource.rs index 5ddab9e..273af26 100644 --- a/examples/resource.rs +++ b/examples/resource.rs @@ -5,46 +5,54 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; use lm3s6965::Interrupt; -use rtfm::app; - -#[app(device = lm3s6965)] -const APP: () = { - // A resource - static mut SHARED: u32 = 0; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[resources] + struct Resources { + // A resource + #[init(0)] + shared: u32, + } #[init] - fn init() { - rtfm::pend(Interrupt::UART0); - rtfm::pend(Interrupt::UART1); + fn init(_: init::Context) -> init::LateResources { + rtic::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART1); + + init::LateResources {} } + // `shared` cannot be accessed from this context #[idle] - fn idle() -> ! { + fn idle(_cx: idle::Context) -> ! { debug::exit(debug::EXIT_SUCCESS); - // error: `SHARED` can't be accessed from this context - // SHARED += 1; + // error: no `resources` field in `idle::Context` + // _cx.resources.shared += 1; - loop {} + loop { + cortex_m::asm::nop(); + } } - // `SHARED` can be access from this context - #[interrupt(resources = [SHARED])] - fn UART0() { - *resources.SHARED += 1; + // `shared` can be accessed from this context + #[task(binds = UART0, resources = [shared])] + fn uart0(cx: uart0::Context) { + let shared: &mut u32 = cx.resources.shared; + *shared += 1; - hprintln!("UART0: SHARED = {}", resources.SHARED).unwrap(); + hprintln!("UART0: shared = {}", shared).unwrap(); } - // `SHARED` can be access from this context - #[interrupt(resources = [SHARED])] - fn UART1() { - *resources.SHARED += 1; + // `shared` can be accessed from this context + #[task(binds = UART1, resources = [shared])] + fn uart1(cx: uart1::Context) { + *cx.resources.shared += 1; - hprintln!("UART1: SHARED = {}", resources.SHARED).unwrap(); + hprintln!("UART1: shared = {}", cx.resources.shared).unwrap(); } -}; +} diff --git a/examples/schedule.rs b/examples/schedule.rs index fd63347..7e6adc1 100644 --- a/examples/schedule.rs +++ b/examples/schedule.rs @@ -5,38 +5,51 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - +use cortex_m::peripheral::DWT; use cortex_m_semihosting::hprintln; -use rtfm::{app, Instant}; +use panic_halt as _; +use rtic::cyccnt::{Instant, U32Ext as _}; // NOTE: does NOT work on QEMU! -#[app(device = lm3s6965)] -const APP: () = { +#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] +mod app { #[init(schedule = [foo, bar])] - fn init() { - let now = Instant::now(); + fn init(mut cx: init::Context) -> init::LateResources { + // Initialize (enable) the monotonic timer (CYCCNT) + cx.core.DCB.enable_trace(); + // required on Cortex-M7 devices that software lock the DWT (e.g. STM32F7) + DWT::unlock(); + cx.core.DWT.enable_cycle_counter(); + + // semantically, the monotonic timer is frozen at time "zero" during `init` + // NOTE do *not* call `Instant::now` in this context; it will return a nonsense value + let now = cx.start; // the start time of the system hprintln!("init @ {:?}", now).unwrap(); // Schedule `foo` to run 8e6 cycles (clock cycles) in the future - schedule.foo(now + 8_000_000.cycles()).unwrap(); + cx.schedule.foo(now + 8_000_000.cycles()).unwrap(); // Schedule `bar` to run 4e6 cycles in the future - schedule.bar(now + 4_000_000.cycles()).unwrap(); + cx.schedule.bar(now + 4_000_000.cycles()).unwrap(); + + init::LateResources {} } #[task] - fn foo() { + fn foo(_: foo::Context) { hprintln!("foo @ {:?}", Instant::now()).unwrap(); } #[task] - fn bar() { + fn bar(_: bar::Context) { hprintln!("bar @ {:?}", Instant::now()).unwrap(); } + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. extern "C" { - fn UART0(); + fn SSI0(); } -}; +} diff --git a/examples/shared-with-init.rs b/examples/shared-with-init.rs new file mode 100644 index 0000000..85c7276 --- /dev/null +++ b/examples/shared-with-init.rs @@ -0,0 +1,45 @@ +//! `examples/shared-with-init.rs` + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m_semihosting::debug; +use lm3s6965::Interrupt; +use panic_halt as _; +use rtic::app; + +pub struct MustBeSend; + +#[app(device = lm3s6965)] +mod app { + use super::MustBeSend; + + #[resources] + struct Resources { + #[init(None)] + shared: Option<MustBeSend>, + } + + #[init(resources = [shared])] + fn init(c: init::Context) -> init::LateResources { + // this `message` will be sent to task `UART0` + let message = MustBeSend; + *c.resources.shared = Some(message); + + rtic::pend(Interrupt::UART0); + + init::LateResources {} + } + + #[task(binds = UART0, resources = [shared])] + fn uart0(c: uart0::Context) { + if let Some(message) = c.resources.shared.take() { + // `message` has been received + drop(message); + + debug::exit(debug::EXIT_SUCCESS); + } + } +} diff --git a/examples/singleton.rs b/examples/singleton.rs deleted file mode 100644 index 9e48e54..0000000 --- a/examples/singleton.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! examples/singleton.rs - -#![deny(unsafe_code)] -#![deny(warnings)] -#![no_main] -#![no_std] - -extern crate panic_semihosting; - -use alloc_singleton::stable::pool::{Box, Pool}; -use cortex_m_semihosting::{debug, hprintln}; -use lm3s6965::Interrupt; -use rtfm::app; - -#[app(device = lm3s6965)] -const APP: () = { - #[Singleton(Send)] - static mut M: [u32; 2] = [0; 2]; - - static mut P: Pool<M> = (); - - #[init(resources = [M])] - fn init() -> init::LateResources { - rtfm::pend(Interrupt::I2C0); - - init::LateResources { - P: Pool::new(resources.M), - } - } - - #[interrupt( - priority = 2, - resources = [P], - spawn = [foo, bar], - )] - fn I2C0() { - spawn.foo(resources.P.alloc(1).unwrap()).unwrap(); - spawn.bar(resources.P.alloc(2).unwrap()).unwrap(); - } - - #[task(resources = [P])] - fn foo(x: Box<M>) { - hprintln!("foo({})", x).unwrap(); - - resources.P.lock(|p| p.dealloc(x)); - - debug::exit(debug::EXIT_SUCCESS); - } - - #[task(priority = 2, resources = [P])] - fn bar(x: Box<M>) { - hprintln!("bar({})", x).unwrap(); - - resources.P.dealloc(x); - } - - extern "C" { - fn UART0(); - fn UART1(); - } -}; diff --git a/examples/smallest.rs b/examples/smallest.rs index e4d86be..b8cbf87 100644 --- a/examples/smallest.rs +++ b/examples/smallest.rs @@ -1,17 +1,10 @@ //! examples/smallest.rs -#![deny(unsafe_code)] -#![deny(warnings)] #![no_main] #![no_std] -// panic-handler crate -extern crate panic_semihosting; - -use rtfm::app; +use panic_semihosting as _; // panic handler +use rtic::app; #[app(device = lm3s6965)] -const APP: () = { - #[init] - fn init() {} -}; +mod app {} diff --git a/examples/static.rs b/examples/static.rs deleted file mode 100644 index 0309b68..0000000 --- a/examples/static.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! examples/static.rs - -#![deny(unsafe_code)] -#![deny(warnings)] -#![no_main] -#![no_std] - -extern crate panic_semihosting; - -use cortex_m_semihosting::{debug, hprintln}; -use lm3s6965::Interrupt; -use rtfm::app; - -#[app(device = lm3s6965)] -const APP: () = { - static KEY: u32 = (); - - #[init] - fn init() -> init::LateResources { - rtfm::pend(Interrupt::UART0); - rtfm::pend(Interrupt::UART1); - - init::LateResources { KEY: 0xdeadbeef } - } - - #[interrupt(resources = [KEY])] - fn UART0() { - hprintln!("UART0(KEY = {:#x})", resources.KEY).unwrap(); - - debug::exit(debug::EXIT_SUCCESS); - } - - #[interrupt(priority = 2, resources = [KEY])] - fn UART1() { - hprintln!("UART1(KEY = {:#x})", resources.KEY).unwrap(); - } -}; diff --git a/examples/t-binds.rs b/examples/t-binds.rs new file mode 100644 index 0000000..3ca4c66 --- /dev/null +++ b/examples/t-binds.rs @@ -0,0 +1,34 @@ +//! [compile-pass] Check that `binds` works as advertised + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use panic_halt as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[init] + fn init(_: init::Context) -> init::LateResources { + init::LateResources {} + } + + // Cortex-M exception + #[task(binds = SVCall)] + fn foo(c: foo::Context) { + foo_trampoline(c) + } + + // LM3S6965 interrupt + #[task(binds = UART0)] + fn bar(c: bar::Context) { + bar_trampoline(c) + } +} + +#[allow(dead_code)] +fn foo_trampoline(_: foo::Context) {} + +#[allow(dead_code)] +fn bar_trampoline(_: bar::Context) {} diff --git a/examples/t-cfg-resources.rs b/examples/t-cfg-resources.rs new file mode 100644 index 0000000..61eb4c7 --- /dev/null +++ b/examples/t-cfg-resources.rs @@ -0,0 +1,36 @@ +//! [compile-pass] check that `#[cfg]` attributes applied on resources work +//! +#![no_main] +#![no_std] + +use panic_halt as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[resources] + struct Resources { + // A resource + #[init(0)] + shared: u32, + // A conditionally compiled resource behind feature_x + #[cfg(feature = "feature_x")] + x: u32, + dummy: (), // dummy such that we have at least one late resource + } + #[init] + fn init(_: init::Context) -> init::LateResources { + init::LateResources { + // The feature needs to be applied everywhere x is defined or used + #[cfg(feature = "feature_x")] + x: 0, + dummy: (), // dummy such that we have at least one late resource + } + } + + #[idle] + fn idle(_cx: idle::Context) -> ! { + loop { + cortex_m::asm::nop(); + } + } +} diff --git a/examples/t-cfg.rs b/examples/t-cfg.rs new file mode 100644 index 0000000..3da20d4 --- /dev/null +++ b/examples/t-cfg.rs @@ -0,0 +1,58 @@ +//! [compile-pass] check that `#[cfg]` attributes are respected + +#![no_main] +#![no_std] + +use panic_halt as _; + +#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] +mod app { + #[resources] + struct Resources { + #[cfg(never)] + #[init(0)] + foo: u32, + } + + #[init] + fn init(_: init::Context) -> init::LateResources { + #[cfg(never)] + static mut BAR: u32 = 0; + + init::LateResources {} + } + + #[idle] + fn idle(_: idle::Context) -> ! { + #[cfg(never)] + static mut BAR: u32 = 0; + + loop { + cortex_m::asm::nop(); + } + } + + #[task(resources = [foo], schedule = [quux], spawn = [quux])] + fn foo(_: foo::Context) { + #[cfg(never)] + static mut BAR: u32 = 0; + } + + #[task(priority = 3, resources = [foo], schedule = [quux], spawn = [quux])] + fn bar(_: bar::Context) { + #[cfg(never)] + static mut BAR: u32 = 0; + } + + #[cfg(never)] + #[task] + fn quux(_: quux::Context) {} + + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. + extern "C" { + fn SSI0(); + fn QEI0(); + } +} diff --git a/examples/t-htask-main.rs b/examples/t-htask-main.rs new file mode 100644 index 0000000..1e38e31 --- /dev/null +++ b/examples/t-htask-main.rs @@ -0,0 +1,22 @@ +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m_semihosting::debug; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[init] + fn init(_: init::Context) -> init::LateResources { + rtic::pend(lm3s6965::Interrupt::UART0); + + init::LateResources {} + } + + #[task(binds = UART0)] + fn taskmain(_: taskmain::Context) { + debug::exit(debug::EXIT_SUCCESS); + } +} diff --git a/examples/t-idle-main.rs b/examples/t-idle-main.rs new file mode 100644 index 0000000..9078628 --- /dev/null +++ b/examples/t-idle-main.rs @@ -0,0 +1,23 @@ +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m_semihosting::debug; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[init] + fn init(_: init::Context) -> init::LateResources { + init::LateResources {} + } + + #[idle] + fn taskmain(_: taskmain::Context) -> ! { + debug::exit(debug::EXIT_SUCCESS); + loop { + cortex_m::asm::nop(); + } + } +} diff --git a/examples/t-init-main.rs b/examples/t-init-main.rs new file mode 100644 index 0000000..7c23cc8 --- /dev/null +++ b/examples/t-init-main.rs @@ -0,0 +1,17 @@ +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m_semihosting::debug; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[init] + fn init(_: init::Context) -> init::LateResources { + debug::exit(debug::EXIT_SUCCESS); + + init::LateResources {} + } +} diff --git a/examples/t-late-not-send.rs b/examples/t-late-not-send.rs new file mode 100644 index 0000000..345d9ae --- /dev/null +++ b/examples/t-late-not-send.rs @@ -0,0 +1,41 @@ +//! [compile-pass] late resources don't need to be `Send` if they are owned by `idle` + +#![no_main] +#![no_std] + +use core::marker::PhantomData; + +use panic_halt as _; + +pub struct NotSend { + _0: PhantomData<*const ()>, +} + +#[rtic::app(device = lm3s6965)] +mod app { + use super::NotSend; + + #[resources] + struct Resources { + x: NotSend, + #[init(None)] + y: Option<NotSend>, + } + + #[init(resources = [y])] + fn init(c: init::Context) -> init::LateResources { + // equivalent to late resource initialization + *c.resources.y = Some(NotSend { _0: PhantomData }); + + init::LateResources { + x: NotSend { _0: PhantomData }, + } + } + + #[idle(resources = [x, y])] + fn idle(_: idle::Context) -> ! { + loop { + cortex_m::asm::nop(); + } + } +} diff --git a/examples/t-resource.rs b/examples/t-resource.rs new file mode 100644 index 0000000..91950d3 --- /dev/null +++ b/examples/t-resource.rs @@ -0,0 +1,92 @@ +//! [compile-pass] Check code generation of resources + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use panic_halt as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[resources] + struct Resources { + #[init(0)] + o1: u32, // init + #[init(0)] + o2: u32, // idle + #[init(0)] + o3: u32, // EXTI0 + #[init(0)] + o4: u32, // idle + #[init(0)] + o5: u32, // EXTI1 + #[init(0)] + o6: u32, // init + #[init(0)] + s1: u32, // idle & uart0 + #[init(0)] + s2: u32, // uart0 & uart1 + #[init(0)] + s3: u32, // idle & uart0 + } + + #[init(resources = [o1, o4, o5, o6, s3])] + fn init(c: init::Context) -> init::LateResources { + // owned by `init` == `&'static mut` + let _: &'static mut u32 = c.resources.o1; + + // owned by `init` == `&'static` if read-only + let _: &'static u32 = c.resources.o6; + + // `init` has exclusive access to all resources + let _: &mut u32 = c.resources.o4; + let _: &mut u32 = c.resources.o5; + let _: &mut u32 = c.resources.s3; + + init::LateResources {} + } + + #[idle(resources = [o2, &o4, s1, &s3])] + fn idle(mut c: idle::Context) -> ! { + // owned by `idle` == `&'static mut` + let _: &'static mut u32 = c.resources.o2; + + // owned by `idle` == `&'static` if read-only + let _: &'static u32 = c.resources.o4; + + // shared with `idle` == `Mutex` + c.resources.s1.lock(|_| {}); + + // `&` if read-only + let _: &u32 = c.resources.s3; + + loop { + cortex_m::asm::nop(); + } + } + + #[task(binds = UART0, resources = [o3, s1, s2, &s3])] + fn uart0(c: uart0::Context) { + // owned by interrupt == `&mut` + let _: &mut u32 = c.resources.o3; + + // no `Mutex` proxy when access from highest priority task + let _: &mut u32 = c.resources.s1; + + // no `Mutex` proxy when co-owned by cooperative (same priority) tasks + let _: &mut u32 = c.resources.s2; + + // `&` if read-only + let _: &u32 = c.resources.s3; + } + + #[task(binds = UART1, resources = [s2, &o5])] + fn uart1(c: uart1::Context) { + // owned by interrupt == `&` if read-only + let _: &u32 = c.resources.o5; + + // no `Mutex` proxy when co-owned by cooperative (same priority) tasks + let _: &mut u32 = c.resources.s2; + } +} diff --git a/examples/t-schedule.rs b/examples/t-schedule.rs new file mode 100644 index 0000000..d5a6d3f --- /dev/null +++ b/examples/t-schedule.rs @@ -0,0 +1,66 @@ +//! [compile-pass] Check `schedule` code generation + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use panic_halt as _; +use rtic::cyccnt::{Instant, U32Ext as _}; + +#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] +mod app { + #[init(schedule = [foo, bar, baz])] + fn init(c: init::Context) -> init::LateResources { + let _: Result<(), ()> = c.schedule.foo(c.start + 10.cycles()); + let _: Result<(), u32> = c.schedule.bar(c.start + 20.cycles(), 0); + let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 30.cycles(), 0, 1); + + init::LateResources {} + } + + #[idle(schedule = [foo, bar, baz])] + fn idle(c: idle::Context) -> ! { + let _: Result<(), ()> = c.schedule.foo(Instant::now() + 40.cycles()); + let _: Result<(), u32> = c.schedule.bar(Instant::now() + 50.cycles(), 0); + let _: Result<(), (u32, u32)> = c.schedule.baz(Instant::now() + 60.cycles(), 0, 1); + + loop { + cortex_m::asm::nop(); + } + } + + #[task(binds = SVCall, schedule = [foo, bar, baz])] + fn svcall(c: svcall::Context) { + let _: Result<(), ()> = c.schedule.foo(c.start + 70.cycles()); + let _: Result<(), u32> = c.schedule.bar(c.start + 80.cycles(), 0); + let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 90.cycles(), 0, 1); + } + + #[task(binds = UART0, schedule = [foo, bar, baz])] + fn uart0(c: uart0::Context) { + let _: Result<(), ()> = c.schedule.foo(c.start + 100.cycles()); + let _: Result<(), u32> = c.schedule.bar(c.start + 110.cycles(), 0); + let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 120.cycles(), 0, 1); + } + + #[task(schedule = [foo, bar, baz])] + fn foo(c: foo::Context) { + let _: Result<(), ()> = c.schedule.foo(c.scheduled + 130.cycles()); + let _: Result<(), u32> = c.schedule.bar(c.scheduled + 140.cycles(), 0); + let _: Result<(), (u32, u32)> = c.schedule.baz(c.scheduled + 150.cycles(), 0, 1); + } + + #[task] + fn bar(_: bar::Context, _x: u32) {} + + #[task] + fn baz(_: baz::Context, _x: u32, _y: u32) {} + + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. + extern "C" { + fn SSI0(); + } +} diff --git a/examples/t-spawn.rs b/examples/t-spawn.rs new file mode 100644 index 0000000..efb748b --- /dev/null +++ b/examples/t-spawn.rs @@ -0,0 +1,65 @@ +//! [compile-pass] Check code generation of `spawn` + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use panic_halt as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[init(spawn = [foo, bar, baz])] + fn init(c: init::Context) -> init::LateResources { + let _: Result<(), ()> = c.spawn.foo(); + let _: Result<(), u32> = c.spawn.bar(0); + let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1); + + init::LateResources {} + } + + #[idle(spawn = [foo, bar, baz])] + fn idle(c: idle::Context) -> ! { + let _: Result<(), ()> = c.spawn.foo(); + let _: Result<(), u32> = c.spawn.bar(0); + let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1); + + loop { + cortex_m::asm::nop(); + } + } + + #[task(binds = SVCall, spawn = [foo, bar, baz])] + fn svcall(c: svcall::Context) { + let _: Result<(), ()> = c.spawn.foo(); + let _: Result<(), u32> = c.spawn.bar(0); + let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1); + } + + #[task(binds = UART0, spawn = [foo, bar, baz])] + fn uart0(c: uart0::Context) { + let _: Result<(), ()> = c.spawn.foo(); + let _: Result<(), u32> = c.spawn.bar(0); + let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1); + } + + #[task(spawn = [foo, bar, baz])] + fn foo(c: foo::Context) { + let _: Result<(), ()> = c.spawn.foo(); + let _: Result<(), u32> = c.spawn.bar(0); + let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1); + } + + #[task] + fn bar(_: bar::Context, _x: u32) {} + + #[task] + fn baz(_: baz::Context, _x: u32, _y: u32) {} + + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. + extern "C" { + fn SSI0(); + } +} diff --git a/examples/t-stask-main.rs b/examples/t-stask-main.rs new file mode 100644 index 0000000..74335c1 --- /dev/null +++ b/examples/t-stask-main.rs @@ -0,0 +1,29 @@ +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m_semihosting::debug; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[init(spawn = [taskmain])] + fn init(cx: init::Context) -> init::LateResources { + cx.spawn.taskmain().ok(); + + init::LateResources {} + } + + #[task] + fn taskmain(_: taskmain::Context) { + debug::exit(debug::EXIT_SUCCESS); + } + + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. + extern "C" { + fn SSI0(); + } +} diff --git a/examples/task.rs b/examples/task.rs index 4f168bb..80a9c43 100644 --- a/examples/task.rs +++ b/examples/task.rs @@ -5,47 +5,53 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::{debug, hprintln}; -use rtfm::app; +use panic_semihosting as _; -#[app(device = lm3s6965)] -const APP: () = { +#[rtic::app(device = lm3s6965)] +mod app { #[init(spawn = [foo])] - fn init() { - spawn.foo().unwrap(); + fn init(c: init::Context) -> init::LateResources { + c.spawn.foo().unwrap(); + + init::LateResources {} } #[task(spawn = [bar, baz])] - fn foo() { - hprintln!("foo").unwrap(); + fn foo(c: foo::Context) { + hprintln!("foo - start").unwrap(); // spawns `bar` onto the task scheduler // `foo` and `bar` have the same priority so `bar` will not run until // after `foo` terminates - spawn.bar().unwrap(); + c.spawn.bar().unwrap(); + + hprintln!("foo - middle").unwrap(); // spawns `baz` onto the task scheduler // `baz` has higher priority than `foo` so it immediately preempts `foo` - spawn.baz().unwrap(); + c.spawn.baz().unwrap(); + + hprintln!("foo - end").unwrap(); } #[task] - fn bar() { + fn bar(_: bar::Context) { hprintln!("bar").unwrap(); debug::exit(debug::EXIT_SUCCESS); } #[task(priority = 2)] - fn baz() { + fn baz(_: baz::Context) { hprintln!("baz").unwrap(); } - // Interrupt handlers used to dispatch software tasks + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. extern "C" { - fn UART0(); - fn UART1(); + fn SSI0(); + fn QEI0(); } -}; +} diff --git a/examples/types.rs b/examples/types.rs index c1b8cd6..251d004 100644 --- a/examples/types.rs +++ b/examples/types.rs @@ -5,51 +5,62 @@ #![no_main] #![no_std] -extern crate panic_semihosting; - use cortex_m_semihosting::debug; -use rtfm::{app, Exclusive, Instant}; +use panic_semihosting as _; +use rtic::cyccnt; -#[app(device = lm3s6965)] -const APP: () = { - static mut SHARED: u32 = 0; +#[rtic::app(device = lm3s6965, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] +mod app { + #[resources] + struct Resources { + #[init(0)] + shared: u32, + } #[init(schedule = [foo], spawn = [foo])] - fn init() { - let _: Instant = start; - let _: rtfm::Peripherals = core; - let _: lm3s6965::Peripherals = device; - let _: init::Schedule = schedule; - let _: init::Spawn = spawn; + fn init(cx: init::Context) -> init::LateResources { + let _: cyccnt::Instant = cx.start; + let _: rtic::Peripherals = cx.core; + let _: lm3s6965::Peripherals = cx.device; + let _: init::Schedule = cx.schedule; + let _: init::Spawn = cx.spawn; debug::exit(debug::EXIT_SUCCESS); + + init::LateResources {} } - #[exception(schedule = [foo], spawn = [foo])] - fn SVCall() { - let _: Instant = start; - let _: SVCall::Schedule = schedule; - let _: SVCall::Spawn = spawn; + #[idle(schedule = [foo], spawn = [foo])] + fn idle(cx: idle::Context) -> ! { + let _: idle::Schedule = cx.schedule; + let _: idle::Spawn = cx.spawn; + + loop { + cortex_m::asm::nop(); + } } - #[interrupt(resources = [SHARED], schedule = [foo], spawn = [foo])] - fn UART0() { - let _: Instant = start; - let _: resources::SHARED = resources.SHARED; - let _: UART0::Schedule = schedule; - let _: UART0::Spawn = spawn; + #[task(binds = UART0, resources = [shared], schedule = [foo], spawn = [foo])] + fn uart0(cx: uart0::Context) { + let _: cyccnt::Instant = cx.start; + let _: resources::shared = cx.resources.shared; + let _: uart0::Schedule = cx.schedule; + let _: uart0::Spawn = cx.spawn; } - #[task(priority = 2, resources = [SHARED], schedule = [foo], spawn = [foo])] - fn foo() { - let _: Instant = scheduled; - let _: Exclusive<u32> = resources.SHARED; - let _: foo::Resources = resources; - let _: foo::Schedule = schedule; - let _: foo::Spawn = spawn; + #[task(priority = 2, resources = [shared], schedule = [foo], spawn = [foo])] + fn foo(cx: foo::Context) { + let _: cyccnt::Instant = cx.scheduled; + let _: &mut u32 = cx.resources.shared; + let _: foo::Resources = cx.resources; + let _: foo::Schedule = cx.schedule; + let _: foo::Spawn = cx.spawn; } + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. extern "C" { - fn UART1(); + fn SSI0(); } -}; +} |
