mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-25 03:19:34 +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
|
# 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