From 1dc2f80eb6cb6ac6d1eaede4169d8cabc51c5e7c Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 17:37:15 +0200 Subject: [PATCH] Begin migration guide --- book/en/src/SUMMARY.md | 12 +- book/en/src/migration/migration_v2.md | 16 ++ .../src/migration/migration_v2/async_tasks.md | 55 ++++ .../migration_v2/complete_example.md | 245 ++++++++++++++++++ .../src/migration/migration_v2/monotonics.md | 11 + book/en/src/migration/migration_v2/nightly.md | 5 + .../src/migration/migration_v2/rtic-sync.md | 1 + 7 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 book/en/src/migration/migration_v2.md create mode 100644 book/en/src/migration/migration_v2/async_tasks.md create mode 100644 book/en/src/migration/migration_v2/complete_example.md create mode 100644 book/en/src/migration/migration_v2/monotonics.md create mode 100644 book/en/src/migration/migration_v2/nightly.md create mode 100644 book/en/src/migration/migration_v2/rtic-sync.md diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index 587117cc95..ceed24e6a9 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -24,6 +24,7 @@ - [RTIC vs. the world](./rtic_vs.md) - [Awesome RTIC examples](./awesome_rtic.md) @@ -43,4 +44,13 @@ - [Message passing & `capacity`](./by-example/message_passing.md) - [Task priorities](./by-example/app_priorities.md) - [Monotonic & `spawn_{at/after}`](./by-example/monotonic.md) - --> \ No newline at end of file + --> + +--- + +- [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) \ No newline at end of file diff --git a/book/en/src/migration/migration_v2.md b/book/en/src/migration/migration_v2.md new file mode 100644 index 0000000000..071d34c00b --- /dev/null +++ b/book/en/src/migration/migration_v2.md @@ -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. \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/async_tasks.md b/book/en/src/migration/migration_v2/async_tasks.md new file mode 100644 index 0000000000..54e0893751 --- /dev/null +++ b/book/en/src/migration/migration_v2/async_tasks.md @@ -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. \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/complete_example.md b/book/en/src/migration/migration_v2/complete_example.md new file mode 100644 index 0000000000..fec475d011 --- /dev/null +++ b/book/en/src/migration/migration_v2/complete_example.md @@ -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>, + 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::::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::::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>, + 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::::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::::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; ++ } ++ } ++ } + } +``` \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/monotonics.md b/book/en/src/migration/migration_v2/monotonics.md new file mode 100644 index 0000000000..f794becb71 --- /dev/null +++ b/book/en/src/migration/migration_v2/monotonics.md @@ -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). \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/nightly.md b/book/en/src/migration/migration_v2/nightly.md new file mode 100644 index 0000000000..09f6e33bda --- /dev/null +++ b/book/en/src/migration/migration_v2/nightly.md @@ -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. \ No newline at end of file diff --git a/book/en/src/migration/migration_v2/rtic-sync.md b/book/en/src/migration/migration_v2/rtic-sync.md new file mode 100644 index 0000000000..d086d5de5b --- /dev/null +++ b/book/en/src/migration/migration_v2/rtic-sync.md @@ -0,0 +1 @@ +# Using `rtic-sync` \ No newline at end of file