rtic/book/ru/src/by-example/resources.md
2020-06-11 17:18:29 +00:00

8.6 KiB
Raw Blame History

Ресурсы

Одно из ограничений атрибутов, предоставляемых библиотекой cortex-m-rt является то, что совместное использование данных (или периферии) между прерываниями, или прерыванием и функцией init, требуют cortex_m::interrupt::Mutex, который всегда требует отключения всех прерываний для доступа к данным. Отключение всех прерываний не всегда необходимо для безопасности памяти, но компилятор не имеет достаточно информации, чтобы оптимизировать доступ к разделяемым данным.

Атрибут app имеет полную картину приложения, поэтому может оптимизировать доступ к static-переменным. В RTIC мы обращаемся к static-переменным, объявленным внутри псевдо-модуля app как к ресурсам. Чтобы получить доступ к ресурсу, контекст (init, idle, interrupt или exception) должен сначала определить аргумент resources в соответствующем атрибуте.

В примере ниже два обработчика прерываний имеют доступ к одному и тому же ресурсу. Никакого Mutex в этом случае не требуется, потому что оба обработчика запускаются с одним приоритетом и никакого вытеснения быть не может. К ресурсу SHARED можно получить доступ только из этих двух прерываний.

{{#include ../../../../examples/resource.rs}}
$ cargo run --example resource
{{#include ../../../../ci/expected/resource.run}}

Приоритеты

Приоритет каждого прерывания можно определить в атрибутах interrupt и exception. Невозможно установить приоритет любым другим способом, потому что рантайм забирает владение прерыванием NVIC; также невозможно изменить приоритет обработчика / задачи в рантайме. Благодаря этому ограничению у фреймворка есть знание о статических приоритетах всех обработчиков прерываний и исключений.

Прерывания и исключения могут иметь приоритеты в интервале 1..=(1 << NVIC_PRIO_BITS), где NVIC_PRIO_BITS - константа, определённая в библиотеке device. Задача idle имеет приоритет 0, наименьший.

Ресурсы, совместно используемые обработчиками, работающими на разных приоритетах, требуют критических секций для безопасности памяти. Фреймворк проверяет, что критические секции используются, но только где необходимы: например, критические секции не нужны для обработчика с наивысшим приоритетом, имеющим доступ к ресурсу.

API критической секции, предоставляемое фреймворком RTIC (см. Mutex), основано на динамических приоритетах вместо отключения прерываний. Из этого следует, что критические секции не будут допускать запуск некоторых обработчиков, включая все соперничающие за ресурс, но будут позволять запуск обработчиков с большим приоритетом не соперничащих за ресурс.

В примере ниже у нас есть 3 обработчика прерываний с приоритетами от одного до трех. Два обработчика с низким приоритетом соперничают за ресурс SHARED. Обработчик с низшим приоритетом должен заблокировать (lock) ресурс SHARED, чтобы получить доступ к его данным, в то время как обработчик со средним приоритетом может напрямую получать доступ к его данным. Обработчик с наивысшим приоритетом может свободно вытеснять критическую секцию, созданную обработчиком с низшим приоритетом.

{{#include ../../../../examples/lock.rs}}
$ cargo run --example lock
{{#include ../../../../ci/expected/lock.run}}```

## Поздние ресурсы

В отличие от обычных `static`-переменных, к которым должно быть присвоено
начальное значение, ресурсы можно инициализировать в рантайме.
Мы называем ресурсы, инициализируемые в рантайме *поздними*. Поздние ресурсы
полезны для *переноса* (как при передаче владения) периферии из `init` в
обработчики прерываний и исключений.

Поздние ресурсы определяются как обычные ресурсы, но им присваивается начальное
значение `()` (the unit value). `init` должен вернуть начальные значения для
всех поздних ресурсов, упакованные в структуру типа `init::LateResources`.

В примере ниже использованы поздние ресурсы, чтобы установить неблокированный,
односторонний канал между обработчиком прерывания `UART0` и функцией `idle`.
Очередь типа один производитель-один потребитель [`Queue`] использована как канал.
Очередь разделена на элементы потребителя и поизводителя в `init` и каждый элемент
расположен в отдельном ресурсе; `UART0` владеет ресурсом произодителя, а `idle`
владеет ресурсом потребителя.

[`Queue`]: ../../../api/heapless/spsc/struct.Queue.html

``` rust
{{#include ../../../../examples/late.rs}}
$ cargo run --example late
{{#include ../../../../ci/expected/late.run}}```

## `static`-ресурсы

Переменные типа `static` также можно использовать в качестве ресурсов. Задачи
могут получать только (разделяемые) `&` ссылки на ресурсы, но блокировки не
нужны для доступа к данным. Вы можете думать о `static`-ресурсах как о простых
`static`-переменных, которые можно инициализировать в рантайме и иметь лучшие
правила видимости: Вы можете контролировать, какие задачи получают доступ к
переменной, чтобы переменная не была видна всем фунциям в область видимости,
где она была объявлена.

В примере ниже ключ загружен (или создан) в рантайме, а затем использован в двух
задачах, запущенных на разных приоритетах.

``` rust
{{#include ../../../../examples/static.rs}}
$ cargo run --example static
{{#include ../../../../ci/expected/static.run}}```