mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-25 19:39:32 +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]
|
||||
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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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`.
|
Loading…
Reference in a new issue