405: Updated migration guide with symmetric locks and new spawn r=AfoHT a=korken89



406: book.toml/by-example/app r=korken89 a=perlindgren

Book update

Co-authored-by: Emil Fresk <emil.fresk@gmail.com>
Co-authored-by: Per Lindgren <per.lindgren@ltu.se>
This commit is contained in:
bors[bot] 2020-11-12 17:24:44 +00:00 committed by GitHub
commit 5b8b2383e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 110 additions and 41 deletions

View file

@ -1,5 +1,5 @@
[book] [book]
authors = ["Jorge Aparicio"] authors = ["Jorge Aparicio, Per Lindgren and The Real-Time Interrupt-driven Concurrency developers"]
multilingual = false multilingual = false
src = "src" src = "src"
title = "Real-Time Interrupt-driven Concurrency" title = "Real-Time Interrupt-driven Concurrency"

View file

@ -34,14 +34,13 @@ And optionally, device specific peripherals through the `core` and `device` fiel
of `init::Context`. of `init::Context`.
`static mut` variables declared at the beginning of `init` will be transformed `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 [`rtic::Peripherals`]: ../../api/rtic/struct.Peripherals.html
The example below shows the types of the `core`, `device` and `cs` fields, and 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 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 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`.
`false`).
``` rust ``` rust
{{#include ../../../../examples/init.rs}} {{#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 [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` 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`. 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 **Note:** The `loop {}` in idle cannot be empty as this will crash the microcontroller due to
in LLVM which miss-optimizes empty loops to a `UDF` instruction in release mode. 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 ``` rust
{{#include ../../../../examples/idle.rs}} {{#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 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 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` task `gpiob` is prioritized over `gpioa` due to its higher priority. `gpioa`
is resumed only after `gpiob` terminates. is resumed only after `gpiob` returns.
One more note about priorities: choosing a priority higher than what the device 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 supports (that is `1 << NVIC_PRIO_BITS`) will result in a compile error. Due to

View file

@ -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"`. 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. ## Move Dispatchers from `extern "C"` to app arguments.
Change Change
@ -36,31 +62,6 @@ mod app {
This works also for ram functions, see examples/ramfunc.rs 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 ## Init always returns late resources
@ -75,7 +76,8 @@ mod app {
fn init(_: init::Context) { fn init(_: init::Context) {
rtic::pend(Interrupt::UART0); rtic::pend(Interrupt::UART0);
} }
[more code]
// [more code]
} }
``` ```
@ -90,11 +92,12 @@ mod app {
init::LateResources {} 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": 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 ``` rust
#[resources] #[resources]
struct whateveryouwant { struct Whateveryouwant {
// Resources defined in here // Resources defined in here
} }
``` ```
would work equally well. 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 ## Additions
### Extern tasks ### 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`.