mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-27 14:04:56 +01:00
Merge #496
496: update the 0.5.x -> 0.6.0 migration guide r=AfoHT a=japaric to use the new resources syntax I also reordered the sections to cover all the resource API first before covering the spawn API I've also added a section about the old `static mut` variable transform Co-authored-by: Jorge Aparicio <jorge.aparicio@ferrous-systems.com>
This commit is contained in:
commit
2f3b5cba80
9 changed files with 144 additions and 73 deletions
|
@ -102,6 +102,134 @@ mod app {
|
|||
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 v0.6.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 v0.6.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 v0.6.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.
|
||||
|
||||
## 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;
|
||||
}
|
||||
```
|
||||
|
||||
v0.6.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.
|
||||
|
@ -125,48 +253,23 @@ to this:
|
|||
``` rust
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
mod app {
|
||||
#[shared]
|
||||
struct MySharedResources {}
|
||||
|
||||
#[local]
|
||||
struct MyLocalResources {}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
fn init(_: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
|
||||
(init::LateResources {}, init::Monotonics())
|
||||
(MySharedResources, MyLocalResources, init::Monotonics())
|
||||
}
|
||||
|
||||
// [more code]
|
||||
}
|
||||
```
|
||||
|
||||
## Resources struct - `#[resources]`
|
||||
|
||||
Previously the RTIC resources had to be in in a struct named exactly "Resources":
|
||||
|
||||
``` rust
|
||||
struct Resources {
|
||||
// Resources defined in here
|
||||
}
|
||||
```
|
||||
|
||||
With RTIC v0.6.0 the resources struct is annotated similarly like
|
||||
`#[task]`, `#[init]`, `#[idle]`: with an attribute `#[resources]`
|
||||
|
||||
``` rust
|
||||
#[resources]
|
||||
struct Resources {
|
||||
// Resources defined in here
|
||||
}
|
||||
```
|
||||
|
||||
In fact, the name of the struct is now up to the developer:
|
||||
|
||||
``` rust
|
||||
#[resources]
|
||||
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:
|
||||
|
@ -201,37 +304,6 @@ fn bar(_c: bar::Context) {
|
|||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
|
@ -242,4 +314,3 @@ Note that the performance does not change thanks to LLVM's optimizations which o
|
|||
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`.
|
||||
|
||||
|
|
|
@ -16,6 +16,6 @@ mod app {
|
|||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||
(Shared {}, Local {}, init::Monotonics {})
|
||||
(Shared {}, Local {}, init::Monotonics())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ mod app {
|
|||
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||
foo::spawn(1, 2).unwrap();
|
||||
|
||||
(Shared {}, Local {}, init::Monotonics {})
|
||||
(Shared {}, Local {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task()]
|
||||
|
|
|
@ -21,7 +21,7 @@ mod app {
|
|||
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||
foo::spawn(1, 2).unwrap();
|
||||
|
||||
(Shared {}, Local {}, init::Monotonics {})
|
||||
(Shared {}, Local {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task]
|
||||
|
|
|
@ -18,7 +18,7 @@ fn analyze() {
|
|||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||
(Shared {}, Local {}, init::Monotonics {})
|
||||
(Shared {}, Local {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(priority = 1)]
|
||||
|
|
|
@ -10,7 +10,7 @@ mod app {
|
|||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||
(Shared {}, Local {}, init::Monotonics {})
|
||||
(Shared {}, Local {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(binds = NonMaskableInt)]
|
||||
|
|
|
@ -10,7 +10,7 @@ mod app {
|
|||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||
(Shared {}, Local {}, init::Monotonics {})
|
||||
(Shared {}, Local {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task]
|
||||
|
|
|
@ -10,7 +10,7 @@ mod app {
|
|||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||
(Shared {}, Local {}, init::Monotonics {})
|
||||
(Shared {}, Local {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(binds = UART0)]
|
||||
|
|
|
@ -10,7 +10,7 @@ mod app {
|
|||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||
(Shared {}, Local {}, init::Monotonics {})
|
||||
(Shared {}, Local {}, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(binds = GPIOA, priority = 1)]
|
||||
|
|
Loading…
Reference in a new issue