Skip to content

Commit a5e18cd

Browse files
bors[bot]jvanderk
andauthored
Merge #686
686: Book: Editorial review r=korken89 a=AfoHT Continuation of #618 Better late than never... A big thanks to `@jvanderk` ! Co-authored-by: John van der Koijk <[email protected]>
2 parents 3240fb3 + 04189cc commit a5e18cd

13 files changed

+81
-53
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
1515
### Fixed
1616

1717
- Attempt to handle docs generation enabling `deny(missing_docs)`
18+
- Book: Editorial review
1819
- Use native GHA rustup and cargo
1920
- Distinguish between thumbv8m.base and thumbv8m.main for basepri usage.
2021

book/en/src/by-example/app_init.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
# App initialization and the `#[init]` task
22

33
An RTIC application requires an `init` task setting up the system. The corresponding `init` function must have the
4-
signature `fn(init::Context) -> (Shared, Local, init::Monotonics)`, where `Shared` and `Local` are the resource
4+
signature `fn(init::Context) -> (Shared, Local, init::Monotonics)`, where `Shared` and `Local` are resource
55
structures defined by the user.
66

7-
The `init` task executes after system reset (after the optionally defined `pre-init` and internal RTIC
8-
initialization). The `init` task runs *with interrupts disabled* and has exclusive access to Cortex-M (the
9-
`bare_metal::CriticalSection` token is available as `cs`) while device specific peripherals are available through
10-
the `core` and `device` fields of `init::Context`.
7+
The `init` task executes after system reset, [after an optionally defined `pre-init` code section][pre-init] and an always occurring internal RTIC
8+
initialization.
9+
10+
[pre-init]: https://docs.rs/cortex-m-rt/latest/cortex_m_rt/attr.pre_init.html
11+
12+
The `init` and optional `pre-init` tasks runs *with interrupts disabled* and have exclusive access to Cortex-M (the
13+
`bare_metal::CriticalSection` token is available as `cs`).
14+
15+
Device specific peripherals are available through the `core` and `device` fields of `init::Context`.
1116

1217
## Example
1318

1419
The example below shows the types of the `core`, `device` and `cs` fields, and showcases the use of a `local`
1520
variable with `'static` lifetime.
1621
Such variables can be delegated from the `init` task to other tasks of the RTIC application.
1722

18-
The `device` field is available when the `peripherals` argument is set to the default value `true`.
23+
The `device` field is only available when the `peripherals` argument is set to the default value `true`.
1924
In the rare case you want to implement an ultra-slim application you can explicitly set `peripherals` to `false`.
2025

2126
``` rust

book/en/src/by-example/app_priorities.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ The highest static priority task takes precedence when more than one
1818
task are ready to execute.
1919

2020
The following scenario demonstrates task prioritization:
21-
Spawning a higher priority task A during execution of a lower priority task B pends
22-
task A. Task A has higher priority thus preempting task B which gets suspended
21+
Spawning a higher priority task A during execution of a lower priority task B suspends
22+
task B. Task A has higher priority thus preempting task B which gets suspended
2323
until task A completes execution. Thus, when task A completes task B resumes execution.
2424

2525
```text
@@ -53,7 +53,8 @@ when `baz`returns. When `bar` returns `foo` can resume.
5353

5454
One more note about priorities: choosing a priority higher than what the device
5555
supports will result in a compilation error.
56-
The error is cryptic due to limitations in the language,
56+
57+
The error is cryptic due to limitations in the Rust language
5758
if `priority = 9` for task `uart0_interrupt` in `example/common.rs` this looks like:
5859

5960
```text

book/en/src/by-example/app_task.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@ Tasks, defined with `#[task]`, are the main mechanism of getting work done in RT
44

55
Tasks can
66

7-
* Be spawned (now or in the future)
8-
* Receive messages (message passing)
9-
* Prioritized allowing preemptive multitasking
7+
* Be spawned (now or in the future, also by themselves)
8+
* Receive messages (passing messages between tasks)
9+
* Be prioritized, allowing preemptive multitasking
1010
* Optionally bind to a hardware interrupt
1111

1212
RTIC makes a distinction between “software tasks” and “hardware tasks”.
13-
Hardware tasks are tasks that are bound to a specific interrupt vector in the MCU while software tasks are not.
1413

15-
This means that if a hardware task is bound to an UART RX interrupt the task will run every
16-
time this interrupt triggers, usually when a character is received.
14+
*Hardware tasks* are tasks that are bound to a specific interrupt vector in the MCU while software tasks are not.
15+
16+
This means that if a hardware task is bound to, lets say, a UART RX interrupt, the task will be run every
17+
time that interrupt triggers, usually when a character is received.
18+
19+
*Software tasks* are explicitly spawned in a task, either immediately or using the Monotonic timer mechanism.
1720

1821
In the coming pages we will explore both tasks and the different options available.

book/en/src/by-example/hardware_tasks.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
# Hardware tasks
22

3-
At its core RTIC is using the hardware interrupt controller ([ARM NVIC on cortex-m][NVIC])
4-
to perform scheduling and executing tasks, and all tasks except `#[init]` and `#[idle]`
3+
At its core RTIC is using a hardware interrupt controller ([ARM NVIC on cortex-m][NVIC])
4+
to schedule and start execution of tasks. All tasks except `pre-init`, `#[init]` and `#[idle]`
55
run as interrupt handlers.
6-
This also means that you can manually bind tasks to interrupt handlers.
76

8-
To bind an interrupt use the `#[task]` attribute argument `binds = InterruptName`.
9-
This task becomes the interrupt handler for this hardware interrupt vector.
7+
Hardware tasks are explicitly bound to interrupt handlers.
108

11-
All tasks bound to an explicit interrupt are *hardware tasks* since they
9+
To bind a task to an interrupt, use the `#[task]` attribute argument `binds = InterruptName`.
10+
This task then becomes the interrupt handler for this hardware interrupt vector.
11+
12+
All tasks bound to an explicit interrupt are called *hardware tasks* since they
1213
start execution in reaction to a hardware event.
1314

1415
Specifying a non-existing interrupt name will cause a compilation error. The interrupt names
1516
are commonly defined by [PAC or HAL][pacorhal] crates.
1617

17-
Any available interrupt vector should work, but different hardware might have
18-
added special properties to select interrupt priority levels, such as the
18+
Any available interrupt vector should work. Specific devices may bind
19+
specific interrupt priorities to specific interrupt vectors outside
20+
user code control. See for example the
1921
[nRF “softdevice”](https://github.com/rtic-rs/cortex-m-rtic/issues/434).
2022

21-
Beware of re-purposing interrupt vectors used internally by hardware features,
23+
Beware of using interrupt vectors that are used internally by hardware features;
2224
RTIC is unaware of such hardware specific details.
2325

2426
[pacorhal]: https://docs.rust-embedded.org/book/start/registers.html

book/en/src/by-example/monotonic.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Monotonic & spawn_{at/after}
22

33
The understanding of time is an important concept in embedded systems, and to be able to run tasks
4-
based on time is useful. For this use-case the framework provides the static methods
4+
based on time is essential. The framework provides the static methods
55
`task::spawn_after(/* duration */)` and `task::spawn_at(/* specific time instant */)`.
66
`spawn_after` is more commonly used, but in cases where it's needed to have spawns happen
77
without drift or to a fixed baseline `spawn_at` is available.
@@ -43,10 +43,14 @@ $ cargo run --target thumbv7m-none-eabi --example schedule
4343
{{#include ../../../../ci/expected/schedule.run}}
4444
```
4545

46+
A key requirement of a Monotonic is that it must deal gracefully with
47+
hardware timer overruns.
48+
4649
## Canceling or rescheduling a scheduled task
4750

4851
Tasks spawned using `task::spawn_after` and `task::spawn_at` returns a `SpawnHandle`,
4952
which allows canceling or rescheduling of the task scheduled to run in the future.
53+
5054
If `cancel` or `reschedule_at`/`reschedule_after` returns an `Err` it means that the operation was
5155
too late and that the task is already sent for execution. The following example shows this in action:
5256

book/en/src/by-example/resources.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ task.
3030
Thus, a task `#[local]` resource can only be accessed by one singular task.
3131
Attempting to assign the same `#[local]` resource to more than one task is a compile-time error.
3232

33-
Types of `#[local]` resources must implement [`Send`] trait as they are being sent from `init`
34-
to target task and thus crossing the thread boundary.
33+
Types of `#[local]` resources must implement a [`Send`] trait as they are being sent from `init`
34+
to a target task, crossing a thread boundary.
3535

3636
[`Send`]: https://doc.rust-lang.org/stable/core/marker/trait.Send.html
3737

3838
The example application shown below contains two tasks where each task has access to its own
39-
`#[local]` resource, plus that the `idle` task has its own `#[local]` as well.
39+
`#[local]` resource; the `idle` task has its own `#[local]` as well.
4040

4141
``` rust
4242
{{#include ../../../../examples/locals.rs}}
@@ -49,12 +49,14 @@ $ cargo run --target thumbv7m-none-eabi --example locals
4949
{{#include ../../../../ci/expected/locals.run}}
5050
```
5151

52+
Local resources in `#[init]` and `#[idle]` have `'static`
53+
lifetimes. This is safe since both tasks are not re-entrant.
54+
5255
### Task local initialized resources
5356

54-
A special use-case of local resources are the ones specified directly in the resource claim,
55-
`#[task(local = [my_var: TYPE = INITIAL_VALUE, ...])]`, this allows for creating locals which do no need to be
57+
Local resources can also be specified directly in the resource claim like so:
58+
`#[task(local = [my_var: TYPE = INITIAL_VALUE, ...])]`; this allows for creating locals which do no need to be
5659
initialized in `#[init]`.
57-
Moreover, local resources in `#[init]` and `#[idle]` have `'static` lifetimes, this is safe since both are not re-entrant.
5860

5961
Types of `#[task(local = [..])]` resources have to be neither [`Send`] nor [`Sync`] as they
6062
are not crossing any thread boundary.
@@ -92,9 +94,9 @@ preempting the critical section. This synchronization protocol is known as the
9294
[srp]: https://en.wikipedia.org/wiki/Stack_Resource_Policy
9395

9496
In the example below we have three interrupt handlers with priorities ranging from one to three.
95-
The two handlers with the lower priorities contend for the `shared` resource and need to lock the
96-
resource for accessing the data. The highest priority handler, which do not access the `shared`
97-
resource, is free to preempt the critical section created by the lowest priority handler.
97+
The two handlers with the lower priorities contend for a `shared` resource and need to succeed in locking the
98+
resource in order to access its data. The highest priority handler, which does not access the `shared`
99+
resource, is free to preempt a critical section created by the lowest priority handler.
98100

99101
``` rust
100102
{{#include ../../../../examples/lock.rs}}

book/en/src/by-example/software_tasks.md

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,33 @@
22

33
The RTIC concept of a software task shares a lot with that of [hardware tasks](./hardware_tasks.md)
44
with the core difference that a software task is not explicitly bound to a specific
5-
interrupt vector, but rather a “dispatcher” interrupt vector running
6-
at the same priority as the software task.
5+
interrupt vector, but rather bound to a “dispatcher” interrupt vector running
6+
at the intended priority of the software task (see below).
77

8-
Thus, software tasks are tasks which are not directly assigned to a specific interrupt vector.
8+
Thus, software tasks are tasks which are not *directly* bound to an interrupt vector.
99

10-
The `#[task]` attribute used on a function declare it as a software tasks.
11-
Observe the absence of a `binds = InterruptName` argument to the attribute.
12-
The static method `task_name::spawn()` spawns (starts) a software task and
13-
given that there are no higher priority tasks running the task will start executing directly.
10+
The `#[task]` attributes used on a function determine if it is
11+
software tasks, specifically the absence of a `binds = InterruptName`
12+
argument to the attribute definition.
1413

15-
All software tasks at the same priority level shares an interrupt handler acting as a dispatcher.
16-
What differentiates software and hardware tasks are the dispatcher versus bound interrupt vector.
14+
The static method `task_name::spawn()` spawns (schedules) a software
15+
task by registering it with a specific dispatcher. If there are no
16+
higher priority tasks available to the scheduler (which serves a set
17+
of dispatchers), the task will start executing directly.
1718

18-
The interrupt vectors used as dispatchers can not be used by hardware tasks.
19+
All software tasks at the same priority level share an interrupt handler bound to their dispatcher.
20+
What differentiates software and hardware tasks is the usage of either a dispatcher or a bound interrupt vector.
1921

20-
A list of “free” (not in use by hardware tasks) and usable interrupts allows the framework
21-
to dispatch software tasks.
22+
The interrupt vectors used as dispatchers cannot be used by hardware tasks.
2223

23-
This list of dispatchers, `dispatchers = [FreeInterrupt1, FreeInterrupt2, ...]` is an
24+
Availability of a set of “free” (not in use by hardware tasks) and usable interrupt vectors allows the framework
25+
to dispatch software tasks via dedicated interrupt handlers.
26+
27+
This set of dispatchers, `dispatchers = [FreeInterrupt1, FreeInterrupt2, ...]` is an
2428
argument to the `#[app]` attribute.
2529

26-
Each interrupt vector acting as dispatcher gets assigned to one priority level meaning that
27-
the list of dispatchers need to cover all priority levels used by software tasks.
30+
Each interrupt vector acting as dispatcher gets assigned to a unique priority level meaning that
31+
the list of dispatchers needs to cover all priority levels used by software tasks.
2832

2933
Example: The `dispatchers =` argument needs to have at least 3 entries for an application using
3034
three different priorities for software tasks.

book/en/src/by-example/starting_a_project.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ If you are targeting ARMv6-M or ARMv8-M-base architecture, check out the section
88
[`defmt-app-template`]: https://github.com/rtic-rs/defmt-app-template
99

1010
This will give you an RTIC application with support for RTT logging with [`defmt`] and stack overflow
11-
protection using [`flip-link`]. There are also a multitude of examples available provided by the community:
11+
protection using [`flip-link`]. There is also a multitude of examples provided by the community:
1212

1313
- [`rtic-examples`] - Multiple projects
1414
- [https://github.com/kalkyl/f411-rtic](https://github.com/kalkyl/f411-rtic)

book/en/src/by-example/tips_indirection.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@ Indirection can minimize message passing overhead:
99
instead of sending the buffer by value, one can send an owning pointer into the
1010
buffer.
1111

12-
One can use a global allocator to achieve indirection (`alloc::Box`,
12+
One can use a global memory allocator to achieve indirection (`alloc::Box`,
1313
`alloc::Rc`, etc.), which requires using the nightly channel as of Rust v1.37.0,
1414
or one can use a statically allocated memory pool like [`heapless::Pool`].
1515

1616
[`heapless::Pool`]: https://docs.rs/heapless/0.5.0/heapless/pool/index.html
1717

18+
As this example of approach goes completely outside of RTIC resource
19+
model with shared and local the program would rely on the correctness
20+
of the memory allocator, in this case `heapless::pool`.
21+
1822
Here's an example where `heapless::Pool` is used to "box" buffers of 128 bytes.
1923

2024
``` rust

0 commit comments

Comments
 (0)