34. FreeRTOS macros and functions: reference
Everything met in sections 23–33, in one place, grouped by object. Every name in the tables of this section is called in a check file and built with kernel 10.5.1: a typo here would be a compile error. For each function the table says where it may be called from: T — from a task, I — from an interrupt, B — before the scheduler starts.
Notation
T from a task; can wait if a time is given I from an interrupt handler; the FromISRtwin, cannot waitB before vTaskStartScheduler— during initializationtickswait time in ticks: 0,pdMS_TO_TICKS(n)orportMAX_DELAY*wokenoutput flag for portYIELD_FROM_ISRTerms used in the documentation
Term Meaning task handle a reference to a task queue a FIFO of copied items binary / counting semaphore a semaphore that is either empty or full / one that keeps a count mutual exclusion / mutex a lock with an owner and priority inheritance recursive mutex a mutex the owner can take several times software timer a timer run by the kernel, not by hardware timer daemon / service task the kernel task that runs the timers event group a set of flags tasks can wait on stream buffer a byte stream between one writer and one reader message buffer a stream buffer that keeps message boundaries task notification a value built into each task block time / ticks to wait how long a call may wait interrupt safe API functions allowed in a handler yield from ISR switch tasks on exit from a handler
34.1 Tasks
Creation and deletion
| Name | What it does | From | Section |
|---|---|---|---|
xTaskCreate(fn, name, depth, arg, prio, *h) |
create from the heap; pdPASS or failure |
T B | 24, 26 |
xTaskCreateStatic(fn, name, depth, arg, prio, stack, *tcb) |
create from your own memory; returns the handle | T B | 24, 26 |
vTaskDelete(h) |
delete; NULL — itself |
T | 26 |
vTaskStartScheduler() |
start; does not return | B | 24 |
depth is in words, not in bytes. A priority of configMAX_PRIORITIES or more:
with configASSERT it halts at creation, without it the priority is silently clipped
to configMAX_PRIORITIES − 1.
Waiting and time
| Name | What it does | From | Section |
|---|---|---|---|
vTaskDelay(ticks) |
sleep for ticks from the moment of the call |
T | 26 |
xTaskDelayUntil(*last, period) |
sleep until last + period; the period is exact |
T | 26 |
xTaskGetTickCount() |
tick counter | T | 26 |
xTaskGetTickCountFromISR() |
the same | I | 28 |
taskYIELD() |
yield to tasks of equal priority | T | 26 |
State and priority
| Name | What it does | From | Section |
|---|---|---|---|
vTaskSuspend(h) / vTaskResume(h) |
suspend / resume | T | 26 |
xTaskResumeFromISR(h) |
resume from an interrupt | I | 28 |
vTaskPrioritySet(h, prio) / uxTaskPriorityGet(h) |
change / read the priority | T | 26 |
eTaskGetState(h) |
eRunning…eDeleted; an endless wait is eBlocked, eSuspended only after vTaskSuspend |
T | 26 |
pcTaskGetName(h) |
name | T | — |
uxTaskGetStackHighWaterMark(h) |
the smallest stack headroom seen, in words | T | 26 |
xTaskGetCurrentTaskHandle() |
handle of the current task; needs INCLUDE_xTaskGetCurrentTaskHandle |
T | — |
xTaskGetSchedulerState() |
not started / running / suspended | T | — |
uxTaskGetNumberOfTasks() |
number of tasks | T | — |
vTaskGetInfo(h, *status, stack?, state) |
everything about a task at once | T | 35 |
Scheduler and critical sections
| Name | What it does | From | Section |
|---|---|---|---|
vTaskSuspendAll() / xTaskResumeAll() |
disable / enable task switching; interrupts still run | T | 30 |
taskENTER_CRITICAL() / taskEXIT_CRITICAL() |
BASEPRI up to the threshold; can be nested |
T | 30 |
taskENTER_CRITICAL_FROM_ISR() / taskEXIT_CRITICAL_FROM_ISR(saved) |
the same, saving the mask | I | 28, 30 |
taskDISABLE_INTERRUPTS() / taskENABLE_INTERRUPTS() |
mask without a nesting counter | T | — |
portYIELD_FROM_ISR(woken) |
switch tasks on exit from the handler | I | 28 |
portEND_SWITCHING_ISR(woken) |
the same under another name | I | 28 |
Task notifications
| Name | What it does | From | Section |
|---|---|---|---|
xTaskNotifyGive(h) |
+1, like a semaphore | T | 31 |
vTaskNotifyGiveFromISR(h, *woken) |
the same | I | 28, 31 |
ulTaskNotifyTake(clear, ticks) |
wait; pdTRUE — clear to zero, pdFALSE — −1 |
T | 31 |
xTaskNotify(h, value, action) |
send a value; one of five actions | T | 31 |
xTaskNotifyFromISR(h, value, action, *woken) |
the same | I | 31 |
xTaskNotifyWait(clearIn, clearOut, *value, ticks) |
wait for a value | T | 31 |
xTaskNotifyStateClear(h) |
clear the pending state | T | — |
ulTaskNotifyValueClear(h, mask) |
clear bits of the value | T | — |
Actions: eNoAction, eSetBits, eIncrement, eSetValueWithOverwrite,
eSetValueWithoutOverwrite.
34.2 Queues
| Name | What it does | From | Section |
|---|---|---|---|
xQueueCreate(len, itemSize) |
from the heap; NULL on failure |
T B | 27 |
xQueueCreateStatic(len, itemSize, storage, *buf) |
from your own memory | T B | 27 |
xQueueSend(q, *item, ticks) |
to the back; same as SendToBack |
T | 27 |
xQueueSendToBack(q, *item, ticks) |
to the back | T | 27 |
xQueueSendToFront(q, *item, ticks) |
to the front — jumping the queue | T | 27 |
xQueueOverwrite(q, *item) |
overwrite; only for a queue of length 1 | T | 27 |
xQueueReceive(q, *item, ticks) |
take an item | T | 27 |
xQueuePeek(q, *item, ticks) |
look without taking | T | 27 |
…FromISR(q, *item, *woken) |
twins of the six above, without ticks; xQueuePeekFromISR(q, *item) has no flag |
I | 27, 28 |
uxQueueMessagesWaiting(q) |
how many items are stored | T | 27 |
uxQueueMessagesWaitingFromISR(q) |
the same | I | — |
uxQueueSpacesAvailable(q) |
how many more fit | T | — |
xQueueIsQueueEmptyFromISR(q) / xQueueIsQueueFullFromISR(q) |
empty / full | I | — |
xQueueReset(q) |
clear | T | — |
vQueueDelete(q) |
delete | T | — |
A queue copies the item. errQUEUE_EMPTY, errQUEUE_FULL and pdFAIL are
one and the same zero.
34.3 Semaphores and mutexes
| Name | What it does | From | Section |
|---|---|---|---|
xSemaphoreCreateBinary() / …Static(*buf) |
binary; created empty | T B | 28 |
xSemaphoreCreateCounting(max, init) / …Static(max, init, *buf) |
counting | T B | 28 |
xSemaphoreCreateMutex() / …Static(*buf) |
mutex; created free, unlike a binary semaphore | T B | 30 |
xSemaphoreCreateRecursiveMutex() / …Static(*buf) |
recursive | T B | 30 |
xSemaphoreTake(s, ticks) |
take | T | 28, 30 |
xSemaphoreTakeFromISR(s, *woken) |
take without waiting; not for a mutex | I | 28 |
xSemaphoreGive(s) |
give; for a mutex only the owner | T | 28, 30 |
xSemaphoreGiveFromISR(s, *woken) |
give; not for a mutex | I | 28 |
xSemaphoreTakeRecursive(m, ticks) / xSemaphoreGiveRecursive(m) |
for a recursive mutex; the ordinary ones do not work | T | 30 |
uxSemaphoreGetCount(s) |
current value | T | — |
xSemaphoreGetMutexHolder(m) |
who holds it; needs INCLUDE_xSemaphoreGetMutexHolder |
T | — |
vSemaphoreDelete(s) |
delete | T | — |
The mutex is the only object that inherits priority. It is not available from an interrupt in any form.
34.4 Software timers
| Name | What it does | From | Section |
|---|---|---|---|
xTimerCreate(name, period, reload, id, cb) |
create; not started | T B | 29 |
xTimerCreateStatic(…, *buf) |
from your own memory | T B | 29 |
xTimerStart(t, ticks) |
start; a running timer is restarted | T B | 29 |
xTimerStop(t, ticks) |
stop | T | 29 |
xTimerReset(t, ticks) |
restart the countdown | T | 29 |
xTimerChangePeriod(t, period, ticks) |
change the period; starts a stopped timer | T | 29 |
xTimerDelete(t, ticks) |
delete | T | — |
…FromISR(t, *woken) |
twins of Start, Stop, Reset, ChangePeriod; xTimerChangePeriodFromISR also takes the period |
I | 29 |
xTimerIsTimerActive(t) |
whether it is running | T | — |
xTimerGetPeriod(t) / xTimerGetExpiryTime(t) |
period / expiry time | T | — |
pvTimerGetTimerID(t) / vTimerSetTimerID(t, id) |
identifier | T | 29 |
xTimerGetReloadMode(t) / vTimerSetReloadMode(t, mode) |
mode (one-shot or auto-reload) | T | — |
xTimerGetTimerDaemonTaskHandle() |
handle of the daemon | T | — |
xTimerPendFunctionCall(fn, arg1, arg2, ticks) |
run a function in the daemon | T | 29 |
xTimerPendFunctionCallFromISR(fn, arg1, arg2, *woken) |
the same | I | 29 |
ticks in the commands is the wait for space in the daemon's queue, not a start delay.
The callback runs in the daemon and must not block.
34.5 Event groups
| Name | What it does | From | Section |
|---|---|---|---|
xEventGroupCreate() / …Static(*buf) |
create; 24 flags | T B | 31 |
xEventGroupSetBits(eg, bits) |
set | T | 31 |
xEventGroupSetBitsFromISR(eg, bits, *woken) |
set via the timer daemon | I | 31 |
xEventGroupClearBits(eg, bits) / …FromISR(eg, bits) |
clear | T / I | 31 |
xEventGroupGetBits(eg) / …FromISR(eg) |
read without waiting | T / I | 31 |
xEventGroupWaitBits(eg, bits, clearOnExit, waitAll, ticks) |
wait for any / all | T | 31 |
xEventGroupSync(eg, setBits, waitBits, ticks) |
set and wait for all atomically | T | 31 |
vEventGroupDelete(eg) |
delete | T | — |
The return value is the group at the moment of wake-up; check it.
34.6 Stream and message buffers
| Name | What it does | From | Section |
|---|---|---|---|
xStreamBufferCreate(size, trigger) / …Static(size, trigger, storage, *buf) |
stream; Create itself allocates size + 1, with Static the array is exactly size and size − 1 fits |
T B | 32 |
xStreamBufferSend(sb, *data, len, ticks) |
write; returns bytes | T | 32 |
xStreamBufferSendFromISR(sb, *data, len, *woken) |
the same; zero means lost | I | 32 |
xStreamBufferReceive(sb, *data, max, ticks) |
read up to max |
T | 32 |
xStreamBufferReceiveFromISR(sb, *data, max, *woken) |
the same | I | — |
xStreamBufferBytesAvailable(sb) / xStreamBufferSpacesAvailable(sb) |
stored / free space | T | 32 |
xStreamBufferIsEmpty(sb) / xStreamBufferIsFull(sb) |
empty / full | T | — |
xStreamBufferSetTriggerLevel(sb, n) |
change the trigger level | T | — |
xStreamBufferReset(sb) |
clear; fails if someone is waiting | T | 32 |
vStreamBufferDelete(sb) |
delete | T | — |
xMessageBufferCreate(size) / …Static(size, storage, *buf) |
with boundaries; +4 bytes per message | T B | 32 |
xMessageBufferSend(mb, *data, len, ticks) |
whole message or nothing | T | 32 |
xMessageBufferSendFromISR(mb, *data, len, *woken) |
the same | I | — |
xMessageBufferReceive(mb, *data, max, ticks) |
one message; max ≥ the longest one |
T | 32 |
xMessageBufferReceiveFromISR(mb, *data, max, *woken) |
the same | I | — |
xMessageBufferSpaceAvailable(mb) |
free space | T | — |
xMessageBufferIsEmpty(mb) / xMessageBufferIsFull(mb) / xMessageBufferReset(mb) |
state / clear | T | — |
vMessageBufferDelete(mb) |
delete | T | — |
One writer, one reader.
34.7 Heap
| Name | What it does | From | Section |
|---|---|---|---|
pvPortMalloc(bytes) |
allocate; NULL on failure |
T B | 25 |
vPortFree(p) |
free; in heap_1 it halts |
T | 25 |
xPortGetFreeHeapSize() |
free right now | T | 25 |
xPortGetMinimumEverFreeHeapSize() |
the worst value ever; heap_4, heap_5 |
T | 25 |
vPortGetHeapStats(*stats) |
a detailed report; heap_4, heap_5 |
T | 25 |
vPortDefineHeapRegions(regions) |
regions for heap_5; in ascending address order |
B | 25 |
vApplicationMallocFailedHook() |
the out-of-memory hook — you write it | — | 25 |
34.8 Constants and time macros
| Name | Value | Meaning |
|---|---|---|
pdMS_TO_TICKS(ms) |
ms × tickRate / 1000 |
milliseconds to ticks; rounds down |
portTICK_PERIOD_MS |
1 at 1 kHz | milliseconds per tick |
portMAX_DELAY |
0xFFFFFFFF |
wait forever with INCLUDE_vTaskSuspend 1, otherwise 49.7 days at 1 kHz (section 27.2) |
pdTRUE / pdFALSE |
1 / 0 | boolean |
pdPASS / pdFAIL |
1 / 0 | success / failure |
errQUEUE_EMPTY / errQUEUE_FULL |
0 / 0 | indistinguishable from each other and from pdFAIL |
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY |
−1 | out of memory |
tskIDLE_PRIORITY |
0 | idle task priority |
configMAX_PRIORITIES |
from the configuration | the highest usable priority is one less |
Hooks you write yourself
| Name | When it is called | Enabled by |
|---|---|---|
vApplicationStackOverflowHook(h, name) |
stack overflow, at a task switch | configCHECK_FOR_STACK_OVERFLOW |
vApplicationMallocFailedHook() |
heap allocation failure | configUSE_MALLOC_FAILED_HOOK |
vApplicationIdleHook() |
every pass of the idle task; must not block | configUSE_IDLE_HOOK |
vApplicationTickHook() |
every tick, from the interrupt; only FromISR |
configUSE_TICK_HOOK |
vApplicationGetIdleTaskMemory(…) |
memory for the idle task | configSUPPORT_STATIC_ALLOCATION |
vApplicationGetTimerTaskMemory(…) |
memory for the timer daemon | the same + configUSE_TIMERS |
34.9 Cost of the objects
Everything is measured with a build for Cortex‑M3 in the handbook configuration.
| Object | Bytes | Plus |
|---|---|---|
| task control block | 92 | stack, at least 512 |
| queue | 80 | len × itemSize |
| semaphore, mutex | 80 | — |
| software timer | 44 | — |
| event group | 32 | — |
| stream buffer, message buffer | 36 | size + 1 |
| task notification | 0 | already in the control block |
| kernel in the firmware | ≈ 6.4 KB | + heap |
Before counting bytes, you choose the object itself. The selection tables from 30.9, 31.4 and 32.7 and the multi-writer queue from 27.4 are gathered in one diagram, with costs from the table above:
34.10 Self-check questions
The answers are in the sections given in brackets. If an answer does not come to mind at once, it is worth rereading that section.
Tasks
- A task with priority 3 spins in an empty loop without waiting. What do tasks with priorities 1 and 2 see? (26)
vTaskDelay(10)in a task that runs for 3 ms. What is the period? How many activations are lost per minute? (26)- Why are there two stack pointers —
MSPandPSP? (23) uxTaskGetStackHighWaterMarkreturned 30. How many bytes is that? (26)- A task waits with
portMAX_DELAY— in one case on a queue, in the other on a notification. What doeTaskGetStateandvTaskListshow? (26) - Why must a task function not exit with a
returnstatement? (26)
Memory
- A call to
pvPortMalloc(512)— how many bytes are taken from theheap_4heap? (25) - Why is
heap_1better thanheap_4when it cannot free memory? (25) - A 10 KB heap on an F103C8: what share of all memory is that, and from what moment is it occupied? (25)
Interrupts
- An interrupt with priority 3 and a threshold of 5 called
xQueueSendFromISR. What happens withconfigASSERTenabled? Without it? (28) - What does a forgotten
portYIELD_FROM_ISRcost in microseconds? (28) - Why can a mutex not be given from an interrupt? (30)
- The value
0x50inBASEPRI— where does it come from? (23, 28)
Synchronization
counter++— how many instructions, and what can happen between them? (30)- Three tasks L, M, H; L holds a mutex, H waits for it. What does M do, and what does the mutex do about it? (30)
- Two tasks take two mutexes in different order. What happens and how is it fixed? (30)
- When does a single variable need no protection at all? (30)
Objects
- A queue of 16 messages of 4 bytes each — how many bytes in total, and what part is overhead? (27)
xTimerStart(t, 100)— what does the second argument mean? (29)- A timer callback called
vTaskDelay. What happens to the other timers? (29) - Why does an event group have 24 flags and not 32? (31)
- How does
xEventGroupSyncdiffer fromSetBitsplusWaitBits? (31) - A stream buffer with a trigger level of 16 at 115200 baud: how many wake-ups per second instead of how many? (32)
xMessageBufferReceivealways returns zero. Why? (32)
Configuration
configCPU_CLOCK_HZ= 36 MHz while the real clock is 72. What happens to delays? (33)- The limit of one sleep in tickless mode on
SysTickat 72 MHz? Why? (33) SVC_Handleris defined twice — where do both copies come from? (24)
34.11 Pitfalls
You cannot tell whether a queue is empty or full. errQUEUE_EMPTY, errQUEUE_FULL and pdFAIL are one and the same
zero; the meaning comes from the function you called (34.8).
The delay is shorter than requested. pdMS_TO_TICKS rounds down (34.8).
Priority configMAX_PRIORITIES does not work. The highest usable one is one less (34.8).
A hang in vApplicationIdleHook or a fault in vApplicationTickHook. The first must not block, the second
is called from an interrupt — only FromISR functions (34.8).
34.12 Summary
- Tables 34.1–34.8 are a reference to the kernel API names: where to call them from, what they return, where they are explained.
- The zeros
errQUEUE_EMPTY,errQUEUE_FULLandpdFAILare indistinguishable — the meaning comes from the function you called. - Cost of objects (34.9): a task is 92 bytes plus the stack, a queue is 80 plus data, a notification is 0.
- Questions 34.10 — one per topic of part IV, each with a reference to the section that has the answer.
Next: section 34а "Zephyr: a different operating system — an overview for those who know FreeRTOS".