mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-26 05:29:38 +01:00
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:
commit
5b8b2383e1
3 changed files with 110 additions and 41 deletions
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,13 +121,79 @@ 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
|
||||||
|
@ -134,3 +203,4 @@ would work equally well.
|
||||||
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`.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue