aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Henrik Tjäder <henrik@grepit.se> 2021-12-14 22:46:15 +0100
committerGravatar Henrik Tjäder <henrik@grepit.se> 2021-12-19 01:33:14 +0100
commit4357d8be1511d28ed16f76439c9af60e78504b28 (patch)
treecf1a74b2d312ae2573b33195a2b7d270a43900f6
parent37facfb5bf9aca11c43868cb8880b12b9f6b336a (diff)
downloadrtic-4357d8be1511d28ed16f76439c9af60e78504b28.tar.gz
rtic-4357d8be1511d28ed16f76439c9af60e78504b28.tar.zst
rtic-4357d8be1511d28ed16f76439c9af60e78504b28.zip
Docs: By-example
-rw-r--r--book/en/src/by-example.md14
-rw-r--r--book/en/src/by-example/app.md14
-rw-r--r--book/en/src/by-example/app_idle.md18
-rw-r--r--book/en/src/by-example/app_init.md22
-rw-r--r--book/en/src/by-example/app_task.md15
-rw-r--r--book/en/src/by-example/hardware_tasks.md25
-rw-r--r--book/en/src/by-example/resources.md41
-rw-r--r--book/en/src/preface.md2
8 files changed, 90 insertions, 61 deletions
diff --git a/book/en/src/by-example.md b/book/en/src/by-example.md
index fef6872e..84f00193 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 09f3371e..2c6aca7a 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 66f40497..537902a4 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 3112ccf9..615c2991 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 a5c8b171..97160041 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 d5968761..30b88d0d 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 71092b2f..9f2c6c57 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 e81542c9..7ad33e14 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.