From 5e3bbada638d1751d7c48b4ec0979c0468080e4d Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 12 Nov 2020 18:19:00 +0100 Subject: [PATCH 1/2] Updated migration guide with symmetric locks and new spawn --- book/en/src/migration/migration_v5.md | 132 ++++++++++++++++++++------ 1 file changed, 101 insertions(+), 31 deletions(-) diff --git a/book/en/src/migration/migration_v5.md b/book/en/src/migration/migration_v5.md index 44af15e21d..8edefd2dfb 100644 --- a/book/en/src/migration/migration_v5.md +++ b/book/en/src/migration/migration_v5.md @@ -6,6 +6,32 @@ This section describes how to upgrade from v0.5.x to v0.6.0 of the RTIC framewor Change the version of `cortex-m-rtic` to `"0.6.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 etc may be required. + ## Move Dispatchers from `extern "C"` to app arguments. Change @@ -36,31 +62,6 @@ mod app { This works also for ram functions, see examples/ramfunc.rs -## Module 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 etc may be required. ## Init always returns late resources @@ -75,7 +76,8 @@ mod app { fn init(_: init::Context) { rtic::pend(Interrupt::UART0); } - [more code] + + // [more code] } ``` @@ -90,11 +92,12 @@ mod app { init::LateResources {} } - [more code] + + // [more code] } ``` -## Resources struct - #[resources] +## Resources struct - `#[resources]` Previously the RTIC resources had to be in in a struct named exactly "Resources": @@ -118,19 +121,86 @@ In fact, the name of the struct is now up to the developer: ``` rust #[resources] -struct whateveryouwant { +struct Whateveryouwant { // Resources defined in here } ``` would work equally well. +## Spawn/schedule from anywhere + +With the new "spawn/schedule from anywhere", old code 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) { + foo::schedule(/* ... */).unwrap(); +} +``` + +Note that the attributes `spawn` and `schedule` are no longer needed. + +## Symmetric locks + +Now RTIC utilizes symmetric locks, this means that the `lock` method need to be used for all 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, resources = [r])] +fn foo(cx: foo::Context) { + cx.resources.r.lock(|r| r = /* ... */); +} + +#[task(resources = [r])] +fn bar(cx: bar::Context) { + cx.resources.r.lock(|r| r = /* ... */); +} +``` + +Note that the performance does not change thanks to LLVM's optimizations which optimizes away unnecessary locks. + --- ## 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. +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`. -See examples `examples/extern_binds.rs` and `examples/extern_spawn.rs`. \ No newline at end of file From 91ea1e428bb92a907ccfe931102625a20d3628c6 Mon Sep 17 00:00:00 2001 From: Per Lindgren Date: Thu, 12 Nov 2020 18:20:16 +0100 Subject: [PATCH 2/2] book.toml/by-example/app --- book/en/book.toml | 2 +- book/en/src/by-example/app.md | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/book/en/book.toml b/book/en/book.toml index caa04ba8fa..98c5bf3f72 100644 --- a/book/en/book.toml +++ b/book/en/book.toml @@ -1,5 +1,5 @@ [book] -authors = ["Jorge Aparicio"] +authors = ["Jorge Aparicio, Per Lindgren and The Real-Time Interrupt-driven Concurrency developers"] multilingual = false src = "src" title = "Real-Time Interrupt-driven Concurrency" diff --git a/book/en/src/by-example/app.md b/book/en/src/by-example/app.md index 2c70af0e09..6a01193641 100644 --- a/book/en/src/by-example/app.md +++ b/book/en/src/by-example/app.md @@ -34,14 +34,13 @@ And optionally, device specific peripherals through the `core` and `device` fiel of `init::Context`. `static mut` variables declared at the beginning of `init` will be transformed -into `&'static mut` references that are safe to access. +into `&'static mut` references that are safe to access. Notice, this feature may be deprecated in next release, see `task_local` resources. [`rtic::Peripherals`]: ../../api/rtic/struct.Peripherals.html The example below shows the types of the `core`, `device` and `cs` fields, and showcases safe access to a `static mut` variable. The `device` field is only -available when the `peripherals` argument is set to `true` (it defaults to -`false`). +available when the `peripherals` argument is set to `true` (default). In the rare case you want to implement an ultra-slim application you can explicitly set `peripherals` to `false`. ``` rust {{#include ../../../../examples/init.rs}} @@ -71,12 +70,12 @@ then sends the microcontroller to sleep after running `init`. [SLEEPONEXIT]: https://developer.arm.com/docs/100737/0100/power-management/sleep-mode/sleep-on-exit-bit Like in `init`, `static mut` variables will be transformed into `&'static mut` -references that are safe to access. +references that are safe to access. Notice, this feature may be deprecated in the next release, see `task_local` resources. The example below shows that `idle` runs after `init`. -**Note:** The `loop {}` in idle cannot be empty as this will crash the microcontroller due to a bug -in LLVM which miss-optimizes empty loops to a `UDF` instruction in release mode. +**Note:** The `loop {}` in idle cannot be empty as this will crash the microcontroller due to +LLVM compiling empty loops to an `UDF` instruction in release mode. To avoid UB, the loop needs to imply a "side-effect" by inserting an assembly instruction (e.g., `WFI`) or a `continue`. ``` rust {{#include ../../../../examples/idle.rs}} @@ -146,9 +145,9 @@ $ cargo run --example preempt ``` Note that the task `gpiob` does *not* preempt task `gpioc` because its priority -is the *same* as `gpioc`'s. However, once `gpioc` terminates the execution of -task, `gpiob` is prioritized over `gpioa` due to its higher priority. `gpioa` -is resumed only after `gpiob` terminates. +is the *same* as `gpioc`'s. However, once `gpioc` returns, the execution of +task `gpiob` is prioritized over `gpioa` due to its higher priority. `gpioa` +is resumed only after `gpiob` returns. One more note about priorities: choosing a priority higher than what the device supports (that is `1 << NVIC_PRIO_BITS`) will result in a compile error. Due to