670: Add documentation for different Cortex-M architectures r=AfoHT a=n8tlarsen

Most of the RTIC documentation focuses on ARMv7-M architectures. Here's some initial thoughts on useful information I would have liked to know before starting with RTIC on ARMv6-M.

Co-authored-by: Nathan <n8tlarsen@gmail.com>
Co-authored-by: n8tlarsen <96437952+n8tlarsen@users.noreply.github.com>
Co-authored-by: Henrik Tjäder <henrik@tjaders.com>
This commit is contained in:
bors[bot] 2023-01-04 20:27:21 +00:00 committed by GitHub
commit de25c4c0c2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 1 deletions

View file

@ -29,6 +29,7 @@
- [v0.4.x to v0.5.x](./migration/migration_v4.md)
- [RTFM to RTIC](./migration/migration_rtic.md)
- [Under the hood](./internals.md)
- [Cortex-M architectures](./internals/targets.md)
<!--- [Interrupt configuration](./internals/interrupt-configuration.md)-->
<!--- [Non-reentrancy](./internals/non-reentrancy.md)-->
<!--- [Access control](./internals/access.md)-->

View file

@ -1,6 +1,9 @@
# Starting a new project
A recommendation when starting a RTIC project from scratch is to follow RTIC's [`defmt-app-template`].
A recommendation when starting a RTIC project from scratch is to
follow RTIC's [`defmt-app-template`].
If you are targeting ARMv6-M or ARMv8-M-base architecture, check out the section [Target Architecture](../internals/targets.md) for more information on hardware limitations to be aware of.
[`defmt-app-template`]: https://github.com/rtic-rs/defmt-app-template

View file

@ -0,0 +1,71 @@
# Target Architecture
While RTIC can currently target all Cortex-m devices there are some key architecure differences that
users should be aware of. Namely the absence of Base Priority Mask Register (`BASEPRI`) which lends
itself exceptionally well to the hardware priority ceiling support used in RTIC, in the ARMv6-M and
ARMv8-M-base architectures, which forces RTIC to use source masking instead. For each implementation
of lock and a detailed commentary of pros and cons, see the implementation of
[lock in src/export.rs][src_export].
[src_export]: https://github.com/rtic-rs/cortex-m-rtic/blob/master/src/export.rs
These differences influence how critical sections are realized, but functionality should be the same
except that ARMv6-M/ARMv8-M-base cannot have tasks with shared resources bound to exception
handlers, as these cannot be masked in hardware.
Table 1 below shows a list of Cortex-m processors and which type of critical section they employ.
#### *Table 1: Critical Section Implementation by Processor Architecture*
| Processor | Architecture | Priority Ceiling | Source Masking |
| :--------- | :----------: | :--------------: | :------------: |
| Cortex-M0 | ARMv6-M | | &#2713 |
| Cortex-M0+ | ARMv6-M | | &#2713 |
| Cortex-M3 | ARMv7-M | &#2713 | |
| Cortex-M4 | ARMv7-M | &#2713 | |
| Cortex-M7 | ARMv7-M | &#2713 | |
| Cortex-M23 | ARMv8-M-base | | &#2713 |
| Cortex-M33 | ARMv8-M-main | &#2713 | |
## Priority Ceiling
This implementation is covered in depth by the [Critical Sections][critical_sections] page of this book.
## Source Masking
Without a `BASEPRI` register which allows for directly setting a priority ceiling in the Nested
Vectored Interrupt Controller (NVIC), RTIC must instead rely on disabling (masking) interrupts.
Consider Figure 1 below, showing two tasks A and B where A has higher priority but shares a resource
with B.
#### *Figure 1: Shared Resources and Source Masking*
```text
┌────────────────────────────────────────────────────────────────┐
│ │
│ │
3 │ Pending Preempts │
2 │ ↑- - -A- - - - -↓A─────────► │
1 │ B───────────────────► - - - - B────────► │
0 │Idle┌─────► Resumes ┌────────► │
├────┴────────────────────────────────────────────┴──────────────┤
│ │
└────────────────────────────────────────────────────────────────┴──► Time
t1 t2 t3 t4
```
At time *t1*, task B locks the shared resource by selectively disabling (using the NVIC) all other
tasks which have a priority equal to or less than any task which shares resouces with B. In effect
this creates a virtual priority ceiling, miroring the `BASEPRI` approach described in the
[Critical Sections][critical_Sections] page. Task A is one such task that shares resources with
task B. At time *t2*, task A is either spawned by task B or becomes pending through an interrupt
condition, but does not yet preempt task B even though its priority is greater. This is because the
NVIC is preventing it from starting due to task A being being disabled. At time *t3*, task B
releases the lock by re-enabling the tasks in the NVIC. Because task A was pending and has a higher
priority than task B, it immediately preempts task B and is free to use the shared resource without
risk of data race conditions. At time *t4*, task A completes and returns the execution context to B.
Since source masking relies on use of the NVIC, core exception sources such as HardFault, SVCall,
PendSV, and SysTick cannot share data with other tasks.
[critical_sections]: https://github.com/rtic-rs/cortex-m-rtic/blob/master/book/en/src/internals/critical-sections.md