34. Макросы и функции FreeRTOS: справочник
Всё, что встретилось в разделах 23–33, — в одном месте, по объектам. Каждое имя из таблиц этого раздела вызвано в проверочном файле и собрано с ядром 10.5.1: опечатка здесь была бы ошибкой компиляции. Для каждой функции указано, откуда её можно вызывать: З — из задачи, П — из прерывания, Н — до запуска планировщика.
Обозначения
З из задачи; может ждать, если задано время П из обработчика прерывания; двойник с FromISR, ждать не умеетН до vTaskStartScheduler— при инициализацииticksвремя ожидания в тиках: 0,pdMS_TO_TICKS(n)илиportMAX_DELAY*wokenвыходной признак для portYIELD_FROM_ISRКак это называется в документации
Оригинал Перевод task handle описатель задачи queue очередь binary / counting semaphore двоичный / считающий семафор mutual exclusion / mutex взаимное исключение / мьютекс recursive mutex рекурсивный мьютекс software timer программный таймер timer daemon / service task задача-демон, обслуживающая таймеры event group группа событий stream buffer потоковый буфер message buffer буфер сообщений task notification уведомление задачи block time / ticks to wait время ожидания interrupt safe API функции, допустимые в обработчике yield from ISR переключиться на выходе из обработчика
34.1 Задачи
Создание и удаление
| Имя | Что делает | Откуда | Раздел |
|---|---|---|---|
xTaskCreate(fn, name, depth, arg, prio, *h) |
создать из кучи; pdPASS или отказ |
З Н | 24, 26 |
xTaskCreateStatic(fn, name, depth, arg, prio, stack, *tcb) |
создать из своей памяти; описатель | З Н | 24, 26 |
vTaskDelete(h) |
удалить; NULL — себя |
З | 26 |
vTaskStartScheduler() |
запустить; не возвращается | Н | 24 |
depth — в словах, не в байтах. Приоритет не меньше configMAX_PRIORITIES:
с configASSERT — остановка при создании, без него — молча урезается
до configMAX_PRIORITIES − 1.
Ожидание и время
| Имя | Что делает | Откуда | Раздел |
|---|---|---|---|
vTaskDelay(ticks) |
заснуть на ticks от момента вызова |
З | 26 |
xTaskDelayUntil(*last, period) |
заснуть до last + period; период точный |
З | 26 |
xTaskGetTickCount() |
счётчик тиков | З | 26 |
xTaskGetTickCountFromISR() |
то же | П | 28 |
taskYIELD() |
уступить равным по приоритету | З | 26 |
Состояние и приоритет
| Имя | Что делает | Откуда | Раздел |
|---|---|---|---|
vTaskSuspend(h) / vTaskResume(h) |
приостановить / вернуть | З | 26 |
xTaskResumeFromISR(h) |
вернуть из прерывания | П | 28 |
vTaskPrioritySet(h, prio) / uxTaskPriorityGet(h) |
сменить / узнать приоритет | З | 26 |
eTaskGetState(h) |
eRunning…eDeleted; вечное ожидание — eBlocked, eSuspended — только после vTaskSuspend |
З | 26 |
pcTaskGetName(h) |
имя | З | — |
uxTaskGetStackHighWaterMark(h) |
наименьший остаток стека, в словах | З | 26 |
xTaskGetCurrentTaskHandle() |
описатель текущей; нужен INCLUDE_xTaskGetCurrentTaskHandle |
З | — |
xTaskGetSchedulerState() |
не запущен / идёт / приостановлен | З | — |
uxTaskGetNumberOfTasks() |
сколько задач | З | — |
vTaskGetInfo(h, *status, stack?, state) |
всё о задаче разом | З | 35 |
Планировщик и критические секции
| Имя | Что делает | Откуда | Раздел |
|---|---|---|---|
vTaskSuspendAll() / xTaskResumeAll() |
запретить / разрешить переключение; прерывания идут | З | 30 |
taskENTER_CRITICAL() / taskEXIT_CRITICAL() |
BASEPRI до порога; вкладываются |
З | 30 |
taskENTER_CRITICAL_FROM_ISR() / taskEXIT_CRITICAL_FROM_ISR(saved) |
то же с сохранением маски | П | 28, 30 |
taskDISABLE_INTERRUPTS() / taskENABLE_INTERRUPTS() |
маска без счётчика | З | — |
portYIELD_FROM_ISR(woken) |
переключиться на выходе из обработчика | П | 28 |
portEND_SWITCHING_ISR(woken) |
то же под другим именем | П | 28 |
Уведомления задачи
| Имя | Что делает | Откуда | Раздел |
|---|---|---|---|
xTaskNotifyGive(h) |
+1, как семафор | З | 31 |
vTaskNotifyGiveFromISR(h, *woken) |
то же | П | 28, 31 |
ulTaskNotifyTake(clear, ticks) |
ждать; pdTRUE — обнулить, pdFALSE — −1 |
З | 31 |
xTaskNotify(h, value, action) |
послать значение; действие из пяти | З | 31 |
xTaskNotifyFromISR(h, value, action, *woken) |
то же | П | 31 |
xTaskNotifyWait(clearIn, clearOut, *value, ticks) |
ждать значение | З | 31 |
xTaskNotifyStateClear(h) |
сбросить ожидание | З | — |
ulTaskNotifyValueClear(h, mask) |
сбросить биты значения | З | — |
Действия: eNoAction, eSetBits, eIncrement, eSetValueWithOverwrite,
eSetValueWithoutOverwrite.
34.2 Очереди
| Имя | Что делает | Откуда | Раздел |
|---|---|---|---|
xQueueCreate(len, itemSize) |
из кучи; NULL при отказе |
З Н | 27 |
xQueueCreateStatic(len, itemSize, storage, *buf) |
из своей памяти | З Н | 27 |
xQueueSend(q, *item, ticks) |
в конец; то же, что SendToBack |
З | 27 |
xQueueSendToBack(q, *item, ticks) |
в конец | З | 27 |
xQueueSendToFront(q, *item, ticks) |
в начало — вне очереди | З | 27 |
xQueueOverwrite(q, *item) |
перезаписать; только для очереди длиной 1 | З | 27 |
xQueueReceive(q, *item, ticks) |
забрать | З | 27 |
xQueuePeek(q, *item, ticks) |
посмотреть, не забирая | З | 27 |
…FromISR(q, *item, *woken) |
двойники шести выше, без ticks; у xQueuePeekFromISR(q, *item) признака нет |
П | 27, 28 |
uxQueueMessagesWaiting(q) |
сколько лежит | З | 27 |
uxQueueMessagesWaitingFromISR(q) |
то же | П | — |
uxQueueSpacesAvailable(q) |
сколько влезет | З | — |
xQueueIsQueueEmptyFromISR(q) / xQueueIsQueueFullFromISR(q) |
пуста / полна | П | — |
xQueueReset(q) |
очистить | З | — |
vQueueDelete(q) |
удалить | З | — |
Очередь копирует элемент. errQUEUE_EMPTY, errQUEUE_FULL и pdFAIL —
один и тот же ноль.
34.3 Семафоры и мьютексы
| Имя | Что делает | Откуда | Раздел |
|---|---|---|---|
xSemaphoreCreateBinary() / …Static(*buf) |
двоичный; создаётся пустым | З Н | 28 |
xSemaphoreCreateCounting(max, init) / …Static(max, init, *buf) |
считающий | З Н | 28 |
xSemaphoreCreateMutex() / …Static(*buf) |
мьютекс; создаётся свободным, в отличие от двоичного семафора | З Н | 30 |
xSemaphoreCreateRecursiveMutex() / …Static(*buf) |
рекурсивный | З Н | 30 |
xSemaphoreTake(s, ticks) |
взять | З | 28, 30 |
xSemaphoreTakeFromISR(s, *woken) |
взять без ожидания; не для мьютекса | П | 28 |
xSemaphoreGive(s) |
отдать; мьютекс — только владелец | З | 28, 30 |
xSemaphoreGiveFromISR(s, *woken) |
отдать; не для мьютекса | П | 28 |
xSemaphoreTakeRecursive(m, ticks) / xSemaphoreGiveRecursive(m) |
для рекурсивного; обычные не работают | З | 30 |
uxSemaphoreGetCount(s) |
текущее значение | З | — |
xSemaphoreGetMutexHolder(m) |
кто держит; нужен INCLUDE_xSemaphoreGetMutexHolder |
З | — |
vSemaphoreDelete(s) |
удалить | З | — |
Мьютекс — единственный, кто наследует приоритет. Из прерывания он недоступен ни в каком виде.
34.4 Программные таймеры
| Имя | Что делает | Откуда | Раздел |
|---|---|---|---|
xTimerCreate(name, period, reload, id, cb) |
создать; не запущен | З Н | 29 |
xTimerCreateStatic(…, *buf) |
из своей памяти | З Н | 29 |
xTimerStart(t, ticks) |
запустить; идущий — перезапустить | З Н | 29 |
xTimerStop(t, ticks) |
остановить | З | 29 |
xTimerReset(t, ticks) |
перезапустить отсчёт | З | 29 |
xTimerChangePeriod(t, period, ticks) |
сменить период; запускает стоящий | З | 29 |
xTimerDelete(t, ticks) |
удалить | З | — |
…FromISR(t, *woken) |
двойники Start, Stop, Reset, ChangePeriod; у xTimerChangePeriodFromISR ещё и период |
П | 29 |
xTimerIsTimerActive(t) |
идёт ли | З | — |
xTimerGetPeriod(t) / xTimerGetExpiryTime(t) |
период / срок | З | — |
pvTimerGetTimerID(t) / vTimerSetTimerID(t, id) |
идентификатор | З | 29 |
xTimerGetReloadMode(t) / vTimerSetReloadMode(t, mode) |
вид | З | — |
xTimerGetTimerDaemonTaskHandle() |
описатель демона | З | — |
xTimerPendFunctionCall(fn, arg1, arg2, ticks) |
выполнить функцию в демоне | З | 29 |
xTimerPendFunctionCallFromISR(fn, arg1, arg2, *woken) |
то же | П | 29 |
ticks у команд — ожидание места в очереди демона, не задержка запуска.
Обратный вызов выполняется в демоне и не имеет права блокироваться.
34.5 Группы событий
| Имя | Что делает | Откуда | Раздел |
|---|---|---|---|
xEventGroupCreate() / …Static(*buf) |
создать; 24 флага | З Н | 31 |
xEventGroupSetBits(eg, bits) |
поставить | З | 31 |
xEventGroupSetBitsFromISR(eg, bits, *woken) |
поставить через демона таймеров | П | 31 |
xEventGroupClearBits(eg, bits) / …FromISR(eg, bits) |
снять | З / П | 31 |
xEventGroupGetBits(eg) / …FromISR(eg) |
прочитать без ожидания | З / П | 31 |
xEventGroupWaitBits(eg, bits, clearOnExit, waitAll, ticks) |
ждать любого / всех | З | 31 |
xEventGroupSync(eg, setBits, waitBits, ticks) |
поставить и ждать всех неразрывно | З | 31 |
vEventGroupDelete(eg) |
удалить | З | — |
Возвращаемое значение — группа в момент пробуждения; разбирать его.
34.6 Буферы потоков и сообщений
| Имя | Что делает | Откуда | Раздел |
|---|---|---|---|
xStreamBufferCreate(size, trigger) / …Static(size, trigger, storage, *buf) |
поток; Create сам берёт size + 1, у Static массив ровно size и влезает size − 1 |
З Н | 32 |
xStreamBufferSend(sb, *data, len, ticks) |
записать; возвращает байты | З | 32 |
xStreamBufferSendFromISR(sb, *data, len, *woken) |
то же; ноль — потеряно | П | 32 |
xStreamBufferReceive(sb, *data, max, ticks) |
прочитать до max |
З | 32 |
xStreamBufferReceiveFromISR(sb, *data, max, *woken) |
то же | П | — |
xStreamBufferBytesAvailable(sb) / xStreamBufferSpacesAvailable(sb) |
лежит / влезет | З | 32 |
xStreamBufferIsEmpty(sb) / xStreamBufferIsFull(sb) |
пуст / полон | З | — |
xStreamBufferSetTriggerLevel(sb, n) |
сменить триггер | З | — |
xStreamBufferReset(sb) |
очистить; отказ, если кто-то ждёт | З | 32 |
vStreamBufferDelete(sb) |
удалить | З | — |
xMessageBufferCreate(size) / …Static(size, storage, *buf) |
с границами; +4 байта на сообщение | З Н | 32 |
xMessageBufferSend(mb, *data, len, ticks) |
целиком или никак | З | 32 |
xMessageBufferSendFromISR(mb, *data, len, *woken) |
то же | П | — |
xMessageBufferReceive(mb, *data, max, ticks) |
одно сообщение; max ≥ самого длинного |
З | 32 |
xMessageBufferReceiveFromISR(mb, *data, max, *woken) |
то же | П | — |
xMessageBufferSpaceAvailable(mb) |
влезет | З | — |
xMessageBufferIsEmpty(mb) / xMessageBufferIsFull(mb) / xMessageBufferReset(mb) |
состояние / очистить | З | — |
vMessageBufferDelete(mb) |
удалить | З | — |
Один писатель, один читатель.
34.7 Куча
| Имя | Что делает | Откуда | Раздел |
|---|---|---|---|
pvPortMalloc(bytes) |
выделить; NULL при отказе |
З Н | 25 |
vPortFree(p) |
вернуть; в heap_1 — останов |
З | 25 |
xPortGetFreeHeapSize() |
свободно сейчас | З | 25 |
xPortGetMinimumEverFreeHeapSize() |
худшее за всё время; heap_4, heap_5 |
З | 25 |
vPortGetHeapStats(*stats) |
подробный отчёт; heap_4, heap_5 |
З | 25 |
vPortDefineHeapRegions(regions) |
области для heap_5; по возрастанию адресов |
Н | 25 |
vApplicationMallocFailedHook() |
ловушка исчерпания — пишете вы | — | 25 |
34.8 Константы и макросы времени
| Имя | Значение | Смысл |
|---|---|---|
pdMS_TO_TICKS(ms) |
ms × tickRate / 1000 |
миллисекунды в тики; округляет вниз |
portTICK_PERIOD_MS |
1 при 1 кГц | миллисекунд в тике |
portMAX_DELAY |
0xFFFFFFFF |
ждать без ограничения при INCLUDE_vTaskSuspend 1, иначе 49,7 суток при 1 кГц (раздел 27.2) |
pdTRUE / pdFALSE |
1 / 0 | логические |
pdPASS / pdFAIL |
1 / 0 | успех / отказ |
errQUEUE_EMPTY / errQUEUE_FULL |
0 / 0 | неразличимы между собой и с pdFAIL |
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY |
−1 | нет памяти |
tskIDLE_PRIORITY |
0 | приоритет задачи простоя |
configMAX_PRIORITIES |
из конфигурации | старший доступный — на единицу меньше |
Ловушки, которые пишете вы
| Имя | Когда вызывается | Включается |
|---|---|---|
vApplicationStackOverflowHook(h, name) |
переполнение стека, при переключении | configCHECK_FOR_STACK_OVERFLOW |
vApplicationMallocFailedHook() |
отказ кучи | configUSE_MALLOC_FAILED_HOOK |
vApplicationIdleHook() |
каждый проход простоя; не блокировать | configUSE_IDLE_HOOK |
vApplicationTickHook() |
каждый тик, из прерывания; только FromISR |
configUSE_TICK_HOOK |
vApplicationGetIdleTaskMemory(…) |
память под задачу простоя | configSUPPORT_STATIC_ALLOCATION |
vApplicationGetTimerTaskMemory(…) |
память под демона таймеров | то же + configUSE_TIMERS |
34.9 Цена объектов
Всё измерено сборкой под Cortex‑M3 в конфигурации справочника.
| Объект | Байт | Плюс |
|---|---|---|
| блок управления задачей | 92 | стек, минимум 512 |
| очередь | 80 | len × itemSize |
| семафор, мьютекс | 80 | — |
| программный таймер | 44 | — |
| группа событий | 32 | — |
| потоковый буфер, буфер сообщений | 36 | size + 1 |
| уведомление задачи | 0 | уже в блоке управления |
| ядро в прошивке | ≈ 6,4 КБ | + куча |
Прежде чем считать байты, выбирают сам объект. Таблицы выбора из 30.9, 31.4 и 32.7 и очередь на несколько писателей из 27.4 собраны на одной схеме, с ценой из таблицы выше:
34.10 Вопросы для самопроверки
Ответы — в разделах, указанных в скобках. Если ответ не вспоминается сразу, раздел стоит перечитать.
Задачи
- Задача с приоритетом 3 крутит пустой цикл без ожиданий. Что видят задачи с приоритетами 1 и 2? (26)
vTaskDelay(10)в задаче, работающей 3 мс. Каков период? Сколько срабатываний потеряется за минуту? (26)- Зачем два указателя стека —
MSPиPSP? (23) uxTaskGetStackHighWaterMarkвернула 30. Сколько это байт? (26)- Задача ждёт с
portMAX_DELAY— в одном случае очередь, в другом уведомление. Что покажутeTaskGetStateиvTaskList? (26) - Почему из функции задачи нельзя выйти оператором
return? (26)
Память
- Запрос
pvPortMalloc(512)— сколько байт уйдёт из кучиheap_4? (25) - Чем
heap_1лучшеheap_4, если он не умеет освобождать? (25) - Куча 10 КБ на F103C8: сколько это от всей памяти и с какого момента она занята? (25)
Прерывания
- Прерывание с приоритетом 3 при пороге 5 вызвало
xQueueSendFromISR. Что произойдёт при включённомconfigASSERT? Без него? (28) - Что стоит забытый
portYIELD_FROM_ISR— в микросекундах? (28) - Почему мьютекс нельзя отдать из прерывания? (30)
- Значение
0x50вBASEPRI— откуда оно? (23, 28)
Синхронизация
counter++— сколько инструкций и что между ними может случиться? (30)- Три задачи L, M, H; L держит мьютекс, H его ждёт. Что делает M и что с этим делает мьютекс? (30)
- Две задачи берут два мьютекса в разном порядке. Что будет и как лечится? (30)
- Когда одна переменная не требует защиты вовсе? (30)
Объекты
- Очередь на 16 сообщений по 4 байта — сколько байт всего и какая часть служебная? (27)
xTimerStart(t, 100)— что означает второй аргумент? (29)- Обратный вызов таймера вызвал
vTaskDelay. Что случится с другими таймерами? (29) - Почему в группе событий 24 флага, а не 32? (31)
- Чем
xEventGroupSyncотличается отSetBitsплюсWaitBits? (31) - Потоковый буфер с триггером 16 при 115 200 бод: сколько пробуждений в секунду вместо скольких? (32)
xMessageBufferReceiveвечно возвращает ноль. Почему? (32)
Конфигурация
configCPU_CLOCK_HZ= 36 МГц при реальных 72. Что с задержками? (33)- Предел одного сна в режиме без тика на
SysTickпри 72 МГц? Почему? (33) SVC_Handlerопределён дважды — откуда обе копии? (24)
34.11 Грабли
Не понять, пуста очередь или полна. errQUEUE_EMPTY, errQUEUE_FULL и pdFAIL — один и тот же
ноль; смысл задаёт вызванная функция (34.8).
Задержка короче заказанной. pdMS_TO_TICKS округляет вниз (34.8).
Приоритет configMAX_PRIORITIES не работает. Старший доступный — на единицу меньше (34.8).
Зависание в vApplicationIdleHook или сбой в vApplicationTickHook. Первую нельзя блокировать, вторая
вызывается из прерывания — только функции FromISR (34.8).
34.12 Итоги
- Таблицы 34.1–34.8 — справка по именам API ядра: откуда вызывать, что возвращает, где разобрано.
- Нули
errQUEUE_EMPTY,errQUEUE_FULLиpdFAILнеразличимы — смысл задаёт вызванная функция. - Цена объектов (34.9): задача — 92 байта плюс стек, очередь — 80 плюс данные, уведомление — 0.
- Вопросы 34.10 — по одному на каждую тему части IV со ссылкой на раздел с ответом.
Дальше: раздел 34а «Zephyr: другая операционная система — обзор для того, кто знает FreeRTOS».