rtic/book/en/src/migration/migration_v5.md

207 lines
3.9 KiB
Markdown
Raw Normal View History

# 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.
## `Cargo.toml` - version bump
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.
2020-10-23 10:35:56 +02:00
Change
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
[code here]
2020-10-23 10:35:56 +02:00
};
```
into
``` rust
#[rtic::app(/* .. */)]
2020-10-23 10:35:56 +02:00
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
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
[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();
}
};
```
into
``` rust
#[rtic::app(/* .. */, dispatchers = [SSI0, QEI0])]
mod app {
[code here]
}
```
This works also for ram functions, see examples/ramfunc.rs
## Init always returns late resources
In order to make the API more symmetric the #[init]-task always returns a late resource.
From this:
``` rust
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {
rtic::pend(Interrupt::UART0);
}
// [more code]
}
```
to this:
``` rust
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
init::LateResources {}
}
// [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.
2020-10-24 19:38:49 +02: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.
## 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.
2020-10-24 19:38:49 +02:00
---
## 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.
See examples `examples/extern_binds.rs` and `examples/extern_spawn.rs`.
2020-10-24 19:38:49 +02:00