From 16f8ea9ba7d0fed1c9f1622b2e9cbcdbbdd807f5 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 16:24:31 +0200 Subject: Fix this link --- book/en/src/internals/targets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'book/en/src') diff --git a/book/en/src/internals/targets.md b/book/en/src/internals/targets.md index 3562eef..67c6a59 100644 --- a/book/en/src/internals/targets.md +++ b/book/en/src/internals/targets.md @@ -29,7 +29,7 @@ Table 1 below shows a list of Cortex-m processors and which type of critical sec ## Priority Ceiling -This is covered by the [Resources][resources] page of this book. +This is covered by the [Resources](../by-example/resources.html) page of this book. ## Source Masking -- cgit v1.2.3 From 1dc2f80eb6cb6ac6d1eaede4169d8cabc51c5e7c Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 17:37:15 +0200 Subject: Begin migration guide --- book/en/src/SUMMARY.md | 12 +- book/en/src/migration/migration_v2.md | 16 ++ book/en/src/migration/migration_v2/async_tasks.md | 55 +++++ .../src/migration/migration_v2/complete_example.md | 245 +++++++++++++++++++++ book/en/src/migration/migration_v2/monotonics.md | 11 + book/en/src/migration/migration_v2/nightly.md | 5 + book/en/src/migration/migration_v2/rtic-sync.md | 1 + 7 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 book/en/src/migration/migration_v2.md create mode 100644 book/en/src/migration/migration_v2/async_tasks.md create mode 100644 book/en/src/migration/migration_v2/complete_example.md create mode 100644 book/en/src/migration/migration_v2/monotonics.md create mode 100644 book/en/src/migration/migration_v2/nightly.md create mode 100644 book/en/src/migration/migration_v2/rtic-sync.md (limited to 'book/en/src') diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index 587117c..ceed24e 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -24,6 +24,7 @@ - [RTIC vs. the world](./rtic_vs.md) - [Awesome RTIC examples](./awesome_rtic.md) @@ -43,4 +44,13 @@ - [Message passing & `capacity`](./by-example/message_passing.md) - [Task priorities](./by-example/app_priorities.md) - [Monotonic & `spawn_{at/after}`](./by-example/monotonic.md) - --> \ No newline at end of file + --> + +--- + +- [Migrating from v1.0.x to v2.0.0](./migration/migration_v2.md) + - [Rust Nightly & features](./migration/migration_v2/nightly.md) + - [Migrating to `rtic-monotonics`](./migration/migration_v2/monotonics.md) + - [Software tasks must now be `async`](./migration/migration_v2/async_tasks.md) + - [Using and understanding `rtic-sync`](./migration/migration_v2/rtic-sync.md) + - [A code example on migration](./migration/migration_v2/complete_example.md) \ No newline at end of file diff --git a/book/en/src/migration/migration_v2.md b/book/en/src/migration/migration_v2.md new file mode 100644 index 0000000..071d34c --- /dev/null +++ b/book/en/src/migration/migration_v2.md @@ -0,0 +1,16 @@ +# Migrating from v1.0.x to v2.0.0 + +Migrating a project from RTIC `v1.0.x` to `v2.0.0` involves the following steps: + +1. `v2.0.0` requires [`#![type_alias_impl_trait]`](https://github.com/rust-lang/rust/issues/63063) and Rust Nightly. +2. Migrating from the monotonics included in `v1.0.x` to `rtic-time` and `rtic-monotonics`, replacing `spawn_after`, `spawn_at`. +3. Software tasks are now required to be `async`, and using them correctly. +4. Understanding and using data types provided by `rtic-sync` to solve migration problems. + +If you wish to see a code example of changes required, you can check out [the full example migration page](./migration_v2/complete_example.md). + +## TL;DR +1. Add `#![type_alias_impl_trait]` to your crate, and use `cargo +nightly`. +2. Instead of `spawn_after` and `spawn_at`, you now use the `async` functions `delay`, `delay_until` (and related) with impls provided by `rtic-monotonics`. +3. Software tasks _must_ be `async fn`s now. Not returning from a task is allowed so long as there is an `await` in the task. You can still `lock` shared resources. +4. Use `rtic_sync::Arbiter` to `await` access to a shared resource, and `rtic-channel` to communicate between tasks instead of `spawn`-ing new ones. \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/async_tasks.md b/book/en/src/migration/migration_v2/async_tasks.md new file mode 100644 index 0000000..54e0893 --- /dev/null +++ b/book/en/src/migration/migration_v2/async_tasks.md @@ -0,0 +1,55 @@ +# Using `async` softare tasks. + +There have been a few changes to software tasks. They are outlined below. + +### Software tasks must now be `async`. + +All software tasks are now required to be `async`. + +#### Required changes. + +All of the tasks in your project that do not bind to an interrupt must now be an `async fn`. For example: + +``` rust +#[task( + local = [ some_resource ], + shared = [ my_shared_resource ], + priority = 2 +)] +fn my_task(cx: my_task::Context) { + cx.local.some_resource.do_trick(); + cx.shared.my_shared_resource.lock(|s| s.do_shared_thing()); +} +``` + +becomes + +``` rust +#[task( + local = [ some_resource ], + shared = [ my_shared_resource ], + priority = 2 +)] +async fn my_task(cx: my_task::Context) { + cx.local.some_resource.do_trick(); + cx.shared.my_shared_resource.lock(|s| s.do_shared_thing()); +} +``` + +## Software tasks may now run forever + +The new `async` software tasks are allowed to run forever, on one precondition: **there must be an `await` within the infinite loop of the task**. An example of such a task: + +``` rust +#[task(local = [ my_channel ] )] +async fn my_task_that_runs_forever(cx: my_task_that_runs_forever::Context) { + loop { + let value = cx.local.my_channel.recv().await; + do_something_with_value(value); + } +} +``` + +## `spawn_after` and `spawn_at` have been removed. + +As discussed in the [Migrating to `rtic-monotonics`](./monotonics.md) chapter, `spawn_after` and `spawn_at` are no longer available. \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/complete_example.md b/book/en/src/migration/migration_v2/complete_example.md new file mode 100644 index 0000000..fec475d --- /dev/null +++ b/book/en/src/migration/migration_v2/complete_example.md @@ -0,0 +1,245 @@ +# A complete example of migration + +Below you can find the code for the implementation of the `stm32f3_blinky` example for v1.0.x and for v2.0.0. Further down, a diff is displayed. + +# v1.0.X + +```rust +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use panic_rtt_target as _; +use rtic::app; +use rtt_target::{rprintln, rtt_init_print}; +use stm32f3xx_hal::gpio::{Output, PushPull, PA5}; +use stm32f3xx_hal::prelude::*; +use systick_monotonic::{fugit::Duration, Systick}; + +#[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])] +mod app { + use super::*; + + #[shared] + struct Shared {} + + #[local] + struct Local { + led: PA5>, + state: bool, + } + + #[monotonic(binds = SysTick, default = true)] + type MonoTimer = Systick<1000>; + + #[init] + fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + // Setup clocks + let mut flash = cx.device.FLASH.constrain(); + let mut rcc = cx.device.RCC.constrain(); + + let mono = Systick::new(cx.core.SYST, 36_000_000); + + rtt_init_print!(); + rprintln!("init"); + + let _clocks = rcc + .cfgr + .use_hse(8.MHz()) + .sysclk(36.MHz()) + .pclk1(36.MHz()) + .freeze(&mut flash.acr); + + // Setup LED + let mut gpioa = cx.device.GPIOA.split(&mut rcc.ahb); + let mut led = gpioa + .pa5 + .into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper); + led.set_high().unwrap(); + + // Schedule the blinking task + blink::spawn_after(Duration::::from_ticks(1000)).unwrap(); + + ( + Shared {}, + Local { led, state: false }, + init::Monotonics(mono), + ) + } + + #[task(local = [led, state])] + fn blink(cx: blink::Context) { + rprintln!("blink"); + if *cx.local.state { + cx.local.led.set_high().unwrap(); + *cx.local.state = false; + } else { + cx.local.led.set_low().unwrap(); + *cx.local.state = true; + } + blink::spawn_after(Duration::::from_ticks(1000)).unwrap(); + } +} + +``` + +# V2.0.0 + +``` rust +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] +#![feature(type_alias_impl_trait)] + +use panic_rtt_target as _; +use rtic::app; +use rtt_target::{rprintln, rtt_init_print}; +use stm32f3xx_hal::gpio::{Output, PushPull, PA5}; +use stm32f3xx_hal::prelude::*; +use rtic_monotonics::Systick; + +#[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])] +mod app { + use super::*; + + #[shared] + struct Shared {} + + #[local] + struct Local { + led: PA5>, + state: bool, + } + + #[init] + fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + // Setup clocks + let mut flash = cx.device.FLASH.constrain(); + let mut rcc = cx.device.RCC.constrain(); + + let mono_token = rtic_monotonics::create_systick_token!(); + let mono = Systick::new(cx.core.SYST, 36_000_000, mono_token); + + rtt_init_print!(); + rprintln!("init"); + + let _clocks = rcc + .cfgr + .use_hse(8.MHz()) + .sysclk(36.MHz()) + .pclk1(36.MHz()) + .freeze(&mut flash.acr); + + // Setup LED + let mut gpioa = cx.device.GPIOA.split(&mut rcc.ahb); + let mut led = gpioa + .pa5 + .into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper); + led.set_high().unwrap(); + + // Schedule the blinking task + blink::spawn().unwrap(); + + ( + Shared {}, + Local { led, state: false }, + init::Monotonics(mono), + ) + } + + #[task(local = [led, state])] + async fn blink(cx: blink::Context) { + loop { + // A task is now allowed to run forever, provided that + // there is an `await` somewhere in the loop. + SysTick::delay(1000.millis()).await; + rprintln!("blink"); + if *cx.local.state { + cx.local.led.set_high().unwrap(); + *cx.local.state = false; + } else { + cx.local.led.set_low().unwrap(); + *cx.local.state = true; + } + } + } +} +``` + +## A diff between the two projects + +``` diff +#![no_main] + #![no_std] ++#![feature(type_alias_impl_trait)] + + use panic_rtt_target as _; + use rtic::app; + use stm32f3xx_hal::gpio::{Output, PushPull, PA5}; + use stm32f3xx_hal::prelude::*; +-use systick_monotonic::{fugit::Duration, Systick}; ++use rtic_monotonics::Systick; + + #[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])] + mod app { +@@ -20,16 +21,14 @@ mod app { + state: bool, + } + +- #[monotonic(binds = SysTick, default = true)] +- type MonoTimer = Systick<1000>; +- + #[init] + fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + // Setup clocks + let mut flash = cx.device.FLASH.constrain(); + let mut rcc = cx.device.RCC.constrain(); + +- let mono = Systick::new(cx.core.SYST, 36_000_000); ++ let mono_token = rtic_monotonics::create_systick_token!(); ++ let mono = Systick::new(cx.core.SYST, 36_000_000, mono_token); + + let _clocks = rcc + .cfgr +@@ -46,7 +45,7 @@ mod app { + led.set_high().unwrap(); + + // Schedule the blinking task +- blink::spawn_after(Duration::::from_ticks(1000)).unwrap(); ++ blink::spawn().unwrap(); + + ( + Shared {}, +@@ -56,14 +55,18 @@ mod app { + } + + #[task(local = [led, state])] +- fn blink(cx: blink::Context) { +- rprintln!("blink"); +- if *cx.local.state { +- cx.local.led.set_high().unwrap(); +- *cx.local.state = false; +- } else { +- cx.local.led.set_low().unwrap(); +- *cx.local.state = true; +- blink::spawn_after(Duration::::from_ticks(1000)).unwrap(); +- } ++ async fn blink(cx: blink::Context) { ++ loop { ++ // A task is now allowed to run forever, provided that ++ // there is an `await` somewhere in the loop. ++ SysTick::delay(1000.millis()).await; ++ rprintln!("blink"); ++ if *cx.local.state { ++ cx.local.led.set_high().unwrap(); ++ *cx.local.state = false; ++ } else { ++ cx.local.led.set_low().unwrap(); ++ *cx.local.state = true; ++ } ++ } ++ } + } +``` \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/monotonics.md b/book/en/src/migration/migration_v2/monotonics.md new file mode 100644 index 0000000..f794bec --- /dev/null +++ b/book/en/src/migration/migration_v2/monotonics.md @@ -0,0 +1,11 @@ +# Migrating to `rtic-monotonics` + +In previous versions of `rtic`, monotonics were an integral, tightly coupled part of the `#[rtic::app]`. In this new version, `rtic-monotonics` provides them in a more decoupled way. + +The `#[monotonic]` attribute is no longer used. Instead, you use a `create_X_token` from `rtic-monotonics`. An invocation of this macro returns an interrupt registration token, which can be used to construct an instance of your desired monotonic. + +`spawn_after` and `spawn_at` are no longer available. Instead, you use the async functions `Monotonic::delay` and `Monotonics::delay_until`. The `Monotonic` trait is provided by `rtic-time`. + +Check out the [code example](./complete_example.md) for an overview of the required changes. + +For more information on current monotonic implementations, see [the `rtic-monotonics` documentation](https://docs.rs/rtic-monotonics). \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/nightly.md b/book/en/src/migration/migration_v2/nightly.md new file mode 100644 index 0000000..09f6e33 --- /dev/null +++ b/book/en/src/migration/migration_v2/nightly.md @@ -0,0 +1,5 @@ +# RTIC now requires Rust Nightly + +The new `async` features require that you use a nightly compiler, and that the feature `type_alias_impl_trait` is enabled for your applications. + +To enable this feature, you must add the line `#![type_alias_impl_trait]` to the root file of your project, on the lines below or above where `#![no_std]` and `#![no_main]` are defined. \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/rtic-sync.md b/book/en/src/migration/migration_v2/rtic-sync.md new file mode 100644 index 0000000..d086d5d --- /dev/null +++ b/book/en/src/migration/migration_v2/rtic-sync.md @@ -0,0 +1 @@ +# Using `rtic-sync` \ No newline at end of file -- cgit v1.2.3 From d90fa95266bc9864d2dec0248fa4bae5c7e5b6ec Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 18:25:00 +0200 Subject: Add some more --- book/en/src/migration/migration_v2.md | 6 ++++-- book/en/src/migration/migration_v2/monotonics.md | 2 +- book/en/src/migration/migration_v2/rtic-sync.md | 10 +++++++++- 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/migration/migration_v2.md b/book/en/src/migration/migration_v2.md index 071d34c..96fa231 100644 --- a/book/en/src/migration/migration_v2.md +++ b/book/en/src/migration/migration_v2.md @@ -5,11 +5,13 @@ Migrating a project from RTIC `v1.0.x` to `v2.0.0` involves the following steps: 1. `v2.0.0` requires [`#![type_alias_impl_trait]`](https://github.com/rust-lang/rust/issues/63063) and Rust Nightly. 2. Migrating from the monotonics included in `v1.0.x` to `rtic-time` and `rtic-monotonics`, replacing `spawn_after`, `spawn_at`. 3. Software tasks are now required to be `async`, and using them correctly. -4. Understanding and using data types provided by `rtic-sync` to solve migration problems. +4. Understanding and using data types provided by `rtic-sync`. + +For a detailed description of the changes, refer to the subchapters. If you wish to see a code example of changes required, you can check out [the full example migration page](./migration_v2/complete_example.md). -## TL;DR +#### TL;DR (Too Long; Didn't Read) 1. Add `#![type_alias_impl_trait]` to your crate, and use `cargo +nightly`. 2. Instead of `spawn_after` and `spawn_at`, you now use the `async` functions `delay`, `delay_until` (and related) with impls provided by `rtic-monotonics`. 3. Software tasks _must_ be `async fn`s now. Not returning from a task is allowed so long as there is an `await` in the task. You can still `lock` shared resources. diff --git a/book/en/src/migration/migration_v2/monotonics.md b/book/en/src/migration/migration_v2/monotonics.md index f794bec..7427408 100644 --- a/book/en/src/migration/migration_v2/monotonics.md +++ b/book/en/src/migration/migration_v2/monotonics.md @@ -8,4 +8,4 @@ The `#[monotonic]` attribute is no longer used. Instead, you use a `create_X_tok Check out the [code example](./complete_example.md) for an overview of the required changes. -For more information on current monotonic implementations, see [the `rtic-monotonics` documentation](https://docs.rs/rtic-monotonics). \ No newline at end of file +For more information on current monotonic implementations, see [the `rtic-monotonics` documentation](https://docs.rs/rtic-monotonics), and [the examples](https://github.com/rtic-rs/rtic/tree/master/examples). \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/rtic-sync.md b/book/en/src/migration/migration_v2/rtic-sync.md index d086d5d..fefde03 100644 --- a/book/en/src/migration/migration_v2/rtic-sync.md +++ b/book/en/src/migration/migration_v2/rtic-sync.md @@ -1 +1,9 @@ -# Using `rtic-sync` \ No newline at end of file +# Using `rtic-sync` + +`rtic-sync` provides primitives that can be used for message passing and resource sharing in async context. + +The important structs are: +* The `Arbiter`, which allows you to await access to a shared resource in async contexts without using `lock`. +* `Channel`, which allows you to communicate between tasks (both `async` and non-`async`). + +For more information on these structs, see the [`rtic-sync` docs](https://docs.rs/rtic-sync) \ No newline at end of file -- cgit v1.2.3 From 6c91ff2d7f83bbba81d8fc24ad9760b5cf6b394e Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 18:28:40 +0200 Subject: Include the examples --- .../src/migration/migration_v2/complete_example.md | 82 +--------------------- 1 file changed, 3 insertions(+), 79 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/migration/migration_v2/complete_example.md b/book/en/src/migration/migration_v2/complete_example.md index fec475d..b68f1ef 100644 --- a/book/en/src/migration/migration_v2/complete_example.md +++ b/book/en/src/migration/migration_v2/complete_example.md @@ -87,89 +87,13 @@ mod app { # V2.0.0 ``` rust -#![deny(unsafe_code)] -#![deny(warnings)] -#![no_main] -#![no_std] -#![feature(type_alias_impl_trait)] - -use panic_rtt_target as _; -use rtic::app; -use rtt_target::{rprintln, rtt_init_print}; -use stm32f3xx_hal::gpio::{Output, PushPull, PA5}; -use stm32f3xx_hal::prelude::*; -use rtic_monotonics::Systick; - -#[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])] -mod app { - use super::*; - - #[shared] - struct Shared {} - - #[local] - struct Local { - led: PA5>, - state: bool, - } - - #[init] - fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { - // Setup clocks - let mut flash = cx.device.FLASH.constrain(); - let mut rcc = cx.device.RCC.constrain(); - - let mono_token = rtic_monotonics::create_systick_token!(); - let mono = Systick::new(cx.core.SYST, 36_000_000, mono_token); - - rtt_init_print!(); - rprintln!("init"); - - let _clocks = rcc - .cfgr - .use_hse(8.MHz()) - .sysclk(36.MHz()) - .pclk1(36.MHz()) - .freeze(&mut flash.acr); - - // Setup LED - let mut gpioa = cx.device.GPIOA.split(&mut rcc.ahb); - let mut led = gpioa - .pa5 - .into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper); - led.set_high().unwrap(); - - // Schedule the blinking task - blink::spawn().unwrap(); - - ( - Shared {}, - Local { led, state: false }, - init::Monotonics(mono), - ) - } - - #[task(local = [led, state])] - async fn blink(cx: blink::Context) { - loop { - // A task is now allowed to run forever, provided that - // there is an `await` somewhere in the loop. - SysTick::delay(1000.millis()).await; - rprintln!("blink"); - if *cx.local.state { - cx.local.led.set_high().unwrap(); - *cx.local.state = false; - } else { - cx.local.led.set_low().unwrap(); - *cx.local.state = true; - } - } - } -} +{{ #include ../../../../../examples/stm32f3_blinky/src/main.rs }} ``` ## A diff between the two projects +_Note_: This diff may not be 100% accurate, but it displays the important changes. + ``` diff #![no_main] #![no_std] -- cgit v1.2.3 From 825b2c2c3a565920a31a87328caa82442a44d209 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 18:34:30 +0200 Subject: Update tips on Monotonic implemenations --- book/en/src/by-example/tips_monotonic_impl.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/by-example/tips_monotonic_impl.md b/book/en/src/by-example/tips_monotonic_impl.md index 57b0a01..85b5709 100644 --- a/book/en/src/by-example/tips_monotonic_impl.md +++ b/book/en/src/by-example/tips_monotonic_impl.md @@ -1,14 +1,23 @@ # Implementing a `Monotonic` timer for scheduling -The framework is flexible because it can use any timer which has compare-match and optionally supporting overflow interrupts for scheduling. The single requirement to make a timer usable with RTIC is implementing the [`rtic-time::Monotonic`] trait. +The framework is flexible because it can use any timer which has compare-match and optionally supporting overflow interrupts for scheduling. The single requirement to make a timer usable with RTIC is implementing the `rtic-time::Monotonic` trait. -For RTIC 1.0 and 2.0 we instead assume the user has a time library, e.g. [`fugit`] or [`embedded_time`], as the basis for all time-based operations when implementing `Monotonic`. These libraries make it much easier to correctly implement the `Monotonic` trait, allowing the use of -almost any timer in the system for scheduling. +For RTIC 1.0 and 2.0 we instead assume the user has a time library, e.g. [`fugit`] or [`embedded_time`], as the basis for all time-based operations when implementing `Monotonic`. These libraries make it much easier to correctly implement the `Monotonic` trait, allowing the use of almost any timer in the system for scheduling. -The trait documents the requirements for each method, and for inspiration -there is a reference implementation based on the `SysTick` timer available on all ARM Cortex M MCUs. +The trait documents the requirements for each method. There are reference implementations available in [`rtic-monotonics`](https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics/src) that can be used for inspriation. - [`Systick based`], runs at a fixed interrupt (tick) rate - with some overhead but simple and provides support for large time spans +- [`RP2040 Timer`], a "proper" implementation with support for waiting for long periods without interrupts. Clearly demonstrates how to use the `TimerQueue` to handle scheduling. +- [`nRF52 timers`] implements monotonic & Timer Queue for the RTC and normal timers in nRF52's + +## Contributing + +Contributing new implementations of `Monotonic` can be done in multiple ways: +* Implement the trait behind a feature flag in [`rtic-monotonics`], and create a PR for them to be included in the main RTIC repository. This way, the implementations of are in-tree, and RTIC can guarantee their correctness, and can update them in the case of a new release. +* Implement the changes in an external repository. + + +# V1.0.x Here is a list of `Monotonic` implementations for RTIC 1.0: @@ -27,3 +36,6 @@ If you know of more implementations feel free to add them to this list. [`Nordic nRF52 series RTC`]: https://gist.github.com/korken89/fe94a475726414dd1bce031c76adc3dd [`Systick based`]: https://github.com/rtic-monotonics [`DWT and Systick based`]: https://github.com/rtic-rs/dwt-systick-monotonic +[`rtic-monotonics`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics +[`RP2040 Timer`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics/src/rp2040.rs +[`nRF52 timers`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics/src/nrf.rs \ No newline at end of file -- cgit v1.2.3 From 4437f12b30e011a229c49d62538284d7ae61324e Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 19:18:43 +0200 Subject: Remove link to inactive `embedded_time` --- book/en/src/by-example/tips_monotonic_impl.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/by-example/tips_monotonic_impl.md b/book/en/src/by-example/tips_monotonic_impl.md index 85b5709..5dc4dd7 100644 --- a/book/en/src/by-example/tips_monotonic_impl.md +++ b/book/en/src/by-example/tips_monotonic_impl.md @@ -2,7 +2,7 @@ The framework is flexible because it can use any timer which has compare-match and optionally supporting overflow interrupts for scheduling. The single requirement to make a timer usable with RTIC is implementing the `rtic-time::Monotonic` trait. -For RTIC 1.0 and 2.0 we instead assume the user has a time library, e.g. [`fugit`] or [`embedded_time`], as the basis for all time-based operations when implementing `Monotonic`. These libraries make it much easier to correctly implement the `Monotonic` trait, allowing the use of almost any timer in the system for scheduling. +For RTIC 1.0 and 2.0 we instead assume the user has a time library, e.g. [`fugit`], as the basis for all time-based operations when implementing `Monotonic`. These libraries make it much easier to correctly implement the `Monotonic` trait, allowing the use of almost any timer in the system for scheduling. The trait documents the requirements for each method. There are reference implementations available in [`rtic-monotonics`](https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics/src) that can be used for inspriation. @@ -30,7 +30,6 @@ If you know of more implementations feel free to add them to this list. [`rtic_time::Monotonic`]: https://docs.rs/rtic_time/ [`fugit`]: https://docs.rs/fugit/ -[`embedded_time`]: https://docs.rs/embedded_time/ [`STM32F411 series`]: https://github.com/kalkyl/f411-rtic/blob/a696fce7d6d19fda2356c37642c4d53547982cca/src/mono.rs [`Nordic nRF52 series Timer`]: https://github.com/kalkyl/nrf-play/blob/47f4410d4e39374c18ff58dc17c25159085fb526/src/mono.rs [`Nordic nRF52 series RTC`]: https://gist.github.com/korken89/fe94a475726414dd1bce031c76adc3dd -- cgit v1.2.3 From 9ddae2054ad0f7bbdcab310816c4b012cf4444aa Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 19:38:16 +0200 Subject: Fix links & info --- book/en/src/migration/migration_v2/monotonics.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/migration/migration_v2/monotonics.md b/book/en/src/migration/migration_v2/monotonics.md index 7427408..a8b0dba 100644 --- a/book/en/src/migration/migration_v2/monotonics.md +++ b/book/en/src/migration/migration_v2/monotonics.md @@ -1,11 +1,13 @@ # Migrating to `rtic-monotonics` -In previous versions of `rtic`, monotonics were an integral, tightly coupled part of the `#[rtic::app]`. In this new version, `rtic-monotonics` provides them in a more decoupled way. +In previous versions of `rtic`, monotonics were an integral, tightly coupled part of the `#[rtic::app]`. In this new version, [`rtic-monotonics`] provides them in a more decoupled way. -The `#[monotonic]` attribute is no longer used. Instead, you use a `create_X_token` from `rtic-monotonics`. An invocation of this macro returns an interrupt registration token, which can be used to construct an instance of your desired monotonic. +The `#[monotonic]` attribute is no longer used. Instead, you use a `create_X_token` from [`rtic-monotonics`]. An invocation of this macro returns an interrupt registration token, which can be used to construct an instance of your desired monotonic. -`spawn_after` and `spawn_at` are no longer available. Instead, you use the async functions `Monotonic::delay` and `Monotonics::delay_until`. The `Monotonic` trait is provided by `rtic-time`. +`spawn_after` and `spawn_at` are no longer available. Instead, you use the async functions `delay` and `delay_until` provided by ipmlementations of the `rtic_time::Monotonic` trait, available through [`rtic-monotonics`]. Check out the [code example](./complete_example.md) for an overview of the required changes. -For more information on current monotonic implementations, see [the `rtic-monotonics` documentation](https://docs.rs/rtic-monotonics), and [the examples](https://github.com/rtic-rs/rtic/tree/master/examples). \ No newline at end of file +For more information on current monotonic implementations, see [the `rtic-monotonics` documentation](https://docs.rs/rtic-monotonics), and [the examples](https://github.com/rtic-rs/rtic/tree/master/examples). + +[`rtic-monotonics`]: ghttps://github.com/rtic/rtic-monotonics \ No newline at end of file -- cgit v1.2.3 From d22faec870b57274b1b2a74c1fe947e969c13379 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 19:55:44 +0200 Subject: Fix run-on sentence --- book/en/src/by-example/message_passing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'book/en/src') diff --git a/book/en/src/by-example/message_passing.md b/book/en/src/by-example/message_passing.md index 0dc8f85..5665c36 100644 --- a/book/en/src/by-example/message_passing.md +++ b/book/en/src/by-example/message_passing.md @@ -3,7 +3,7 @@ Software tasks support message passing, this means that software tasks can be spawned with an argument: `foo::spawn(1)` which will run the task `foo` with the argument `1`. -Capacity sets the size of the spawn queue for the task, if not specified capacity defaults to 1. +Capacity sets the size of the spawn queue for the task. If it is not specified, the capacity defaults to 1. In the example below, the capacity of task `foo` is `3`, allowing three simultaneous pending spawns of `foo`. Exceeding this capacity is an `Error`. -- cgit v1.2.3 From ed465b0c3b8b4c588f5cc7945af79a504f928cc8 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 19:54:42 +0200 Subject: Fix #699 --- book/en/src/by-example/channel.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/by-example/channel.md b/book/en/src/by-example/channel.md index c020870..50c3278 100644 --- a/book/en/src/by-example/channel.md +++ b/book/en/src/by-example/channel.md @@ -1,6 +1,6 @@ # Communication over channels. -Channels can be used to communicate data between running *software* tasks. The channel is essentially a wait queue, allowing tasks with multiple producers and a single receiver. A channel is constructed in the `init` task and backed by statically allocated memory. Send and receive endpoints are distributed to *software* tasks: +Channels can be used to communicate data between running tasks. The channel is essentially a wait queue, allowing tasks with multiple producers and a single receiver. A channel is constructed in the `init` task and backed by statically allocated memory. Send and receive endpoints are distributed to *software* tasks: ``` rust ... @@ -16,6 +16,8 @@ const CAPACITY: usize = 5; In this case the channel holds data of `u32` type with a capacity of 5 elements. +Channels can also be used from *hardware* tasks, but only in a non-`async` manner using the [Try API](#try-api). + ## Sending data The `send` method post a message on the channel as shown below: @@ -107,11 +109,11 @@ $ cargo run --target thumbv7m-none-eabi --example async-channel-no-receiver --fe {{#include ../../../../rtic/ci/expected/async-channel-no-receiver.run}} ``` - - ## Try API -In cases you wish the sender to proceed even in case the channel is full. To that end, a `try_send` API is provided. +Using the Try API, you can send or receive data from or to a channel without requiring that the operation succeeds, and in non-`async` contexts. + +This API is exposed through `Receiver::try_recv` and `Sender::try_send`. ``` rust {{#include ../../../../rtic/examples/async-channel-try.rs}} -- cgit v1.2.3 From 3d97c9e431d7fcb20b1b30bc15c34ccffee03c79 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 21:27:26 +0200 Subject: Move deprecated migration guides to deprecated folder --- book/en/src/SUMMARY.md | 22 +- book/en/src/migration.md | 4 - book/en/src/migration/migration_rtic.md | 50 --- book/en/src/migration/migration_v2.md | 18 - book/en/src/migration/migration_v2/async_tasks.md | 55 --- .../src/migration/migration_v2/complete_example.md | 169 ---------- book/en/src/migration/migration_v2/monotonics.md | 13 - book/en/src/migration/migration_v2/nightly.md | 5 - book/en/src/migration/migration_v2/rtic-sync.md | 9 - book/en/src/migration/migration_v4.md | 247 -------------- book/en/src/migration/migration_v5.md | 372 --------------------- book/en/src/migration_v1_v2.md | 18 + book/en/src/migration_v1_v2/async_tasks.md | 55 +++ book/en/src/migration_v1_v2/complete_example.md | 169 ++++++++++ book/en/src/migration_v1_v2/monotonics.md | 13 + book/en/src/migration_v1_v2/nightly.md | 5 + book/en/src/migration_v1_v2/rtic-sync.md | 9 + 17 files changed, 276 insertions(+), 957 deletions(-) delete mode 100644 book/en/src/migration.md delete mode 100644 book/en/src/migration/migration_rtic.md delete mode 100644 book/en/src/migration/migration_v2.md delete mode 100644 book/en/src/migration/migration_v2/async_tasks.md delete mode 100644 book/en/src/migration/migration_v2/complete_example.md delete mode 100644 book/en/src/migration/migration_v2/monotonics.md delete mode 100644 book/en/src/migration/migration_v2/nightly.md delete mode 100644 book/en/src/migration/migration_v2/rtic-sync.md delete mode 100644 book/en/src/migration/migration_v4.md delete mode 100644 book/en/src/migration/migration_v5.md create mode 100644 book/en/src/migration_v1_v2.md create mode 100644 book/en/src/migration_v1_v2/async_tasks.md create mode 100644 book/en/src/migration_v1_v2/complete_example.md create mode 100644 book/en/src/migration_v1_v2/monotonics.md create mode 100644 book/en/src/migration_v1_v2/nightly.md create mode 100644 book/en/src/migration_v1_v2/rtic-sync.md (limited to 'book/en/src') diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index ceed24e..8b19bf1 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -23,11 +23,12 @@ - [RTIC vs. the world](./rtic_vs.md) - [Awesome RTIC examples](./awesome_rtic.md) - +- [Migrating from v1.0.x to v2.0.0](./migration_v1_v2.md) + - [Rust Nightly & features](./migration_v1_v2/nightly.md) + - [Migrating to `rtic-monotonics`](./migration_v1_v2/monotonics.md) + - [Software tasks must now be `async`](./migration_v1_v2/async_tasks.md) + - [Using and understanding `rtic-sync`](./migration_v1_v2/rtic-sync.md) + - [A code example on migration](./migration_v1_v2/complete_example.md) - [Under the hood](./internals.md) - [Cortex-M architectures](./internals/targets.md) @@ -44,13 +45,4 @@ - [Message passing & `capacity`](./by-example/message_passing.md) - [Task priorities](./by-example/app_priorities.md) - [Monotonic & `spawn_{at/after}`](./by-example/monotonic.md) - --> - ---- - -- [Migrating from v1.0.x to v2.0.0](./migration/migration_v2.md) - - [Rust Nightly & features](./migration/migration_v2/nightly.md) - - [Migrating to `rtic-monotonics`](./migration/migration_v2/monotonics.md) - - [Software tasks must now be `async`](./migration/migration_v2/async_tasks.md) - - [Using and understanding `rtic-sync`](./migration/migration_v2/rtic-sync.md) - - [A code example on migration](./migration/migration_v2/complete_example.md) \ No newline at end of file + --> \ No newline at end of file diff --git a/book/en/src/migration.md b/book/en/src/migration.md deleted file mode 100644 index f52b0a5..0000000 --- a/book/en/src/migration.md +++ /dev/null @@ -1,4 +0,0 @@ -# Migration Guides - -This section describes how to migrate between different versions of RTIC. -It also acts as a comparing reference between versions. diff --git a/book/en/src/migration/migration_rtic.md b/book/en/src/migration/migration_rtic.md deleted file mode 100644 index c027da3..0000000 --- a/book/en/src/migration/migration_rtic.md +++ /dev/null @@ -1,50 +0,0 @@ -# Migrating from RTFM to RTIC - -This section covers how to upgrade an application written against RTFM v0.5.x to -the same version of RTIC. This applies since the renaming of the framework as per [RFC #33]. - -**Note:** There are no code differences between RTFM v0.5.3 and RTIC v0.5.3, it is purely a name -change. - -[RFC #33]: https://github.com/rtic-rs/rfcs/pull/33 - -## `Cargo.toml` - -First, the `cortex-m-rtfm` dependency needs to be updated to -`cortex-m-rtic`. - -``` toml -[dependencies] -# change this -cortex-m-rtfm = "0.5.3" - -# into this -cortex-m-rtic = "0.5.3" -``` - -## Code changes - -The only code change that needs to be made is that any reference to `rtfm` before now need to point -to `rtic` as follows: - -``` rust -// -// Change this -// - -#[rtfm::app(/* .. */, monotonic = rtfm::cyccnt::CYCCNT)] -const APP: () = { - // ... - -}; - -// -// Into this -// - -#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)] -const APP: () = { - // ... - -}; -``` diff --git a/book/en/src/migration/migration_v2.md b/book/en/src/migration/migration_v2.md deleted file mode 100644 index 96fa231..0000000 --- a/book/en/src/migration/migration_v2.md +++ /dev/null @@ -1,18 +0,0 @@ -# Migrating from v1.0.x to v2.0.0 - -Migrating a project from RTIC `v1.0.x` to `v2.0.0` involves the following steps: - -1. `v2.0.0` requires [`#![type_alias_impl_trait]`](https://github.com/rust-lang/rust/issues/63063) and Rust Nightly. -2. Migrating from the monotonics included in `v1.0.x` to `rtic-time` and `rtic-monotonics`, replacing `spawn_after`, `spawn_at`. -3. Software tasks are now required to be `async`, and using them correctly. -4. Understanding and using data types provided by `rtic-sync`. - -For a detailed description of the changes, refer to the subchapters. - -If you wish to see a code example of changes required, you can check out [the full example migration page](./migration_v2/complete_example.md). - -#### TL;DR (Too Long; Didn't Read) -1. Add `#![type_alias_impl_trait]` to your crate, and use `cargo +nightly`. -2. Instead of `spawn_after` and `spawn_at`, you now use the `async` functions `delay`, `delay_until` (and related) with impls provided by `rtic-monotonics`. -3. Software tasks _must_ be `async fn`s now. Not returning from a task is allowed so long as there is an `await` in the task. You can still `lock` shared resources. -4. Use `rtic_sync::Arbiter` to `await` access to a shared resource, and `rtic-channel` to communicate between tasks instead of `spawn`-ing new ones. \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/async_tasks.md b/book/en/src/migration/migration_v2/async_tasks.md deleted file mode 100644 index 54e0893..0000000 --- a/book/en/src/migration/migration_v2/async_tasks.md +++ /dev/null @@ -1,55 +0,0 @@ -# Using `async` softare tasks. - -There have been a few changes to software tasks. They are outlined below. - -### Software tasks must now be `async`. - -All software tasks are now required to be `async`. - -#### Required changes. - -All of the tasks in your project that do not bind to an interrupt must now be an `async fn`. For example: - -``` rust -#[task( - local = [ some_resource ], - shared = [ my_shared_resource ], - priority = 2 -)] -fn my_task(cx: my_task::Context) { - cx.local.some_resource.do_trick(); - cx.shared.my_shared_resource.lock(|s| s.do_shared_thing()); -} -``` - -becomes - -``` rust -#[task( - local = [ some_resource ], - shared = [ my_shared_resource ], - priority = 2 -)] -async fn my_task(cx: my_task::Context) { - cx.local.some_resource.do_trick(); - cx.shared.my_shared_resource.lock(|s| s.do_shared_thing()); -} -``` - -## Software tasks may now run forever - -The new `async` software tasks are allowed to run forever, on one precondition: **there must be an `await` within the infinite loop of the task**. An example of such a task: - -``` rust -#[task(local = [ my_channel ] )] -async fn my_task_that_runs_forever(cx: my_task_that_runs_forever::Context) { - loop { - let value = cx.local.my_channel.recv().await; - do_something_with_value(value); - } -} -``` - -## `spawn_after` and `spawn_at` have been removed. - -As discussed in the [Migrating to `rtic-monotonics`](./monotonics.md) chapter, `spawn_after` and `spawn_at` are no longer available. \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/complete_example.md b/book/en/src/migration/migration_v2/complete_example.md deleted file mode 100644 index b68f1ef..0000000 --- a/book/en/src/migration/migration_v2/complete_example.md +++ /dev/null @@ -1,169 +0,0 @@ -# A complete example of migration - -Below you can find the code for the implementation of the `stm32f3_blinky` example for v1.0.x and for v2.0.0. Further down, a diff is displayed. - -# v1.0.X - -```rust -#![deny(unsafe_code)] -#![deny(warnings)] -#![no_main] -#![no_std] - -use panic_rtt_target as _; -use rtic::app; -use rtt_target::{rprintln, rtt_init_print}; -use stm32f3xx_hal::gpio::{Output, PushPull, PA5}; -use stm32f3xx_hal::prelude::*; -use systick_monotonic::{fugit::Duration, Systick}; - -#[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])] -mod app { - use super::*; - - #[shared] - struct Shared {} - - #[local] - struct Local { - led: PA5>, - state: bool, - } - - #[monotonic(binds = SysTick, default = true)] - type MonoTimer = Systick<1000>; - - #[init] - fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { - // Setup clocks - let mut flash = cx.device.FLASH.constrain(); - let mut rcc = cx.device.RCC.constrain(); - - let mono = Systick::new(cx.core.SYST, 36_000_000); - - rtt_init_print!(); - rprintln!("init"); - - let _clocks = rcc - .cfgr - .use_hse(8.MHz()) - .sysclk(36.MHz()) - .pclk1(36.MHz()) - .freeze(&mut flash.acr); - - // Setup LED - let mut gpioa = cx.device.GPIOA.split(&mut rcc.ahb); - let mut led = gpioa - .pa5 - .into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper); - led.set_high().unwrap(); - - // Schedule the blinking task - blink::spawn_after(Duration::::from_ticks(1000)).unwrap(); - - ( - Shared {}, - Local { led, state: false }, - init::Monotonics(mono), - ) - } - - #[task(local = [led, state])] - fn blink(cx: blink::Context) { - rprintln!("blink"); - if *cx.local.state { - cx.local.led.set_high().unwrap(); - *cx.local.state = false; - } else { - cx.local.led.set_low().unwrap(); - *cx.local.state = true; - } - blink::spawn_after(Duration::::from_ticks(1000)).unwrap(); - } -} - -``` - -# V2.0.0 - -``` rust -{{ #include ../../../../../examples/stm32f3_blinky/src/main.rs }} -``` - -## A diff between the two projects - -_Note_: This diff may not be 100% accurate, but it displays the important changes. - -``` diff -#![no_main] - #![no_std] -+#![feature(type_alias_impl_trait)] - - use panic_rtt_target as _; - use rtic::app; - use stm32f3xx_hal::gpio::{Output, PushPull, PA5}; - use stm32f3xx_hal::prelude::*; --use systick_monotonic::{fugit::Duration, Systick}; -+use rtic_monotonics::Systick; - - #[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])] - mod app { -@@ -20,16 +21,14 @@ mod app { - state: bool, - } - -- #[monotonic(binds = SysTick, default = true)] -- type MonoTimer = Systick<1000>; -- - #[init] - fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { - // Setup clocks - let mut flash = cx.device.FLASH.constrain(); - let mut rcc = cx.device.RCC.constrain(); - -- let mono = Systick::new(cx.core.SYST, 36_000_000); -+ let mono_token = rtic_monotonics::create_systick_token!(); -+ let mono = Systick::new(cx.core.SYST, 36_000_000, mono_token); - - let _clocks = rcc - .cfgr -@@ -46,7 +45,7 @@ mod app { - led.set_high().unwrap(); - - // Schedule the blinking task -- blink::spawn_after(Duration::::from_ticks(1000)).unwrap(); -+ blink::spawn().unwrap(); - - ( - Shared {}, -@@ -56,14 +55,18 @@ mod app { - } - - #[task(local = [led, state])] -- fn blink(cx: blink::Context) { -- rprintln!("blink"); -- if *cx.local.state { -- cx.local.led.set_high().unwrap(); -- *cx.local.state = false; -- } else { -- cx.local.led.set_low().unwrap(); -- *cx.local.state = true; -- blink::spawn_after(Duration::::from_ticks(1000)).unwrap(); -- } -+ async fn blink(cx: blink::Context) { -+ loop { -+ // A task is now allowed to run forever, provided that -+ // there is an `await` somewhere in the loop. -+ SysTick::delay(1000.millis()).await; -+ rprintln!("blink"); -+ if *cx.local.state { -+ cx.local.led.set_high().unwrap(); -+ *cx.local.state = false; -+ } else { -+ cx.local.led.set_low().unwrap(); -+ *cx.local.state = true; -+ } -+ } -+ } - } -``` \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/monotonics.md b/book/en/src/migration/migration_v2/monotonics.md deleted file mode 100644 index a8b0dba..0000000 --- a/book/en/src/migration/migration_v2/monotonics.md +++ /dev/null @@ -1,13 +0,0 @@ -# Migrating to `rtic-monotonics` - -In previous versions of `rtic`, monotonics were an integral, tightly coupled part of the `#[rtic::app]`. In this new version, [`rtic-monotonics`] provides them in a more decoupled way. - -The `#[monotonic]` attribute is no longer used. Instead, you use a `create_X_token` from [`rtic-monotonics`]. An invocation of this macro returns an interrupt registration token, which can be used to construct an instance of your desired monotonic. - -`spawn_after` and `spawn_at` are no longer available. Instead, you use the async functions `delay` and `delay_until` provided by ipmlementations of the `rtic_time::Monotonic` trait, available through [`rtic-monotonics`]. - -Check out the [code example](./complete_example.md) for an overview of the required changes. - -For more information on current monotonic implementations, see [the `rtic-monotonics` documentation](https://docs.rs/rtic-monotonics), and [the examples](https://github.com/rtic-rs/rtic/tree/master/examples). - -[`rtic-monotonics`]: ghttps://github.com/rtic/rtic-monotonics \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/nightly.md b/book/en/src/migration/migration_v2/nightly.md deleted file mode 100644 index 09f6e33..0000000 --- a/book/en/src/migration/migration_v2/nightly.md +++ /dev/null @@ -1,5 +0,0 @@ -# RTIC now requires Rust Nightly - -The new `async` features require that you use a nightly compiler, and that the feature `type_alias_impl_trait` is enabled for your applications. - -To enable this feature, you must add the line `#![type_alias_impl_trait]` to the root file of your project, on the lines below or above where `#![no_std]` and `#![no_main]` are defined. \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/rtic-sync.md b/book/en/src/migration/migration_v2/rtic-sync.md deleted file mode 100644 index fefde03..0000000 --- a/book/en/src/migration/migration_v2/rtic-sync.md +++ /dev/null @@ -1,9 +0,0 @@ -# Using `rtic-sync` - -`rtic-sync` provides primitives that can be used for message passing and resource sharing in async context. - -The important structs are: -* The `Arbiter`, which allows you to await access to a shared resource in async contexts without using `lock`. -* `Channel`, which allows you to communicate between tasks (both `async` and non-`async`). - -For more information on these structs, see the [`rtic-sync` docs](https://docs.rs/rtic-sync) \ No newline at end of file diff --git a/book/en/src/migration/migration_v4.md b/book/en/src/migration/migration_v4.md deleted file mode 100644 index d1a7ebe..0000000 --- a/book/en/src/migration/migration_v4.md +++ /dev/null @@ -1,247 +0,0 @@ -# Migrating from v0.4.x to v0.5.0 - -This section covers how to upgrade an application written against RTFM v0.4.x to -the version v0.5.0 of the framework. - -## Project name change RTFM -> RTIC - -With release [v0.5.2][rtic0.5.2] the name was change to Real-Time Interrupt-driven Concurrency - -All occurrences of `RTFM` needs to change to `RTIC`. - -See [migration guide RTFM to RTIC](./migration_rtic.md) - -[rtic0.5.2]: https://crates.io/crates/cortex-m-rtic/0.5.2 - -## `Cargo.toml` - -Change the version of `cortex-m-rtfm` to -`"0.5.0"`, change `rtfm` to `rtic`. -Remove the `timer-queue` feature. - -``` toml -[dependencies.cortex-m-rtfm] -# change this -version = "0.4.3" - -# into this -[dependencies.cortex-m-rtic] -version = "0.5.0" - -# and remove this Cargo feature -features = ["timer-queue"] -# ^^^^^^^^^^^^^ -``` - -## `Context` argument - -All functions inside the `#[rtfm::app]` item need to take as first argument a -`Context` structure. This `Context` type will contain the variables that were -magically injected into the scope of the function by version v0.4.x of the -framework: `resources`, `spawn`, `schedule` -- these variables will become -fields of the `Context` structure. Each function within the `#[rtfm::app]` item -gets a different `Context` type. - -``` rust -#[rtfm::app(/* .. */)] -const APP: () = { - // change this - #[task(resources = [x], spawn = [a], schedule = [b])] - fn foo() { - resources.x.lock(|x| /* .. */); - spawn.a(message); - schedule.b(baseline); - } - - // into this - #[task(resources = [x], spawn = [a], schedule = [b])] - fn foo(mut cx: foo::Context) { - // ^^^^^^^^^^^^^^^^^^^^ - - cx.resources.x.lock(|x| /* .. */); - // ^^^ - - cx.spawn.a(message); - // ^^^ - - cx.schedule.b(message, baseline); - // ^^^ - } - - // change this - #[init] - fn init() { - // .. - } - - // into this - #[init] - fn init(cx: init::Context) { - // ^^^^^^^^^^^^^^^^^ - // .. - } - - // .. -}; -``` - -## Resources - -The syntax used to declare resources has changed from `static mut` -variables to a `struct Resources`. - -``` rust -#[rtfm::app(/* .. */)] -const APP: () = { - // change this - static mut X: u32 = 0; - static mut Y: u32 = (); // late resource - - // into this - struct Resources { - #[init(0)] // <- initial value - X: u32, // NOTE: we suggest changing the naming style to `snake_case` - - Y: u32, // late resource - } - - // .. -}; -``` - -## Device peripherals - -If your application was accessing the device peripherals in `#[init]` through -the `device` variable then you'll need to add `peripherals = true` to the -`#[rtfm::app]` attribute to continue to access the device peripherals through -the `device` field of the `init::Context` structure. - -Change this: - -``` rust -#[rtfm::app(/* .. */)] -const APP: () = { - #[init] - fn init() { - device.SOME_PERIPHERAL.write(something); - } - - // .. -}; -``` - -Into this: - -``` rust -#[rtfm::app(/* .. */, peripherals = true)] -// ^^^^^^^^^^^^^^^^^^ -const APP: () = { - #[init] - fn init(cx: init::Context) { - // ^^^^^^^^^^^^^^^^^ - cx.device.SOME_PERIPHERAL.write(something); - // ^^^ - } - - // .. -}; -``` - -## `#[interrupt]` and `#[exception]` - -Remove the attributes `#[interrupt]` and `#[exception]`. -To declare hardware tasks in v0.5.x use the `#[task]` -attribute with the `binds` argument instead. - -Change this: - -``` rust -#[rtfm::app(/* .. */)] -const APP: () = { - // hardware tasks - #[exception] - fn SVCall() { /* .. */ } - - #[interrupt] - fn UART0() { /* .. */ } - - // software task - #[task] - fn foo() { /* .. */ } - - // .. -}; -``` - -Into this: - -``` rust -#[rtfm::app(/* .. */)] -const APP: () = { - #[task(binds = SVCall)] - // ^^^^^^^^^^^^^^ - fn svcall(cx: svcall::Context) { /* .. */ } - // ^^^^^^ we suggest you use a `snake_case` name here - - #[task(binds = UART0)] - // ^^^^^^^^^^^^^ - fn uart0(cx: uart0::Context) { /* .. */ } - - #[task] - fn foo(cx: foo::Context) { /* .. */ } - - // .. -}; -``` - -## `schedule` - -The `schedule` API no longer requires the `timer-queue` cargo feature. -To use the `schedule` API one must first define the monotonic timer the -runtime will use using the `monotonic` argument of the `#[rtfm::app]` attribute. -To continue using the cycle counter (CYCCNT) as the monotonic timer, -and match the behavior of version v0.4.x, add the `monotonic = rtfm::cyccnt::CYCCNT` -argument to the `#[rtfm::app]` attribute. - -Also, the `Duration` and `Instant` types and the `U32Ext` trait moved -into the `rtfm::cyccnt` module. -This module is only available on ARMv7-M+ devices. -The removal of the `timer-queue` also brings back the `DWT` peripheral -inside the core peripherals struct, if `DWT` is required, -ensure it is enabled by the application inside `init`. - -Change this: - -``` rust -use rtfm::{Duration, Instant, U32Ext}; - -#[rtfm::app(/* .. */)] -const APP: () = { - #[task(schedule = [b])] - fn a() { - // .. - } -}; -``` - -Into this: - -``` rust -use rtfm::cyccnt::{Duration, Instant, U32Ext}; -// ^^^^^^^^ - -#[rtfm::app(/* .. */, monotonic = rtfm::cyccnt::CYCCNT)] -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -const APP: () = { - #[init] - fn init(cx: init::Context) { - cx.core.DWT.enable_cycle_counter(); - // optional, configure the DWT run without a debugger connected - cx.core.DCB.enable_trace(); - } - #[task(schedule = [b])] - fn a(cx: a::Context) { - // .. - } -}; -``` diff --git a/book/en/src/migration/migration_v5.md b/book/en/src/migration/migration_v5.md deleted file mode 100644 index 5a8fabc..0000000 --- a/book/en/src/migration/migration_v5.md +++ /dev/null @@ -1,372 +0,0 @@ -# Migrating from v0.5.x to v1.0.0 - -This section describes how to upgrade from v0.5.x to v1.0.0 of the RTIC framework. - -## `Cargo.toml` - version bump - -Change the version of `cortex-m-rtic` to `"1.0.0"`. - -## `mod` instead of `const` - -With the support of attributes on modules the `const APP` workaround is not needed. - -Change - -``` rust -#[rtic::app(/* .. */)] -const APP: () = { - [code here] -}; -``` - -into - -``` rust -#[rtic::app(/* .. */)] -mod app { - [code here] -} -``` - -Now that a regular Rust module is used it means it is possible to have custom -user code within that module. -Additionally, it means that `use`-statements for resources used in user -code must be moved inside `mod app`, or be referred to with `super`. For -example, change: - -```rust -use some_crate::some_func; - -#[rtic::app(/* .. */)] -const APP: () = { - fn func() { - some_crate::some_func(); - } -}; -``` - -into - -```rust -#[rtic::app(/* .. */)] -mod app { - use some_crate::some_func; - - fn func() { - some_crate::some_func(); - } -} -``` - -or - -```rust -use some_crate::some_func; - -#[rtic::app(/* .. */)] -mod app { - fn func() { - super::some_crate::some_func(); - } -} -``` - -## Move Dispatchers from `extern "C"` to app arguments - -Change - -``` rust -#[rtic::app(/* .. */)] -const APP: () = { - [code here] - - // 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(); - } -}; -``` - -into - -``` rust -#[rtic::app(/* .. */, dispatchers = [SSI0, QEI0])] -mod app { - [code here] -} -``` - -This works also for ram functions, see examples/ramfunc.rs - - -## Resources structs - `#[shared]`, `#[local]` - -Previously the RTIC resources had to be in in a struct named exactly "Resources": - -``` rust -struct Resources { - // Resources defined in here -} -``` - -With RTIC v1.0.0 the resources structs are annotated similarly like -`#[task]`, `#[init]`, `#[idle]`: with the attributes `#[shared]` and `#[local]` - -``` rust -#[shared] -struct MySharedResources { - // Resources shared between tasks are defined here -} - -#[local] -struct MyLocalResources { - // Resources defined here cannot be shared between tasks; each one is local to a single task -} -``` - -These structs can be freely named by the developer. - -## `shared` and `local` arguments in `#[task]`s - -In v1.0.0 resources are split between `shared` resources and `local` resources. -`#[task]`, `#[init]` and `#[idle]` no longer have a `resources` argument; they must now use the `shared` and `local` arguments. - -In v0.5.x: - -``` rust -struct Resources { - local_to_b: i64, - shared_by_a_and_b: i64, -} - -#[task(resources = [shared_by_a_and_b])] -fn a(_: a::Context) {} - -#[task(resources = [shared_by_a_and_b, local_to_b])] -fn b(_: b::Context) {} -``` - -In v1.0.0: - -``` rust -#[shared] -struct Shared { - shared_by_a_and_b: i64, -} - -#[local] -struct Local { - local_to_b: i64, -} - -#[task(shared = [shared_by_a_and_b])] -fn a(_: a::Context) {} - -#[task(shared = [shared_by_a_and_b], local = [local_to_b])] -fn b(_: b::Context) {} -``` - -## Symmetric locks - -Now RTIC utilizes symmetric locks, this means that the `lock` method need -to be used for all `shared` resource access. -In old code one could do the following as the high priority -task has exclusive access to the resource: - -``` rust -#[task(priority = 2, resources = [r])] -fn foo(cx: foo::Context) { - cx.resources.r = /* ... */; -} - -#[task(resources = [r])] -fn bar(cx: bar::Context) { - cx.resources.r.lock(|r| r = /* ... */); -} -``` - -And with symmetric locks one needs to use locks in both tasks: - -``` rust -#[task(priority = 2, shared = [r])] -fn foo(cx: foo::Context) { - cx.shared.r.lock(|r| r = /* ... */); -} - -#[task(shared = [r])] -fn bar(cx: bar::Context) { - cx.shared.r.lock(|r| r = /* ... */); -} -``` - -Note that the performance does not change thanks to LLVM's optimizations which optimizes away unnecessary locks. - -## Lock-free resource access - -In RTIC 0.5 resources shared by tasks running at the same priority could be accessed *without* the `lock` API. -This is still possible in 1.0: the `#[shared]` resource must be annotated with the field-level `#[lock_free]` attribute. - -v0.5 code: - -``` rust -struct Resources { - counter: u64, -} - -#[task(resources = [counter])] -fn a(cx: a::Context) { - *cx.resources.counter += 1; -} - -#[task(resources = [counter])] -fn b(cx: b::Context) { - *cx.resources.counter += 1; -} -``` - -v1.0 code: - -``` rust -#[shared] -struct Shared { - #[lock_free] - counter: u64, -} - -#[task(shared = [counter])] -fn a(cx: a::Context) { - *cx.shared.counter += 1; -} - -#[task(shared = [counter])] -fn b(cx: b::Context) { - *cx.shared.counter += 1; -} -``` - -## no `static mut` transform - -`static mut` variables are no longer transformed to safe `&'static mut` references. -Instead of that syntax, use the `local` argument in `#[init]`. - -v0.5.x code: - -``` rust -#[init] -fn init(_: init::Context) { - static mut BUFFER: [u8; 1024] = [0; 1024]; - let buffer: &'static mut [u8; 1024] = BUFFER; -} -``` - -v1.0.0 code: - -``` rust -#[init(local = [ - buffer: [u8; 1024] = [0; 1024] -// type ^^^^^^^^^^^^ ^^^^^^^^^ initial value -])] -fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { - let buffer: &'static mut [u8; 1024] = cx.local.buffer; - - (Shared {}, Local {}, init::Monotonics()) -} -``` - -## Init always returns late resources - -In order to make the API more symmetric the #[init]-task always returns a late resource. - -From this: - -``` rust -#[rtic::app(device = lm3s6965)] -const APP: () = { - #[init] - fn init(_: init::Context) { - rtic::pend(Interrupt::UART0); - } - - // [more code] -}; -``` - -to this: - -``` rust -#[rtic::app(device = lm3s6965)] -mod app { - #[shared] - struct MySharedResources {} - - #[local] - struct MyLocalResources {} - - #[init] - fn init(_: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { - rtic::pend(Interrupt::UART0); - - (MySharedResources, MyLocalResources, init::Monotonics()) - } - - // [more code] -} -``` - -## Spawn from anywhere - -With the new spawn/spawn_after/spawn_at interface, -old code requiring the context `cx` for spawning such as: - -``` rust -#[task(spawn = [bar])] -fn foo(cx: foo::Context) { - cx.spawn.bar().unwrap(); -} - -#[task(schedule = [bar])] -fn bar(cx: bar::Context) { - cx.schedule.foo(/* ... */).unwrap(); -} -``` - -Will now be written as: - -``` rust -#[task] -fn foo(_c: foo::Context) { - bar::spawn().unwrap(); -} - -#[task] -fn bar(_c: bar::Context) { - // Takes a Duration, relative to “now” - let spawn_handle = foo::spawn_after(/* ... */); -} - -#[task] -fn bar(_c: bar::Context) { - // Takes an Instant - let spawn_handle = foo::spawn_at(/* ... */); -} -``` - -Thus the requirement of having access to the context is dropped. - -Note that the attributes `spawn`/`schedule` in the task definition are no longer needed. - ---- - -## Additions - -### Extern tasks - -Both software and hardware tasks can now be defined external to the `mod app`. -Previously this was possible only by implementing a trampoline calling out the task implementation. - -See examples `examples/extern_binds.rs` and `examples/extern_spawn.rs`. - -This enables breaking apps into multiple files. diff --git a/book/en/src/migration_v1_v2.md b/book/en/src/migration_v1_v2.md new file mode 100644 index 0000000..96fa231 --- /dev/null +++ b/book/en/src/migration_v1_v2.md @@ -0,0 +1,18 @@ +# Migrating from v1.0.x to v2.0.0 + +Migrating a project from RTIC `v1.0.x` to `v2.0.0` involves the following steps: + +1. `v2.0.0` requires [`#![type_alias_impl_trait]`](https://github.com/rust-lang/rust/issues/63063) and Rust Nightly. +2. Migrating from the monotonics included in `v1.0.x` to `rtic-time` and `rtic-monotonics`, replacing `spawn_after`, `spawn_at`. +3. Software tasks are now required to be `async`, and using them correctly. +4. Understanding and using data types provided by `rtic-sync`. + +For a detailed description of the changes, refer to the subchapters. + +If you wish to see a code example of changes required, you can check out [the full example migration page](./migration_v2/complete_example.md). + +#### TL;DR (Too Long; Didn't Read) +1. Add `#![type_alias_impl_trait]` to your crate, and use `cargo +nightly`. +2. Instead of `spawn_after` and `spawn_at`, you now use the `async` functions `delay`, `delay_until` (and related) with impls provided by `rtic-monotonics`. +3. Software tasks _must_ be `async fn`s now. Not returning from a task is allowed so long as there is an `await` in the task. You can still `lock` shared resources. +4. Use `rtic_sync::Arbiter` to `await` access to a shared resource, and `rtic-channel` to communicate between tasks instead of `spawn`-ing new ones. \ No newline at end of file diff --git a/book/en/src/migration_v1_v2/async_tasks.md b/book/en/src/migration_v1_v2/async_tasks.md new file mode 100644 index 0000000..54e0893 --- /dev/null +++ b/book/en/src/migration_v1_v2/async_tasks.md @@ -0,0 +1,55 @@ +# Using `async` softare tasks. + +There have been a few changes to software tasks. They are outlined below. + +### Software tasks must now be `async`. + +All software tasks are now required to be `async`. + +#### Required changes. + +All of the tasks in your project that do not bind to an interrupt must now be an `async fn`. For example: + +``` rust +#[task( + local = [ some_resource ], + shared = [ my_shared_resource ], + priority = 2 +)] +fn my_task(cx: my_task::Context) { + cx.local.some_resource.do_trick(); + cx.shared.my_shared_resource.lock(|s| s.do_shared_thing()); +} +``` + +becomes + +``` rust +#[task( + local = [ some_resource ], + shared = [ my_shared_resource ], + priority = 2 +)] +async fn my_task(cx: my_task::Context) { + cx.local.some_resource.do_trick(); + cx.shared.my_shared_resource.lock(|s| s.do_shared_thing()); +} +``` + +## Software tasks may now run forever + +The new `async` software tasks are allowed to run forever, on one precondition: **there must be an `await` within the infinite loop of the task**. An example of such a task: + +``` rust +#[task(local = [ my_channel ] )] +async fn my_task_that_runs_forever(cx: my_task_that_runs_forever::Context) { + loop { + let value = cx.local.my_channel.recv().await; + do_something_with_value(value); + } +} +``` + +## `spawn_after` and `spawn_at` have been removed. + +As discussed in the [Migrating to `rtic-monotonics`](./monotonics.md) chapter, `spawn_after` and `spawn_at` are no longer available. \ No newline at end of file diff --git a/book/en/src/migration_v1_v2/complete_example.md b/book/en/src/migration_v1_v2/complete_example.md new file mode 100644 index 0000000..dc29b25 --- /dev/null +++ b/book/en/src/migration_v1_v2/complete_example.md @@ -0,0 +1,169 @@ +# A complete example of migration + +Below you can find the code for the implementation of the `stm32f3_blinky` example for v1.0.x and for v2.0.0. Further down, a diff is displayed. + +# v1.0.X + +```rust +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use panic_rtt_target as _; +use rtic::app; +use rtt_target::{rprintln, rtt_init_print}; +use stm32f3xx_hal::gpio::{Output, PushPull, PA5}; +use stm32f3xx_hal::prelude::*; +use systick_monotonic::{fugit::Duration, Systick}; + +#[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])] +mod app { + use super::*; + + #[shared] + struct Shared {} + + #[local] + struct Local { + led: PA5>, + state: bool, + } + + #[monotonic(binds = SysTick, default = true)] + type MonoTimer = Systick<1000>; + + #[init] + fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + // Setup clocks + let mut flash = cx.device.FLASH.constrain(); + let mut rcc = cx.device.RCC.constrain(); + + let mono = Systick::new(cx.core.SYST, 36_000_000); + + rtt_init_print!(); + rprintln!("init"); + + let _clocks = rcc + .cfgr + .use_hse(8.MHz()) + .sysclk(36.MHz()) + .pclk1(36.MHz()) + .freeze(&mut flash.acr); + + // Setup LED + let mut gpioa = cx.device.GPIOA.split(&mut rcc.ahb); + let mut led = gpioa + .pa5 + .into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper); + led.set_high().unwrap(); + + // Schedule the blinking task + blink::spawn_after(Duration::::from_ticks(1000)).unwrap(); + + ( + Shared {}, + Local { led, state: false }, + init::Monotonics(mono), + ) + } + + #[task(local = [led, state])] + fn blink(cx: blink::Context) { + rprintln!("blink"); + if *cx.local.state { + cx.local.led.set_high().unwrap(); + *cx.local.state = false; + } else { + cx.local.led.set_low().unwrap(); + *cx.local.state = true; + } + blink::spawn_after(Duration::::from_ticks(1000)).unwrap(); + } +} + +``` + +# V2.0.0 + +``` rust +{{ #include ../../../../examples/stm32f3_blinky/src/main.rs }} +``` + +## A diff between the two projects + +_Note_: This diff may not be 100% accurate, but it displays the important changes. + +``` diff +#![no_main] + #![no_std] ++#![feature(type_alias_impl_trait)] + + use panic_rtt_target as _; + use rtic::app; + use stm32f3xx_hal::gpio::{Output, PushPull, PA5}; + use stm32f3xx_hal::prelude::*; +-use systick_monotonic::{fugit::Duration, Systick}; ++use rtic_monotonics::Systick; + + #[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])] + mod app { +@@ -20,16 +21,14 @@ mod app { + state: bool, + } + +- #[monotonic(binds = SysTick, default = true)] +- type MonoTimer = Systick<1000>; +- + #[init] + fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + // Setup clocks + let mut flash = cx.device.FLASH.constrain(); + let mut rcc = cx.device.RCC.constrain(); + +- let mono = Systick::new(cx.core.SYST, 36_000_000); ++ let mono_token = rtic_monotonics::create_systick_token!(); ++ let mono = Systick::new(cx.core.SYST, 36_000_000, mono_token); + + let _clocks = rcc + .cfgr +@@ -46,7 +45,7 @@ mod app { + led.set_high().unwrap(); + + // Schedule the blinking task +- blink::spawn_after(Duration::::from_ticks(1000)).unwrap(); ++ blink::spawn().unwrap(); + + ( + Shared {}, +@@ -56,14 +55,18 @@ mod app { + } + + #[task(local = [led, state])] +- fn blink(cx: blink::Context) { +- rprintln!("blink"); +- if *cx.local.state { +- cx.local.led.set_high().unwrap(); +- *cx.local.state = false; +- } else { +- cx.local.led.set_low().unwrap(); +- *cx.local.state = true; +- blink::spawn_after(Duration::::from_ticks(1000)).unwrap(); +- } ++ async fn blink(cx: blink::Context) { ++ loop { ++ // A task is now allowed to run forever, provided that ++ // there is an `await` somewhere in the loop. ++ SysTick::delay(1000.millis()).await; ++ rprintln!("blink"); ++ if *cx.local.state { ++ cx.local.led.set_high().unwrap(); ++ *cx.local.state = false; ++ } else { ++ cx.local.led.set_low().unwrap(); ++ *cx.local.state = true; ++ } ++ } ++ } + } +``` \ No newline at end of file diff --git a/book/en/src/migration_v1_v2/monotonics.md b/book/en/src/migration_v1_v2/monotonics.md new file mode 100644 index 0000000..a8b0dba --- /dev/null +++ b/book/en/src/migration_v1_v2/monotonics.md @@ -0,0 +1,13 @@ +# Migrating to `rtic-monotonics` + +In previous versions of `rtic`, monotonics were an integral, tightly coupled part of the `#[rtic::app]`. In this new version, [`rtic-monotonics`] provides them in a more decoupled way. + +The `#[monotonic]` attribute is no longer used. Instead, you use a `create_X_token` from [`rtic-monotonics`]. An invocation of this macro returns an interrupt registration token, which can be used to construct an instance of your desired monotonic. + +`spawn_after` and `spawn_at` are no longer available. Instead, you use the async functions `delay` and `delay_until` provided by ipmlementations of the `rtic_time::Monotonic` trait, available through [`rtic-monotonics`]. + +Check out the [code example](./complete_example.md) for an overview of the required changes. + +For more information on current monotonic implementations, see [the `rtic-monotonics` documentation](https://docs.rs/rtic-monotonics), and [the examples](https://github.com/rtic-rs/rtic/tree/master/examples). + +[`rtic-monotonics`]: ghttps://github.com/rtic/rtic-monotonics \ No newline at end of file diff --git a/book/en/src/migration_v1_v2/nightly.md b/book/en/src/migration_v1_v2/nightly.md new file mode 100644 index 0000000..09f6e33 --- /dev/null +++ b/book/en/src/migration_v1_v2/nightly.md @@ -0,0 +1,5 @@ +# RTIC now requires Rust Nightly + +The new `async` features require that you use a nightly compiler, and that the feature `type_alias_impl_trait` is enabled for your applications. + +To enable this feature, you must add the line `#![type_alias_impl_trait]` to the root file of your project, on the lines below or above where `#![no_std]` and `#![no_main]` are defined. \ No newline at end of file diff --git a/book/en/src/migration_v1_v2/rtic-sync.md b/book/en/src/migration_v1_v2/rtic-sync.md new file mode 100644 index 0000000..fefde03 --- /dev/null +++ b/book/en/src/migration_v1_v2/rtic-sync.md @@ -0,0 +1,9 @@ +# Using `rtic-sync` + +`rtic-sync` provides primitives that can be used for message passing and resource sharing in async context. + +The important structs are: +* The `Arbiter`, which allows you to await access to a shared resource in async contexts without using `lock`. +* `Channel`, which allows you to communicate between tasks (both `async` and non-`async`). + +For more information on these structs, see the [`rtic-sync` docs](https://docs.rs/rtic-sync) \ No newline at end of file -- cgit v1.2.3 From 3d98102a54c660d54ddfb36ad02cba0f25783750 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 21:27:50 +0200 Subject: Refer to rtic-rs/rtic/examples instead --- book/en/src/awesome_rtic.md | 7 +++---- book/en/src/by-example/starting_a_project.md | 8 ++------ 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/awesome_rtic.md b/book/en/src/awesome_rtic.md index 36d38e6..2fa4ec9 100644 --- a/book/en/src/awesome_rtic.md +++ b/book/en/src/awesome_rtic.md @@ -1,8 +1,7 @@ # Awesome RTIC examples -See the [`rtic-rs/rtic-examples`][rticexamples] repository for community -provided complete examples. +See the [`rtic-rs/rtic/examples`][rticexamples] repository for complete examples. -Pull-requests to this repo are welcome! +Pull-requests are welcome! -[rticexamples]: https://github.com/rtic-rs/rtic-examples +[rticexamples]: https://github.com/rtic-rs/rtic/tree/master/examples diff --git a/book/en/src/by-example/starting_a_project.md b/book/en/src/by-example/starting_a_project.md index 86d7e71..ae979f4 100644 --- a/book/en/src/by-example/starting_a_project.md +++ b/book/en/src/by-example/starting_a_project.md @@ -10,12 +10,8 @@ If you are targeting ARMv6-M or ARMv8-M-base architecture, check out the section This will give you an RTIC application with support for RTT logging with [`defmt`] and stack overflow protection using [`flip-link`]. There is also a multitude of examples provided by the community: -For inspiration, you may look at the below resources. For now, they cover RTIC v1.x, but will be updated with RTIC v2.x examples over time. - -- [`rtic-examples`] - Multiple projects -- [https://github.com/kalkyl/f411-rtic](https://github.com/kalkyl/f411-rtic) -- ... More to come +For inspiration, you may look at the [rtic examples]. [`defmt`]: https://github.com/knurling-rs/defmt/ [`flip-link`]: https://github.com/knurling-rs/flip-link/ -[`rtic-examples`]: https://github.com/rtic-rs/rtic-examples +[rtic examples]: https://github.com/rtic-rs/rtic/tree/master/examples -- cgit v1.2.3 From a14d24007ae6391121dc493782b900d6edb7d992 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 22:47:07 +0200 Subject: Update delay.md file to be a bit easier to read, and add spoiler tags for the walls of code --- book/en/src/by-example/delay.md | 58 +++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 22 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/by-example/delay.md b/book/en/src/by-example/delay.md index f286363..893ead9 100644 --- a/book/en/src/by-example/delay.md +++ b/book/en/src/by-example/delay.md @@ -1,18 +1,20 @@ # Tasks with delay -A convenient way to express *miniminal* timing requirements is by means of delaying progression. +A convenient way to express miniminal timing requirements is by delaying progression. -This can be achieved by instantiating a monotonic timer: +This can be achieved by instantiating a monotonic timer (for implementations, see [`rtic-monotonics`]): + +[`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics +[`rtic-time`]: https://github.com/rtic-rs/rtic/tree/master/rtic-time ``` rust ... -rtic_monotonics::make_systick_handler!(); - #[init] fn init(cx: init::Context) -> (Shared, Local) { hprintln!("init"); - Systick::start(cx.core.SYST, 12_000_000); + let token = rtic_monotonics::create_systick_token!(); + Systick::start(cx.core.SYST, 12_000_000, token); ... ``` @@ -28,11 +30,14 @@ async fn foo(_cx: foo::Context) { ``` -Technically, the timer queue is implemented as a list based priority queue, where list-nodes are statically allocated as part of the underlying task `Future`. Thus, the timer queue is infallible at run-time (its size and allocation is determined at compile time). + + +Technically, the timer queue is implemented as a list based priority queue, where list-nodes are statically allocated as part of the underlying task `Future`. Thus, the timer queue is infallible at run-time (its size and allocation are determined at compile time). Similarly the channels implementation, the timer-queue implementation relies on a global *Critical Section* (CS) for race protection. For the examples a CS implementation is provided by adding `--features test-critical-section` to the build options. -For a complete example: +
+A complete example ``` rust {{#include ../../../../rtic/examples/async-delay.rs}} @@ -46,11 +51,15 @@ $ cargo run --target thumbv7m-none-eabi --example async-delay --features test-cr {{#include ../../../../rtic/ci/expected/async-delay.run}} ``` +
+ ## Timeout -Rust `Futures` (underlying Rust `async`/`await`) are composable. This makes it possible to `select` in between `Futures` that have completed. +Rust [`Future`]s (underlying Rust `async`/`await`) are composable. This makes it possible to `select` in between `Futures` that have completed. -A common use case is transactions with associated timeout. In the examples shown below, we introduce a fake HAL device which performs some transaction. We have modelled the time it takes based on the input parameter (`n`) as `350ms + n * 100ms)`. +[`Future`]: https://doc.rust-lang.org/std/future/trait.Future.html + +A common use case is transactions with an associated timeout. In the examples shown below, we introduce a fake HAL device that performs some transaction. We have modelled the time it takes based on the input parameter (`n`) as `350ms + n * 100ms`. Using the `select_biased` macro from the `futures` crate it may look like this: @@ -62,19 +71,13 @@ select_biased! { } ``` -Assuming the `hal_get` will take 450ms to finish, a short timeout of 200ms will expire. +Assuming the `hal_get` will take 450ms to finish, a short timeout of 200ms will expire before `hal_get` can complete. -``` rust -// Call hal with long relative timeout using `select_biased` -select_biased! { - v = hal_get(1).fuse() => hprintln!("hal returned {}", v), // hal finish first - _ = Systick::delay(1000.millis()).fuse() => hprintln!("timeout", ), -} -``` +Extending the timeout to 1000ms would cause `hal_get` will to complete first. -By extending the timeout to 1000ms, the `hal_get` will finish first. +Using `select_biased` any number of futures can be combined, so its very powerful. However, as the timeout pattern is frequently used, more ergonomic support is baked into RTIC, provided by the [`rtic-monotonics`] and [`rtic-time`] crates. -Using `select_biased` any number of futures can be combined, so its very powerful. However, as the timeout pattern is frequently used, it is directly supported by the RTIC [rtc-monotonics] and [rtic-time] crates. The second example from above using `timeout_after`: +Rewriting the second example from above using `timeout_after` gives: ``` rust // Call hal with long relative timeout using monotonic `timeout_after` @@ -84,7 +87,7 @@ match Systick::timeout_after(1000.millis(), hal_get(1)).await { } ``` -In cases you want exact control over time without drift. For this purpose we can use exact points in time using `Instance`, and spans of time using `Duration`. Operations on the `Instance` and `Duration` types are given by the [fugit] crate. +In cases where you want exact control over time without drift we can use exact points in time using `Instant`, and spans of time using `Duration`. Operations on the `Instant` and `Duration` types come from the [`fugit`] crate. [fugit]: https://crates.io/crates/fugit @@ -109,10 +112,20 @@ for n in 0..3 { } ``` -`instant = Systick::now()` gives the baseline (i.e., the absolute current point in time). We want to call `hal_get` after 1000ms relative to this absolute point in time. This can be accomplished by `Systick::delay_until(instant).await;`. We define the absolute point in time for the `timeout`, and call `Systick::timeout_at(timeout, hal_get(n)).await`. For the first loop iteration `n == 0`, and the `hal_get` will take 350ms (and finishes before the timeout). For the second iteration `n == 1`, and `hal_get` will take 450ms (and again succeeds to finish before the timeout). For the third iteration `n == 2` (`hal_get` will take 5500ms to finish). In this case we will run into a timeout. +`let mut instant = Systick::now()` sets the starting time of execution. + +We want to call `hal_get` after 1000ms relative to this starting time. This can be accomplished by using `Systick::delay_until(instant).await`. + +Then, we define a point in time called `timeout`, and call `Systick::timeout_at(timeout, hal_get(n)).await`. + +For the first iteration of the loop, with `n == 0`, the `hal_get` will take 350ms (and finishes before the timeout). + +For the second iteration, with `n == 1`, the `hal_get` will take 450ms (and again succeeds to finish before the timeout). +For the third iteration, with `n == 2`, `hal_get` will take 550ms to finish, in which case we will run into a timeout. -The complete example: +
+A complete example ``` rust {{#include ../../../../rtic/examples/async-timeout.rs}} @@ -125,3 +138,4 @@ $ cargo run --target thumbv7m-none-eabi --example async-timeout --features test- ``` console {{#include ../../../../rtic/ci/expected/async-timeout.run}} ``` +
-- cgit v1.2.3 From 552ecd4458e24369932bc4a3dd641c4c4e3e59fc Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 22:53:45 +0200 Subject: Promote starting a new project to it's own chapter --- book/en/src/SUMMARY.md | 2 +- book/en/src/by-example/starting_a_project.md | 17 ----------------- book/en/src/starting_a_project.md | 17 +++++++++++++++++ 3 files changed, 18 insertions(+), 18 deletions(-) delete mode 100644 book/en/src/by-example/starting_a_project.md create mode 100644 book/en/src/starting_a_project.md (limited to 'book/en/src') diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index 8b19bf1..a500fd9 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -2,6 +2,7 @@ [Preface](./preface.md) +- [Starting a new project](./starting_a_project.md) - [RTIC by example](./by-example.md) - [The `app`](./by-example/app.md) - [Hardware tasks & `pend`](./by-example/hardware_tasks.md) @@ -11,7 +12,6 @@ - [The idle task](./by-example/app_idle.md) - [Channel based communication](./by-example/channel.md) - [Delay and Timeout](./by-example/delay.md) - - [Starting a new project](./by-example/starting_a_project.md) - [The minimal app](./by-example/app_minimal.md) - [Tips & Tricks](./by-example/tips.md) - [Implementing Monotonic](./by-example/tips_monotonic_impl.md) diff --git a/book/en/src/by-example/starting_a_project.md b/book/en/src/by-example/starting_a_project.md deleted file mode 100644 index ae979f4..0000000 --- a/book/en/src/by-example/starting_a_project.md +++ /dev/null @@ -1,17 +0,0 @@ -# Starting a new project - -A recommendation when starting a RTIC project from scratch is to -follow RTIC's [`defmt-app-template`]. - -If you are targeting ARMv6-M or ARMv8-M-base architecture, check out the section [Target Architecture](../internals/targets.md) for more information on hardware limitations to be aware of. - -[`defmt-app-template`]: https://github.com/rtic-rs/defmt-app-template - -This will give you an RTIC application with support for RTT logging with [`defmt`] and stack overflow -protection using [`flip-link`]. There is also a multitude of examples provided by the community: - -For inspiration, you may look at the [rtic examples]. - -[`defmt`]: https://github.com/knurling-rs/defmt/ -[`flip-link`]: https://github.com/knurling-rs/flip-link/ -[rtic examples]: https://github.com/rtic-rs/rtic/tree/master/examples diff --git a/book/en/src/starting_a_project.md b/book/en/src/starting_a_project.md new file mode 100644 index 0000000..ae979f4 --- /dev/null +++ b/book/en/src/starting_a_project.md @@ -0,0 +1,17 @@ +# Starting a new project + +A recommendation when starting a RTIC project from scratch is to +follow RTIC's [`defmt-app-template`]. + +If you are targeting ARMv6-M or ARMv8-M-base architecture, check out the section [Target Architecture](../internals/targets.md) for more information on hardware limitations to be aware of. + +[`defmt-app-template`]: https://github.com/rtic-rs/defmt-app-template + +This will give you an RTIC application with support for RTT logging with [`defmt`] and stack overflow +protection using [`flip-link`]. There is also a multitude of examples provided by the community: + +For inspiration, you may look at the [rtic examples]. + +[`defmt`]: https://github.com/knurling-rs/defmt/ +[`flip-link`]: https://github.com/knurling-rs/flip-link/ +[rtic examples]: https://github.com/rtic-rs/rtic/tree/master/examples -- cgit v1.2.3 From a76f4cd85fd8eef258c6bf1b54211a96e626931e Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 22:57:16 +0200 Subject: monotonic.md is now deprecated --- book/en/src/by-example/monotonic.md | 64 ------------------------------------- 1 file changed, 64 deletions(-) delete mode 100644 book/en/src/by-example/monotonic.md (limited to 'book/en/src') diff --git a/book/en/src/by-example/monotonic.md b/book/en/src/by-example/monotonic.md deleted file mode 100644 index 3a23681..0000000 --- a/book/en/src/by-example/monotonic.md +++ /dev/null @@ -1,64 +0,0 @@ -# Monotonic & spawn_{at/after} - -The understanding of time is an important concept in embedded systems, and to be able to run tasks -based on time is essential. The framework provides the static methods -`task::spawn_after(/* duration */)` and `task::spawn_at(/* specific time instant */)`. -`spawn_after` is more commonly used, but in cases where it's needed to have spawns happen -without drift or to a fixed baseline `spawn_at` is available. - -The `#[monotonic]` attribute, applied to a type alias definition, exists to support this. -This type alias must point to a type which implements the [`rtic_monotonic::Monotonic`] trait. -This is generally some timer which handles the timing of the system. -One or more monotonics can coexist in the same system, for example a slow timer that wakes the -system from sleep and another which purpose is for fine grained scheduling while the -system is awake. - -[`rtic_monotonic::Monotonic`]: https://docs.rs/rtic-monotonic - -The attribute has one required parameter and two optional parameters, `binds`, `default` and -`priority` respectively. -The required parameter, `binds = InterruptName`, associates an interrupt vector to the timer's -interrupt, while `default = true` enables a shorthand API when spawning and accessing -time (`monotonics::now()` vs `monotonics::MyMono::now()`), and `priority` sets the priority -of the interrupt vector. - -> The default `priority` is the **maximum priority** of the system. -> If your system has a high priority task with tight scheduling requirements, -> it might be desirable to demote the `monotonic` task to a lower priority -> to reduce scheduling jitter for the high priority task. -> This however might introduce jitter and delays into scheduling via the `monotonic`, -> making it a trade-off. - -The monotonics are initialized in `#[init]` and returned within the `init::Monotonic( ... )` tuple. -This activates the monotonics making it possible to use them. - -See the following example: - -``` rust -{{#include ../../../../examples/schedule.rs}} -``` - -``` console -$ cargo run --target thumbv7m-none-eabi --example schedule -{{#include ../../../../ci/expected/schedule.run}} -``` - -A key requirement of a Monotonic is that it must deal gracefully with -hardware timer overruns. - -## Canceling or rescheduling a scheduled task - -Tasks spawned using `task::spawn_after` and `task::spawn_at` returns a `SpawnHandle`, -which allows canceling or rescheduling of the task scheduled to run in the future. - -If `cancel` or `reschedule_at`/`reschedule_after` returns an `Err` it means that the operation was -too late and that the task is already sent for execution. The following example shows this in action: - -``` rust -{{#include ../../../../examples/cancel-reschedule.rs}} -``` - -``` console -$ cargo run --target thumbv7m-none-eabi --example cancel-reschedule -{{#include ../../../../ci/expected/cancel-reschedule.run}} -``` -- cgit v1.2.3 From 6c2c1ab25197ab4a202cda3620370714aebc663a Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 22:57:24 +0200 Subject: Clarify delay and timeout uses monotonics --- book/en/src/SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'book/en/src') diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index a500fd9..3e2b9ca 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -11,7 +11,7 @@ - [The init task](./by-example/app_init.md) - [The idle task](./by-example/app_idle.md) - [Channel based communication](./by-example/channel.md) - - [Delay and Timeout](./by-example/delay.md) + - [Delay and Timeout using Monotonics](./by-example/delay.md) - [The minimal app](./by-example/app_minimal.md) - [Tips & Tricks](./by-example/tips.md) - [Implementing Monotonic](./by-example/tips_monotonic_impl.md) -- cgit v1.2.3 From cb0ceea472f33ed7a8b17fe7e0b98f24927d9185 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 23 Apr 2023 13:17:39 +0200 Subject: Remove v1 reference here --- book/en/src/by-example/tips_monotonic_impl.md | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/by-example/tips_monotonic_impl.md b/book/en/src/by-example/tips_monotonic_impl.md index 5dc4dd7..9f88c19 100644 --- a/book/en/src/by-example/tips_monotonic_impl.md +++ b/book/en/src/by-example/tips_monotonic_impl.md @@ -4,7 +4,7 @@ The framework is flexible because it can use any timer which has compare-match a For RTIC 1.0 and 2.0 we instead assume the user has a time library, e.g. [`fugit`], as the basis for all time-based operations when implementing `Monotonic`. These libraries make it much easier to correctly implement the `Monotonic` trait, allowing the use of almost any timer in the system for scheduling. -The trait documents the requirements for each method. There are reference implementations available in [`rtic-monotonics`](https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics/src) that can be used for inspriation. +The trait documents the requirements for each method. There are reference implementations available in [`rtic-monotonics`] that can be used for inspriation. - [`Systick based`], runs at a fixed interrupt (tick) rate - with some overhead but simple and provides support for large time spans - [`RP2040 Timer`], a "proper" implementation with support for waiting for long periods without interrupts. Clearly demonstrates how to use the `TimerQueue` to handle scheduling. @@ -16,25 +16,10 @@ Contributing new implementations of `Monotonic` can be done in multiple ways: * Implement the trait behind a feature flag in [`rtic-monotonics`], and create a PR for them to be included in the main RTIC repository. This way, the implementations of are in-tree, and RTIC can guarantee their correctness, and can update them in the case of a new release. * Implement the changes in an external repository. - -# V1.0.x - -Here is a list of `Monotonic` implementations for RTIC 1.0: - -- [`STM32F411 series`], implemented for the 32-bit timers -- [`Nordic nRF52 series Timer`], implemented for the 32-bit timers -- [`Nordic nRF52 series RTC`], implemented for the RTCs -- [`DWT and Systick based`], a more efficient (tickless) implementation - requires both `SysTick` and `DWT`, supports both high resolution and large time spans - -If you know of more implementations feel free to add them to this list. - +[`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics/ [`rtic_time::Monotonic`]: https://docs.rs/rtic_time/ [`fugit`]: https://docs.rs/fugit/ -[`STM32F411 series`]: https://github.com/kalkyl/f411-rtic/blob/a696fce7d6d19fda2356c37642c4d53547982cca/src/mono.rs -[`Nordic nRF52 series Timer`]: https://github.com/kalkyl/nrf-play/blob/47f4410d4e39374c18ff58dc17c25159085fb526/src/mono.rs -[`Nordic nRF52 series RTC`]: https://gist.github.com/korken89/fe94a475726414dd1bce031c76adc3dd [`Systick based`]: https://github.com/rtic-monotonics -[`DWT and Systick based`]: https://github.com/rtic-rs/dwt-systick-monotonic [`rtic-monotonics`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics [`RP2040 Timer`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics/src/rp2040.rs [`nRF52 timers`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics/src/nrf.rs \ No newline at end of file -- cgit v1.2.3 From e51146a98cc7c83ea574d13b4b5d8e7ceeeb004b Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 23 Apr 2023 13:22:35 +0200 Subject: Move tips into their own subdir --- book/en/src/SUMMARY.md | 14 ++++---- book/en/src/by-example/tips.md | 3 -- book/en/src/by-example/tips/destructureing.md | 15 ++++++++ book/en/src/by-example/tips/from_ram.md | 45 +++++++++++++++++++++++ book/en/src/by-example/tips/index.md | 3 ++ book/en/src/by-example/tips/indirection.md | 26 ++++++++++++++ book/en/src/by-example/tips/monotonic_impl.md | 25 +++++++++++++ book/en/src/by-example/tips/static_lifetimes.md | 23 ++++++++++++ book/en/src/by-example/tips/view_code.md | 47 +++++++++++++++++++++++++ book/en/src/by-example/tips_destructureing.md | 15 -------- book/en/src/by-example/tips_from_ram.md | 45 ----------------------- book/en/src/by-example/tips_indirection.md | 26 -------------- book/en/src/by-example/tips_monotonic_impl.md | 25 ------------- book/en/src/by-example/tips_static_lifetimes.md | 23 ------------ book/en/src/by-example/tips_view_code.md | 47 ------------------------- 15 files changed, 191 insertions(+), 191 deletions(-) delete mode 100644 book/en/src/by-example/tips.md create mode 100644 book/en/src/by-example/tips/destructureing.md create mode 100644 book/en/src/by-example/tips/from_ram.md create mode 100644 book/en/src/by-example/tips/index.md create mode 100644 book/en/src/by-example/tips/indirection.md create mode 100644 book/en/src/by-example/tips/monotonic_impl.md create mode 100644 book/en/src/by-example/tips/static_lifetimes.md create mode 100644 book/en/src/by-example/tips/view_code.md delete mode 100644 book/en/src/by-example/tips_destructureing.md delete mode 100644 book/en/src/by-example/tips_from_ram.md delete mode 100644 book/en/src/by-example/tips_indirection.md delete mode 100644 book/en/src/by-example/tips_monotonic_impl.md delete mode 100644 book/en/src/by-example/tips_static_lifetimes.md delete mode 100644 book/en/src/by-example/tips_view_code.md (limited to 'book/en/src') diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index 3e2b9ca..ff9cffe 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -13,13 +13,13 @@ - [Channel based communication](./by-example/channel.md) - [Delay and Timeout using Monotonics](./by-example/delay.md) - [The minimal app](./by-example/app_minimal.md) - - [Tips & Tricks](./by-example/tips.md) - - [Implementing Monotonic](./by-example/tips_monotonic_impl.md) - - [Resource de-structure-ing](./by-example/tips_destructureing.md) - - [Avoid copies when message passing](./by-example/tips_indirection.md) - - [`'static` super-powers](./by-example/tips_static_lifetimes.md) - - [Inspecting generated code](./by-example/tips_view_code.md) - + - [Tips & Tricks](./by-example/tips/index.md) + - [Implementing Monotonic](./by-example/tips/monotonic_impl.md) + - [Resource de-structure-ing](./by-example/tips/destructureing.md) + - [Avoid copies when message passing](./by-example/tips/indirection.md) + - [`'static` super-powers](./by-example/tips/static_lifetimes.md) + - [Inspecting generated code](./by-example/tips/view_code.md) + - [RTIC vs. the world](./rtic_vs.md) - [Awesome RTIC examples](./awesome_rtic.md) diff --git a/book/en/src/by-example/tips.md b/book/en/src/by-example/tips.md deleted file mode 100644 index 18d5991..0000000 --- a/book/en/src/by-example/tips.md +++ /dev/null @@ -1,3 +0,0 @@ -# Tips & tricks - -In this section we will explore common tips & tricks related to using RTIC. diff --git a/book/en/src/by-example/tips/destructureing.md b/book/en/src/by-example/tips/destructureing.md new file mode 100644 index 0000000..6e1d796 --- /dev/null +++ b/book/en/src/by-example/tips/destructureing.md @@ -0,0 +1,15 @@ +# Resource de-structure-ing + +Destructuring task resources might help readability if a task takes multiple +resources. Here are two examples on how to split up the resource struct: + +``` rust +{{#include ../../../../../rtic/examples/destructure.rs}} +``` + +``` console +$ cargo run --target thumbv7m-none-eabi --example destructure +``` +``` console +{{#include ../../../../../rtic/ci/expected/destructure.run}} +``` diff --git a/book/en/src/by-example/tips/from_ram.md b/book/en/src/by-example/tips/from_ram.md new file mode 100644 index 0000000..7306e12 --- /dev/null +++ b/book/en/src/by-example/tips/from_ram.md @@ -0,0 +1,45 @@ +# Running tasks from RAM + +The main goal of moving the specification of RTIC applications to attributes in RTIC v0.4.0 was to allow inter-operation with other attributes. For example, the `link_section` attribute can be applied to tasks to place them in RAM; this can +improve performance in some cases. + +> **IMPORTANT**: In general, the `link_section`, `export_name` and `no_mangle` attributes are powerful but also easy to misuse. Incorrectly using any of these attributes can cause undefined behavior; you should always prefer to use safe, higher level attributes around them like `cortex-m-rt`'s `interrupt` and `exception` attributes. +> +> In the particular case of RAM functions there's no safe abstraction for it in `cortex-m-rt` v0.6.5 but there's an [RFC] for adding a `ramfunc` attribute in a future release. + +[RFC]: https://github.com/rust-embedded/cortex-m-rt/pull/100 + +The example below shows how to place the higher priority task, `bar`, in RAM. + +``` rust +{{#include ../../../../../rtic/examples/ramfunc.rs}} +``` + +Running this program produces the expected output. + +``` console +$ cargo run --target thumbv7m-none-eabi --example ramfunc +``` + +``` console +{{#include ../../../../../rtic/ci/expected/ramfunc.run}} +``` + +One can look at the output of `cargo-nm` to confirm that `bar` ended in RAM +(`0x2000_0000`), whereas `foo` ended in Flash (`0x0000_0000`). + +``` console +$ cargo nm --example ramfunc --release | grep ' foo::' +``` + +``` console +{{#include ../../../../../rtic/ci/expected/ramfunc.run.grep.foo}} +``` + +``` console +$ cargo nm --example ramfunc --target thumbv7m-none-eabi --release | grep '*bar::' +``` + +``` console +{{#include ../../../../../rtic/ci/expected/ramfunc.run.grep.bar}} +``` diff --git a/book/en/src/by-example/tips/index.md b/book/en/src/by-example/tips/index.md new file mode 100644 index 0000000..18d5991 --- /dev/null +++ b/book/en/src/by-example/tips/index.md @@ -0,0 +1,3 @@ +# Tips & tricks + +In this section we will explore common tips & tricks related to using RTIC. diff --git a/book/en/src/by-example/tips/indirection.md b/book/en/src/by-example/tips/indirection.md new file mode 100644 index 0000000..eef0d8e --- /dev/null +++ b/book/en/src/by-example/tips/indirection.md @@ -0,0 +1,26 @@ +# Using indirection for faster message passing + +Message passing always involves copying the payload from the sender into a static variable and then from the static variable into the receiver. Thus sending a large buffer, like a `[u8; 128]`, as a message involves two expensive +`memcpy`s. + +Indirection can minimize message passing overhead: instead of sending the buffer by value, one can send an owning pointer into the buffer. + +One can use a global memory allocator to achieve indirection (`alloc::Box`, `alloc::Rc`, etc.), which requires using the nightly channel as of Rust v1.37.0, or one can use a statically allocated memory pool like [`heapless::Pool`]. + +[`heapless::Pool`]: https://docs.rs/heapless/0.5.0/heapless/pool/index.html + +As this example of approach goes completely outside of RTIC resource model with shared and local the program would rely on the correctness of the memory allocator, in this case `heapless::pool`. + +Here's an example where `heapless::Pool` is used to "box" buffers of 128 bytes. + +``` rust +{{#include ../../../../../rtic/examples/pool.rs}} +``` + +``` console +$ cargo run --target thumbv7m-none-eabi --example pool +``` + +``` console +{{#include ../../../../../rtic/ci/expected/pool.run}} +``` diff --git a/book/en/src/by-example/tips/monotonic_impl.md b/book/en/src/by-example/tips/monotonic_impl.md new file mode 100644 index 0000000..9f88c19 --- /dev/null +++ b/book/en/src/by-example/tips/monotonic_impl.md @@ -0,0 +1,25 @@ +# Implementing a `Monotonic` timer for scheduling + +The framework is flexible because it can use any timer which has compare-match and optionally supporting overflow interrupts for scheduling. The single requirement to make a timer usable with RTIC is implementing the `rtic-time::Monotonic` trait. + +For RTIC 1.0 and 2.0 we instead assume the user has a time library, e.g. [`fugit`], as the basis for all time-based operations when implementing `Monotonic`. These libraries make it much easier to correctly implement the `Monotonic` trait, allowing the use of almost any timer in the system for scheduling. + +The trait documents the requirements for each method. There are reference implementations available in [`rtic-monotonics`] that can be used for inspriation. + +- [`Systick based`], runs at a fixed interrupt (tick) rate - with some overhead but simple and provides support for large time spans +- [`RP2040 Timer`], a "proper" implementation with support for waiting for long periods without interrupts. Clearly demonstrates how to use the `TimerQueue` to handle scheduling. +- [`nRF52 timers`] implements monotonic & Timer Queue for the RTC and normal timers in nRF52's + +## Contributing + +Contributing new implementations of `Monotonic` can be done in multiple ways: +* Implement the trait behind a feature flag in [`rtic-monotonics`], and create a PR for them to be included in the main RTIC repository. This way, the implementations of are in-tree, and RTIC can guarantee their correctness, and can update them in the case of a new release. +* Implement the changes in an external repository. + +[`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics/ +[`rtic_time::Monotonic`]: https://docs.rs/rtic_time/ +[`fugit`]: https://docs.rs/fugit/ +[`Systick based`]: https://github.com/rtic-monotonics +[`rtic-monotonics`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics +[`RP2040 Timer`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics/src/rp2040.rs +[`nRF52 timers`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics/src/nrf.rs \ No newline at end of file diff --git a/book/en/src/by-example/tips/static_lifetimes.md b/book/en/src/by-example/tips/static_lifetimes.md new file mode 100644 index 0000000..b1fd606 --- /dev/null +++ b/book/en/src/by-example/tips/static_lifetimes.md @@ -0,0 +1,23 @@ +# 'static super-powers + +In `#[init]` and `#[idle]` `local` resources have `'static` lifetime. + +Useful when pre-allocating and/or splitting resources between tasks, drivers or some other object. This comes in handy when drivers, such as USB drivers, need to allocate memory and when using splittable data structures such as [`heapless::spsc::Queue`]. + +In the following example two different tasks share a [`heapless::spsc::Queue`] for lock-free access to the shared queue. + +[`heapless::spsc::Queue`]: https://docs.rs/heapless/0.7.5/heapless/spsc/struct.Queue.html + +``` rust +{{#include ../../../../../rtic/examples/static.rs}} +``` + +Running this program produces the expected output. + +``` console +$ cargo run --target thumbv7m-none-eabi --example static +``` + +``` console +{{#include ../../../../../rtic/ci/expected/static.run}} +``` diff --git a/book/en/src/by-example/tips/view_code.md b/book/en/src/by-example/tips/view_code.md new file mode 100644 index 0000000..b4a9066 --- /dev/null +++ b/book/en/src/by-example/tips/view_code.md @@ -0,0 +1,47 @@ +# Inspecting generated code + +`#[rtic::app]` is a procedural macro that produces support code. If for some reason you need to inspect the code generated by this macro you have two options: + +You can inspect the file `rtic-expansion.rs` inside the `target` directory. This file contains the expansion of the `#[rtic::app]` item (not your whole program!) of the *last built* (via `cargo build` or `cargo check`) RTIC application. The expanded code is not pretty printed by default, so you'll want to run `rustfmt` on it before you read it. + +``` console +$ cargo build --example smallest --target thumbv7m-none-eabi +``` + +``` console +$ rustfmt target/rtic-expansion.rs +``` + +``` console +$ tail target/rtic-expansion.rs +``` + +``` rust +#[doc = r" Implementation details"] +mod app { + #[doc = r" Always include the device crate which contains the vector table"] + use lm3s6965 as _; + #[no_mangle] + unsafe extern "C" fn main() -> ! { + rtic::export::interrupt::disable(); + let mut core: rtic::export::Peripherals = core::mem::transmute(()); + core.SCB.scr.modify(|r| r | 1 << 1); + rtic::export::interrupt::enable(); + loop { + rtic::export::wfi() + } + } +} +``` + +Or, you can use the [`cargo-expand`] sub-command. This sub-command will expand *all* the macros, including the `#[rtic::app]` attribute, and modules in your crate and print the output to the console. + +[`cargo-expand`]: https://crates.io/crates/cargo-expand + +``` console +# produces the same output as before +``` + +``` console +cargo expand --example smallest | tail +``` diff --git a/book/en/src/by-example/tips_destructureing.md b/book/en/src/by-example/tips_destructureing.md deleted file mode 100644 index ab27987..0000000 --- a/book/en/src/by-example/tips_destructureing.md +++ /dev/null @@ -1,15 +0,0 @@ -# Resource de-structure-ing - -Destructuring task resources might help readability if a task takes multiple -resources. Here are two examples on how to split up the resource struct: - -``` rust -{{#include ../../../../rtic/examples/destructure.rs}} -``` - -``` console -$ cargo run --target thumbv7m-none-eabi --example destructure -``` -``` console -{{#include ../../../../rtic/ci/expected/destructure.run}} -``` diff --git a/book/en/src/by-example/tips_from_ram.md b/book/en/src/by-example/tips_from_ram.md deleted file mode 100644 index f6b2173..0000000 --- a/book/en/src/by-example/tips_from_ram.md +++ /dev/null @@ -1,45 +0,0 @@ -# Running tasks from RAM - -The main goal of moving the specification of RTIC applications to attributes in RTIC v0.4.0 was to allow inter-operation with other attributes. For example, the `link_section` attribute can be applied to tasks to place them in RAM; this can -improve performance in some cases. - -> **IMPORTANT**: In general, the `link_section`, `export_name` and `no_mangle` attributes are powerful but also easy to misuse. Incorrectly using any of these attributes can cause undefined behavior; you should always prefer to use safe, higher level attributes around them like `cortex-m-rt`'s `interrupt` and `exception` attributes. -> -> In the particular case of RAM functions there's no safe abstraction for it in `cortex-m-rt` v0.6.5 but there's an [RFC] for adding a `ramfunc` attribute in a future release. - -[RFC]: https://github.com/rust-embedded/cortex-m-rt/pull/100 - -The example below shows how to place the higher priority task, `bar`, in RAM. - -``` rust -{{#include ../../../../rtic/examples/ramfunc.rs}} -``` - -Running this program produces the expected output. - -``` console -$ cargo run --target thumbv7m-none-eabi --example ramfunc -``` - -``` console -{{#include ../../../../rtic/ci/expected/ramfunc.run}} -``` - -One can look at the output of `cargo-nm` to confirm that `bar` ended in RAM -(`0x2000_0000`), whereas `foo` ended in Flash (`0x0000_0000`). - -``` console -$ cargo nm --example ramfunc --release | grep ' foo::' -``` - -``` console -{{#include ../../../../rtic/ci/expected/ramfunc.run.grep.foo}} -``` - -``` console -$ cargo nm --example ramfunc --target thumbv7m-none-eabi --release | grep '*bar::' -``` - -``` console -{{#include ../../../../rtic/ci/expected/ramfunc.run.grep.bar}} -``` diff --git a/book/en/src/by-example/tips_indirection.md b/book/en/src/by-example/tips_indirection.md deleted file mode 100644 index 0de14a6..0000000 --- a/book/en/src/by-example/tips_indirection.md +++ /dev/null @@ -1,26 +0,0 @@ -# Using indirection for faster message passing - -Message passing always involves copying the payload from the sender into a static variable and then from the static variable into the receiver. Thus sending a large buffer, like a `[u8; 128]`, as a message involves two expensive -`memcpy`s. - -Indirection can minimize message passing overhead: instead of sending the buffer by value, one can send an owning pointer into the buffer. - -One can use a global memory allocator to achieve indirection (`alloc::Box`, `alloc::Rc`, etc.), which requires using the nightly channel as of Rust v1.37.0, or one can use a statically allocated memory pool like [`heapless::Pool`]. - -[`heapless::Pool`]: https://docs.rs/heapless/0.5.0/heapless/pool/index.html - -As this example of approach goes completely outside of RTIC resource model with shared and local the program would rely on the correctness of the memory allocator, in this case `heapless::pool`. - -Here's an example where `heapless::Pool` is used to "box" buffers of 128 bytes. - -``` rust -{{#include ../../../../rtic/examples/pool.rs}} -``` - -``` console -$ cargo run --target thumbv7m-none-eabi --example pool -``` - -``` console -{{#include ../../../../rtic/ci/expected/pool.run}} -``` diff --git a/book/en/src/by-example/tips_monotonic_impl.md b/book/en/src/by-example/tips_monotonic_impl.md deleted file mode 100644 index 9f88c19..0000000 --- a/book/en/src/by-example/tips_monotonic_impl.md +++ /dev/null @@ -1,25 +0,0 @@ -# Implementing a `Monotonic` timer for scheduling - -The framework is flexible because it can use any timer which has compare-match and optionally supporting overflow interrupts for scheduling. The single requirement to make a timer usable with RTIC is implementing the `rtic-time::Monotonic` trait. - -For RTIC 1.0 and 2.0 we instead assume the user has a time library, e.g. [`fugit`], as the basis for all time-based operations when implementing `Monotonic`. These libraries make it much easier to correctly implement the `Monotonic` trait, allowing the use of almost any timer in the system for scheduling. - -The trait documents the requirements for each method. There are reference implementations available in [`rtic-monotonics`] that can be used for inspriation. - -- [`Systick based`], runs at a fixed interrupt (tick) rate - with some overhead but simple and provides support for large time spans -- [`RP2040 Timer`], a "proper" implementation with support for waiting for long periods without interrupts. Clearly demonstrates how to use the `TimerQueue` to handle scheduling. -- [`nRF52 timers`] implements monotonic & Timer Queue for the RTC and normal timers in nRF52's - -## Contributing - -Contributing new implementations of `Monotonic` can be done in multiple ways: -* Implement the trait behind a feature flag in [`rtic-monotonics`], and create a PR for them to be included in the main RTIC repository. This way, the implementations of are in-tree, and RTIC can guarantee their correctness, and can update them in the case of a new release. -* Implement the changes in an external repository. - -[`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics/ -[`rtic_time::Monotonic`]: https://docs.rs/rtic_time/ -[`fugit`]: https://docs.rs/fugit/ -[`Systick based`]: https://github.com/rtic-monotonics -[`rtic-monotonics`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics -[`RP2040 Timer`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics/src/rp2040.rs -[`nRF52 timers`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics/src/nrf.rs \ No newline at end of file diff --git a/book/en/src/by-example/tips_static_lifetimes.md b/book/en/src/by-example/tips_static_lifetimes.md deleted file mode 100644 index 0eaa59f..0000000 --- a/book/en/src/by-example/tips_static_lifetimes.md +++ /dev/null @@ -1,23 +0,0 @@ -# 'static super-powers - -In `#[init]` and `#[idle]` `local` resources have `'static` lifetime. - -Useful when pre-allocating and/or splitting resources between tasks, drivers or some other object. This comes in handy when drivers, such as USB drivers, need to allocate memory and when using splittable data structures such as [`heapless::spsc::Queue`]. - -In the following example two different tasks share a [`heapless::spsc::Queue`] for lock-free access to the shared queue. - -[`heapless::spsc::Queue`]: https://docs.rs/heapless/0.7.5/heapless/spsc/struct.Queue.html - -``` rust -{{#include ../../../../rtic/examples/static.rs}} -``` - -Running this program produces the expected output. - -``` console -$ cargo run --target thumbv7m-none-eabi --example static -``` - -``` console -{{#include ../../../../rtic/ci/expected/static.run}} -``` diff --git a/book/en/src/by-example/tips_view_code.md b/book/en/src/by-example/tips_view_code.md deleted file mode 100644 index b4a9066..0000000 --- a/book/en/src/by-example/tips_view_code.md +++ /dev/null @@ -1,47 +0,0 @@ -# Inspecting generated code - -`#[rtic::app]` is a procedural macro that produces support code. If for some reason you need to inspect the code generated by this macro you have two options: - -You can inspect the file `rtic-expansion.rs` inside the `target` directory. This file contains the expansion of the `#[rtic::app]` item (not your whole program!) of the *last built* (via `cargo build` or `cargo check`) RTIC application. The expanded code is not pretty printed by default, so you'll want to run `rustfmt` on it before you read it. - -``` console -$ cargo build --example smallest --target thumbv7m-none-eabi -``` - -``` console -$ rustfmt target/rtic-expansion.rs -``` - -``` console -$ tail target/rtic-expansion.rs -``` - -``` rust -#[doc = r" Implementation details"] -mod app { - #[doc = r" Always include the device crate which contains the vector table"] - use lm3s6965 as _; - #[no_mangle] - unsafe extern "C" fn main() -> ! { - rtic::export::interrupt::disable(); - let mut core: rtic::export::Peripherals = core::mem::transmute(()); - core.SCB.scr.modify(|r| r | 1 << 1); - rtic::export::interrupt::enable(); - loop { - rtic::export::wfi() - } - } -} -``` - -Or, you can use the [`cargo-expand`] sub-command. This sub-command will expand *all* the macros, including the `#[rtic::app]` attribute, and modules in your crate and print the output to the console. - -[`cargo-expand`]: https://crates.io/crates/cargo-expand - -``` console -# produces the same output as before -``` - -``` console -cargo expand --example smallest | tail -``` -- cgit v1.2.3 From 0807aa548c865d12746ce17aa1c17f7968b139a9 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 23 Apr 2023 15:33:29 +0200 Subject: Include this code as blocks instead --- book/en/src/by-example/delay.md | 44 ++++++++--------------------------------- 1 file changed, 8 insertions(+), 36 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/by-example/delay.md b/book/en/src/by-example/delay.md index 893ead9..479fd42 100644 --- a/book/en/src/by-example/delay.md +++ b/book/en/src/by-example/delay.md @@ -9,13 +9,8 @@ This can be achieved by instantiating a monotonic timer (for implementations, se ``` rust ... -#[init] -fn init(cx: init::Context) -> (Shared, Local) { - hprintln!("init"); - - let token = rtic_monotonics::create_systick_token!(); - Systick::start(cx.core.SYST, 12_000_000, token); - ... +{{#include ../../../../rtic/examples/async-timeout.rs:init}} + ... ``` A *software* task can `await` the delay to expire: @@ -63,12 +58,8 @@ A common use case is transactions with an associated timeout. In the examples sh Using the `select_biased` macro from the `futures` crate it may look like this: -``` rust -// Call hal with short relative timeout using `select_biased` -select_biased! { - v = hal_get(1).fuse() => hprintln!("hal returned {}", v), - _ = Systick::delay(200.millis()).fuse() => hprintln!("timeout", ), // this will finish first -} +``` rust,noplayground +{{#include ../../../../rtic/examples/async-timeout.rs:select_biased}} ``` Assuming the `hal_get` will take 450ms to finish, a short timeout of 200ms will expire before `hal_get` can complete. @@ -80,11 +71,7 @@ Using `select_biased` any number of futures can be combined, so its very powerfu Rewriting the second example from above using `timeout_after` gives: ``` rust -// Call hal with long relative timeout using monotonic `timeout_after` -match Systick::timeout_after(1000.millis(), hal_get(1)).await { - Ok(v) => hprintln!("hal returned {}", v), - _ => hprintln!("timeout"), -} +{{#include ../../../../rtic/examples/async-timeout.rs:timeout_at_basic}} ``` In cases where you want exact control over time without drift we can use exact points in time using `Instant`, and spans of time using `Duration`. Operations on the `Instant` and `Duration` types come from the [`fugit`] crate. @@ -92,24 +79,9 @@ In cases where you want exact control over time without drift we can use exact p [fugit]: https://crates.io/crates/fugit ``` rust -// get the current time instance -let mut instant = Systick::now(); - -// do this 3 times -for n in 0..3 { - // absolute point in time without drift - instant += 1000.millis(); - Systick::delay_until(instant).await; - - // absolute point it time for timeout - let timeout = instant + 500.millis(); - hprintln!("now is {:?}, timeout at {:?}", Systick::now(), timeout); - - match Systick::timeout_at(timeout, hal_get(n)).await { - Ok(v) => hprintln!("hal returned {} at time {:?}", v, Systick::now()), - _ => hprintln!("timeout"), - } -} + +{{#include ../../../../rtic/examples/async-timeout.rs:timeout_at}} + ``` `let mut instant = Systick::now()` sets the starting time of execution. -- cgit v1.2.3 From a66540efa014b3716d252612bfc7f8f17ed765c4 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 23 Apr 2023 15:33:56 +0200 Subject: Disable the playground on all of these --- book/en/src/by-example/app.md | 2 +- book/en/src/by-example/app_idle.md | 4 ++-- book/en/src/by-example/app_init.md | 2 +- book/en/src/by-example/app_minimal.md | 2 +- book/en/src/by-example/app_priorities.md | 2 +- book/en/src/by-example/channel.md | 16 ++++++++-------- book/en/src/by-example/delay.md | 14 +++++++------- book/en/src/by-example/hardware_tasks.md | 2 +- book/en/src/by-example/message_passing.md | 2 +- book/en/src/by-example/resources.md | 12 ++++++------ book/en/src/by-example/software_tasks.md | 10 +++++----- book/en/src/by-example/tips/destructureing.md | 2 +- book/en/src/by-example/tips/from_ram.md | 2 +- book/en/src/by-example/tips/indirection.md | 2 +- book/en/src/by-example/tips/static_lifetimes.md | 2 +- book/en/src/by-example/tips/view_code.md | 2 +- book/en/src/internals/access.md | 4 ++-- book/en/src/internals/ceilings.md | 2 +- book/en/src/internals/critical-sections.md | 20 ++++++++++---------- book/en/src/internals/interrupt-configuration.md | 4 ++-- book/en/src/internals/late-resources.md | 4 ++-- book/en/src/internals/non-reentrancy.md | 4 ++-- book/en/src/internals/tasks.md | 12 ++++++------ book/en/src/internals/timer-queue.md | 12 ++++++------ book/en/src/migration_v1_v2/async_tasks.md | 6 +++--- book/en/src/migration_v1_v2/complete_example.md | 2 +- 26 files changed, 74 insertions(+), 74 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/by-example/app.md b/book/en/src/by-example/app.md index 0d977a1..8450bb9 100644 --- a/book/en/src/by-example/app.md +++ b/book/en/src/by-example/app.md @@ -27,6 +27,6 @@ Overall, the generated code infers no additional overhead in comparison to a han To give a flavour of RTIC, the following example contains commonly used features. In the following sections we will go through each feature in detail. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/common.rs}} ``` diff --git a/book/en/src/by-example/app_idle.md b/book/en/src/by-example/app_idle.md index cbfd7ba..c0b4139 100644 --- a/book/en/src/by-example/app_idle.md +++ b/book/en/src/by-example/app_idle.md @@ -11,7 +11,7 @@ Like in `init`, locally declared resources will have `'static` lifetimes that ar The example below shows that `idle` runs after `init`. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/idle.rs}} ``` @@ -38,7 +38,7 @@ The following example shows how to enable sleep by setting the [WFI]: https://developer.arm.com/documentation/dui0662/b/The-Cortex-M0--Instruction-Set/Miscellaneous-instructions/WFI [NOP]: https://developer.arm.com/documentation/dui0662/b/The-Cortex-M0--Instruction-Set/Miscellaneous-instructions/NOP -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/idle-wfi.rs}} ``` diff --git a/book/en/src/by-example/app_init.md b/book/en/src/by-example/app_init.md index fb37387..e581ef5 100644 --- a/book/en/src/by-example/app_init.md +++ b/book/en/src/by-example/app_init.md @@ -16,7 +16,7 @@ The example below shows the types of the `core`, `device` and `cs` fields, and s The `device` field is only available when the `peripherals` argument is set to the default value `true`. In the rare case you want to implement an ultra-slim application you can explicitly set `peripherals` to `false`. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/init.rs}} ``` diff --git a/book/en/src/by-example/app_minimal.md b/book/en/src/by-example/app_minimal.md index 714f543..2c6f218 100644 --- a/book/en/src/by-example/app_minimal.md +++ b/book/en/src/by-example/app_minimal.md @@ -2,7 +2,7 @@ This is the smallest possible RTIC application: -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/smallest.rs}} ``` diff --git a/book/en/src/by-example/app_priorities.md b/book/en/src/by-example/app_priorities.md index 9d27658..86ff985 100644 --- a/book/en/src/by-example/app_priorities.md +++ b/book/en/src/by-example/app_priorities.md @@ -33,7 +33,7 @@ Task Priority The following example showcases the priority based scheduling of tasks: -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/preempt.rs}} ``` diff --git a/book/en/src/by-example/channel.md b/book/en/src/by-example/channel.md index 50c3278..75ecbfd 100644 --- a/book/en/src/by-example/channel.md +++ b/book/en/src/by-example/channel.md @@ -2,7 +2,7 @@ Channels can be used to communicate data between running tasks. The channel is essentially a wait queue, allowing tasks with multiple producers and a single receiver. A channel is constructed in the `init` task and backed by statically allocated memory. Send and receive endpoints are distributed to *software* tasks: -``` rust +``` rust,noplayground ... const CAPACITY: usize = 5; #[init] @@ -22,7 +22,7 @@ Channels can also be used from *hardware* tasks, but only in a non-`async` manne The `send` method post a message on the channel as shown below: -``` rust +``` rust,noplayground #[task] async fn sender1(_c: sender1::Context, mut sender: Sender<'static, u32, CAPACITY>) { hprintln!("Sender 1 sending: 1"); @@ -34,7 +34,7 @@ async fn sender1(_c: sender1::Context, mut sender: Sender<'static, u32, CAPACITY The receiver can `await` incoming messages: -``` rust +``` rust,noplayground #[task] async fn receiver(_c: receiver::Context, mut receiver: Receiver<'static, u32, CAPACITY>) { while let Ok(val) = receiver.recv().await { @@ -48,7 +48,7 @@ Channels are implemented using a small (global) *Critical Section* (CS) for prot For a complete example: -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-channel.rs}} ``` @@ -64,7 +64,7 @@ Also sender endpoint can be awaited. In case the channel capacity has not yet be In the following example the `CAPACITY` has been reduced to 1, forcing sender tasks to wait until the data in the channel has been received. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-channel-done.rs}} ``` @@ -81,7 +81,7 @@ $ cargo run --target thumbv7m-none-eabi --example async-channel-done --features In case all senders have been dropped `await`-ing on an empty receiver channel results in an error. This allows to gracefully implement different types of shutdown operations. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-channel-no-sender.rs}} ``` @@ -97,7 +97,7 @@ Similarly, `await`-ing on a send channel results in an error in case the receive The resulting error returns the data back to the sender, allowing the sender to take appropriate action (e.g., storing the data to later retry sending it). -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-channel-no-receiver.rs}} ``` @@ -115,7 +115,7 @@ Using the Try API, you can send or receive data from or to a channel without req This API is exposed through `Receiver::try_recv` and `Sender::try_send`. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-channel-try.rs}} ``` diff --git a/book/en/src/by-example/delay.md b/book/en/src/by-example/delay.md index 479fd42..a6ad0e0 100644 --- a/book/en/src/by-example/delay.md +++ b/book/en/src/by-example/delay.md @@ -7,7 +7,7 @@ This can be achieved by instantiating a monotonic timer (for implementations, se [`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics [`rtic-time`]: https://github.com/rtic-rs/rtic/tree/master/rtic-time -``` rust +``` rust,noplayground ... {{#include ../../../../rtic/examples/async-timeout.rs:init}} ... @@ -15,7 +15,7 @@ This can be achieved by instantiating a monotonic timer (for implementations, se A *software* task can `await` the delay to expire: -``` rust +``` rust,noplayground #[task] async fn foo(_cx: foo::Context) { ... @@ -34,7 +34,7 @@ Similarly the channels implementation, the timer-queue implementation relies on
A complete example -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-delay.rs}} ``` @@ -58,7 +58,7 @@ A common use case is transactions with an associated timeout. In the examples sh Using the `select_biased` macro from the `futures` crate it may look like this: -``` rust,noplayground +``` rust,noplayground,noplayground {{#include ../../../../rtic/examples/async-timeout.rs:select_biased}} ``` @@ -70,7 +70,7 @@ Using `select_biased` any number of futures can be combined, so its very powerfu Rewriting the second example from above using `timeout_after` gives: -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-timeout.rs:timeout_at_basic}} ``` @@ -78,7 +78,7 @@ In cases where you want exact control over time without drift we can use exact p [fugit]: https://crates.io/crates/fugit -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-timeout.rs:timeout_at}} @@ -99,7 +99,7 @@ For the third iteration, with `n == 2`, `hal_get` will take 550ms to finish, in
A complete example -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-timeout.rs}} ``` diff --git a/book/en/src/by-example/hardware_tasks.md b/book/en/src/by-example/hardware_tasks.md index 75dd1a4..bf00dc4 100644 --- a/book/en/src/by-example/hardware_tasks.md +++ b/book/en/src/by-example/hardware_tasks.md @@ -19,7 +19,7 @@ Beware of using interrupt vectors that are used internally by hardware features; The example below demonstrates the use of the `#[task(binds = InterruptName)]` attribute to declare a hardware task bound to an interrupt handler. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/hardware.rs}} ``` diff --git a/book/en/src/by-example/message_passing.md b/book/en/src/by-example/message_passing.md index 5665c36..02fd298 100644 --- a/book/en/src/by-example/message_passing.md +++ b/book/en/src/by-example/message_passing.md @@ -10,7 +10,7 @@ pending spawns of `foo`. Exceeding this capacity is an `Error`. The number of arguments to a task is not limited: -``` rust +``` rust,noplayground {{#include ../../../../examples/message_passing.rs}} ``` diff --git a/book/en/src/by-example/resources.md b/book/en/src/by-example/resources.md index 0bf5d11..c2472bc 100644 --- a/book/en/src/by-example/resources.md +++ b/book/en/src/by-example/resources.md @@ -25,7 +25,7 @@ Types of `#[local]` resources must implement a [`Send`] trait as they are being The example application shown below contains three tasks `foo`, `bar` and `idle`, each having access to its own `#[local]` resource. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/locals.rs}} ``` @@ -51,7 +51,7 @@ Types of `#[task(local = [..])]` resources have to be neither [`Send`] nor [`Syn In the example below the different uses and lifetimes are shown: -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/declared_locals.rs}} ``` @@ -76,7 +76,7 @@ The critical section created by the `lock` API is based on dynamic priorities: i In the example below we have three interrupt handlers with priorities ranging from one to three. The two handlers with the lower priorities contend for a `shared` resource and need to succeed in locking the resource in order to access its data. The highest priority handler, which does not access the `shared` resource, is free to preempt a critical section created by the lowest priority handler. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/lock.rs}} ``` @@ -94,7 +94,7 @@ Types of `#[shared]` resources have to be [`Send`]. As an extension to `lock`, and to reduce rightward drift, locks can be taken as tuples. The following examples show this in use: -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/multilock.rs}} ``` @@ -116,7 +116,7 @@ Note that in this release of RTIC it is not possible to request both exclusive a In the example below a key (e.g. a cryptographic key) is loaded (or created) at runtime (returned by `init`) and then used from two tasks that run at different priorities without any kind of lock. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/only-shared-access.rs}} ``` @@ -142,7 +142,7 @@ To adhere to the Rust [aliasing] rule, a resource may be either accessed through Using `#[lock_free]` on resources shared by tasks running at different priorities will result in a *compile-time* error -- not using the `lock` API would violate the aforementioned alias rule. Similarly, for each priority there can be only a single *software* task accessing a shared resource (as an `async` task may yield execution to other *software* or *hardware* tasks running at the same priority). However, under this single-task restriction, we make the observation that the resource is in effect no longer `shared` but rather `local`. Thus, using a `#[lock_free]` shared resource will result in a *compile-time* error -- where applicable, use a `#[local]` resource instead. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/lock-free.rs}} ``` diff --git a/book/en/src/by-example/software_tasks.md b/book/en/src/by-example/software_tasks.md index 0efc57b..ddf88fd 100644 --- a/book/en/src/by-example/software_tasks.md +++ b/book/en/src/by-example/software_tasks.md @@ -23,7 +23,7 @@ The framework will give a compilation error if there are not enough dispatchers See the following example: -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/spawn.rs}} ``` @@ -40,7 +40,7 @@ In the below example, we `spawn` the *software* task `foo` from the `idle` task. Technically the async executor will `poll` the `foo` *future* which in this case leaves the *future* in a *completed* state. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/spawn_loop.rs}} ``` @@ -56,7 +56,7 @@ An attempt to `spawn` an already spawned task (running) task will result in an e Technically, a `spawn` to a *future* that is not in *completed* state is considered an error. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/spawn_err.rs}} ``` @@ -71,7 +71,7 @@ $ cargo run --target thumbv7m-none-eabi --example spawn_err ## Passing arguments You can also pass arguments at spawn as follows. -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/spawn_arguments.rs}} ``` @@ -92,7 +92,7 @@ Conceptually, one can see such tasks as running in the `main` thread of the appl [Send]: https://doc.rust-lang.org/nomicon/send-and-sync.html -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/zero-prio-task.rs}} ``` diff --git a/book/en/src/by-example/tips/destructureing.md b/book/en/src/by-example/tips/destructureing.md index 6e1d796..752311d 100644 --- a/book/en/src/by-example/tips/destructureing.md +++ b/book/en/src/by-example/tips/destructureing.md @@ -3,7 +3,7 @@ Destructuring task resources might help readability if a task takes multiple resources. Here are two examples on how to split up the resource struct: -``` rust +``` rust,noplayground {{#include ../../../../../rtic/examples/destructure.rs}} ``` diff --git a/book/en/src/by-example/tips/from_ram.md b/book/en/src/by-example/tips/from_ram.md index 7306e12..a153139 100644 --- a/book/en/src/by-example/tips/from_ram.md +++ b/book/en/src/by-example/tips/from_ram.md @@ -11,7 +11,7 @@ improve performance in some cases. The example below shows how to place the higher priority task, `bar`, in RAM. -``` rust +``` rust,noplayground {{#include ../../../../../rtic/examples/ramfunc.rs}} ``` diff --git a/book/en/src/by-example/tips/indirection.md b/book/en/src/by-example/tips/indirection.md index eef0d8e..58b3bde 100644 --- a/book/en/src/by-example/tips/indirection.md +++ b/book/en/src/by-example/tips/indirection.md @@ -13,7 +13,7 @@ As this example of approach goes completely outside of RTIC resource model with Here's an example where `heapless::Pool` is used to "box" buffers of 128 bytes. -``` rust +``` rust,noplayground {{#include ../../../../../rtic/examples/pool.rs}} ``` diff --git a/book/en/src/by-example/tips/static_lifetimes.md b/book/en/src/by-example/tips/static_lifetimes.md index b1fd606..f4e4829 100644 --- a/book/en/src/by-example/tips/static_lifetimes.md +++ b/book/en/src/by-example/tips/static_lifetimes.md @@ -8,7 +8,7 @@ In the following example two different tasks share a [`heapless::spsc::Queue`] f [`heapless::spsc::Queue`]: https://docs.rs/heapless/0.7.5/heapless/spsc/struct.Queue.html -``` rust +``` rust,noplayground {{#include ../../../../../rtic/examples/static.rs}} ``` diff --git a/book/en/src/by-example/tips/view_code.md b/book/en/src/by-example/tips/view_code.md index b4a9066..64af7ad 100644 --- a/book/en/src/by-example/tips/view_code.md +++ b/book/en/src/by-example/tips/view_code.md @@ -16,7 +16,7 @@ $ rustfmt target/rtic-expansion.rs $ tail target/rtic-expansion.rs ``` -``` rust +``` rust,noplayground #[doc = r" Implementation details"] mod app { #[doc = r" Always include the device crate which contains the vector table"] diff --git a/book/en/src/internals/access.md b/book/en/src/internals/access.md index 3894470..b9cc621 100644 --- a/book/en/src/internals/access.md +++ b/book/en/src/internals/access.md @@ -27,7 +27,7 @@ section on [critical sections](critical-sections.html)). The code below is an example of the kind of source level transformation that happens behind the scenes: -``` rust +``` rust,noplayground #[rtic::app(device = ..)] mod app { static mut X: u64: 0; @@ -54,7 +54,7 @@ mod app { The framework produces codes like this: -``` rust +``` rust,noplayground fn init(c: init::Context) { // .. user code .. } diff --git a/book/en/src/internals/ceilings.md b/book/en/src/internals/ceilings.md index 07bd0ad..325e2ad 100644 --- a/book/en/src/internals/ceilings.md +++ b/book/en/src/internals/ceilings.md @@ -26,7 +26,7 @@ gets a unique reference (`&mut-`) to resources. An example to illustrate the ceiling analysis: -``` rust +``` rust,noplayground #[rtic::app(device = ..)] mod app { struct Resources { diff --git a/book/en/src/internals/critical-sections.md b/book/en/src/internals/critical-sections.md index a064ad0..cd66c2b 100644 --- a/book/en/src/internals/critical-sections.md +++ b/book/en/src/internals/critical-sections.md @@ -30,7 +30,7 @@ task we give it a *resource proxy*, whereas we give a unique reference The example below shows the different types handed out to each task: -``` rust +``` rust,noplayground #[rtic::app(device = ..)] mut app { struct Resources { @@ -62,7 +62,7 @@ mut app { Now let's see how these types are created by the framework. -``` rust +``` rust,noplayground fn foo(c: foo::Context) { // .. user code .. } @@ -149,7 +149,7 @@ The semantics of the `BASEPRI` register are as follows: Thus the dynamic priority at any point in time can be computed as -``` rust +``` rust,noplayground dynamic_priority = max(hw2logical(BASEPRI), hw2logical(static_priority)) ``` @@ -160,7 +160,7 @@ In this particular example we could implement the critical section as follows: > **NOTE:** this is a simplified implementation -``` rust +``` rust,noplayground impl rtic::Mutex for resources::x { type T = u64; @@ -194,7 +194,7 @@ calls to it. This is required for memory safety, as nested calls would produce multiple unique references (`&mut-`) to `x` breaking Rust aliasing rules. See below: -``` rust +``` rust,noplayground #[interrupt(binds = UART0, priority = 1, resources = [x])] fn foo(c: foo::Context) { // resource proxy @@ -223,7 +223,7 @@ provides extra information to the compiler. Consider this program: -``` rust +``` rust,noplayground #[rtic::app(device = ..)] mod app { struct Resources { @@ -282,7 +282,7 @@ mod app { The code generated by the framework looks like this: -``` rust +``` rust,noplayground // omitted: user code pub mod resources { @@ -374,7 +374,7 @@ mod app { At the end the compiler will optimize the function `foo` into something like this: -``` rust +``` rust,noplayground fn foo(c: foo::Context) { // NOTE: BASEPRI contains the value `0` (its reset value) at this point @@ -428,7 +428,7 @@ should not result in an observable change of BASEPRI. This invariant needs to be preserved to avoid raising the dynamic priority of a handler through preemption. This is best observed in the following example: -``` rust +``` rust,noplayground #[rtic::app(device = ..)] mod app { struct Resources { @@ -490,7 +490,7 @@ mod app { IMPORTANT: let's say we *forget* to roll back `BASEPRI` in `UART1` -- this would be a bug in the RTIC code generator. -``` rust +``` rust,noplayground // code generated by RTIC mod app { diff --git a/book/en/src/internals/interrupt-configuration.md b/book/en/src/internals/interrupt-configuration.md index 7aec9c9..531c2bb 100644 --- a/book/en/src/internals/interrupt-configuration.md +++ b/book/en/src/internals/interrupt-configuration.md @@ -11,7 +11,7 @@ configuration is done before the `init` function runs. This example gives you an idea of the code that the RTIC framework runs: -``` rust +``` rust,noplayground #[rtic::app(device = lm3s6965)] mod app { #[init] @@ -33,7 +33,7 @@ mod app { The framework generates an entry point that looks like this: -``` rust +``` rust,noplayground // the real entry point of the program #[no_mangle] unsafe fn main() -> ! { diff --git a/book/en/src/internals/late-resources.md b/book/en/src/internals/late-resources.md index f3a0b0a..ce36756 100644 --- a/book/en/src/internals/late-resources.md +++ b/book/en/src/internals/late-resources.md @@ -8,7 +8,7 @@ interrupts are disabled. The example below shows the kind of code that the framework generates to initialize late resources. -``` rust +``` rust,noplayground #[rtic::app(device = ..)] mod app { struct Resources { @@ -39,7 +39,7 @@ mod app { The code generated by the framework looks like this: -``` rust +``` rust,noplayground fn init(c: init::Context) -> init::LateResources { // .. user code .. } diff --git a/book/en/src/internals/non-reentrancy.md b/book/en/src/internals/non-reentrancy.md index 17b34d0..04785c3 100644 --- a/book/en/src/internals/non-reentrancy.md +++ b/book/en/src/internals/non-reentrancy.md @@ -10,7 +10,7 @@ To reenter a task handler in software its underlying interrupt handler must be invoked using FFI (see example below). FFI requires `unsafe` code so end users are discouraged from directly invoking an interrupt handler. -``` rust +``` rust,noplayground #[rtic::app(device = ..)] mod app { #[init] @@ -48,7 +48,7 @@ call from user code. The above example expands into: -``` rust +``` rust,noplayground fn foo(c: foo::Context) { // .. user code .. } diff --git a/book/en/src/internals/tasks.md b/book/en/src/internals/tasks.md index db7afad..a58db8f 100644 --- a/book/en/src/internals/tasks.md +++ b/book/en/src/internals/tasks.md @@ -26,7 +26,7 @@ is treated as a resource contended by the tasks that can `spawn` other tasks. Let's first take a look the code generated by the framework to dispatch tasks. Consider this example: -``` rust +``` rust,noplayground #[rtic::app(device = ..)] mod app { // .. @@ -57,7 +57,7 @@ mod app { The framework produces the following task dispatcher which consists of an interrupt handler and a ready queue: -``` rust +``` rust,noplayground fn bar(c: bar::Context) { // .. user code .. } @@ -121,7 +121,7 @@ There's one `Spawn` struct per task. The `Spawn` code generated by the framework for the previous example looks like this: -``` rust +``` rust,noplayground mod foo { // .. @@ -206,7 +206,7 @@ task capacities. We have omitted how message passing actually works so let's revisit the `spawn` implementation but this time for task `baz` which receives a `u64` message. -``` rust +``` rust,noplayground fn baz(c: baz::Context, input: u64) { // .. user code .. } @@ -268,7 +268,7 @@ mod app { And now let's look at the real implementation of the task dispatcher: -``` rust +``` rust,noplayground mod app { // .. @@ -355,7 +355,7 @@ endpoint is owned by a task dispatcher. Consider the following example: -``` rust +``` rust,noplayground #[rtic::app(device = ..)] mod app { #[idle(spawn = [foo, bar])] diff --git a/book/en/src/internals/timer-queue.md b/book/en/src/internals/timer-queue.md index fcd345c..06056e2 100644 --- a/book/en/src/internals/timer-queue.md +++ b/book/en/src/internals/timer-queue.md @@ -10,7 +10,7 @@ appropriate ready queue. Let's see how this in implemented in code. Consider the following program: -``` rust +``` rust,noplayground #[rtic::app(device = ..)] mod app { // .. @@ -31,7 +31,7 @@ mod app { Let's first look at the `schedule` API. -``` rust +``` rust,noplayground mod foo { pub struct Schedule<'a> { priority: &'a Cell, @@ -122,7 +122,7 @@ is up. Let's see the associated code. -``` rust +``` rust,noplayground mod app { #[no_mangle] fn SysTick() { @@ -220,7 +220,7 @@ analysis. To illustrate, consider the following example: -``` rust +``` rust,noplayground #[rtic::app(device = ..)] mod app { #[task(priority = 3, spawn = [baz])] @@ -269,7 +269,7 @@ an `INSTANTS` buffers used to store the time at which a task was scheduled to run; this `Instant` is read in the task dispatcher and passed to the user code as part of the task context. -``` rust +``` rust,noplayground mod app { // .. @@ -311,7 +311,7 @@ buffer. The value to be written is stored in the `Spawn` struct and its either the `start` time of the hardware task or the `scheduled` time of the software task. -``` rust +``` rust,noplayground mod foo { // .. diff --git a/book/en/src/migration_v1_v2/async_tasks.md b/book/en/src/migration_v1_v2/async_tasks.md index 54e0893..60f7033 100644 --- a/book/en/src/migration_v1_v2/async_tasks.md +++ b/book/en/src/migration_v1_v2/async_tasks.md @@ -10,7 +10,7 @@ All software tasks are now required to be `async`. All of the tasks in your project that do not bind to an interrupt must now be an `async fn`. For example: -``` rust +``` rust,noplayground #[task( local = [ some_resource ], shared = [ my_shared_resource ], @@ -24,7 +24,7 @@ fn my_task(cx: my_task::Context) { becomes -``` rust +``` rust,noplayground #[task( local = [ some_resource ], shared = [ my_shared_resource ], @@ -40,7 +40,7 @@ async fn my_task(cx: my_task::Context) { The new `async` software tasks are allowed to run forever, on one precondition: **there must be an `await` within the infinite loop of the task**. An example of such a task: -``` rust +``` rust,noplayground #[task(local = [ my_channel ] )] async fn my_task_that_runs_forever(cx: my_task_that_runs_forever::Context) { loop { diff --git a/book/en/src/migration_v1_v2/complete_example.md b/book/en/src/migration_v1_v2/complete_example.md index dc29b25..19a746a 100644 --- a/book/en/src/migration_v1_v2/complete_example.md +++ b/book/en/src/migration_v1_v2/complete_example.md @@ -86,7 +86,7 @@ mod app { # V2.0.0 -``` rust +``` rust,noplayground {{ #include ../../../../examples/stm32f3_blinky/src/main.rs }} ``` -- cgit v1.2.3 From 0b8ea078e5df356e6ad86c5c7f9facbc0822ed8b Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Fri, 5 May 2023 18:54:53 +0200 Subject: Fix links --- book/en/src/migration_v1_v2.md | 2 +- book/en/src/starting_a_project.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/migration_v1_v2.md b/book/en/src/migration_v1_v2.md index 96fa231..173b964 100644 --- a/book/en/src/migration_v1_v2.md +++ b/book/en/src/migration_v1_v2.md @@ -9,7 +9,7 @@ Migrating a project from RTIC `v1.0.x` to `v2.0.0` involves the following steps: For a detailed description of the changes, refer to the subchapters. -If you wish to see a code example of changes required, you can check out [the full example migration page](./migration_v2/complete_example.md). +If you wish to see a code example of changes required, you can check out [the full example migration page](./migration_v1_v2/complete_example.md). #### TL;DR (Too Long; Didn't Read) 1. Add `#![type_alias_impl_trait]` to your crate, and use `cargo +nightly`. diff --git a/book/en/src/starting_a_project.md b/book/en/src/starting_a_project.md index ae979f4..437248f 100644 --- a/book/en/src/starting_a_project.md +++ b/book/en/src/starting_a_project.md @@ -3,7 +3,7 @@ A recommendation when starting a RTIC project from scratch is to follow RTIC's [`defmt-app-template`]. -If you are targeting ARMv6-M or ARMv8-M-base architecture, check out the section [Target Architecture](../internals/targets.md) for more information on hardware limitations to be aware of. +If you are targeting ARMv6-M or ARMv8-M-base architecture, check out the section [Target Architecture](./internals/targets.md) for more information on hardware limitations to be aware of. [`defmt-app-template`]: https://github.com/rtic-rs/defmt-app-template -- cgit v1.2.3 From e3603d1d0531a4593c4c75863fc77162813cf34f Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Fri, 5 May 2023 18:58:06 +0200 Subject: Rename deprecated to archive --- book/en/src/SUMMARY.md | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'book/en/src') diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index ff9cffe..4a852f7 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -2,6 +2,8 @@ [Preface](./preface.md) +--- + - [Starting a new project](./starting_a_project.md) - [RTIC by example](./by-example.md) - [The `app`](./by-example/app.md) @@ -23,12 +25,18 @@ - [RTIC vs. the world](./rtic_vs.md) - [Awesome RTIC examples](./awesome_rtic.md) + +--- + - [Migrating from v1.0.x to v2.0.0](./migration_v1_v2.md) - [Rust Nightly & features](./migration_v1_v2/nightly.md) - [Migrating to `rtic-monotonics`](./migration_v1_v2/monotonics.md) - [Software tasks must now be `async`](./migration_v1_v2/async_tasks.md) - [Using and understanding `rtic-sync`](./migration_v1_v2/rtic-sync.md) - [A code example on migration](./migration_v1_v2/complete_example.md) + +--- + - [Under the hood](./internals.md) - [Cortex-M architectures](./internals/targets.md) -- cgit v1.2.3 From f2a57de5c172ee8f20ee449b593b05e18b0314b8 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Fri, 5 May 2023 19:06:34 +0200 Subject: taste the rainbow! --- book/en/src/by-example/app.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'book/en/src') diff --git a/book/en/src/by-example/app.md b/book/en/src/by-example/app.md index 8450bb9..fae13cb 100644 --- a/book/en/src/by-example/app.md +++ b/book/en/src/by-example/app.md @@ -24,7 +24,7 @@ Overall, the generated code infers no additional overhead in comparison to a han ## An RTIC application example -To give a flavour of RTIC, the following example contains commonly used features. +To give a taste of RTIC, the following example contains commonly used features. In the following sections we will go through each feature in detail. ``` rust,noplayground -- cgit v1.2.3 From 03b16a3a2d83af9b520fa5b5bad3ba76155f594d Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Fri, 5 May 2023 19:20:57 +0200 Subject: Archive app_task.md --- book/en/src/by-example/app_task.md | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 book/en/src/by-example/app_task.md (limited to 'book/en/src') diff --git a/book/en/src/by-example/app_task.md b/book/en/src/by-example/app_task.md deleted file mode 100644 index b2731f6..0000000 --- a/book/en/src/by-example/app_task.md +++ /dev/null @@ -1,23 +0,0 @@ - - -# Defining tasks with `#[task]` - -Tasks, defined with `#[task]`, are the main mechanism of getting work done in RTIC. - -Tasks can - -* Be spawned (now or in the future, also by themselves) -* Receive messages (passing messages between tasks) -* Be prioritized, allowing preemptive multitasking -* Optionally bind to a hardware interrupt - -RTIC makes a distinction between “software tasks” and “hardware tasks”. - -*Hardware tasks* are tasks that are bound to a specific interrupt vector in the MCU while software tasks are not. - -This means that if a hardware task is bound to, lets say, a UART RX interrupt, the task will be run every -time that interrupt triggers, usually when a character is received. - -*Software tasks* are explicitly spawned in a task, either immediately or using the Monotonic timer mechanism. - -In the coming pages we will explore both tasks and the different options available. -- cgit v1.2.3 From 5c6483f71b1622e518847006147f2360c7563aa6 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Fri, 5 May 2023 19:21:02 +0200 Subject: Update these --- book/en/src/SUMMARY.md | 2 +- book/en/src/by-example/app.md | 18 +++++++++++++----- book/en/src/by-example/hardware_tasks.md | 6 +++--- 3 files changed, 17 insertions(+), 9 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index 4a852f7..baeb036 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -7,7 +7,7 @@ - [Starting a new project](./starting_a_project.md) - [RTIC by example](./by-example.md) - [The `app`](./by-example/app.md) - - [Hardware tasks & `pend`](./by-example/hardware_tasks.md) + - [Hardware tasks](./by-example/hardware_tasks.md) - [Software tasks & `spawn`](./by-example/software_tasks.md) - [Resources](./by-example/resources.md) - [The init task](./by-example/app_init.md) diff --git a/book/en/src/by-example/app.md b/book/en/src/by-example/app.md index fae13cb..b5815fc 100644 --- a/book/en/src/by-example/app.md +++ b/book/en/src/by-example/app.md @@ -2,7 +2,9 @@ ## Requirements on the `app` attribute -All RTIC applications use the [`app`] attribute (`#[app(..)]`). This attribute only applies to a `mod`-item containing the RTIC application. The `app` attribute has a mandatory `device` argument that takes a *path* as a value. This must be a full path pointing to a *peripheral access crate* (PAC) generated using [`svd2rust`] **v0.14.x** or newer. +All RTIC applications use the [`app`] attribute (`#[app(..)]`). This attribute only applies to a `mod`-item containing the RTIC application. + +The `app` attribute has a mandatory `device` argument that takes a *path* as a value. This must be a full path pointing to a *peripheral access crate* (PAC) generated using [`svd2rust`] **v0.14.x** or newer. The `app` attribute will expand into a suitable entry point and thus replaces the use of the [`cortex_m_rt::entry`] attribute. @@ -12,13 +14,19 @@ The `app` attribute will expand into a suitable entry point and thus replaces th ## Structure and zero-cost concurrency -An RTIC `app` is an executable system model for single-core applications, declaring a set of `local` and `shared` resources operated on by a set of `init`, `idle`, *hardware* and *software* tasks. In short the `init` task runs before any other task returning the set of `local` and `shared` resources. Tasks run preemptively based on their associated static priority, `idle` has the lowest priority (and can be used for background work, and/or to put the system to sleep until woken by some event). Hardware tasks are bound to underlying hardware interrupts, while software tasks are scheduled by asynchronous executors (one for each software task priority). +An RTIC `app` is an executable system model for single-core applications, declaring a set of `local` and `shared` resources operated on by a set of `init`, `idle`, *hardware* and *software* tasks. + +* `init` runs before any other task, and returns the `local` and `shared` resources. +* Tasks (both hardware and software) run preemptively based on their associated static priority. +* Hardware tasks are bound to underlying hardware interrupts. +* Software tasks are schedulied by an set of asynchronous executors, one for each software task priority. +* `idle` has the lowest priority, and can be used for background work, and/or to put the system to sleep until it is woken by some event. At compile time the task/resource model is analyzed under the Stack Resource Policy (SRP) and executable code generated with the following outstanding properties: -- guaranteed race-free resource access and deadlock-free execution on a single-shared stack - - hardware task scheduling is performed directly by the hardware, and - - software task scheduling is performed by auto generated async executors tailored to the application. +- Guaranteed race-free resource access and deadlock-free execution on a single-shared stack. +- Hardware task scheduling is performed directly by the hardware. +- Software task scheduling is performed by auto generated async executors tailored to the application. Overall, the generated code infers no additional overhead in comparison to a hand-written implementation, thus in Rust terms RTIC offers a zero-cost abstraction to concurrency. diff --git a/book/en/src/by-example/hardware_tasks.md b/book/en/src/by-example/hardware_tasks.md index bf00dc4..ded488c 100644 --- a/book/en/src/by-example/hardware_tasks.md +++ b/book/en/src/by-example/hardware_tasks.md @@ -1,8 +1,6 @@ # Hardware tasks -At its core RTIC is using a hardware interrupt controller ([ARM NVIC on cortex-m][NVIC]) to schedule and start execution of tasks. All tasks except `pre-init`, `#[init]` and `#[idle]` run as interrupt handlers. - -Hardware tasks are explicitly bound to interrupt handlers. +At its core RTIC is using a hardware interrupt controller ([ARM NVIC on cortex-m][NVIC]) to schedule and start execution of tasks. All tasks except `pre-init` (a hidden "task"), `#[init]` and `#[idle]` run as interrupt handlers. To bind a task to an interrupt, use the `#[task]` attribute argument `binds = InterruptName`. This task then becomes the interrupt handler for this hardware interrupt vector. @@ -17,6 +15,8 @@ Beware of using interrupt vectors that are used internally by hardware features; [pacorhal]: https://docs.rust-embedded.org/book/start/registers.html [NVIC]: https://developer.arm.com/documentation/100166/0001/Nested-Vectored-Interrupt-Controller/NVIC-functional-description/NVIC-interrupts +## Example + The example below demonstrates the use of the `#[task(binds = InterruptName)]` attribute to declare a hardware task bound to an interrupt handler. ``` rust,noplayground -- cgit v1.2.3 From ab17bbf9f37e81b9aab88694e73d23f54664fa01 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Fri, 5 May 2023 19:31:25 +0200 Subject: Demarcate a bit more --- book/en/src/by-example/app.md | 6 ++++++ book/en/src/by-example/software_tasks.md | 9 ++++----- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'book/en/src') diff --git a/book/en/src/by-example/app.md b/book/en/src/by-example/app.md index b5815fc..0aeed5b 100644 --- a/book/en/src/by-example/app.md +++ b/book/en/src/by-example/app.md @@ -30,6 +30,12 @@ At compile time the task/resource model is analyzed under the Stack Resource Pol Overall, the generated code infers no additional overhead in comparison to a hand-written implementation, thus in Rust terms RTIC offers a zero-cost abstraction to concurrency. +## Priority + +Priorities in RTIC are specified using the `priority = N` (where N is a positive number) argument passed to the `#[task]` attribute. All `#[task]`s can have a priority. If the priority of a task is not specified, it is set to the default value of 1. + +Priorities in RTIC follow a higher value = more important scheme. For examples, a task with priority 2 will preempt a task with priority 1. + ## An RTIC application example To give a taste of RTIC, the following example contains commonly used features. diff --git a/book/en/src/by-example/software_tasks.md b/book/en/src/by-example/software_tasks.md index ddf88fd..444f4a6 100644 --- a/book/en/src/by-example/software_tasks.md +++ b/book/en/src/by-example/software_tasks.md @@ -1,7 +1,6 @@ # Software tasks & spawn -The RTIC concept of a software task shares a lot with that of [hardware tasks](./hardware_tasks.md) with the core difference that a software task is not explicitly bound to a specific -interrupt vector, but rather bound to a “dispatcher” interrupt vector running at the intended priority of the software task (see below). +The RTIC concept of a software task shares a lot with that of [hardware tasks](./hardware_tasks.md). The core difference is that a software task is not explicitly bound to a specific interrupt vector, but rather bound to a “dispatcher” interrupt vector running at the intended priority of the software task (see below). Similarly to *hardware* tasks, the `#[task]` attribute used on a function declare it as a task. The absence of a `binds = InterruptName` argument to the attribute declares the function as a *software task*. @@ -9,11 +8,11 @@ The static method `task_name::spawn()` spawns (starts) a software task and given The *software* task itself is given as an `async` Rust function, which allows the user to optionally `await` future events. This allows to blend reactive programming (by means of *hardware* tasks) with sequential programming (by means of *software* tasks). -Whereas, *hardware* tasks are assumed to run-to-completion (and return), *software* tasks may be started (`spawned`) once and run forever, with the side condition that any loop (execution path) is broken by at least one `await` (yielding operation). +While *hardware* tasks are assumed to run-to-completion (and return), *software* tasks may be started (`spawned`) once and run forever, on the condition that any loop (execution path) is broken by at least one `await` (yielding operation). -All *software* tasks at the same priority level shares an interrupt handler acting as an async executor dispatching the software tasks. +## Dispatchers -This list of dispatchers, `dispatchers = [FreeInterrupt1, FreeInterrupt2, ...]` is an argument to the `#[app]` attribute, where you define the set of free and usable interrupts. +All *software* tasks at the same priority level share an interrupt handler acting as an async executor dispatching the software tasks. This list of dispatchers, `dispatchers = [FreeInterrupt1, FreeInterrupt2, ...]` is an argument to the `#[app]` attribute, where you define the set of free and usable interrupts. Each interrupt vector acting as dispatcher gets assigned to one priority level meaning that the list of dispatchers need to cover all priority levels used by software tasks. -- cgit v1.2.3 From 4b3bf59215d682e9473ca66545a1f7c2acbccbfe Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 20 May 2023 11:24:03 +0200 Subject: Move some more stuff to the archive, update this link --- book/en/src/SUMMARY.md | 2 -- book/en/src/by-example/tips/from_ram.md | 45 ------------------------------ book/en/src/by-example/tips/indirection.md | 2 +- 3 files changed, 1 insertion(+), 48 deletions(-) delete mode 100644 book/en/src/by-example/tips/from_ram.md (limited to 'book/en/src') diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index baeb036..e8c8ee6 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -21,8 +21,6 @@ - [Avoid copies when message passing](./by-example/tips/indirection.md) - [`'static` super-powers](./by-example/tips/static_lifetimes.md) - [Inspecting generated code](./by-example/tips/view_code.md) - - - [RTIC vs. the world](./rtic_vs.md) - [Awesome RTIC examples](./awesome_rtic.md) diff --git a/book/en/src/by-example/tips/from_ram.md b/book/en/src/by-example/tips/from_ram.md deleted file mode 100644 index a153139..0000000 --- a/book/en/src/by-example/tips/from_ram.md +++ /dev/null @@ -1,45 +0,0 @@ -# Running tasks from RAM - -The main goal of moving the specification of RTIC applications to attributes in RTIC v0.4.0 was to allow inter-operation with other attributes. For example, the `link_section` attribute can be applied to tasks to place them in RAM; this can -improve performance in some cases. - -> **IMPORTANT**: In general, the `link_section`, `export_name` and `no_mangle` attributes are powerful but also easy to misuse. Incorrectly using any of these attributes can cause undefined behavior; you should always prefer to use safe, higher level attributes around them like `cortex-m-rt`'s `interrupt` and `exception` attributes. -> -> In the particular case of RAM functions there's no safe abstraction for it in `cortex-m-rt` v0.6.5 but there's an [RFC] for adding a `ramfunc` attribute in a future release. - -[RFC]: https://github.com/rust-embedded/cortex-m-rt/pull/100 - -The example below shows how to place the higher priority task, `bar`, in RAM. - -``` rust,noplayground -{{#include ../../../../../rtic/examples/ramfunc.rs}} -``` - -Running this program produces the expected output. - -``` console -$ cargo run --target thumbv7m-none-eabi --example ramfunc -``` - -``` console -{{#include ../../../../../rtic/ci/expected/ramfunc.run}} -``` - -One can look at the output of `cargo-nm` to confirm that `bar` ended in RAM -(`0x2000_0000`), whereas `foo` ended in Flash (`0x0000_0000`). - -``` console -$ cargo nm --example ramfunc --release | grep ' foo::' -``` - -``` console -{{#include ../../../../../rtic/ci/expected/ramfunc.run.grep.foo}} -``` - -``` console -$ cargo nm --example ramfunc --target thumbv7m-none-eabi --release | grep '*bar::' -``` - -``` console -{{#include ../../../../../rtic/ci/expected/ramfunc.run.grep.bar}} -``` diff --git a/book/en/src/by-example/tips/indirection.md b/book/en/src/by-example/tips/indirection.md index 58b3bde..aa68190 100644 --- a/book/en/src/by-example/tips/indirection.md +++ b/book/en/src/by-example/tips/indirection.md @@ -7,7 +7,7 @@ Indirection can minimize message passing overhead: instead of sending the buffer One can use a global memory allocator to achieve indirection (`alloc::Box`, `alloc::Rc`, etc.), which requires using the nightly channel as of Rust v1.37.0, or one can use a statically allocated memory pool like [`heapless::Pool`]. -[`heapless::Pool`]: https://docs.rs/heapless/0.5.0/heapless/pool/index.html +[`heapless::Pool`]: https://docs.rs/heapless/latest/heapless/pool/index.html As this example of approach goes completely outside of RTIC resource model with shared and local the program would rely on the correctness of the memory allocator, in this case `heapless::pool`. -- cgit v1.2.3 From 039c2b8bd440018531d79785c63bbfb74f0e686c Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 20 May 2023 11:45:23 +0200 Subject: Add some docs on RTIC AND embassy --- book/en/src/SUMMARY.md | 1 + book/en/src/rtic_and_embassy.md | 17 +++++++++++++++++ book/en/src/rtic_vs.md | 6 ++---- 3 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 book/en/src/rtic_and_embassy.md (limited to 'book/en/src') diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index e8c8ee6..c5e69e5 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -22,6 +22,7 @@ - [`'static` super-powers](./by-example/tips/static_lifetimes.md) - [Inspecting generated code](./by-example/tips/view_code.md) - [RTIC vs. the world](./rtic_vs.md) +- [RTIC and Embassy](./rtic_and_embassy.md) - [Awesome RTIC examples](./awesome_rtic.md) --- diff --git a/book/en/src/rtic_and_embassy.md b/book/en/src/rtic_and_embassy.md new file mode 100644 index 0000000..c1347aa --- /dev/null +++ b/book/en/src/rtic_and_embassy.md @@ -0,0 +1,17 @@ +# RTIC vs. Embassy + +## Differences + +Embassy provides both Hardware Abstraction Layers, and an executor/runtime, while RTIC aims to only provide an execution framework. For example, embassy provides `embassy-stm32` (a HAL), and `embassy-executor` (an executor). On the other hand, RTIC provides the framework in the form of [`rtic`], and the user is responsible for providing a PAC and HAL implementation (generally from the [`stm32-rs`] project). + +Additionally, RTIC aims to provide exclusive access to resources on as low a level of possible, ideally guarded by some form of hardware protection. This allows for access to hardware while not necessarily requiring locking mechanisms on the software level. + +## Mixing use of Embassy and RTIC + +Since most Embassy and RTIC libraries are runtime agnostic, many details from one project can be used in the other. For example, using [`rtic-monotonics`] in an `embassy-executor` powered project works, and using [`embassy-sync`] (though [`rtic-sync`] is recommended) in an RTIC project works. + +[`stm32-rs`]: https://github.com/stm32-rs +[`rtic`]: https://docs.rs/rtic/latest/rtic/ +[`rtic-monotonics`]: https://docs.rs/rtic-monotonics/latest/rtic_monotonics/ +[`embassy-sync`]: https://docs.rs/embassy-sync/latest/embassy_sync/ +[`rtic-sync`]: https://docs.rs/rtic-sync/latest/rtic_sync/ \ No newline at end of file diff --git a/book/en/src/rtic_vs.md b/book/en/src/rtic_vs.md index 454b239..9d6f4f2 100644 --- a/book/en/src/rtic_vs.md +++ b/book/en/src/rtic_vs.md @@ -4,8 +4,6 @@ RTIC aims to provide the lowest level of abstraction needed for developing robus It provides a minimal set of required mechanisms for safe sharing of mutable resources among interrupts and asynchronously executing tasks. The scheduling primitives leverages on the underlying hardware for unparalleled performance and predictability, in effect RTIC provides in Rust terms a zero-cost abstraction to concurrent real-time programming. - - ## Comparison regarding safety and security Comparing RTIC to traditional a Real-Time Operating System (RTOS) is hard. Firstly, a traditional RTOS typically comes with no guarantees regarding system safety, even the most hardened kernels like the formally verified [seL4] kernel. Their claims to integrity, confidentiality, and availability regards only the kernel itself (under additional assumptions its configuration and environment). They even state: @@ -16,7 +14,7 @@ Comparing RTIC to traditional a Real-Time Operating System (RTOS) is hard. First [seL4]: https://sel4.systems/ -### Security by design +## Security by design In the world of information security we commonly find: @@ -30,4 +28,4 @@ Thus their claim is correct, security is completely out of hands for the OS, the RTIC on the other hand holds your back. The declarative system wide model gives you a static set of tasks and resources, with precise control over what data is shared and between which parties. Moreover, Rust as a programming language comes with strong properties regarding integrity (compile time aliasing, mutability and lifetime guarantees, together with ensured data validity). -Using RTIC these properties propagate to the system wide model, without interference of other applications running. The RTIC kernel is internally infallible without any need of dynamically allocated data. \ No newline at end of file +Using RTIC these properties propagate to the system wide model, without interference of other applications running. The RTIC kernel is internally infallible without any need of dynamically allocated data. -- cgit v1.2.3 From 311291b95adbd24ecd037f5e555e4c30138f4339 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 20 May 2023 12:02:51 +0200 Subject: Make Monotonic implementation more obvious --- book/en/src/SUMMARY.md | 2 +- book/en/src/by-example/delay.md | 11 ++++---- book/en/src/by-example/tips/monotonic_impl.md | 25 ------------------ book/en/src/monotonic_impl.md | 38 +++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 32 deletions(-) delete mode 100644 book/en/src/by-example/tips/monotonic_impl.md create mode 100644 book/en/src/monotonic_impl.md (limited to 'book/en/src') diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index c5e69e5..4083284 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -16,11 +16,11 @@ - [Delay and Timeout using Monotonics](./by-example/delay.md) - [The minimal app](./by-example/app_minimal.md) - [Tips & Tricks](./by-example/tips/index.md) - - [Implementing Monotonic](./by-example/tips/monotonic_impl.md) - [Resource de-structure-ing](./by-example/tips/destructureing.md) - [Avoid copies when message passing](./by-example/tips/indirection.md) - [`'static` super-powers](./by-example/tips/static_lifetimes.md) - [Inspecting generated code](./by-example/tips/view_code.md) +- [Monotonics & the Timer Queue](./monotonic_impl.md) - [RTIC vs. the world](./rtic_vs.md) - [RTIC and Embassy](./rtic_and_embassy.md) - [Awesome RTIC examples](./awesome_rtic.md) diff --git a/book/en/src/by-example/delay.md b/book/en/src/by-example/delay.md index a6ad0e0..09091fc 100644 --- a/book/en/src/by-example/delay.md +++ b/book/en/src/by-example/delay.md @@ -6,6 +6,8 @@ This can be achieved by instantiating a monotonic timer (for implementations, se [`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics [`rtic-time`]: https://github.com/rtic-rs/rtic/tree/master/rtic-time +[`Monotonic`]: https://docs.rs/rtic-time/latest/rtic_time/trait.Monotonic.html +[Implementing a `Monotonic`]: ../../monotonic_impl.md ``` rust,noplayground ... @@ -25,12 +27,6 @@ async fn foo(_cx: foo::Context) { ``` - - -Technically, the timer queue is implemented as a list based priority queue, where list-nodes are statically allocated as part of the underlying task `Future`. Thus, the timer queue is infallible at run-time (its size and allocation are determined at compile time). - -Similarly the channels implementation, the timer-queue implementation relies on a global *Critical Section* (CS) for race protection. For the examples a CS implementation is provided by adding `--features test-critical-section` to the build options. -
A complete example @@ -48,6 +44,9 @@ $ cargo run --target thumbv7m-none-eabi --example async-delay --features test-cr
+> Interested in contributing new implementations of [`Monotonic`], or more information about the inner workings of monotonics? +> Check out the [Implementing a `Monotonic`] chapter! + ## Timeout Rust [`Future`]s (underlying Rust `async`/`await`) are composable. This makes it possible to `select` in between `Futures` that have completed. diff --git a/book/en/src/by-example/tips/monotonic_impl.md b/book/en/src/by-example/tips/monotonic_impl.md deleted file mode 100644 index 9f88c19..0000000 --- a/book/en/src/by-example/tips/monotonic_impl.md +++ /dev/null @@ -1,25 +0,0 @@ -# Implementing a `Monotonic` timer for scheduling - -The framework is flexible because it can use any timer which has compare-match and optionally supporting overflow interrupts for scheduling. The single requirement to make a timer usable with RTIC is implementing the `rtic-time::Monotonic` trait. - -For RTIC 1.0 and 2.0 we instead assume the user has a time library, e.g. [`fugit`], as the basis for all time-based operations when implementing `Monotonic`. These libraries make it much easier to correctly implement the `Monotonic` trait, allowing the use of almost any timer in the system for scheduling. - -The trait documents the requirements for each method. There are reference implementations available in [`rtic-monotonics`] that can be used for inspriation. - -- [`Systick based`], runs at a fixed interrupt (tick) rate - with some overhead but simple and provides support for large time spans -- [`RP2040 Timer`], a "proper" implementation with support for waiting for long periods without interrupts. Clearly demonstrates how to use the `TimerQueue` to handle scheduling. -- [`nRF52 timers`] implements monotonic & Timer Queue for the RTC and normal timers in nRF52's - -## Contributing - -Contributing new implementations of `Monotonic` can be done in multiple ways: -* Implement the trait behind a feature flag in [`rtic-monotonics`], and create a PR for them to be included in the main RTIC repository. This way, the implementations of are in-tree, and RTIC can guarantee their correctness, and can update them in the case of a new release. -* Implement the changes in an external repository. - -[`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics/ -[`rtic_time::Monotonic`]: https://docs.rs/rtic_time/ -[`fugit`]: https://docs.rs/fugit/ -[`Systick based`]: https://github.com/rtic-monotonics -[`rtic-monotonics`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics -[`RP2040 Timer`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics/src/rp2040.rs -[`nRF52 timers`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics/src/nrf.rs \ No newline at end of file diff --git a/book/en/src/monotonic_impl.md b/book/en/src/monotonic_impl.md new file mode 100644 index 0000000..97c0da8 --- /dev/null +++ b/book/en/src/monotonic_impl.md @@ -0,0 +1,38 @@ +# The magic behind Monotonics + +Internally, all monotonics use a [Timer Queue](#the-timer-queue), which is a priority queue with entries describing the time at which their respective `Future`s should complete. + +## Implementing a `Monotonic` timer for scheduling + +The [`rtic-time`] framework is flexible because it can use any timer which has compare-match and optionally supporting overflow interrupts for scheduling. The single requirement to make a timer usable with RTIC is implementing the [`rtic-time::Monotonic`] trait. + +For RTIC 2.0, we assume that the user has a time library, e.g. [`fugit`], as the basis for all time-based operations when implementing [`Monotonic`]. These libraries make it much easier to correctly implement the [`Monotonic`] trait, allowing the use of almost any timer in the system for scheduling. + +The trait documents the requirements for each method. There are reference implementations available in [`rtic-monotonics`] that can be used for inspriation. + +- [`Systick based`], runs at a fixed interrupt (tick) rate - with some overhead but simple and provides support for large time spans +- [`RP2040 Timer`], a "proper" implementation with support for waiting for long periods without interrupts. Clearly demonstrates how to use the [`TimerQueue`] to handle scheduling. +- [`nRF52 timers`] implements monotonic & Timer Queue for the RTC and normal timers in nRF52's + +## Contributing + +Contributing new implementations of `Monotonic` can be done in multiple ways: +* Implement the trait behind a feature flag in [`rtic-monotonics`], and create a PR for them to be included in the main RTIC repository. This way, the implementations of are in-tree, RTIC can guarantee their correctness, and can update them in the case of a new release. +* Implement the changes in an external repository. Doing so will not have them included in [`rtic-monotonics`], but may make it easier to do so in the future. + +[`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics/ +[`fugit`]: https://docs.rs/fugit/ +[`Systick based`]: https://github.com/rtic-monotonics +[`rtic-monotonics`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics +[`RP2040 Timer`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics/src/rp2040.rs +[`nRF52 timers`]: https://github.com/rtic-rs/rtic/blob/master/rtic-monotonics/src/nrf.rs +[`rtic-time`]: https://docs.rs/rtic-time/latest/rtic_time +[`rtic-time::Monotonic`]: https://docs.rs/rtic-time/latest/rtic_time/trait.Monotonic.html +[`Monotonic`]: https://docs.rs/rtic-time/latest/rtic_time/trait.Monotonic.html +[`TimerQueue`]: https://docs.rs/rtic-time/latest/rtic_time/struct.TimerQueue.html + +## The timer queue + +The timer queue is implemented as a list based priority queue, where list-nodes are statically allocated as part of the `Future` created when `await`-ing a Future created when waiting for the monotonic. Thus, the timer queue is infallible at run-time (its size and allocation are determined at compile time). + +Similarly the channels implementation, the timer-queue implementation relies on a global *Critical Section* (CS) for race protection. For the examples a CS implementation is provided by adding `--features test-critical-section` to the build options. \ No newline at end of file -- cgit v1.2.3 From 9fa073f7936782bddf5d02b7b1949032e84de1bd Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 20 May 2023 13:08:44 +0200 Subject: Fix link --- book/en/src/by-example/delay.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'book/en/src') diff --git a/book/en/src/by-example/delay.md b/book/en/src/by-example/delay.md index 09091fc..81f855f 100644 --- a/book/en/src/by-example/delay.md +++ b/book/en/src/by-example/delay.md @@ -7,7 +7,7 @@ This can be achieved by instantiating a monotonic timer (for implementations, se [`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics [`rtic-time`]: https://github.com/rtic-rs/rtic/tree/master/rtic-time [`Monotonic`]: https://docs.rs/rtic-time/latest/rtic_time/trait.Monotonic.html -[Implementing a `Monotonic`]: ../../monotonic_impl.md +[Implementing a `Monotonic`]: ../monotonic_impl.md ``` rust,noplayground ... -- cgit v1.2.3