## Ресурсы Одно из ограничений атрибутов, предоставляемых библиотекой `cortex-m-rt` является то, что совместное использование данных (или периферии) между прерываниями, или прерыванием и функцией `init`, требуют `cortex_m::interrupt::Mutex`, который *всегда* требует отключения *всех* прерываний для доступа к данным. Отключение всех прерываний не всегда необходимо для безопасности памяти, но компилятор не имеет достаточно информации, чтобы оптимизировать доступ к разделяемым данным. Атрибут `app` имеет полную картину приложения, поэтому может оптимизировать доступ к `static`-переменным. В RTIC мы обращаемся к `static`-переменным, объявленным внутри псевдо-модуля `app` как к *ресурсам*. Чтобы получить доступ к ресурсу, контекст (`init`, `idle`, `interrupt` или `exception`) должен сначала определить аргумент `resources` в соответствующем атрибуте. В примере ниже два обработчика прерываний имеют доступ к одному и тому же ресурсу. Никакого `Mutex` в этом случае не требуется, потому что оба обработчика запускаются с одним приоритетом и никакого вытеснения быть не может. К ресурсу `SHARED` можно получить доступ только из этих двух прерываний. ``` rust {{#include ../../../../examples/resource.rs}} ``` ``` console $ 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`]), основано на динамических приоритетах вместо отключения прерываний. Из этого следует, что критические секции не будут допускать *запуск некоторых* обработчиков, включая все соперничающие за ресурс, но будут позволять запуск обработчиков с большим приоритетом не соперничащих за ресурс. [`Mutex`]: ../../../api/rtic/trait.Mutex.html В примере ниже у нас есть 3 обработчика прерываний с приоритетами от одного до трех. Два обработчика с низким приоритетом соперничают за ресурс `SHARED`. Обработчик с низшим приоритетом должен заблокировать ([`lock`]) ресурс `SHARED`, чтобы получить доступ к его данным, в то время как обработчик со средним приоритетом может напрямую получать доступ к его данным. Обработчик с наивысшим приоритетом может свободно вытеснять критическую секцию, созданную обработчиком с низшим приоритетом. [`lock`]: ../../../api/rtic/trait.Mutex.html#method.lock ``` rust {{#include ../../../../examples/lock.rs}} ``` ``` console $ 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}} ``` ``` console $ cargo run --example late {{#include ../../../../ci/expected/late.run}}``` ## `static`-ресурсы Переменные типа `static` также можно использовать в качестве ресурсов. Задачи могут получать только (разделяемые) `&` ссылки на ресурсы, но блокировки не нужны для доступа к данным. Вы можете думать о `static`-ресурсах как о простых `static`-переменных, которые можно инициализировать в рантайме и иметь лучшие правила видимости: Вы можете контролировать, какие задачи получают доступ к переменной, чтобы переменная не была видна всем фунциям в область видимости, где она была объявлена. В примере ниже ключ загружен (или создан) в рантайме, а затем использован в двух задачах, запущенных на разных приоритетах. ``` rust {{#include ../../../../examples/static.rs}} ``` ``` console $ cargo run --example static {{#include ../../../../ci/expected/static.run}}```