aboutsummaryrefslogtreecommitdiff
path: root/book/en/archive/migration
diff options
context:
space:
mode:
Diffstat (limited to 'book/en/archive/migration')
-rw-r--r--book/en/archive/migration/migration_rtic.md50
-rw-r--r--book/en/archive/migration/migration_v4.md247
-rw-r--r--book/en/archive/migration/migration_v5.md372
3 files changed, 669 insertions, 0 deletions
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.