mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-27 14:04:56 +01:00
Begin migration guide
This commit is contained in:
parent
16f8ea9ba7
commit
1dc2f80eb6
7 changed files with 344 additions and 1 deletions
|
@ -24,6 +24,7 @@
|
||||||
- [RTIC vs. the world](./rtic_vs.md)
|
- [RTIC vs. the world](./rtic_vs.md)
|
||||||
- [Awesome RTIC examples](./awesome_rtic.md)
|
- [Awesome RTIC examples](./awesome_rtic.md)
|
||||||
<!-- - [Migration Guides](./migration.md)
|
<!-- - [Migration Guides](./migration.md)
|
||||||
|
- [v1.0.x to v2.0.0](./migration/migration_v2.md)
|
||||||
- [v0.5.x to v1.0.x](./migration/migration_v5.md)
|
- [v0.5.x to v1.0.x](./migration/migration_v5.md)
|
||||||
- [v0.4.x to v0.5.x](./migration/migration_v4.md)
|
- [v0.4.x to v0.5.x](./migration/migration_v4.md)
|
||||||
- [RTFM to RTIC](./migration/migration_rtic.md) -->
|
- [RTFM to RTIC](./migration/migration_rtic.md) -->
|
||||||
|
@ -44,3 +45,12 @@
|
||||||
- [Task priorities](./by-example/app_priorities.md)
|
- [Task priorities](./by-example/app_priorities.md)
|
||||||
- [Monotonic & `spawn_{at/after}`](./by-example/monotonic.md)
|
- [Monotonic & `spawn_{at/after}`](./by-example/monotonic.md)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- [Migrating from v1.0.x to v2.0.0](./migration/migration_v2.md)
|
||||||
|
- [Rust Nightly & features](./migration/migration_v2/nightly.md)
|
||||||
|
- [Migrating to `rtic-monotonics`](./migration/migration_v2/monotonics.md)
|
||||||
|
- [Software tasks must now be `async`](./migration/migration_v2/async_tasks.md)
|
||||||
|
- [Using and understanding `rtic-sync`](./migration/migration_v2/rtic-sync.md)
|
||||||
|
- [A code example on migration](./migration/migration_v2/complete_example.md)
|
16
book/en/src/migration/migration_v2.md
Normal file
16
book/en/src/migration/migration_v2.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Migrating from v1.0.x to v2.0.0
|
||||||
|
|
||||||
|
Migrating a project from RTIC `v1.0.x` to `v2.0.0` involves the following steps:
|
||||||
|
|
||||||
|
1. `v2.0.0` requires [`#![type_alias_impl_trait]`](https://github.com/rust-lang/rust/issues/63063) and Rust Nightly.
|
||||||
|
2. Migrating from the monotonics included in `v1.0.x` to `rtic-time` and `rtic-monotonics`, replacing `spawn_after`, `spawn_at`.
|
||||||
|
3. Software tasks are now required to be `async`, and using them correctly.
|
||||||
|
4. Understanding and using data types provided by `rtic-sync` to solve migration problems.
|
||||||
|
|
||||||
|
If you wish to see a code example of changes required, you can check out [the full example migration page](./migration_v2/complete_example.md).
|
||||||
|
|
||||||
|
## TL;DR
|
||||||
|
1. Add `#![type_alias_impl_trait]` to your crate, and use `cargo +nightly`.
|
||||||
|
2. Instead of `spawn_after` and `spawn_at`, you now use the `async` functions `delay`, `delay_until` (and related) with impls provided by `rtic-monotonics`.
|
||||||
|
3. Software tasks _must_ be `async fn`s now. Not returning from a task is allowed so long as there is an `await` in the task. You can still `lock` shared resources.
|
||||||
|
4. Use `rtic_sync::Arbiter` to `await` access to a shared resource, and `rtic-channel` to communicate between tasks instead of `spawn`-ing new ones.
|
55
book/en/src/migration/migration_v2/async_tasks.md
Normal file
55
book/en/src/migration/migration_v2/async_tasks.md
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# Using `async` softare tasks.
|
||||||
|
|
||||||
|
There have been a few changes to software tasks. They are outlined below.
|
||||||
|
|
||||||
|
### Software tasks must now be `async`.
|
||||||
|
|
||||||
|
All software tasks are now required to be `async`.
|
||||||
|
|
||||||
|
#### Required changes.
|
||||||
|
|
||||||
|
All of the tasks in your project that do not bind to an interrupt must now be an `async fn`. For example:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[task(
|
||||||
|
local = [ some_resource ],
|
||||||
|
shared = [ my_shared_resource ],
|
||||||
|
priority = 2
|
||||||
|
)]
|
||||||
|
fn my_task(cx: my_task::Context) {
|
||||||
|
cx.local.some_resource.do_trick();
|
||||||
|
cx.shared.my_shared_resource.lock(|s| s.do_shared_thing());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
becomes
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[task(
|
||||||
|
local = [ some_resource ],
|
||||||
|
shared = [ my_shared_resource ],
|
||||||
|
priority = 2
|
||||||
|
)]
|
||||||
|
async fn my_task(cx: my_task::Context) {
|
||||||
|
cx.local.some_resource.do_trick();
|
||||||
|
cx.shared.my_shared_resource.lock(|s| s.do_shared_thing());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Software tasks may now run forever
|
||||||
|
|
||||||
|
The new `async` software tasks are allowed to run forever, on one precondition: **there must be an `await` within the infinite loop of the task**. An example of such a task:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[task(local = [ my_channel ] )]
|
||||||
|
async fn my_task_that_runs_forever(cx: my_task_that_runs_forever::Context) {
|
||||||
|
loop {
|
||||||
|
let value = cx.local.my_channel.recv().await;
|
||||||
|
do_something_with_value(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `spawn_after` and `spawn_at` have been removed.
|
||||||
|
|
||||||
|
As discussed in the [Migrating to `rtic-monotonics`](./monotonics.md) chapter, `spawn_after` and `spawn_at` are no longer available.
|
245
book/en/src/migration/migration_v2/complete_example.md
Normal file
245
book/en/src/migration/migration_v2/complete_example.md
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
# A complete example of migration
|
||||||
|
|
||||||
|
Below you can find the code for the implementation of the `stm32f3_blinky` example for v1.0.x and for v2.0.0. Further down, a diff is displayed.
|
||||||
|
|
||||||
|
# v1.0.X
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![deny(warnings)]
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtic::app;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use stm32f3xx_hal::gpio::{Output, PushPull, PA5};
|
||||||
|
use stm32f3xx_hal::prelude::*;
|
||||||
|
use systick_monotonic::{fugit::Duration, Systick};
|
||||||
|
|
||||||
|
#[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])]
|
||||||
|
mod app {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[shared]
|
||||||
|
struct Shared {}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct Local {
|
||||||
|
led: PA5<Output<PushPull>>,
|
||||||
|
state: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[monotonic(binds = SysTick, default = true)]
|
||||||
|
type MonoTimer = Systick<1000>;
|
||||||
|
|
||||||
|
#[init]
|
||||||
|
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
|
// Setup clocks
|
||||||
|
let mut flash = cx.device.FLASH.constrain();
|
||||||
|
let mut rcc = cx.device.RCC.constrain();
|
||||||
|
|
||||||
|
let mono = Systick::new(cx.core.SYST, 36_000_000);
|
||||||
|
|
||||||
|
rtt_init_print!();
|
||||||
|
rprintln!("init");
|
||||||
|
|
||||||
|
let _clocks = rcc
|
||||||
|
.cfgr
|
||||||
|
.use_hse(8.MHz())
|
||||||
|
.sysclk(36.MHz())
|
||||||
|
.pclk1(36.MHz())
|
||||||
|
.freeze(&mut flash.acr);
|
||||||
|
|
||||||
|
// Setup LED
|
||||||
|
let mut gpioa = cx.device.GPIOA.split(&mut rcc.ahb);
|
||||||
|
let mut led = gpioa
|
||||||
|
.pa5
|
||||||
|
.into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper);
|
||||||
|
led.set_high().unwrap();
|
||||||
|
|
||||||
|
// Schedule the blinking task
|
||||||
|
blink::spawn_after(Duration::<u64, 1, 1000>::from_ticks(1000)).unwrap();
|
||||||
|
|
||||||
|
(
|
||||||
|
Shared {},
|
||||||
|
Local { led, state: false },
|
||||||
|
init::Monotonics(mono),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(local = [led, state])]
|
||||||
|
fn blink(cx: blink::Context) {
|
||||||
|
rprintln!("blink");
|
||||||
|
if *cx.local.state {
|
||||||
|
cx.local.led.set_high().unwrap();
|
||||||
|
*cx.local.state = false;
|
||||||
|
} else {
|
||||||
|
cx.local.led.set_low().unwrap();
|
||||||
|
*cx.local.state = true;
|
||||||
|
}
|
||||||
|
blink::spawn_after(Duration::<u64, 1, 1000>::from_ticks(1000)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
# V2.0.0
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![deny(warnings)]
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtic::app;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use stm32f3xx_hal::gpio::{Output, PushPull, PA5};
|
||||||
|
use stm32f3xx_hal::prelude::*;
|
||||||
|
use rtic_monotonics::Systick;
|
||||||
|
|
||||||
|
#[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])]
|
||||||
|
mod app {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[shared]
|
||||||
|
struct Shared {}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct Local {
|
||||||
|
led: PA5<Output<PushPull>>,
|
||||||
|
state: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[init]
|
||||||
|
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
|
// Setup clocks
|
||||||
|
let mut flash = cx.device.FLASH.constrain();
|
||||||
|
let mut rcc = cx.device.RCC.constrain();
|
||||||
|
|
||||||
|
let mono_token = rtic_monotonics::create_systick_token!();
|
||||||
|
let mono = Systick::new(cx.core.SYST, 36_000_000, mono_token);
|
||||||
|
|
||||||
|
rtt_init_print!();
|
||||||
|
rprintln!("init");
|
||||||
|
|
||||||
|
let _clocks = rcc
|
||||||
|
.cfgr
|
||||||
|
.use_hse(8.MHz())
|
||||||
|
.sysclk(36.MHz())
|
||||||
|
.pclk1(36.MHz())
|
||||||
|
.freeze(&mut flash.acr);
|
||||||
|
|
||||||
|
// Setup LED
|
||||||
|
let mut gpioa = cx.device.GPIOA.split(&mut rcc.ahb);
|
||||||
|
let mut led = gpioa
|
||||||
|
.pa5
|
||||||
|
.into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper);
|
||||||
|
led.set_high().unwrap();
|
||||||
|
|
||||||
|
// Schedule the blinking task
|
||||||
|
blink::spawn().unwrap();
|
||||||
|
|
||||||
|
(
|
||||||
|
Shared {},
|
||||||
|
Local { led, state: false },
|
||||||
|
init::Monotonics(mono),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(local = [led, state])]
|
||||||
|
async fn blink(cx: blink::Context) {
|
||||||
|
loop {
|
||||||
|
// A task is now allowed to run forever, provided that
|
||||||
|
// there is an `await` somewhere in the loop.
|
||||||
|
SysTick::delay(1000.millis()).await;
|
||||||
|
rprintln!("blink");
|
||||||
|
if *cx.local.state {
|
||||||
|
cx.local.led.set_high().unwrap();
|
||||||
|
*cx.local.state = false;
|
||||||
|
} else {
|
||||||
|
cx.local.led.set_low().unwrap();
|
||||||
|
*cx.local.state = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## A diff between the two projects
|
||||||
|
|
||||||
|
``` diff
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
+#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtic::app;
|
||||||
|
use stm32f3xx_hal::gpio::{Output, PushPull, PA5};
|
||||||
|
use stm32f3xx_hal::prelude::*;
|
||||||
|
-use systick_monotonic::{fugit::Duration, Systick};
|
||||||
|
+use rtic_monotonics::Systick;
|
||||||
|
|
||||||
|
#[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])]
|
||||||
|
mod app {
|
||||||
|
@@ -20,16 +21,14 @@ mod app {
|
||||||
|
state: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
- #[monotonic(binds = SysTick, default = true)]
|
||||||
|
- type MonoTimer = Systick<1000>;
|
||||||
|
-
|
||||||
|
#[init]
|
||||||
|
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
|
// Setup clocks
|
||||||
|
let mut flash = cx.device.FLASH.constrain();
|
||||||
|
let mut rcc = cx.device.RCC.constrain();
|
||||||
|
|
||||||
|
- let mono = Systick::new(cx.core.SYST, 36_000_000);
|
||||||
|
+ let mono_token = rtic_monotonics::create_systick_token!();
|
||||||
|
+ let mono = Systick::new(cx.core.SYST, 36_000_000, mono_token);
|
||||||
|
|
||||||
|
let _clocks = rcc
|
||||||
|
.cfgr
|
||||||
|
@@ -46,7 +45,7 @@ mod app {
|
||||||
|
led.set_high().unwrap();
|
||||||
|
|
||||||
|
// Schedule the blinking task
|
||||||
|
- blink::spawn_after(Duration::<u64, 1, 1000>::from_ticks(1000)).unwrap();
|
||||||
|
+ blink::spawn().unwrap();
|
||||||
|
|
||||||
|
(
|
||||||
|
Shared {},
|
||||||
|
@@ -56,14 +55,18 @@ mod app {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(local = [led, state])]
|
||||||
|
- fn blink(cx: blink::Context) {
|
||||||
|
- rprintln!("blink");
|
||||||
|
- if *cx.local.state {
|
||||||
|
- cx.local.led.set_high().unwrap();
|
||||||
|
- *cx.local.state = false;
|
||||||
|
- } else {
|
||||||
|
- cx.local.led.set_low().unwrap();
|
||||||
|
- *cx.local.state = true;
|
||||||
|
- blink::spawn_after(Duration::<u64, 1, 1000>::from_ticks(1000)).unwrap();
|
||||||
|
- }
|
||||||
|
+ async fn blink(cx: blink::Context) {
|
||||||
|
+ loop {
|
||||||
|
+ // A task is now allowed to run forever, provided that
|
||||||
|
+ // there is an `await` somewhere in the loop.
|
||||||
|
+ SysTick::delay(1000.millis()).await;
|
||||||
|
+ rprintln!("blink");
|
||||||
|
+ if *cx.local.state {
|
||||||
|
+ cx.local.led.set_high().unwrap();
|
||||||
|
+ *cx.local.state = false;
|
||||||
|
+ } else {
|
||||||
|
+ cx.local.led.set_low().unwrap();
|
||||||
|
+ *cx.local.state = true;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
```
|
11
book/en/src/migration/migration_v2/monotonics.md
Normal file
11
book/en/src/migration/migration_v2/monotonics.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# Migrating to `rtic-monotonics`
|
||||||
|
|
||||||
|
In previous versions of `rtic`, monotonics were an integral, tightly coupled part of the `#[rtic::app]`. In this new version, `rtic-monotonics` provides them in a more decoupled way.
|
||||||
|
|
||||||
|
The `#[monotonic]` attribute is no longer used. Instead, you use a `create_X_token` from `rtic-monotonics`. An invocation of this macro returns an interrupt registration token, which can be used to construct an instance of your desired monotonic.
|
||||||
|
|
||||||
|
`spawn_after` and `spawn_at` are no longer available. Instead, you use the async functions `Monotonic::delay` and `Monotonics::delay_until`. The `Monotonic` trait is provided by `rtic-time`.
|
||||||
|
|
||||||
|
Check out the [code example](./complete_example.md) for an overview of the required changes.
|
||||||
|
|
||||||
|
For more information on current monotonic implementations, see [the `rtic-monotonics` documentation](https://docs.rs/rtic-monotonics).
|
5
book/en/src/migration/migration_v2/nightly.md
Normal file
5
book/en/src/migration/migration_v2/nightly.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# RTIC now requires Rust Nightly
|
||||||
|
|
||||||
|
The new `async` features require that you use a nightly compiler, and that the feature `type_alias_impl_trait` is enabled for your applications.
|
||||||
|
|
||||||
|
To enable this feature, you must add the line `#![type_alias_impl_trait]` to the root file of your project, on the lines below or above where `#![no_std]` and `#![no_main]` are defined.
|
1
book/en/src/migration/migration_v2/rtic-sync.md
Normal file
1
book/en/src/migration/migration_v2/rtic-sync.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# Using `rtic-sync`
|
Loading…
Reference in a new issue