diff options
| author | datdenkikniet <jcdra1@gmail.com> | 2023-05-05 18:58:06 +0200 |
|---|---|---|
| committer | datdenkikniet <jcdra1@gmail.com> | 2023-05-11 19:20:58 +0200 |
| commit | e3603d1d0531a4593c4c75863fc77162813cf34f (patch) | |
| tree | f2b5562851c68c6e4ba9b6a79f96d9b292a4d8e7 /book/en/archive | |
| parent | 0b8ea078e5df356e6ad86c5c7f9facbc0822ed8b (diff) | |
Rename deprecated to archive
Diffstat (limited to 'book/en/archive')
| -rw-r--r-- | book/en/archive/by_example/monotonic.md | 64 | ||||
| -rw-r--r-- | book/en/archive/migration.md | 4 | ||||
| -rw-r--r-- | book/en/archive/migration/migration_rtic.md | 50 | ||||
| -rw-r--r-- | book/en/archive/migration/migration_v4.md | 247 | ||||
| -rw-r--r-- | book/en/archive/migration/migration_v5.md | 372 |
5 files changed, 737 insertions, 0 deletions
diff --git a/book/en/archive/by_example/monotonic.md b/book/en/archive/by_example/monotonic.md new file mode 100644 index 0000000..0ed4340 --- /dev/null +++ b/book/en/archive/by_example/monotonic.md @@ -0,0 +1,64 @@ +# Monotonic & spawn_{at/after} + +The understanding of time is an important concept in embedded systems, and to be able to run tasks +based on time is essential. The framework provides the static methods +`task::spawn_after(/* duration */)` and `task::spawn_at(/* specific time instant */)`. +`spawn_after` is more commonly used, but in cases where it's needed to have spawns happen +without drift or to a fixed baseline `spawn_at` is available. + +The `#[monotonic]` attribute, applied to a type alias definition, exists to support this. +This type alias must point to a type which implements the [`rtic_monotonic::Monotonic`] trait. +This is generally some timer which handles the timing of the system. +One or more monotonics can coexist in the same system, for example a slow timer that wakes the +system from sleep and another which purpose is for fine grained scheduling while the +system is awake. + +[`rtic_monotonic::Monotonic`]: https://docs.rs/rtic-monotonic + +The attribute has one required parameter and two optional parameters, `binds`, `default` and +`priority` respectively. +The required parameter, `binds = InterruptName`, associates an interrupt vector to the timer's +interrupt, while `default = true` enables a shorthand API when spawning and accessing +time (`monotonics::now()` vs `monotonics::MyMono::now()`), and `priority` sets the priority +of the interrupt vector. + +> The default `priority` is the **maximum priority** of the system. +> If your system has a high priority task with tight scheduling requirements, +> it might be desirable to demote the `monotonic` task to a lower priority +> to reduce scheduling jitter for the high priority task. +> This however might introduce jitter and delays into scheduling via the `monotonic`, +> making it a trade-off. + +The monotonics are initialized in `#[init]` and returned within the `init::Monotonic( ... )` tuple. +This activates the monotonics making it possible to use them. + +See the following example: + +``` rust,noplayground +{{#include ../../../../examples/schedule.rs}} +``` + +``` console +$ cargo run --target thumbv7m-none-eabi --example schedule +{{#include ../../../../ci/expected/schedule.run}} +``` + +A key requirement of a Monotonic is that it must deal gracefully with +hardware timer overruns. + +## Canceling or rescheduling a scheduled task + +Tasks spawned using `task::spawn_after` and `task::spawn_at` returns a `SpawnHandle`, +which allows canceling or rescheduling of the task scheduled to run in the future. + +If `cancel` or `reschedule_at`/`reschedule_after` returns an `Err` it means that the operation was +too late and that the task is already sent for execution. The following example shows this in action: + +``` rust,noplayground +{{#include ../../../../examples/cancel-reschedule.rs}} +``` + +``` console +$ cargo run --target thumbv7m-none-eabi --example cancel-reschedule +{{#include ../../../../ci/expected/cancel-reschedule.run}} +``` diff --git a/book/en/archive/migration.md b/book/en/archive/migration.md new file mode 100644 index 0000000..f52b0a5 --- /dev/null +++ b/book/en/archive/migration.md @@ -0,0 +1,4 @@ +# Migration Guides + +This section describes how to migrate between different versions of RTIC. +It also acts as a comparing reference between versions. diff --git a/book/en/archive/migration/migration_rtic.md b/book/en/archive/migration/migration_rtic.md new file mode 100644 index 0000000..e079cbf --- /dev/null +++ b/book/en/archive/migration/migration_rtic.md @@ -0,0 +1,50 @@ +# Migrating from RTFM to RTIC + +This section covers how to upgrade an application written against RTFM v0.5.x to +the same version of RTIC. This applies since the renaming of the framework as per [RFC #33]. + +**Note:** There are no code differences between RTFM v0.5.3 and RTIC v0.5.3, it is purely a name +change. + +[RFC #33]: https://github.com/rtic-rs/rfcs/pull/33 + +## `Cargo.toml` + +First, the `cortex-m-rtfm` dependency needs to be updated to +`cortex-m-rtic`. + +``` toml +[dependencies] +# change this +cortex-m-rtfm = "0.5.3" + +# into this +cortex-m-rtic = "0.5.3" +``` + +## Code changes + +The only code change that needs to be made is that any reference to `rtfm` before now need to point +to `rtic` as follows: + +``` rust,noplayground +// +// Change this +// + +#[rtfm::app(/* .. */, monotonic = rtfm::cyccnt::CYCCNT)] +const APP: () = { + // ... + +}; + +// +// Into this +// + +#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)] +const APP: () = { + // ... + +}; +``` diff --git a/book/en/archive/migration/migration_v4.md b/book/en/archive/migration/migration_v4.md new file mode 100644 index 0000000..f28b6d9 --- /dev/null +++ b/book/en/archive/migration/migration_v4.md @@ -0,0 +1,247 @@ +# Migrating from v0.4.x to v0.5.0 + +This section covers how to upgrade an application written against RTFM v0.4.x to +the version v0.5.0 of the framework. + +## Project name change RTFM -> RTIC + +With release [v0.5.2][rtic0.5.2] the name was change to Real-Time Interrupt-driven Concurrency + +All occurrences of `RTFM` needs to change to `RTIC`. + +See [migration guide RTFM to RTIC](./migration_rtic.md) + +[rtic0.5.2]: https://crates.io/crates/cortex-m-rtic/0.5.2 + +## `Cargo.toml` + +Change the version of `cortex-m-rtfm` to +`"0.5.0"`, change `rtfm` to `rtic`. +Remove the `timer-queue` feature. + +``` toml +[dependencies.cortex-m-rtfm] +# change this +version = "0.4.3" + +# into this +[dependencies.cortex-m-rtic] +version = "0.5.0" + +# and remove this Cargo feature +features = ["timer-queue"] +# ^^^^^^^^^^^^^ +``` + +## `Context` argument + +All functions inside the `#[rtfm::app]` item need to take as first argument a +`Context` structure. This `Context` type will contain the variables that were +magically injected into the scope of the function by version v0.4.x of the +framework: `resources`, `spawn`, `schedule` -- these variables will become +fields of the `Context` structure. Each function within the `#[rtfm::app]` item +gets a different `Context` type. + +``` rust,noplayground +#[rtfm::app(/* .. */)] +const APP: () = { + // change this + #[task(resources = [x], spawn = [a], schedule = [b])] + fn foo() { + resources.x.lock(|x| /* .. */); + spawn.a(message); + schedule.b(baseline); + } + + // into this + #[task(resources = [x], spawn = [a], schedule = [b])] + fn foo(mut cx: foo::Context) { + // ^^^^^^^^^^^^^^^^^^^^ + + cx.resources.x.lock(|x| /* .. */); + // ^^^ + + cx.spawn.a(message); + // ^^^ + + cx.schedule.b(message, baseline); + // ^^^ + } + + // change this + #[init] + fn init() { + // .. + } + + // into this + #[init] + fn init(cx: init::Context) { + // ^^^^^^^^^^^^^^^^^ + // .. + } + + // .. +}; +``` + +## Resources + +The syntax used to declare resources has changed from `static mut` +variables to a `struct Resources`. + +``` rust,noplayground +#[rtfm::app(/* .. */)] +const APP: () = { + // change this + static mut X: u32 = 0; + static mut Y: u32 = (); // late resource + + // into this + struct Resources { + #[init(0)] // <- initial value + X: u32, // NOTE: we suggest changing the naming style to `snake_case` + + Y: u32, // late resource + } + + // .. +}; +``` + +## Device peripherals + +If your application was accessing the device peripherals in `#[init]` through +the `device` variable then you'll need to add `peripherals = true` to the +`#[rtfm::app]` attribute to continue to access the device peripherals through +the `device` field of the `init::Context` structure. + +Change this: + +``` rust,noplayground +#[rtfm::app(/* .. */)] +const APP: () = { + #[init] + fn init() { + device.SOME_PERIPHERAL.write(something); + } + + // .. +}; +``` + +Into this: + +``` rust,noplayground +#[rtfm::app(/* .. */, peripherals = true)] +// ^^^^^^^^^^^^^^^^^^ +const APP: () = { + #[init] + fn init(cx: init::Context) { + // ^^^^^^^^^^^^^^^^^ + cx.device.SOME_PERIPHERAL.write(something); + // ^^^ + } + + // .. +}; +``` + +## `#[interrupt]` and `#[exception]` + +Remove the attributes `#[interrupt]` and `#[exception]`. +To declare hardware tasks in v0.5.x use the `#[task]` +attribute with the `binds` argument instead. + +Change this: + +``` rust,noplayground +#[rtfm::app(/* .. */)] +const APP: () = { + // hardware tasks + #[exception] + fn SVCall() { /* .. */ } + + #[interrupt] + fn UART0() { /* .. */ } + + // software task + #[task] + fn foo() { /* .. */ } + + // .. +}; +``` + +Into this: + +``` rust,noplayground +#[rtfm::app(/* .. */)] +const APP: () = { + #[task(binds = SVCall)] + // ^^^^^^^^^^^^^^ + fn svcall(cx: svcall::Context) { /* .. */ } + // ^^^^^^ we suggest you use a `snake_case` name here + + #[task(binds = UART0)] + // ^^^^^^^^^^^^^ + fn uart0(cx: uart0::Context) { /* .. */ } + + #[task] + fn foo(cx: foo::Context) { /* .. */ } + + // .. +}; +``` + +## `schedule` + +The `schedule` API no longer requires the `timer-queue` cargo feature. +To use the `schedule` API one must first define the monotonic timer the +runtime will use using the `monotonic` argument of the `#[rtfm::app]` attribute. +To continue using the cycle counter (CYCCNT) as the monotonic timer, +and match the behavior of version v0.4.x, add the `monotonic = rtfm::cyccnt::CYCCNT` +argument to the `#[rtfm::app]` attribute. + +Also, the `Duration` and `Instant` types and the `U32Ext` trait moved +into the `rtfm::cyccnt` module. +This module is only available on ARMv7-M+ devices. +The removal of the `timer-queue` also brings back the `DWT` peripheral +inside the core peripherals struct, if `DWT` is required, +ensure it is enabled by the application inside `init`. + +Change this: + +``` rust,noplayground +use rtfm::{Duration, Instant, U32Ext}; + +#[rtfm::app(/* .. */)] +const APP: () = { + #[task(schedule = [b])] + fn a() { + // .. + } +}; +``` + +Into this: + +``` rust,noplayground +use rtfm::cyccnt::{Duration, Instant, U32Ext}; +// ^^^^^^^^ + +#[rtfm::app(/* .. */, monotonic = rtfm::cyccnt::CYCCNT)] +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +const APP: () = { + #[init] + fn init(cx: init::Context) { + cx.core.DWT.enable_cycle_counter(); + // optional, configure the DWT run without a debugger connected + cx.core.DCB.enable_trace(); + } + #[task(schedule = [b])] + fn a(cx: a::Context) { + // .. + } +}; +``` diff --git a/book/en/archive/migration/migration_v5.md b/book/en/archive/migration/migration_v5.md new file mode 100644 index 0000000..1b4fa0d --- /dev/null +++ b/book/en/archive/migration/migration_v5.md @@ -0,0 +1,372 @@ +# Migrating from v0.5.x to v1.0.0 + +This section describes how to upgrade from v0.5.x to v1.0.0 of the RTIC framework. + +## `Cargo.toml` - version bump + +Change the version of `cortex-m-rtic` to `"1.0.0"`. + +## `mod` instead of `const` + +With the support of attributes on modules the `const APP` workaround is not needed. + +Change + +``` rust,noplayground +#[rtic::app(/* .. */)] +const APP: () = { + [code here] +}; +``` + +into + +``` rust,noplayground +#[rtic::app(/* .. */)] +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 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(); + } +} +``` + +## Move Dispatchers from `extern "C"` to app arguments + +Change + +``` rust,noplayground +#[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,noplayground +#[rtic::app(/* .. */, dispatchers = [SSI0, QEI0])] +mod app { + [code here] +} +``` + +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,noplayground +struct Resources { + // Resources defined in here +} +``` + +With RTIC v1.0.0 the resources structs are annotated similarly like +`#[task]`, `#[init]`, `#[idle]`: with the attributes `#[shared]` and `#[local]` + +``` rust,noplayground +#[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 v1.0.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,noplayground +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 v1.0.0: + +``` rust,noplayground +#[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,noplayground +#[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,noplayground +#[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. + +## 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 1.0: the `#[shared]` resource must be annotated with the field-level `#[lock_free]` attribute. + +v0.5 code: + +``` rust,noplayground +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; +} +``` + +v1.0 code: + +``` rust,noplayground +#[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; +} +``` + +## 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,noplayground +#[init] +fn init(_: init::Context) { + static mut BUFFER: [u8; 1024] = [0; 1024]; + let buffer: &'static mut [u8; 1024] = BUFFER; +} +``` + +v1.0.0 code: + +``` rust,noplayground +#[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. + +From this: + +``` rust,noplayground +#[rtic::app(device = lm3s6965)] +const APP: () = { + #[init] + fn init(_: init::Context) { + rtic::pend(Interrupt::UART0); + } + + // [more code] +}; +``` + +to this: + +``` rust,noplayground +#[rtic::app(device = lm3s6965)] +mod app { + #[shared] + struct MySharedResources {} + + #[local] + struct MyLocalResources {} + + #[init] + fn init(_: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { + rtic::pend(Interrupt::UART0); + + (MySharedResources, MyLocalResources, init::Monotonics()) + } + + // [more code] +} +``` + +## Spawn from anywhere + +With the new spawn/spawn_after/spawn_at interface, +old code requiring the context `cx` for spawning such as: + +``` rust,noplayground +#[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,noplayground +#[task] +fn foo(_c: foo::Context) { + bar::spawn().unwrap(); +} + +#[task] +fn bar(_c: bar::Context) { + // Takes a Duration, relative to “now” + let spawn_handle = foo::spawn_after(/* ... */); +} + +#[task] +fn bar(_c: bar::Context) { + // Takes an Instant + let spawn_handle = foo::spawn_at(/* ... */); +} +``` + +Thus the requirement of having access to the context is dropped. + +Note that the attributes `spawn`/`schedule` in the task definition are no longer needed. + +--- + +## 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`. + +This enables breaking apps into multiple files. |
