2020-10-05 20:38:52 +02:00
# Migrating from v0.5.x to v0.6.0
This section describes how to upgrade from v0.5.x to v0.6.0 of the RTIC framework.
2020-10-07 00:31:30 +02:00
## `Cargo.toml` - version bump
2020-10-05 20:38:52 +02:00
Change the version of `cortex-m-rtic` to `"0.6.0"` .
2020-11-12 18:19:00 +01:00
## `mod` instead of `const`
With the support of attributes on modules the `const APP` workaround is not needed.
2020-10-23 10:35:56 +02:00
Change
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
2020-11-12 18:19:00 +01:00
[code here]
2020-10-23 10:35:56 +02:00
};
```
into
``` rust
2020-11-12 18:19:00 +01:00
#[rtic::app(/* .. */)]
2020-10-23 10:35:56 +02:00
mod app {
[code here]
}
```
2020-11-12 18:19:00 +01:00
Now that a regular Rust module is used it means it is possible to have custom
user code within that module.
2021-04-21 15:25:58 +02:00
Additionally, it means that `use` -statements for resources used in user
code must be moved inside `mod app` , or be referred to with `super` . For
example, change:
```rust
use some_crate::some_func;
#[rtic::app(/* .. */)]
const APP: () = {
fn func() {
some_crate::some_func();
}
};
```
into
```rust
#[rtic::app(/* .. */)]
mod app {
use some_crate::some_func;
fn func() {
some_crate::some_func();
}
}
```
or
```rust
use some_crate::some_func;
#[rtic::app(/* .. */)]
mod app {
fn func() {
super::some_crate::some_func();
}
2021-07-02 02:09:07 +02:00
}
2021-04-21 15:25:58 +02:00
```
2020-10-05 20:38:52 +02:00
2020-11-12 18:19:00 +01:00
## Move Dispatchers from `extern "C"` to app arguments.
2020-10-05 20:38:52 +02:00
Change
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
2020-11-12 18:19:00 +01:00
[code here]
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
fn QEI0();
}
2020-10-05 20:38:52 +02:00
};
```
into
``` rust
2020-11-12 18:19:00 +01:00
#[rtic::app(/* .. */, dispatchers = [SSI0, QEI0])]
2020-10-05 20:38:52 +02:00
mod app {
[code here]
}
```
2020-11-12 18:19:00 +01:00
This works also for ram functions, see examples/ramfunc.rs
2020-10-05 20:38:52 +02:00
2021-07-14 12:44:25 +02:00
## 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.
2021-07-22 09:27:42 +02:00
## Lock-free resource access
In RTIC 0.5 resources shared by tasks running at the same priority could be accessed *without* the `lock` API.
This is still possible in 0.6: the `#[shared]` resource must be annotated with the field-level `#[lock_free]` attribute.
v0.5 code:
``` rust
struct Resources {
counter: u64,
}
#[task(resources = [counter])]
fn a(cx: a::Context) {
*cx.resources.counter += 1;
}
#[task(resources = [counter])]
fn b(cx: b::Context) {
*cx.resources.counter += 1;
}
```
v0.6 code:
``` rust
#[shared]
struct Shared {
#[lock_free]
counter: u64,
}
#[task(shared = [counter])]
fn a(cx: a::Context) {
*cx.shared.counter += 1;
}
#[task(shared = [counter])]
fn b(cx: b::Context) {
*cx.shared.counter += 1;
}
```
2021-07-14 12:44:25 +02:00
## 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;
2021-07-21 10:14:00 +02:00
(Shared {}, Local {}, init::Monotonics())
2021-07-14 12:44:25 +02:00
}
```
2020-10-07 00:31:30 +02:00
## Init always returns late resources
2020-10-05 20:38:52 +02:00
In order to make the API more symmetric the #[init]-task always returns a late resource.
From this:
``` rust
#[rtic::app(device = lm3s6965)]
2021-04-21 15:33:50 +02:00
const APP: () = {
2020-10-05 20:38:52 +02:00
#[init]
fn init(_: init::Context) {
rtic::pend(Interrupt::UART0);
}
2020-11-12 18:19:00 +01:00
// [more code]
2021-04-21 15:33:50 +02:00
};
2020-10-05 20:38:52 +02:00
```
to this:
``` rust
#[rtic::app(device = lm3s6965)]
mod app {
2021-07-14 12:44:25 +02:00
#[shared]
struct MySharedResources {}
#[local]
struct MyLocalResources {}
2020-10-05 20:38:52 +02:00
#[init]
2021-07-14 12:44:25 +02:00
fn init(_: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
2020-10-05 20:38:52 +02:00
rtic::pend(Interrupt::UART0);
2021-07-21 10:14:00 +02:00
(MySharedResources, MyLocalResources, init::Monotonics())
2020-10-05 20:38:52 +02:00
}
2020-11-12 18:19:00 +01:00
// [more code]
2020-10-05 20:38:52 +02:00
}
```
2020-11-12 18:19:00 +01:00
## 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.
2020-10-24 19:38:49 +02:00
---
## Additions
### Extern tasks
2020-11-12 18:19:00 +01:00
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` .