Перейти к содержанию

Группа событий (event group)

Задача управления CAN должна проснуться, если пришло сообщение, если есть что отправить или если пора слать SYNC — три разных события, один ожидающий. Семафор хранит одно состояние, очередь — лишняя. Для набора независимых флагов во FreeRTOS есть группа событий.

Обновлено Редакция GAW

Группа событий (event group) — объект FreeRTOS, который хранит набор битов-флагов. Каждый бит означает, произошло ли событие: например, бит 0 — «принято сообщение CAN», бит 1 — «есть сообщение для отправки», бит 2 — «пора отправить SYNC». Задача может установить или сбросить биты, а главное — заблокироваться в ожидании одного, любого или всех битов из набора, не тратя процессорное время. Группа адресуется описателем EventGroupHandle_t, биты лежат в одной переменной типа EventBits_t: бит 0 в позиции 0, бит 1 в позиции 1 и так далее.

Сколько битов доступно

EventBits_t — это тот же тип, что и TickType_t, а старший байт переменной занят служебными битами ядра (маска eventEVENT_BITS_CONTROL_BYTES).

Ширина тикаКак задаётсяДоступно битов
16 битconfigUSE_16_BIT_TICKS = 1 или configTICK_TYPE_WIDTH_IN_BITS = TICK_TYPE_WIDTH_16_BITS8
32 битаconfigUSE_16_BIT_TICKS = 0 или TICK_TYPE_WIDTH_32_BITS24
64 битаTICK_TYPE_WIDTH_64_BITS56

Значения 8 и 24 названы на странице документации; все три, включая 56 для 64-битного тика, — в комментарии к xEventGroupCreate() в event_groups.h, где маска 0xff00000000000000 оставляет младшие 56 битов.

API и рандеву

Группу создают xEventGroupCreate() или xEventGroupCreateStatic(). xEventGroupSetBits() и xEventGroupClearBits() меняют биты, xEventGroupWaitBits() ждёт их: параметрами задаются маска, нужно ли ждать все биты или любой, и сбрасывать ли их на выходе. Функция xEventGroupSync() синхронизирует несколько задач в точке «рандеву»: каждая задача ждёт, пока все остальные участники дойдут до своей точки. Так удобно запускать конечный автомат только после того, как инициализацию закончили все подсистемы.

Гонки и детерминизм

Наивная реализация флагов в обычной переменной порождает гонки: непонятно, кто и когда сбрасывает бит и был ли он установлен в момент выхода из функции проверки. В FreeRTOS установка, проверка и сброс битов выглядят для приложения атомарными — за счёт локального хранилища задачи и возвращаемых значений функций.

Вторая проблема — недетерминизм: при установке бита заранее неизвестно, сколько задач придётся разблокировать. Поэтому из задачи биты ставятся под блокировкой планировщика с разрешёнными прерываниями, а xEventGroupSetBitsFromISR() не делает работу в обработчике, а отправляет команду задаче программных таймеров — это тот же механизм отложенной обработки прерываний. Функция доступна только при INCLUDE_xTimerPendFunctionCall = 1 и configUSE_TIMERS = 1. Сама поддержка групп включена по умолчанию (configUSE_EVENT_GROUPS = 1).

С чем не путать

  • Семафор хранит одно состояние или счётчик, а не набор независимых флагов.
  • Очередь передаёт данные, а не факт события; для «пришло — не пришло» она избыточна.
  • Уведомление задачи тоже умеет устанавливать биты, но только у одной задачи-получателя; документация FreeRTOS называет его лёгкой альтернативой группе событий, когда ожидающий один.

Частые вопросы

Сколько битов в группе событий FreeRTOS?

Тип EventBits_t совпадает с TickType_t, а старший байт занят управляющими битами ядра. Поэтому при 16-битном тике (configUSE_16_BIT_TICKS = 1 или configTICK_TYPE_WIDTH_IN_BITS = TICK_TYPE_WIDTH_16_BITS) доступно 8 битов, при 32-битном — 24. Для 64-битного тика маска управляющих битов тоже занимает старший байт, и остаётся 56 битов — это число названо в комментарии к xEventGroupCreate() в event_groups.h.

Почему xEventGroupSetBitsFromISR() требует включённых программных таймеров?

Установка бита может разблокировать неизвестное заранее число задач, а FreeRTOS не выполняет недетерминированных действий в прерывании. Поэтому xEventGroupSetBitsFromISR() не ставит бит сама, а отправляет команду задаче таймеров (демону), и биты устанавливаются уже в её контексте под блокировкой планировщика. Функция доступна только при INCLUDE_xTimerPendFunctionCall = 1 и configUSE_TIMERS = 1.

Когда вместо группы событий лучше уведомление задачи?

Когда событий ждёт ровно одна задача. Уведомление задачи умеет устанавливать биты в 32-битном значении получателя и работает без отдельного объекта ядра, поэтому документация FreeRTOS называет его лёгкой альтернативой группе событий. Группа нужна, если на одни и те же флаги ждут несколько задач или требуется рандеву.

Источники

  1. FreeRTOS. FreeRTOS Kernel documentation: Event groups (Kernel features), 2026 — разд. Event Bits: бит события показывает, произошло ли событие, иначе называется флагом; разд. Event Groups: группа событий — набор битов, к каждому обращаются по номеру; разд. Data Types: тип EventGroupHandle_t; число битов 8 при configUSE_16_BIT_TICKS = 1 и 24 при 0 — из-за типа, используемого для локального хранилища задачи; биты хранятся в одной переменной EventBits_t, бит 0 в позиции 0; разд. API: установка, сброс, ожидание в состоянии Blocked без расхода процессорного времени; синхронизация задач — «рандеву», задача ждёт, пока все участники дойдут до точки; разд. Challenges: реализация должна исключить гонки — неясно, кто и когда сбрасывает бит и был ли он установлен на выходе из функции; FreeRTOS делает установку, проверку и сброс атомарными за счёт локального хранилища задачи и возвращаемых значений; недетерминизм — неизвестно, сколько задач заблокировано на группе; установка бита из задачи — под блокировкой планировщика при разрешённых прерываниях, из прерывания — через механизм отложенной обработки в задаче; совет: уведомления задач — лёгкая альтернатива группам событий
  2. FreeRTOS. FreeRTOS-Kernel V11.3.3: include/event_groups.h и include/FreeRTOS.h (GitHub, MIT) — пример в заголовке: бит 0 — принято сообщение CAN, бит 1 — есть сообщение для отправки, бит 2 — пора слать SYNC; typedef TickType_t EventBits_t — число битов задаёт configTICK_TYPE_WIDTH_IN_BITS (16, 32 или 64); маска управляющих битов eventEVENT_BITS_CONTROL_BYTES — старший байт: 0xff00, 0xff000000 или 0xff00000000000000; комментарий к xEventGroupCreate(): 8 полезных битов при 16-битном тике, 24 при 32-битном, 56 при 64-битном; функции xEventGroupCreate(), xEventGroupCreateStatic(), xEventGroupWaitBits(), xEventGroupSetBits(), xEventGroupClearBits(), xEventGroupClearBitsFromISR(); xEventGroupSetBitsFromISR() отправляет команду задаче таймеров, чтобы установить биты в её контексте, и доступна только при INCLUDE_xTimerPendFunctionCall = 1 и configUSE_TIMERS = 1; FreeRTOS.h: configUSE_EVENT_GROUPS равно 1, если не определено; при configUSE_16_BIT_TICKS = 1 ширина тика 16 бит, иначе 32
Страница помогла?

Нашли ошибку? ·