Embedded HandbookApps
All sections › IV. FreeRTOS
STM32F103, STM32F407 · level reference · 15 min read
Open in the interactive handbook

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.

Three calling contexts of the FreeRTOS API: before vTaskStartScheduler you create tasks, queues and timers; from a task the whole API is available with a wait from zero to portMAX_DELAY; from an interrupt only the FromISR twins, without waiting, with the woken flag and portYIELD FROM ISR on exit; an interrupt more urgent than the threshold — with a priority number below 5 — cannot call the kernel at all, and a mutex is not available from an interrupt in any form

Notation

T from a task; can wait if a time is given
I from an interrupt handler; the FromISR twin, cannot wait
B before vTaskStartScheduler — during initialization
ticks wait time in ticks: 0, pdMS_TO_TICKS(n) or portMAX_DELAY
*woken output flag for portYIELD_FROM_ISR

Terms 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

FreeRTOS kernel objects around a task: queue, semaphore and mutex, software timer, event group, stream buffer and message buffer, task notification; from an interrupt — the FromISR twins


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

Cost of FreeRTOS objects on Cortex‑M3 in bytes: task control block 92 plus a stack of at least 512, queue 80 plus len × itemSize, semaphore and mutex 80, software timer 44, event group 32, stream buffer and message buffer 36 plus size + 1, notification 0; one task with the minimum stack is 604 bytes, more than all other objects together without data — 272

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:

What to choose for communication: a bare fact — notification, binary semaphore or event group; data — notification with a value, a one-slot queue, stream buffer, message buffer or queue; a shared resource — a single word write, critical section, scheduler suspension, mutex or gatekeeper task; the cost of each comes from table 34.9


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

  1. A task with priority 3 spins in an empty loop without waiting. What do tasks with priorities 1 and 2 see? (26)
  2. vTaskDelay(10) in a task that runs for 3 ms. What is the period? How many activations are lost per minute? (26)
  3. Why are there two stack pointers — MSP and PSP? (23)
  4. uxTaskGetStackHighWaterMark returned 30. How many bytes is that? (26)
  5. A task waits with portMAX_DELAY — in one case on a queue, in the other on a notification. What do eTaskGetState and vTaskList show? (26)
  6. Why must a task function not exit with a return statement? (26)

Memory

  1. A call to pvPortMalloc(512) — how many bytes are taken from the heap_4 heap? (25)
  2. Why is heap_1 better than heap_4 when it cannot free memory? (25)
  3. A 10 KB heap on an F103C8: what share of all memory is that, and from what moment is it occupied? (25)

Interrupts

  1. An interrupt with priority 3 and a threshold of 5 called xQueueSendFromISR. What happens with configASSERT enabled? Without it? (28)
  2. What does a forgotten portYIELD_FROM_ISR cost in microseconds? (28)
  3. Why can a mutex not be given from an interrupt? (30)
  4. The value 0x50 in BASEPRI — where does it come from? (23, 28)

Synchronization

  1. counter++ — how many instructions, and what can happen between them? (30)
  2. 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)
  3. Two tasks take two mutexes in different order. What happens and how is it fixed? (30)
  4. When does a single variable need no protection at all? (30)

Objects

  1. A queue of 16 messages of 4 bytes each — how many bytes in total, and what part is overhead? (27)
  2. xTimerStart(t, 100) — what does the second argument mean? (29)
  3. A timer callback called vTaskDelay. What happens to the other timers? (29)
  4. Why does an event group have 24 flags and not 32? (31)
  5. How does xEventGroupSync differ from SetBits plus WaitBits? (31)
  6. A stream buffer with a trigger level of 16 at 115200 baud: how many wake-ups per second instead of how many? (32)
  7. xMessageBufferReceive always returns zero. Why? (32)

Configuration

  1. configCPU_CLOCK_HZ = 36 MHz while the real clock is 72. What happens to delays? (33)
  2. The limit of one sleep in tickless mode on SysTick at 72 MHz? Why? (33)
  3. SVC_Handler is 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


Next: section 34а "Zephyr: a different operating system — an overview for those who know FreeRTOS".

Open in the interactive handbook