mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-26 05:29:38 +01:00
russian translation
This commit is contained in:
parent
45659fdbbc
commit
5ef1f2088a
17 changed files with 753 additions and 2 deletions
104
ru/src/README_RU.md
Normal file
104
ru/src/README_RU.md
Normal file
|
@ -0,0 +1,104 @@
|
|||
# Real Time For the Masses
|
||||
|
||||
Конкурентный фреймворк для создания систем реального времени.
|
||||
|
||||
**ВАЖНО** Эта библиотека в настоящее время в состоянии пре-релиза (бета).
|
||||
Мы зарезервировали право делать ломающие синтакс изменения или патчить дыры
|
||||
в безопасности памяти до релиза v0.4.0, который запланирован на 2018-12-07.
|
||||
Когда выйдет v0.4.0, *все пре-релизы будут убраны*. Если при запуске Вы
|
||||
получите сообщение о панике или бесполезное сообщение об ошибке
|
||||
(вводящее в заблуждение), или что-то будет работать не так, как Вы ожидаете,
|
||||
пожалуйста, сообщите о [проблеме]!
|
||||
|
||||
[проблеме]: https://github.com/japaric/cortex-m-rtfm/issues
|
||||
|
||||
## Возможности
|
||||
|
||||
- **Задачи** - единица конкуренции [^1]. Задачи могут *запускаться по событию*
|
||||
(в ответ на асинхронный стимул) или вызываться программно по желанию.
|
||||
|
||||
- **Передача сообщений** между задачами. А именно, сообщения можно передавать
|
||||
программным задачам в момент вызова.
|
||||
|
||||
- **Очередь таймера** [^2]. Программные задачи можно планировать на запуск в
|
||||
определенный момент в будущем. Это свойство можно использовать, чтобы
|
||||
реализовывать периодические задачи.
|
||||
|
||||
- Поддержка приоритетов задач, и таким образом, **вытесняющей многозадачности**.
|
||||
|
||||
- **Эффективное, свободное от гонок данных разделение памяти** через хорошо
|
||||
разграниченные критические секции на *основе приоритетов* [^1].
|
||||
|
||||
- **Выполнение без взаимной блокировки задач**, гарантированное на этапе
|
||||
компиляции. Это более сильная гарантия, чем предоставляемая
|
||||
[стандартной абстракцией `Mutex`][std-mutex].
|
||||
|
||||
[std-mutex]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
|
||||
|
||||
- **Минимальные затраты на диспетчеризацию**. Диспетчер задач имеет
|
||||
минимальный след; основная часть работы по диспетчеризации делается аппаратно.
|
||||
|
||||
- **Высокоэффективное использование памяти**: Все задачи используют общий стек
|
||||
вызовов и нет сильной зависимости от динамического распределителя памяти.
|
||||
|
||||
- **Все устройства Cortex-M полностью поддерживаются**.
|
||||
|
||||
- Эта модель задач поддается известному анализу методом WCET (наихудшего
|
||||
времени исполнения) и техникам анализа диспетчеризации. (Хотя мы еще не
|
||||
разработали для дружественных инструментов для этого).
|
||||
|
||||
## Требования
|
||||
|
||||
- Rust 1.31.0+
|
||||
|
||||
- Программы нужно писать используя 2018 edition.
|
||||
|
||||
## [User documentation](https://japaric.github.io/cortex-m-rtfm/book)
|
||||
|
||||
## [API reference](https://japaric.github.io/cortex-m-rtfm/api/rtfm/index.html)
|
||||
|
||||
## Благодарности
|
||||
|
||||
Эта библиотека основана на [языке RTFM][rtfm-lang], созданном Embedded
|
||||
Systems group в [Техническом Университете Luleå][ltu], под рук.
|
||||
[Prof. Per Lindgren][per].
|
||||
|
||||
[rtfm-lang]: http://www.rtfm-lang.org/
|
||||
[ltu]: https://www.ltu.se/?l=en
|
||||
[per]: https://www.ltu.se/staff/p/pln-1.11258?l=en
|
||||
|
||||
## Ссылки
|
||||
|
||||
[^1]: Eriksson, J., Häggström, F., Aittamaa, S., Kruglyak, A., & Lindgren, P.
|
||||
(2013, June). Real-time for the masses, step 1: Programming API and static
|
||||
priority SRP kernel primitives. In Industrial Embedded Systems (SIES), 2013
|
||||
8th IEEE International Symposium on (pp. 110-113). IEEE.
|
||||
|
||||
[^2]: Lindgren, P., Fresk, E., Lindner, M., Lindner, A., Pereira, D., & Pinho,
|
||||
L. M. (2016). Abstract timers and their implementation onto the arm cortex-m
|
||||
family of mcus. ACM SIGBED Review, 13(1), 48-53.
|
||||
|
||||
## Лицензия
|
||||
|
||||
Все исходные тексты (включая примеры кода) лицензированы либо под:
|
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) или
|
||||
[https://www.apache.org/licenses/LICENSE-2.0][L1])
|
||||
- MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
[https://opensource.org/licenses/MIT][L2])
|
||||
|
||||
[L1]: https://www.apache.org/licenses/LICENSE-2.0
|
||||
[L2]: https://opensource.org/licenses/MIT
|
||||
|
||||
на Ваше усмотрение.
|
||||
|
||||
Текст книги лицензирован по условиям лицензий
|
||||
Creative Commons CC-BY-SA v4.0 ([LICENSE-CC-BY-SA](LICENSE-CC-BY-SA) или
|
||||
[https://creativecommons.org/licenses/by-sa/4.0/legalcode][L3]).
|
||||
|
||||
[L3]: https://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
### Contribution
|
||||
|
||||
Если вы явно не заявляете иначе, любой взнос, преднамеренно представленный
|
||||
для включения в эту работу, как определено в лицензии Apache-2.0, лицензируется, как указано выше, без каких-либо дополнительных условий.
|
|
@ -1,3 +1,16 @@
|
|||
# Summary
|
||||
|
||||
- [Chapter 1](./chapter_1.md)
|
||||
[Введение](./preface.md)
|
||||
- [RTFM в примерах](./by-example.md)
|
||||
- [Атрибут `app](./by-example/app.md)
|
||||
- [Ресурсы](./by-example/resources.md)
|
||||
- [Задачи](./by-example/tasks.md)
|
||||
- [Очередь таймера](./by-example/timer-queue.md)
|
||||
- [Одиночки](./by-example/singletons.md)
|
||||
- [Типы, Send и Sync](./by-example/types-send-sync.md)
|
||||
- [Создание нового проекта](./by-example/new.md)
|
||||
- [Советы и хитрости](./by-example/tips.md)
|
||||
- [Под капотом](./internals.md)
|
||||
- [Ceiling analysis](./internals/ceilings.md)
|
||||
- [Диспетчер задач](./internals/tasks.md)
|
||||
- [Очередь таймера](./internals/timer-queue.md)
|
||||
|
|
16
ru/src/by-example.md
Normal file
16
ru/src/by-example.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# RTFM в примерах
|
||||
|
||||
Эта часть книги представляет фреймворк Real Time For the Masses (RTFM)
|
||||
новым пользователям через примеры с растущей сложностью.
|
||||
|
||||
Все примеры в этой книге можно найти в [репозитории] проекта на GitHub,
|
||||
и большинство примеров можно запустить на эмуляторе QEMU, поэтому никакого
|
||||
специальног оборудования не требуется to follow along.
|
||||
|
||||
[репозитории]: https://github.com/japaric/cortex-m-rtfm
|
||||
|
||||
Чтобы запустить примеры на Вашем ноутбуке / PC, Вам нужна программа
|
||||
`qemu-system-arm`. Посмотрите [the embedded Rust book] на предмет инструкций
|
||||
как настроить окружение для разработки встраиваемых устройств, в том числе QEMU.
|
||||
|
||||
[the embedded Rust book]: https://rust-embedded.github.io/book/intro/install.html
|
101
ru/src/by-example/app.md
Normal file
101
ru/src/by-example/app.md
Normal file
|
@ -0,0 +1,101 @@
|
|||
# The `app` attribute
|
||||
|
||||
Это наименьшая возможная программа на RTFM:
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/smallest.rs}}
|
||||
```
|
||||
|
||||
Все программы на RTFM используют атрибут [`app`] (`#[app(..)]`). Этот атрибут
|
||||
нужно применять к `const`-элементам, содержащим элементы. Атрибут `app` имеет
|
||||
обязательный аргумент `device`, в качестве значения которому передается *путь*.
|
||||
Этот путь должен указывать на библиотеку *устройства*, сгенерированную с помощью
|
||||
[`svd2rust`] **v0.14.x**. Атрибут `app` развернется в удобную точку входа,
|
||||
поэтому нет необходимости использовать атрибут [`cortex_m_rt::entry`].
|
||||
|
||||
[`app`]: ../../api/cortex_m_rtfm_macros/attr.app.html
|
||||
[`svd2rust`]: https://crates.io/crates/svd2rust
|
||||
[`cortex_m_rt::entry`]: ../../api/cortex_m_rt_macros/attr.entry.html
|
||||
|
||||
> **ОТСТУПЛЕНИЕ**: Некоторые из вас удивятся, почему мы используем ключевое слово `const` как
|
||||
> модуль, а не правильное `mod`. Причина в том, что использование атрибутов на
|
||||
> модулях требует feature gate, который требует ночную сборку. Чтобы заставить
|
||||
> RTFM работать на стабильной сборке, мы используем вместо него слово `const`.
|
||||
> Когда большая часть макросов 1.2 стабилизируются, мы прейдем от `const` к `mod` и в конце концов в атрибуту уровне приложения (`#![app]`).
|
||||
|
||||
## `init`
|
||||
|
||||
Внутри псевдо-модуля атрибут `app` ожидает найти функцию инициализации, обозначенную
|
||||
атрибутом `init`. Эта функция должна иметь сигнатуру `[unsafe] fn()`.
|
||||
|
||||
Эта функция инициализации будет первой частью запускаемого приложения.
|
||||
Функция `init` запустится *с отключенными прерываниями* и будет иметь эксклюзивный
|
||||
доступ к периферии Cortex-M и специфичной для устройства периферии через переменные
|
||||
`core` and `device`, которые внедряются в область видимости `init` атрибутом `app`.
|
||||
Не вся периферия Cortex-M доступна в `core`, потому что рантайм RTFM принимает владение
|
||||
частью из неё -- более подробно см. структуру [`rtfm::Peripherals`].
|
||||
|
||||
Переменные `static mut`, определённые в начале `init` будут преобразованы
|
||||
в ссылки `&'static mut` с безопасным доступом.
|
||||
|
||||
[`rtfm::Peripherals`]: ../../api/rtfm/struct.Peripherals.html
|
||||
|
||||
Пример ниже показывает типы переменных `core` и `device` и
|
||||
демонстрирует безопасный доступ к переменной `static mut`.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/init.rs}}
|
||||
```
|
||||
|
||||
Запуск примера напечатает `init` в консоли и завершит процесс QEMU.
|
||||
|
||||
``` console
|
||||
$ cargo run --example init
|
||||
{{#include ../../../ci/expected/init.run}}```
|
||||
|
||||
## `idle`
|
||||
|
||||
Функция, помеченная атрибутом `idle` может присутствовать в псевдо-модуле
|
||||
опционально. Эта функция используется как специальная *задача ожидания* и должна иметь
|
||||
сигнатуру `[unsafe] fn() - > !`.
|
||||
|
||||
Когда она присутствует, рантайм запустит задачу `idle` после `init`. В отличие от
|
||||
`init`, `idle` запустится *с включенными прерываниями* и не может завершиться,
|
||||
поэтому будет работать бесконечно.
|
||||
|
||||
Когда функция `idle` определена, рантайм устанавливает бит [SLEEPONEXIT], после чего
|
||||
отправляет микроконтроллер в состояние сна после выполнения `init`.
|
||||
|
||||
[SLEEPONEXIT]: https://developer.arm.com/products/architecture/cpu-architecture/m-profile/docs/100737/0100/power-management/sleep-mode/sleep-on-exit-bit
|
||||
|
||||
Как и в `init`, переменные `static mut`будут преобразованы в ссылки `&'static mut`
|
||||
с безопасным доступом.
|
||||
|
||||
В примере ниже показан запуск `idle` после `init`.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/idle.rs}}
|
||||
```
|
||||
|
||||
``` console
|
||||
$ cargo run --example idle
|
||||
{{#include ../../../ci/expected/idle.run}}```
|
||||
|
||||
## `interrupt` / `exception`
|
||||
|
||||
Как Вы бы сделали с помощью библиотеки `cortex-m-rt`, Вы можете использовать атрибуты
|
||||
`interrupt` и `exception` внутри псевдо-модуля `app`, чтобы определить обработчики
|
||||
прерываний и исключений. В RTFM, мы называем обработчики прерываний и исключений
|
||||
*аппаратными* задачами.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/interrupt.rs}}
|
||||
```
|
||||
|
||||
``` console
|
||||
$ cargo run --example interrupt
|
||||
{{#include ../../../ci/expected/interrupt.run}}```
|
||||
|
||||
До сих пор программы RTFM, которые мы видели не отличались от программ, которые
|
||||
можно написать, используя только библиотеку `cortex-m-rt`. В следующем разделе
|
||||
мы начнем знакомиться с функционалом, присущим только RTFM.
|
67
ru/src/by-example/new.md
Normal file
67
ru/src/by-example/new.md
Normal file
|
@ -0,0 +1,67 @@
|
|||
# Создание нового проекта
|
||||
|
||||
Теперь, когда Вы изучили основные возможности фреймворка RTFM, Вы можете
|
||||
попробовать его использовать на Вашем оборудовании следуя этим инструкциям.
|
||||
|
||||
1. Создайте экземпляр из шаблона [`cortex-m-quickstart`].
|
||||
|
||||
[`cortex-m-quickstart`]: https://github.com/rust-embedded/cortex-m-quickstart#cortex-m-quickstart
|
||||
|
||||
``` console
|
||||
$ # например используя `cargo-generate`
|
||||
$ cargo generate \
|
||||
--git https://github.com/rust-embedded/cortex-m-quickstart \
|
||||
--name app
|
||||
|
||||
$ # следуйте остальным инструкциям
|
||||
```
|
||||
|
||||
2. Добавьте крейт устройства, сгенерированный с помощью [`svd2rust`] **v0.14.x**,
|
||||
или библиотеку отладочной платы, у которой в зависимостях одно из устройств.
|
||||
Убедитесь, что опция `rt` крейта включена.
|
||||
|
||||
[`svd2rust`]: https://crates.io/crates/svd2rust
|
||||
|
||||
В этом примере я покажу использование крейта устройства [`lm3s6965`].
|
||||
Эта библиотека не имеет Cargo-опции `rt`; эта опция всегда включена.
|
||||
|
||||
[`lm3s6965`]: https://crates.io/crates/lm3s6965
|
||||
|
||||
Этот крейт устройства предоставляет линковочный скрипт с макетом памяти
|
||||
целевого устройства, поэтому `memory.x` и `build.rs` не нужно удалять.
|
||||
|
||||
``` console
|
||||
$ cargo add lm3s6965 --vers 0.1.3
|
||||
|
||||
$ rm memory.x build.rs
|
||||
```
|
||||
|
||||
3. Добавьте библиотеку `cortex-m-rtfm` как зависимость, и если необходимо,
|
||||
включите опцию `timer-queue`.
|
||||
|
||||
``` console
|
||||
$ cargo add cortex-m-rtfm --allow-prerelease --upgrade=none
|
||||
```
|
||||
|
||||
4. Напишите программу RTFM.
|
||||
|
||||
Здесь я буду использовать пример `init` из библиотеки `cortex-m-rtfm`.
|
||||
|
||||
``` console
|
||||
$ curl \
|
||||
-L https://github.com/japaric/cortex-m-rtfm/raw/v0.4.0-beta.1/examples/init.rs \
|
||||
> src/main.rs
|
||||
```
|
||||
|
||||
Этот пример зависит от библиотеки `panic-semihosting`:
|
||||
|
||||
``` console
|
||||
$ cargo add panic-semihosting
|
||||
```
|
||||
|
||||
5. Соберите его, загрузите в микроконтроллер и запустите.
|
||||
|
||||
``` console
|
||||
$ # ПРИМЕЧАНИЕ: Я раскомментировал опцию `runner` в `.cargo/config`
|
||||
$ cargo run
|
||||
{{#include ../../../ci/expected/init.run}}```
|
122
ru/src/by-example/resources.md
Normal file
122
ru/src/by-example/resources.md
Normal file
|
@ -0,0 +1,122 @@
|
|||
## Ресурсы
|
||||
|
||||
Одно из ограничений атрибутов, предоставляемых библиотекой `cortex-m-rt` является
|
||||
то, что совместное использование данных (или периферии) между прерываниями,
|
||||
или прерыванием и функцией `init`, требуют `cortex_m::interrupt::Mutex`, который
|
||||
*всегда* требует отключения *всех* прерываний для доступа к данным. Отключение всех
|
||||
прерываний не всегда необходимо для безопасности памяти, но компилятор не имеет
|
||||
достаточно информации, чтобы оптимизировать доступ к разделяемым данным.
|
||||
|
||||
Атрибут `app` имеет полную картину приложения, поэтому может оптимизировать доступ к
|
||||
`static`-переменным. В RTFM мы обращаемся к `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 критической секции, предоставляемое фреймворком RTFM (см. [`Mutex`]),
|
||||
основано на динамических приоритетах вместо отключения прерываний. Из этого следует,
|
||||
что критические секции не будут допускать *запуск некоторых* обработчиков,
|
||||
включая все соперничающие за ресурс, но будут позволять запуск обработчиков с
|
||||
большим приоритетом не соперничащих за ресурс.
|
||||
|
||||
[`Mutex`]: ../../api/rtfm/trait.Mutex.html
|
||||
|
||||
В примере ниже у нас есть 3 обработчика прерываний с приоритетами от одного
|
||||
до трех. Два обработчика с низким приоритетом соперничают за ресурс `SHARED`.
|
||||
Обработчик с низшим приоритетом должен заблокировать ([`lock`]) ресурс
|
||||
`SHARED`, чтобы получить доступ к его данным, в то время как обработчик со
|
||||
средним приоритетом может напрямую получать доступ к его данным. Обработчик
|
||||
с наивысшим приоритетом может свободно вытеснять критическую секцию,
|
||||
созданную обработчиком с низшим приоритетом.
|
||||
|
||||
[`lock`]: ../../api/rtfm/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` используя обычное присвоение (например `FOO = 1`).
|
||||
|
||||
В примере ниже использованы поздние ресурсы, чтобы установить неблокированный,
|
||||
односторонний канал между обработчиком прерывания `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}}```
|
26
ru/src/by-example/singletons.md
Normal file
26
ru/src/by-example/singletons.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Одиночки
|
||||
|
||||
Атрибут `app` знает о библиотеке [`owned-singleton`] и её атрибуте [`Singleton`].
|
||||
Когда этот атрибут применяется к одному из ресурсов, рантайм производит для Вас
|
||||
`unsafe` инициализацию одиночки, проверяя, что только один экземпляр одиночки
|
||||
когда-либо создан.
|
||||
|
||||
[`owned-singleton`]: ../../api/owned_singleton/index.html
|
||||
[`Singleton`]: ../../api/owned_singleton_macros/attr.Singleton.html
|
||||
|
||||
Заметьте, что когда Вы используете атрибут `Singleton`, Вым нужно иметь
|
||||
`owned_singleton` в зависимостях.
|
||||
|
||||
Ниже, в примере, использован атрибут `Singleton` на куске памяти, а затем
|
||||
использован экземпляр одиночки как фиксированный по размеру пул памяти,
|
||||
используя одну из абстракций [`alloc-singleton`].
|
||||
|
||||
[`alloc-singleton`]: https://crates.io/crates/alloc-singleton
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/singleton.rs}}
|
||||
```
|
||||
|
||||
``` console
|
||||
$ cargo run --example singleton
|
||||
{{#include ../../../ci/expected/singleton.run}}```
|
63
ru/src/by-example/tasks.md
Normal file
63
ru/src/by-example/tasks.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
# Программные задачи
|
||||
|
||||
RTFM обрабатывает прерывания и исключения как *аппаратные* задачи. Аппаратные
|
||||
задачи могут вызываться устройством в ответ на события, такие как нажатие кнопки.
|
||||
RTFM также поддерживает *программные* задачи, порождаемые программой из любого
|
||||
контекста выполнения.
|
||||
|
||||
Программным задачам также можно назначать приоритет и диспетчеризовать из
|
||||
обработчиков прерываний. RTFM требует определения свободных прерываний в блоке
|
||||
`extern`, когда используются программные задачи; эти свободные прерывания будут использованы, чтобы диспетчеризовать программные задачи. Преимущество программных
|
||||
задач перед аппаратными в том, что на один обработчик прерывания можно назначить
|
||||
множество задач.
|
||||
|
||||
Программные задачи определяются заданием функциям атрибута `task`. Чтобы было
|
||||
возможно вызывать программные задачи, имя задачи нужно передать в аргументе
|
||||
`spawn` контекста атрибута (`init`, `idle`, `interrupt`, etc.).
|
||||
|
||||
В примере ниже продемонстрированы три программных задачи, запускаемые на 2-х
|
||||
разных приоритетах. Трем задачам назначены 2 обработчика прерываний.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/task.rs}}
|
||||
```
|
||||
|
||||
``` console
|
||||
$ cargo run --example task
|
||||
{{#include ../../../ci/expected/task.run}}```
|
||||
|
||||
## Передача сообщений
|
||||
|
||||
Другое преимущество программных задач - возможность передавать сообщения задачам
|
||||
во время их вызова. Тип полезной нагрузки сообщения должен быть определен в
|
||||
сигнатуре обработчика задачи.
|
||||
|
||||
Пример ниже демонстрирует три задачи, две из которых ожидают сообщения.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/message.rs}}
|
||||
```
|
||||
|
||||
``` console
|
||||
$ cargo run --example message
|
||||
{{#include ../../../ci/expected/message.run}}```
|
||||
|
||||
## Ёмкость
|
||||
|
||||
Диспетчеры задач *не* используют динамическое выделение памяти. Память
|
||||
необходимая для размещения сообщений, резервируется статически. Фреймворк
|
||||
зарезервирует достаточно памяти для каждого контекста, чтобы можно было вызвать
|
||||
каждую задачу как минимум единожды. Это разумно по умолчанию, но
|
||||
"внутреннюю" ёмкость каждой задачи можно контролировать используя аргумент
|
||||
`capacicy` атрибута `task`.
|
||||
|
||||
В примере ниже установлена ёмкость программной задачи `foo` на 4. Если ёмкость
|
||||
не определена, тогда второй вызов `spawn.foo` в `UART0` вызовет ошибку.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/capacity.rs}}
|
||||
```
|
||||
|
||||
``` console
|
||||
$ cargo run --example capacity
|
||||
{{#include ../../../ci/expected/capacity.run}}```
|
90
ru/src/by-example/timer-queue.md
Normal file
90
ru/src/by-example/timer-queue.md
Normal file
|
@ -0,0 +1,90 @@
|
|||
# Очередь таймера
|
||||
|
||||
Когда включена опция `timer-queue`, фреймворк RTFM включает
|
||||
*глобальную очередь таймера*, которую приложения могут использовать, чтобы
|
||||
*планировать* программные задачи на запуск через некоторое время в будущем.
|
||||
|
||||
Чтобы была возможность планировать программную задачу, имя задачи должно
|
||||
присутствовать в аргументе `schedule` контекста атрибута. Когда задача
|
||||
планируется, момент ([`Instant`]), в который задачу нужно запустить, нужно передать
|
||||
как первый аргумент вызова `schedule`.
|
||||
|
||||
[`Instant`]: ../../api/rtfm/struct.Instant.html
|
||||
|
||||
Рантайм RTFM включает монотонный, растущий только вверх, 32-битный таймер,
|
||||
значение которого можно запросить конструктором `Instant::now`. Время ([`Duration`])
|
||||
можно передать в `Instant::now()`, чтобы получить `Instant` в будущем. Монотонный
|
||||
таймер отключен пока запущен `init`, поэтому `Instant::now()` всегда возвращает
|
||||
значение `Instant(0 /* циклов тактовой частоты */)`; таймер включается сразу перед
|
||||
включением прерываний и запуском `idle`.
|
||||
|
||||
[`Duration`]: ../../api/rtfm/struct.Duration.html
|
||||
|
||||
В примере ниже две задачи планируются из `init`: `foo` и `bar`. `foo` -
|
||||
запланирована на запуск через 8 миллионов тактов в будущем. Кроме того, `bar`
|
||||
запланирован на запуск через 4 миллиона тактов в будущем. `bar` запустится раньше
|
||||
`foo`, т.к. он запланирован на запуск первым.
|
||||
|
||||
> **ВАЖНО**: Примеры, использующие API `schedule` или абстракцию `Instant`
|
||||
> **не** будут правильно работать на QEMU, потому что функциональность счетчика
|
||||
> тактов Cortex-M не реализована в `qemu-system-arm`.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/schedule.rs}}
|
||||
```
|
||||
|
||||
Запуск программы на реальном оборудовании производит следующий вывод в консоли:
|
||||
|
||||
``` text
|
||||
{{#include ../../../ci/expected/schedule.run}}
|
||||
```
|
||||
|
||||
## Периодические задачи
|
||||
|
||||
Программные задачи имеют доступ к `Instant` в момент, когда были запланированы
|
||||
на запуск через переменную `scheduled`. Эта информация и API `schedule` могут
|
||||
быть использованы для реализации периодических задач, как показано в примере ниже.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/periodic.rs}}
|
||||
```
|
||||
|
||||
Это вывод, произведенный примером. Заметьте, что есть смещение / колебание нуля
|
||||
даже если `schedule.foo` была вызвана в *конце* `foo`. Использование
|
||||
`Instant::now` вместо `scheduled` имело бы влияние на смещение / колебание.
|
||||
|
||||
``` text
|
||||
{{#include ../../../ci/expected/periodic.run}}
|
||||
```
|
||||
|
||||
## Базовое время
|
||||
|
||||
Для задач, планируемых из `init` мы имеем точную информацию о их планируемом
|
||||
(`scheduled`) времени. Для аппаратных задач нет `scheduled` времени, потому
|
||||
что эти задачи асинхронны по природе. Для аппаратных задач рантайм предоставляет
|
||||
время старта (`start`), которе отражает время, в которое обработчик прерывания
|
||||
был запущен.
|
||||
|
||||
Заметьте, что `start` **не** равен времени возникновения события, вызвавшего
|
||||
задачу. В зависимости от приоритета задачи и загрузки системы время
|
||||
`start` может быть сильно отдалено от времени возникновения события.
|
||||
|
||||
Какое по Вашему мнению будет значение `scheduled` для программных задач которые
|
||||
*вызываются*, вместо того чтобы планироваться? Ответ в том, что вызываемые
|
||||
задачи наследуют *базовое* время контекста, в котором вызваны. Бызовым для
|
||||
аппаратных задач является `start`, базовым для программных задач - `scheduled`
|
||||
и базовым для `init` - `start = Instant(0)`. `idle` на сомом деле не имеет
|
||||
базового времени но задачи, вызванные из него будут использовать `Instant::now()`
|
||||
как их базовое время.
|
||||
|
||||
Пример ниже демонстрирует разное значение *базового времени*.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/baseline.rs}}
|
||||
```
|
||||
|
||||
Запуск программы на реальном оборудовании произведет следующий вывод в консоли:
|
||||
|
||||
``` text
|
||||
{{#include ../../../ci/expected/baseline.run}}
|
||||
```
|
63
ru/src/by-example/tips.md
Normal file
63
ru/src/by-example/tips.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
# Советы и хитрости
|
||||
|
||||
## Generics
|
||||
|
||||
Ресурсы, совместно используемые двумя или более задачами реализуют трейт `Mutex`
|
||||
во *всех* контекстах, даже в тех, где для доступа к данным не требуются
|
||||
критические секции. Это позволяет легко писать обобщенный код оперирующий
|
||||
ресурсами, который можно вызывать из различных задач. Вот такой пример:
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/generics.rs}}
|
||||
```
|
||||
|
||||
``` console
|
||||
$ cargo run --example generics
|
||||
{{#include ../../../ci/expected/generics.run}}```
|
||||
|
||||
Это также позволяет Вам изменять статические приоритеты задач без
|
||||
переписывания кода. Если Вы единообразно используете `lock`-и для доступа
|
||||
к данным в разделяемых ресурсах, тогда Ваш код продолжит компилироваться,
|
||||
когда Вы измените приоритет задач.
|
||||
|
||||
## Запуск задач из RAM
|
||||
|
||||
Главной целью переноса описания программы на RTFM в атрибуты в
|
||||
RTFM v0.4.x была возможность взаимодействия с другими атрибутами.
|
||||
Напримерe, атрибут `link_section` можно применять к задачам, чтобы разместить
|
||||
из в RAM; это может улучшить производительность в некоторых случаях.
|
||||
|
||||
> **ВАЖНО**: Обычно атрибуты `link_section`, `export_name` и `no_mangle`
|
||||
> очень мощные, но их легко использовать неправильно. Неверное использование
|
||||
> любого из этих атрибутов может вызвать неопределенное поведение;
|
||||
> Вам следует всегда предпочитать использование безопасных, высокоуровневых
|
||||
> атрибутов вокруг них, таких как атрибуты `interrupt` и `exception`
|
||||
> из `cortex-m-rt`.
|
||||
>
|
||||
> В особых случаях функций RAM нет безопасной абстракции в `cortex-m-rt`
|
||||
> v0.6.5 но создано [RFC] для добавления атрибута `ramfunc` в будущем релизе.
|
||||
|
||||
[RFC]: https://github.com/rust-embedded/cortex-m-rt/pull/100
|
||||
|
||||
В примере ниже показано как разместить высокоприоритетную задачу `bar` в RAM.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/ramfunc.rs}}
|
||||
```
|
||||
|
||||
Запуск этой программы произведет ожидаемый вывод.
|
||||
|
||||
``` console
|
||||
$ cargo run --example ramfunc
|
||||
{{#include ../../../ci/expected/ramfunc.run}}```
|
||||
|
||||
Можно посмотреть на вывод `cargo-nm`, чтобы убедиться, что `bar` расположен в RAM
|
||||
(`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}}```
|
59
ru/src/by-example/types-send-sync.md
Normal file
59
ru/src/by-example/types-send-sync.md
Normal file
|
@ -0,0 +1,59 @@
|
|||
# Типы, Send и Sync
|
||||
|
||||
Атрибут `app` вводит контекст, коллекцию переменных в каждую из функций.
|
||||
Все эти переменные имеют предсказуемые, неанонимные типы, поэтому Вы можете
|
||||
писать простые функции, получающие их как аргументы.
|
||||
|
||||
Описание API определяет как эти типы эти типы генерируются из входных данных.
|
||||
Вы можете также сгенерировать документацию для Вашей бинарной библиотеки
|
||||
(`cargo doc --bin <name>`); в документации Вы найдете структуры `Context`
|
||||
(например `init::Context` и `idle::Context`), чьи поля представляют переменные
|
||||
включенные в каждую функцию.
|
||||
|
||||
В примере ниже сгенерированы разные типы с помощью атрибута `app`.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/types.rs}}
|
||||
```
|
||||
|
||||
## `Send`
|
||||
|
||||
[`Send`] - маркерный трейт для "типов, которые можно передавать через границы
|
||||
потоков", как это определено в `core`. В контексте RTFM трейт `Send` необходим
|
||||
только там, где возможна передача значения между задачами, запускаемыми на
|
||||
*разных* приоритетах. Это возникает в нескольких случаях: при передаче сообщений,
|
||||
в совместно используемых `static mut` ресурсах и инициализации поздних ресурсов.
|
||||
|
||||
[`Send`]: https://doc.rust-lang.org/core/marker/trait.Send.html
|
||||
|
||||
Атрибут `app` проверит, что `Send` реализован, где необходимо, поэтому Вам не
|
||||
стоит волноваться об этом. Более важно знать, где Вам *не* нужен трейт `Send`:
|
||||
в типах, передаваемых между задачами с *одинаковым* приоритетом. Это возникает
|
||||
в двух случаях: при передаче сообщений и в совместно используемых `static mut`
|
||||
ресурсах.
|
||||
|
||||
В примере ниже показано, где можно использовать типы, не реализующие `Send`.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/not-send.rs}}
|
||||
```
|
||||
|
||||
## `Sync`
|
||||
|
||||
Похожая ситуация, [`Sync`] - маркерный трейт для "типов, на которых можно
|
||||
ссылаться в разных потоках", как это определено в `core`. В контексте RTFM
|
||||
трейт `Sync` необходим только там, где возможны две или более задачи,
|
||||
запускаемые на разных приоритетах, чтобы захватить разделяемую ссылку на
|
||||
ресурс. Это возникает только совместно используемых `static`-ресурсах.
|
||||
|
||||
[`Sync`]: https://doc.rust-lang.org/core/marker/trait.Sync.html
|
||||
|
||||
Атрибут `app` проверит, что `Sync` реализован, где необходимо, но важно знать,
|
||||
где ограничение `Sync` не требуется: в `static`-ресурсах, разделяемых между
|
||||
задачами с *одинаковым* приоритетом.
|
||||
|
||||
В примере ниже показано, где можно использовать типы, не реализующие `Sync`.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../examples/not-sync.rs}}
|
||||
```
|
|
@ -1 +0,0 @@
|
|||
# Chapter 1
|
7
ru/src/internals.md
Normal file
7
ru/src/internals.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Под капотом
|
||||
|
||||
В этом разделе описывабтся внутренности фркймворка на *высоком уровне*.
|
||||
Низкоуровневые тонкости, такие как парсинг и кодогенерация производимые
|
||||
процедурным макросом (`#[app]`) здесь объясняться не будут. Мы сосредоточимся
|
||||
на анализе пользовательской спецификации и структурах данных, используемых
|
||||
рантаймом.
|
3
ru/src/internals/ceilings.md
Normal file
3
ru/src/internals/ceilings.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Ceiling analysis
|
||||
|
||||
**TODO**
|
3
ru/src/internals/tasks.md
Normal file
3
ru/src/internals/tasks.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Task dispatcher
|
||||
|
||||
**TODO**
|
3
ru/src/internals/timer-queue.md
Normal file
3
ru/src/internals/timer-queue.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Timer queue
|
||||
|
||||
**TODO**
|
12
ru/src/preface.md
Normal file
12
ru/src/preface.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
<h1 align="center">Real Time For the Masses</h1>
|
||||
|
||||
<p align="center">Конкурентный фреймворк для создания систем реального времени</p>
|
||||
|
||||
# Введение
|
||||
|
||||
Эта книга содержит документацию уровня пользователя фреймворком Real Time For the Masses
|
||||
(RTFM). Описание API можно найти [здесь](../api/rtfm/index.html).
|
||||
|
||||
{{#include README_RU.md:5:54}}
|
||||
|
||||
{{#include README_RU.md:60:}}
|
Loading…
Reference in a new issue