rtic/book/ru/src/by-example/timer-queue.md
2019-02-11 21:40:53 +01:00

5.8 KiB
Raw Permalink Blame History

Очередь таймера

Когда включена опция timer-queue, фреймворк RTFM включает глобальную очередь таймера, которую приложения могут использовать, чтобы планировать программные задачи на запуск через некоторое время в будущем.

Чтобы была возможность планировать программную задачу, имя задачи должно присутствовать в аргументе schedule контекста атрибута. Когда задача планируется, момент (Instant), в который задачу нужно запустить, нужно передать как первый аргумент вызова schedule.

Рантайм RTFM включает монотонный, растущий только вверх, 32-битный таймер, значение которого можно запросить конструктором Instant::now. Время (Duration) можно передать в Instant::now(), чтобы получить Instant в будущем. Монотонный таймер отключен пока запущен init, поэтому Instant::now() всегда возвращает значение Instant(0 /* циклов тактовой частоты */); таймер включается сразу перед включением прерываний и запуском idle.

В примере ниже две задачи планируются из init: foo и bar. foo - запланирована на запуск через 8 миллионов тактов в будущем. Кроме того, bar запланирован на запуск через 4 миллиона тактов в будущем. bar запустится раньше foo, т.к. он запланирован на запуск первым.

ВАЖНО: Примеры, использующие API schedule или абстракцию Instant не будут правильно работать на QEMU, потому что функциональность счетчика тактов Cortex-M не реализована в qemu-system-arm.

{{#include ../../../../examples/schedule.rs}}

Запуск программы на реальном оборудовании производит следующий вывод в консоли:

{{#include ../../../../ci/expected/schedule.run}}

Периодические задачи

Программные задачи имеют доступ к Instant в момент, когда были запланированы на запуск через переменную scheduled. Эта информация и API schedule могут быть использованы для реализации периодических задач, как показано в примере ниже.

{{#include ../../../../examples/periodic.rs}}

Это вывод, произведенный примером. Заметьте, что есть смещение / колебание нуля даже если schedule.foo была вызвана в конце foo. Использование Instant::now вместо scheduled имело бы влияние на смещение / колебание.

{{#include ../../../../ci/expected/periodic.run}}

Базовое время

Для задач, планируемых из init мы имеем точную информацию о их планируемом (scheduled) времени. Для аппаратных задач нет scheduled времени, потому что эти задачи асинхронны по природе. Для аппаратных задач рантайм предоставляет время старта (start), которе отражает время, в которое обработчик прерывания был запущен.

Заметьте, что start не равен времени возникновения события, вызвавшего задачу. В зависимости от приоритета задачи и загрузки системы время start может быть сильно отдалено от времени возникновения события.

Какое по Вашему мнению будет значение scheduled для программных задач которые вызываются, вместо того чтобы планироваться? Ответ в том, что вызываемые задачи наследуют базовое время контекста, в котором вызваны. Бызовым для аппаратных задач является start, базовым для программных задач - scheduled и базовым для init - start = Instant(0). idle на сомом деле не имеет базового времени но задачи, вызванные из него будут использовать Instant::now() как их базовое время.

Пример ниже демонстрирует разное значение базового времени.

{{#include ../../../../examples/baseline.rs}}

Запуск программы на реальном оборудовании произведет следующий вывод в консоли:

{{#include ../../../../ci/expected/baseline.run}}