1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
# Советы и хитрости
Полные примеры для RTIC смотрите в репозитарии [rtic-examples][rtic-examples].
[rtic-examples]: https://github.com/rtic-rs/rtic-examples
## Обобщенное программирование (Generics)
Все объекты, предоставляющие ресурысы реализуют трейт `rtic::Mutex`.
Если ресурс не реализует его, можно обернуть его в новый тип [`rtic::Exclusive`],
который реализует трейт `Mutex`. С помощью этого нового типа
можно написать обобщенную функцию, которая работает с обобщенным ресурсом и
вызывать его из различных задач, чтобы производить однотипные операции над
похожим множеством ресурсов.
Вот один такой пример:
[`rtic::Exclusive`]: ../../../api/rtic/struct.Exclusive.html
``` rust
{{#include ../../../../examples/generics.rs}}
```
``` console
$ cargo run --example generics
{{#include ../../../../ci/expected/generics.run}}
```
## Условная компиляция
Вы можете использовать условную компиляцию (`#[cfg]`) на ресурсах (полях структуры
`#[resources] struct Resources`) и задачах (элементах `fn`).
Эффект использования атрибутов `#[cfg]` в том, что ресурс/ задача
будут *не* доступны в соответствующих структурах `Context` если условие не выполняется.
В примере ниже выводится сообщение каждый раз, когда вызывается задача `foo`, но только
если программы скомпилирова с профилем `dev`.
``` rust
{{#include ../../../../examples/cfg.rs}}
```
``` console
$ cargo run --example cfg --release
$ cargo run --example cfg
{{#include ../../../../ci/expected/cfg.run}}
```
## Запуск задач из ОЗУ
Главной целью переноса описания программы на RTIC в атрибуты в
RTIC v0.4.x была возможность взаимодействия с другими атрибутами.
Напримерe, атрибут `link_section` можно применять к задачам, чтобы разместить
их в ОЗУ; это может улучшить производительность в некоторых случаях.
> **ВАЖНО**: Обычно атрибуты `link_section`, `export_name` и `no_mangle`
> очень мощные, но их легко использовать неправильно. Неверное использование
> любого из этих атрибутов может вызвать неопределенное поведение;
> Вам следует всегда предпочитать использование безопасных, высокоуровневых
> атрибутов вместо них, таких как атрибуты `interrupt` и `exception`
> из `cortex-m-rt`.
>
> В особых функций, размещаемых в ОЗУ нет безопасной абстракции в `cortex-m-rt`
> v0.6.5 но создано [RFC] для добавления атрибута `ramfunc` в будущем релизе.
[RFC]: https://github.com/rust-embedded/cortex-m-rt/pull/100
В примере ниже показано как разместить высокоприоритетную задачу `bar` в ОЗУ.
``` rust
{{#include ../../../../examples/ramfunc.rs}}
```
Запуск этой программы создаст ожидаемый вывод.
``` console
$ cargo run --example ramfunc
{{#include ../../../../ci/expected/ramfunc.run}}
```
Можно посмотреть на вывод `cargo-nm`, чтобы убедиться, что `bar` расположен в ОЗУ
(`0x2000_0000`), тогда как `foo` расположен во Flash (`0x0000_0000`).
``` console
$ cargo nm --example ramfunc --release | grep ' foo::'
{{#include ../../../../ci/expected/ramfunc.grep.foo}}
```
``` console
$ cargo nm --example ramfunc --release | grep ' bar::'
{{#include ../../../../ci/expected/ramfunc.grep.bar}}
```
## Обходной путь для быстрой передачи сообщений
Передача сообщений всегда вызывает копирование от отправителя в
статическую переменную, а затем из статической переменной получателю.
Таким образом, при передаче большого буфера, например `[u8; 128]`, передача сообщения
вызывает два дорогих вызова `memcpy`. Чтобы минимизировать накладные расходы на передачу
сообщения, можно использовать обходной путь: вместо передачи буфера по значению,
можно передавать владеющий указатель на буфер.
Можно использовать глобальный аллокатор, чтобы реализовать данный трюк (`alloc::Box`,
`alloc::Rc`, и т.п.), либо использовать статически аллоцируемый пул памяти, например [`heapless::Pool`].
[`heapless::Pool`]: https://docs.rs/heapless/0.5.0/heapless/pool/index.html
Здесь приведен пример использования `heapless::Pool` для "упаковки" буфера из 128 байт.
``` rust
{{#include ../../../../examples/pool.rs}}
```
``` console
$ cargo run --example pool
{{#include ../../../../ci/expected/pool.run}}
```
## Инспектирование раскрываемого кода
`#[rtic::app]` - это процедурный макрос, который создает код.
Если по какой-то причине вам нужно увидеть код, сгенерированный этим макросом,
у вас есть два пути:
Вы можете изучить файл `rtic-expansion.rs` внутри папки `target`. Этот файл
содержит элемент `#[rtic::app]` в раскрытом виде (не всю вашу программу!)
из *последней сборки* (с помощью `cargo build` или `cargo check`) RTIC программы.
Раскрытый код не отформатирован по-умолчанию, но вы можете запустить `rustfmt`
на нем перед тем, как читать.
``` console
$ cargo build --example foo
$ rustfmt target/rtic-expansion.rs
$ tail target/rtic-expansion.rs
```
``` rust
#[doc = r" Implementation details"]
mod app {
#[doc = r" Always include the device crate which contains the vector table"]
use lm3s6965 as _;
#[no_mangle]
unsafe extern "C" fn main() -> ! {
rtic::export::interrupt::disable();
let mut core: rtic::export::Peripherals = core::mem::transmute(());
core.SCB.scr.modify(|r| r | 1 << 1);
rtic::export::interrupt::enable();
loop {
rtic::export::wfi()
}
}
}
```
Или, вы можете использовать подкоманду [`cargo-expand`]. Она раскроет
*все* макросы, включая атрибут `#[rtic::app]`, и модули в вашем крейте и
напечатает вывод в консоль.
[`cargo-expand`]: https://crates.io/crates/cargo-expand
``` console
$ # создаст такой же вывод, как выше
$ cargo expand --example smallest | tail
```
## Деструктуризация ресурса
Если задача требует нескольких ресурсов, разбиение структуры ресурсов
может улучшить читабельность. Вот два примера того, как это можно сделать:
``` rust
{{#include ../../../../examples/destructure.rs}}
```
|