diff options
-rw-r--r-- | book/en/src/by-example/tasks.md | 6 | ||||
-rw-r--r-- | book/en/src/by-example/timer-queue.md | 4 | ||||
-rw-r--r-- | book/en/src/by-example/tips.md | 23 | ||||
-rw-r--r-- | book/en/src/by-example/types-send-sync.md | 27 | ||||
-rw-r--r-- | book/en/src/migration/migration_v5.md | 122 |
5 files changed, 108 insertions, 74 deletions
diff --git a/book/en/src/by-example/tasks.md b/book/en/src/by-example/tasks.md index ba164048..8558a542 100644 --- a/book/en/src/by-example/tasks.md +++ b/book/en/src/by-example/tasks.md @@ -6,15 +6,13 @@ application from any execution context. Software tasks can also be assigned priorities and, under the hood, are dispatched from interrupt handlers. RTIC requires that free interrupts are -declared in an `extern` block when using software tasks; some of these free +declared in the `dispatchers` app argument when using software tasks; some of these free interrupts will be used to dispatch the software tasks. An advantage of software tasks over hardware tasks is that many tasks can be mapped to a single interrupt handler. Software tasks are also declared using the `task` attribute but the `binds` -argument must be omitted. To be able to spawn a software task from a context -the name of the task must appear in the `spawn` argument of the context -attribute (`init`, `idle`, `task`, etc.). +argument must be omitted. The example below showcases three software tasks that run at 2 different priorities. The three software tasks are mapped to 2 interrupts handlers. diff --git a/book/en/src/by-example/timer-queue.md b/book/en/src/by-example/timer-queue.md index 482aebc1..29641750 100644 --- a/book/en/src/by-example/timer-queue.md +++ b/book/en/src/by-example/timer-queue.md @@ -29,9 +29,7 @@ on the built-in CYCle CouNTer (CYCCNT). Note that this is a 32-bit timer clocked at the frequency of the CPU and as such it is not suitable for tracking time spans in the order of seconds. -To be able to schedule a software task from a context the name of the task must -first appear in the `schedule` argument of the context attribute. When -scheduling a task the (user-defined) `Instant` at which the task should be +When scheduling a task the (user-defined) `Instant` at which the task should be executed must be passed as the first argument of the `schedule` invocation. Additionally, the chosen `monotonic` timer must be configured and initialized diff --git a/book/en/src/by-example/tips.md b/book/en/src/by-example/tips.md index 090b30ad..f537173d 100644 --- a/book/en/src/by-example/tips.md +++ b/book/en/src/by-example/tips.md @@ -2,15 +2,8 @@ ## Generics -Resources may appear in contexts as resource proxies or as unique references -(`&mut-`) depending on the priority of the task. Because the same resource may -appear as *different* types in different contexts one cannot refactor a common -operation that uses resources into a plain function; however, such refactor is -possible using *generics*. - -All resource proxies implement the `rtic::Mutex` trait. On the other hand, -unique references (`&mut-`) do *not* implement this trait (due to limitations in -the trait system) but one can wrap these references in the [`rtic::Exclusive`] +All resource proxies implement the `rtic::Mutex` trait. +If a resource does not implement this, one can wrap it in the [`rtic::Exclusive`] newtype which does implement the `Mutex` trait. With the help of this newtype one can write a generic function that operates on generic resources and call it from different tasks to perform some operation on the same set of resources. @@ -27,15 +20,13 @@ $ cargo run --example generics {{#include ../../../../ci/expected/generics.run}} ``` -Using generics also lets you change the static priorities of tasks during -development without having to rewrite a bunch code every time. - ## Conditional compilation You can use conditional compilation (`#[cfg]`) on resources (the fields of -`struct Resources`) and tasks (the `fn` items). The effect of using `#[cfg]` -attributes is that the resource / task will *not* be available through the -corresponding `Context` `struct` if the condition doesn't hold. +`#[resources] struct Resources`) and tasks (the `fn` items). +The effect of using `#[cfg]` attributes is that the resource / task +will *not* be available through the corresponding `Context` `struct` +if the condition doesn't hold. The example below logs a message whenever the `foo` task is spawned, but only if the program has been compiled using the `dev` profile. @@ -132,7 +123,7 @@ You can inspect the file `rtic-expansion.rs` inside the `target` directory. This file contains the expansion of the `#[rtic::app]` item (not your whole program!) of the *last built* (via `cargo build` or `cargo check`) RTIC application. The expanded code is not pretty printed by default so you'll want to run `rustfmt` -over it before you read it. +on it before you read it. ``` console $ cargo build --example foo diff --git a/book/en/src/by-example/types-send-sync.md b/book/en/src/by-example/types-send-sync.md index 9cdb8894..a45f179e 100644 --- a/book/en/src/by-example/types-send-sync.md +++ b/book/en/src/by-example/types-send-sync.md @@ -27,31 +27,8 @@ resources. [`Send`]: https://doc.rust-lang.org/core/marker/trait.Send.html The `app` attribute will enforce that `Send` is implemented where required so -you don't need to worry much about it. It's more important to know where you do -*not* need the `Send` trait: on types that are transferred between tasks that -run at the *same* priority. This occurs in two places: in message passing and in -shared resources. - -The example below shows where a type that doesn't implement `Send` can be used. - -``` rust -{{#include ../../../../examples/not-send.rs}} -``` - -It's important to note that late initialization of resources is effectively a -send operation where the initial value is sent from the background context, -which has the lowest priority of `0`, to a task, which will run at a priority -greater than or equal to `1`. Thus all late resources need to implement the -`Send` trait, except for those exclusively accessed by `idle`, which runs at a -priority of `0`. - -Sharing a resource with `init` can be used to implement late initialization, see -example below. For that reason, resources shared with `init` must also implement -the `Send` trait. - -``` rust -{{#include ../../../../examples/shared-with-init.rs}} -``` +you don't need to worry much about it. Currently all types that are passed need +to be `Send` in RTIC, however this restriction might be relaxed in the future. ## `Sync` diff --git a/book/en/src/migration/migration_v5.md b/book/en/src/migration/migration_v5.md index 44af15e2..8edefd2d 100644 --- a/book/en/src/migration/migration_v5.md +++ b/book/en/src/migration/migration_v5.md @@ -6,61 +6,62 @@ This section describes how to upgrade from v0.5.x to v0.6.0 of the RTIC framewor Change the version of `cortex-m-rtic` to `"0.6.0"`. -## Move Dispatchers from `extern "C"` to app arguments. +## `mod` instead of `const` + +With the support of attributes on modules the `const APP` workaround is not needed. Change ``` rust #[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(); - } + [code here] }; ``` into ``` rust -#[rtic::app(/* .. */, dispatchers = [SSI0, QEI0])] +#[rtic::app(/* .. */)] mod app { [code here] } ``` -This works also for ram functions, see examples/ramfunc.rs - -## Module instead of Const +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 etc may be required. -With the support of attributes on modules the `const APP` workaround is not needed. +## Move Dispatchers from `extern "C"` to app arguments. Change ``` rust #[rtic::app(/* .. */)] const APP: () = { - [code here] + [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 -#[rtic::app(/* .. */)] +#[rtic::app(/* .. */, dispatchers = [SSI0, QEI0])] 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 etc may be required. +This works also for ram functions, see examples/ramfunc.rs + ## Init always returns late resources @@ -75,7 +76,8 @@ mod app { fn init(_: init::Context) { rtic::pend(Interrupt::UART0); } - [more code] + + // [more code] } ``` @@ -90,11 +92,12 @@ mod app { init::LateResources {} } - [more code] + + // [more code] } ``` -## Resources struct - #[resources] +## Resources struct - `#[resources]` Previously the RTIC resources had to be in in a struct named exactly "Resources": @@ -118,19 +121,86 @@ In fact, the name of the struct is now up to the developer: ``` rust #[resources] -struct whateveryouwant { +struct Whateveryouwant { // Resources defined in here } ``` would work equally well. +## Spawn/schedule from anywhere + +With the new "spawn/schedule from anywhere", old code such as: + + + +``` rust +#[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 +#[task] +fn foo(_c: foo::Context) { + bar::spawn().unwrap(); +} + +#[task] +fn bar(_c: bar::Context) { + foo::schedule(/* ... */).unwrap(); +} +``` + +Note that the attributes `spawn` and `schedule` are no longer needed. + +## Symmetric locks + +Now RTIC utilizes symmetric locks, this means that the `lock` method need to be used for all resource access. In old code one could do the following as the high priority task has exclusive access to the resource: + +``` rust +#[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 +#[task(priority = 2, resources = [r])] +fn foo(cx: foo::Context) { + cx.resources.r.lock(|r| r = /* ... */); +} + +#[task(resources = [r])] +fn bar(cx: bar::Context) { + cx.resources.r.lock(|r| r = /* ... */); +} +``` + +Note that the performance does not change thanks to LLVM's optimizations which optimizes away unnecessary locks. + --- ## 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. +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`. -See examples `examples/extern_binds.rs` and `examples/extern_spawn.rs`.
\ No newline at end of file |