mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-30 23:44:34 +01:00
175 lines
8.2 KiB
Markdown
175 lines
8.2 KiB
Markdown
# Советы и хитрости
|
||
|
||
Полные примеры для 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.run.grep.foo}}
|
||
```
|
||
|
||
``` console
|
||
$ cargo nm --example ramfunc --release | grep ' bar::'
|
||
{{#include ../../../../ci/expected/ramfunc.run.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}}
|
||
```
|