From 4357d8be1511d28ed16f76439c9af60e78504b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Tj=C3=A4der?= Date: Tue, 14 Dec 2021 22:46:15 +0100 Subject: [PATCH] Docs: By-example --- book/en/src/by-example.md | 14 ++++---- book/en/src/by-example/app.md | 14 ++++---- book/en/src/by-example/app_idle.md | 18 +++++++---- book/en/src/by-example/app_init.md | 22 +++++++++---- book/en/src/by-example/app_task.md | 15 +++++++-- book/en/src/by-example/hardware_tasks.md | 25 ++++++++------- book/en/src/by-example/resources.md | 41 +++++++++++++----------- book/en/src/preface.md | 2 +- 8 files changed, 90 insertions(+), 61 deletions(-) diff --git a/book/en/src/by-example.md b/book/en/src/by-example.md index fef6872e49..84f00193ae 100644 --- a/book/en/src/by-example.md +++ b/book/en/src/by-example.md @@ -3,15 +3,15 @@ This part of the book introduces the Real-Time Interrupt-driven Concurrency (RTIC) framework to new users by walking them through examples of increasing complexity. -All examples in this part of the book can be found in the GitHub [repository] of -the project. The examples can be run on QEMU (emulating a Cortex M3 target) so no special hardware -is required to follow along. +All examples in this part of the book are accessible at the +[GitHub repository][repoexamples]. +The examples are runnable on QEMU (emulating a Cortex M3 target), +thus no special hardware required to follow along. -[repository]: https://github.com/rtic-rs/cortex-m-rtic +[repoexamples]: https://github.com/rtic-rs/cortex-m-rtic/tree/master/examples -To run the examples on your computer you'll need the `qemu-system-arm` -program. Check [the embedded Rust book] for instructions on how to set up an +To run the examples with QEMU you will need the `qemu-system-arm` program. +Check [the embedded Rust book] for instructions on how to set up an embedded development environment that includes QEMU. [the embedded Rust book]: https://rust-embedded.github.io/book/intro/install.html - diff --git a/book/en/src/by-example/app.md b/book/en/src/by-example/app.md index 09f3371e26..2c6aca7a2b 100644 --- a/book/en/src/by-example/app.md +++ b/book/en/src/by-example/app.md @@ -3,14 +3,14 @@ ## Requirements on the `app` attribute All RTIC applications use the [`app`] attribute (`#[app(..)]`). This attribute -must be applied to a `mod`-item containing the RTIC application. The `app` -attribute has a mandatory `device` -argument that takes a *path* as a value. This must be a full path pointing to a +only applies to a `mod`-item containing the RTIC application. The `app` +attribute has a mandatory `device` argument that takes a *path* as a value. +This must be a full path pointing to a *peripheral access crate* (PAC) generated using [`svd2rust`] **v0.14.x** or newer. -The `app` attribute will expand into a suitable entry point so it's not required -to use the [`cortex_m_rt::entry`] attribute. +The `app` attribute will expand into a suitable entry point and thus replaces +the use of the [`cortex_m_rt::entry`] attribute. [`app`]: ../../../api/cortex_m_rtic_macros/attr.app.html [`svd2rust`]: https://crates.io/crates/svd2rust @@ -18,9 +18,9 @@ to use the [`cortex_m_rt::entry`] attribute. ## An RTIC application example -To give a flavor of RTIC, the following example contains commonly used features. In the following sections we will go through each feature in detail. +To give a flavour of RTIC, the following example contains commonly used features. +In the following sections we will go through each feature in detail. ``` rust {{#include ../../../../examples/common.rs}} ``` - diff --git a/book/en/src/by-example/app_idle.md b/book/en/src/by-example/app_idle.md index 66f40497fb..537902a442 100644 --- a/book/en/src/by-example/app_idle.md +++ b/book/en/src/by-example/app_idle.md @@ -1,14 +1,18 @@ # The background task `#[idle]` A function marked with the `idle` attribute can optionally appear in the -module. This function is used as the special *idle task* and must have -signature `fn(idle::Context) -> !`. +module. This becomes the special *idle task* and must have signature +`fn(idle::Context) -> !`. When present, the runtime will execute the `idle` task after `init`. Unlike -`init`, `idle` will run *with interrupts enabled* and it's not allowed to return -so it must run forever. +`init`, `idle` will run *with interrupts enabled* and must never return, +as the `-> !` function signature indicates. +[The Rust type `!` means “never”][nevertype]. -Like in `init`, locally declared resources will have `'static` lifetimes that are safe to access. +[nevertype]: https://doc.rust-lang.org/core/primitive.never.html + +Like in `init`, locally declared resources will have `'static` lifetimes that +are safe to access. The example below shows that `idle` runs after `init`. @@ -21,9 +25,9 @@ $ cargo run --target thumbv7m-none-eabi --example idle {{#include ../../../../ci/expected/idle.run}} ``` -By default the RTIC `idle` task does not try to optimise for any specific targets. +By default, the RTIC `idle` task does not try to optimize for any specific targets. -A common useful optimisation is to enable the [SLEEPONEXIT] and allow the MCU +A common useful optimization is to enable the [SLEEPONEXIT] and allow the MCU to enter sleep when reaching `idle`. >**Caution** some hardware unless configured disables the debug unit during sleep mode. diff --git a/book/en/src/by-example/app_init.md b/book/en/src/by-example/app_init.md index 3112ccf9e1..615c299102 100644 --- a/book/en/src/by-example/app_init.md +++ b/book/en/src/by-example/app_init.md @@ -1,14 +1,22 @@ # App initialization and the `#[init]` task -An RTIC application is required an `init` task setting up the system. The corresponding function must have the signature `fn(init::Context) -> (Shared, Local, init::Monotonics)`, where `Shared` and `Local` are the resource structures defined by the user. +An RTIC application requires an `init` task setting up the system. The corresponding `init` function must have the +signature `fn(init::Context) -> (Shared, Local, init::Monotonics)`, where `Shared` and `Local` are the resource +structures defined by the user. -On system reset, the `init` task is executed (after the optionally defined `pre-init` and internal RTIC initialization). The `init` task runs *with interrupts disabled* and has exclusive access to Cortex-M (the `bare_metal::CriticalSection` token is available as `cs`) while device specific peripherals are available through the `core` and `device` fields of `init::Context`. +The `init` task executes after system reset (after the optionally defined `pre-init` and internal RTIC +initialization). The `init` task runs *with interrupts disabled* and has exclusive access to Cortex-M (the +`bare_metal::CriticalSection` token is available as `cs`) while device specific peripherals are available through +the `core` and `device` fields of `init::Context`. ## Example -The example below shows the types of the `core`, `device` and `cs` fields, and showcases the use of a `local` variable with `'static` lifetime. As we will see later, such variables can later be delegated from `init` to other tasks of the RTIC application. +The example below shows the types of the `core`, `device` and `cs` fields, and showcases the use of a `local` +variable with `'static` lifetime. +Such variables can be delegated from the `init` task to other tasks of the RTIC application. -The `device` field is only available when the `peripherals` argument is set to `true` (which is the default). In the rare case you want to implement an ultra-slim application you can explicitly set `peripherals` to `false`. +The `device` field is available when the `peripherals` argument is set to the default value `true`. +In the rare case you want to implement an ultra-slim application you can explicitly set `peripherals` to `false`. ``` rust {{#include ../../../../examples/init.rs}} @@ -16,13 +24,13 @@ The `device` field is only available when the `peripherals` argument is set to ` Running the example will print `init` to the console and then exit the QEMU process. -``` console +``` console $ cargo run --target thumbv7m-none-eabi --example init {{#include ../../../../ci/expected/init.run}} ``` > **NOTE**: You can choose target device by passing a target -> triple to cargo (e.g `cargo run --example init --target thumbv7m-none-eabi`) or +> triple to cargo (e.g. `cargo run --example init --target thumbv7m-none-eabi`) or > configure a default target in `.cargo/config.toml`. > -> For running the examples, we use a Cortex M3 emulated in QEMU so the target is `thumbv7m-none-eabi`. +> For running the examples, we use a Cortex M3 emulated in QEMU, so the target is `thumbv7m-none-eabi`. diff --git a/book/en/src/by-example/app_task.md b/book/en/src/by-example/app_task.md index a5c8b171a2..97160041e3 100644 --- a/book/en/src/by-example/app_task.md +++ b/book/en/src/by-example/app_task.md @@ -1,7 +1,18 @@ # Defining tasks with `#[task]` -Tasks, defined with `#[task]`, are the main mechanism of getting work done in RTIC. Every task can be spawned, now or later, be sent messages (message passing) and be given priorities for preemptive multitasking. +Tasks, defined with `#[task]`, are the main mechanism of getting work done in RTIC. -There are two kinds of tasks, software tasks and hardware tasks, and the difference is that hardware tasks are bound to a specific interrupt vector in the MCU while software tasks are not. This means that if a hardware task is bound to the UART's RX interrupt the task will run every time a character is received. +Tasks can + +* Be spawned (now or in the future) +* Receive messages (message passing) +* Prioritized allowing preemptive multitasking +* Optionally bind to a hardware interrupt + +RTIC makes a distinction between “software tasks” and “hardware tasks”. +Hardware tasks are tasks that are bound to a specific interrupt vector in the MCU while software tasks are not. + +This means that if a hardware task is bound to an UART RX interrupt the task will run every +time this interrupt triggers, usually when a character is received. In the coming pages we will explore both tasks and the different options available. diff --git a/book/en/src/by-example/hardware_tasks.md b/book/en/src/by-example/hardware_tasks.md index d5968761dc..30b88d0df8 100644 --- a/book/en/src/by-example/hardware_tasks.md +++ b/book/en/src/by-example/hardware_tasks.md @@ -1,17 +1,21 @@ # Hardware tasks -At its core RTIC is based on using the interrupt controller in the hardware to do scheduling and -run tasks, as all tasks in the framework are run as interrupt handlers (except `#[init]` and -`#[idle]`). This also means that you can directly bind tasks to interrupt handlers. +At its core RTIC is using the hardware interrupt controller ([ARM NVIC on cortex-m][NVIC]) +to perform scheduling and executing tasks, and all tasks except `#[init]` and `#[idle]` +run as interrupt handlers. +This also means that you can manually bind tasks to interrupt handlers. -To declare interrupt handlers the `#[task]` attribute takes a `binds = InterruptName` argument whose -value is the name of the interrupt to which the handler will be bound to; the -function used with this attribute becomes the interrupt handler. Within the -framework these type of tasks are referred to as *hardware* tasks, because they -start executing in reaction to a hardware event. +To bind an interrupt use the `#[task]` attribute argument `binds = InterruptName`. +This task becomes the interrupt handler for this hardware interrupt vector. -Providing an interrupt name that does not exist will cause a compile error to help with accidental -errors. +All tasks bound to an explicit interrupt are *hardware tasks* since they +start execution in reaction to a hardware event. + +Specifying a non-existing interrupt name will cause a compilation error. The interrupt names +are commonly defined by [PAC or HAL][pacorhal] crates. + +[pacorhal]: https://docs.rust-embedded.org/book/start/registers.html +[NVIC]: https://developer.arm.com/documentation/100166/0001/Nested-Vectored-Interrupt-Controller/NVIC-functional-description/NVIC-interrupts The example below demonstrates the use of the `#[task]` attribute to declare an interrupt handler. @@ -24,4 +28,3 @@ interrupt handler. $ cargo run --target thumbv7m-none-eabi --example hardware {{#include ../../../../ci/expected/hardware.run}} ``` - diff --git a/book/en/src/by-example/resources.md b/book/en/src/by-example/resources.md index 71092b2fd2..9f2c6c577f 100644 --- a/book/en/src/by-example/resources.md +++ b/book/en/src/by-example/resources.md @@ -1,22 +1,22 @@ # Resource usage -The RTIC framework manages shared and task local resources which allows data to be persistently -stored and safely accessed without the use of unsafe code. +The RTIC framework manages shared and task local resources allowing persistent data +storage and safe accesses without the use of `unsafe` code. RTIC resources are visible only to functions declared within the `#[app]` module and the framework gives the user complete control (on a per-task basis) over resource accessibility. -System wide resources are declared as **two** `struct`'s within the `#[app]` module annotated with -the attribute `#[local]` and `#[shared]` respectively. Each field in these structures corresponds -to a different resource (identified by field name). The difference between these two sets of -resources will be covered below. +Declaration of system-wide resources are by annotating **two** `struct`s within the `#[app]` module +with the attribute `#[local]` and `#[shared]`. +Each field in these structures corresponds to a different resource (identified by field name). +The difference between these two sets of resources will be covered below. Each task must declare the resources it intends to access in its corresponding metadata attribute -using the `local` and `shared` arguments. Each argument takes a list of resource identifiers. The -listed resources are made available to the context under the `local` and `shared` fields of the +using the `local` and `shared` arguments. Each argument takes a list of resource identifiers. +The listed resources are made available to the context under the `local` and `shared` fields of the `Context` structure. -The `init` task returns the initial values for the system wide (`#[shared]` and `#[local]`) +The `init` task returns the initial values for the system-wide (`#[shared]` and `#[local]`) resources, and the set of initialized timers used by the application. The monotonic timers will be further discussed in [Monotonic & `spawn_{at/after}`](./monotonic.md). @@ -27,6 +27,9 @@ access the resource and does so without locks or critical sections. This allows commonly drivers or large objects, to be initialized in `#[init]` and then be passed to a specific task. +Thus, a task `#[local]` resource can only be accessed by one singular task. +Attempting to assign the same `#[local]` resource to more than one task is a compile-time error. + The example application shown below contains two tasks where each task has access to its own `#[local]` resource, plus that the `idle` task has its own `#[local]` as well. @@ -39,15 +42,12 @@ $ cargo run --target thumbv7m-none-eabi --example locals {{#include ../../../../ci/expected/locals.run}} ``` -A `#[local]` resource cannot be accessed from outside the task it was associated to in a `#[task]` attribute. -Assigning the same `#[local]` resource to more than one task is a compile-time error. - ### Task local initialized resources A special use-case of local resources are the ones specified directly in the resource claim, `#[task(local = [my_var: TYPE = INITIAL_VALUE, ...])]`, this allows for creating locals which do no need to be initialized in `#[init]`. -Moreover local resources in `#[init]` and `#[idle]` have `'static` lifetimes, this is safe since both are not re-entrant. +Moreover, local resources in `#[init]` and `#[idle]` have `'static` lifetimes, this is safe since both are not re-entrant. In the example below the different uses and lifetimes are shown: @@ -96,7 +96,7 @@ $ cargo run --target thumbv7m-none-eabi --example lock ## Multi-lock As an extension to `lock`, and to reduce rightward drift, locks can be taken as tuples. The -following examples shows this in use: +following examples show this in use: ``` rust {{#include ../../../../examples/multilock.rs}} @@ -109,12 +109,12 @@ $ cargo run --target thumbv7m-none-eabi --example multilock ## Only shared (`&-`) access -By default the framework assumes that all tasks require exclusive access (`&mut-`) to resources but -it is possible to specify that a task only requires shared access (`&-`) to a resource using the +By default, the framework assumes that all tasks require exclusive access (`&mut-`) to resources, +but it is possible to specify that a task only requires shared access (`&-`) to a resource using the `&resource_name` syntax in the `shared` list. The advantage of specifying shared access (`&-`) to a resource is that no locks are required to -access the resource even if the resource is contended by several tasks running at different +access the resource even if the resource is contended by more than one task running at different priorities. The downside is that the task only gets a shared reference (`&-`) to the resource, limiting the operations it can perform on it, but where a shared reference is enough this approach reduces the number of required locks. In addition to simple immutable data, this shared access can @@ -142,8 +142,11 @@ $ cargo run --target thumbv7m-none-eabi --example only-shared-access A critical section is *not* required to access a `#[shared]` resource that's only accessed by tasks running at the *same* priority. In this case, you can opt out of the `lock` API by adding the `#[lock_free]` field-level attribute to the resource declaration (see example below). Note that -this is merely a convenience: if you do use the `lock` API, at runtime the framework will -**not** produce a critical section. Also worth noting: using `#[lock_free]` on resources shared by +this is merely a convenience to reduce needless resource locking code, because even if the +`lock` API is used, at runtime the framework will **not** produce a critical section due to how +the underlying resource-ceiling preemption works. + +Also worth noting: using `#[lock_free]` on resources shared by tasks running at different priorities will result in a *compile-time* error -- not using the `lock` API would be a data race in that case. diff --git a/book/en/src/preface.md b/book/en/src/preface.md index e81542c997..7ad33e1423 100644 --- a/book/en/src/preface.md +++ b/book/en/src/preface.md @@ -8,7 +8,7 @@ # Preface This book contains user level documentation for the Real-Time Interrupt-driven Concurrency -(RTIC) framework. The API reference can be found [here](../../api/). +(RTIC) framework. The API reference available [here](../../api/). Formerly known as Real-Time For the Masses.