diff options
Diffstat (limited to 'book/en/archive/migration/migration_v5.md')
| -rw-r--r-- | book/en/archive/migration/migration_v5.md | 372 |
1 files changed, 372 insertions, 0 deletions
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. |
