FreeRTOS Notes
Page Contents
Book
- The book Mastering the FreeRTOS™ Real Time Kerne is freely available.
- MPU Support Chapter & Webpage
Naming Conventions
TickType_t
- Either a U16 or U32 based on FreeRTOS configuration settings.BaseType_t
- U16 on 16-bit architechture, U32 on 32-bit architecture- Variable prefixes:
c
- chars
- short or U16l
- long or U32x
-BaseType_t
or any other non-standard types like structures, task handlers etc etc.u
- unsignedp
- pointerv
- void
- Function prefixes:
- return type letter (see variable prefixes) and then first word is filename, next works are function name:
vTaskPrioritySet
- Function returning void, intask.c
, function isPrioritySet
.
- return type letter (see variable prefixes) and then first word is filename, next works are function name:
- Macro names:
- Prefix in lower case, giving macro definitions file.
- Macro name is upper case
- Examples
portMAX_DELAY
-port
indicates it is fromportable.h
, and the macro isMAX_DELAY
.taskENTER_CRITICAL
-task
indicates it is fromtask.h
pdTRUE
-pd
indicates it is fromprojdefs.h
configUSE_PREEMPTION
-config
indicates it is fromFreeRTOSConfig.h
Memory Allocation
I work in systems that generally don't want dynamic memory allocation, so to use static allocation set
configSUPPORT_STATIC_ALLOCATION
to 1
in FreeRTOSConfig.h
.
All functions then need to be replaced with thair ...Static
counterparts:
xTaskCreateStatic
xEventGroupCreateStatic
xEventGroupGetStaticBuffer
xQueueGenericCreateStatic
xQueueGenericGetStaticBuffers
xQueueCreateMutexStatic
- if
configUSE_MUTEXES
is1
- if
xQueueCreateCountingSemaphoreStatic
- if
configUSE_COUNTING_SEMAPHORES
is1
- if
xStreamBufferGenericCreateStatic
xStreamBufferGetStaticBuffers
xTimerCreateStatic
- if
configUSE_TIMERS
is1
- if
- xTimerGetStaticBuffer
- if
configUSE_TIMERS
is1
- if
If configSUPPORT_STATIC_ALLOCATION
and configUSE_TIMERS
are both enabled, the kernel will call
vApplicationGetTimerTaskMemory()
to allow the application to create and return a memory buffer for the
timer task TCB and the timer task stack.
The vApplicationGetIdleTaskMemory
function is called to allow the application to create the needed buffers
for the "main" idle task.
Tasks
States:
┌─────────────────┐
│ │
┌───────────► Suspended ◄───────────────────────┐
│ │ │ │
│ └───▲─────────┬───┘ │
│ │ │ │ vTaskSusped()
│ vTaskSuspend()│ │ vTaskResume() │
│ │ │ │
│ │ │ │
│ ┌───┴─────────▼───┐ ┌────────┴────────┐
│ ┌┐ │ ├──────────────► │
TaskSuspend() │ │┼─────► Ready │ │ Running │
│ └┘ │ ◄──────────────┤ │
│ └────────▲────────┘ └────────┬────────┘
│ │ │
│ │ │
│ │Event │ Blocking API
│ │ │ called, which blocks
│ ┌────────┴────────┐ │
│ │ │ │
└───────────┤ Blocked ◄───────────────────────┘
│ │
└─────────────────┘
Many of the following functions can be included or excluded from the API definition using macros from FreeRTOSConfig.h
, such as INCLUDE_vTaskSuspend()
etc.
Task Creation & Deletion & Priority
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char* pcName, uint16_t usStackDepth, void * pvParameters, UBaseType_t uxPriority, TaskHandle_t *pxCreatedTask)
x
means it returnsBasetype_t
or other non-standard type.Task
means it is found intask.c
- Parameters:
pvTaskCode
- Pointer to function that runs the task:void MyTask(void *pvParameters)
pcName
- Pointer to string used to identify task during debuggingusStackDepth
- Stack depth - duhpvParameters
- Pointer to task parameters. May beNULL
. Opaque to FreeRTPS, just pass a pointer to astruct
or whatever you like in here.uxPriority
- Smaller the number the higher the priority. Tasks of equal priority run for a time quanta.pxCreatedTask
- Used to return the task handle. May beNULL
.
vTaskStartScheduler()
- Once tasks created starts the scheduler.vTaskPrioritySet(TaskHandle_t *pxCreatedTask, UBaseType_t uxPriority)
- Set a task priority dynamically. Can useNULL
task to set threads own priority.uxTaskPriorityGet(TaskHandle_t *pxCreatedTask)
- Get task priority.vTaskDelete(TaskHandle_t *pxCreatedTask)
Task State Modification
vTaskSuspend(TaskHandle_t *pxCreatedTask)
- Suspend a task. Shouldn't need to call this manually - use correct CRs and scheduling.vTaskResume(TaskHandle_t *pxCreatedTask)
- Resume a task. Shouldn't need to call this manually - use correct CRs and scheduling.vTaskDelay(TickType_t xTicksToDelay)
- Causes task to move to the blocked state for a number of ticks. Make sureINCLUDE_vTaskDelay
is set to1
inFreeRTOSConfig.h
. UsepdMS_TO_TICKS()
, e.g.vTaskDelay(pdMS_TO_TICKS(...))
. See alsoxTaskGetTickCount()
.vTaskDelayUntil()
Idle Task
- There must be at least one task in the Running state, so the Idle task will run where there are no other tasks pending.
- It is created automatically when the scheduler is started.
- Has lowest priority (0) so that it can never prempt any other task.
- Can add functionality to the task using an Idle hook (Idle callback function), which is called automatically by the idle task once per iteration of the idle task loop.
- See
configUSE_IDLE_HOOK
andconfigIDLE_SHOULD_YIELD
inFreeRTOSConfig.h
. - Override weakly linked function
void vApplicationIdleHook(void)
. - Commonly used to put MCU to sleep - drawback is tick interrupt will cause continual enter/exit from this state!
- To overcome, FreeRTOS tickless idle mode stops the periodic tick interrupt during idle periods.
Ticks
- Tick hook (callback) can be overridden, but is must be AS QUICK AS POSSIBLE because it executes in interrupt context
and must not call any API functions that do not end in
...FromISR()
.
Context Switching
When a task calls an API function, if configUSE_PREEMPTION
is set to 1
in FreeRTOSConfig.h
then the
switch to the higher priority task occurs automatically within the API function, in other words, before the
API function has exited.
IPC
Queues
- Must
#include "queue.h"
. - Finite FIFO buffers.
- Blocks on a read if no data is available, blocks on a write if no room in the queue is available.
- Functions:
xQueueCreate()
,xQueueSend()
,xQueueSendFromISR90
,xQueueSendToFront()
,xQueueSendToBack()
,xQueueReceive()
.QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType uxItemSize)
.BaseType_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType xTickToWait)
.- The item is queued by copy, not by reference.
BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvbuffer, TickType xTickToWait)
.- The item is received by copy so a buffer of adequate size must be provided.
xQueueSendFromISR()
- Communicate from backend ISR to front end task. Note, of course, that this function cannot block so if the queue is full items will be dropped.
- Queue sets: A lot like
poll()
- task can receive data from many queues without having to poll each queue.- See
configUSE_QUEUE_SETS
inFreeRTOSConfig.h
. If not present in file define it yourself and set value as 1. QueueSetHandle_t xQueueCreateSet(const UBaseType_t exEventQueueLength)
, whereexEventQueueLength
is the max number of queues that this set can hold.BaseType_t xQueueAddToSet(QueueSetMemberHandler_t xQueueOrSempahore, QueueSetHandler_t xQueueSet)
.- Note
xQueueOrSempahore
is so named because semaphores can also be added to queue sets.
- Note
- See
static QueueHandle_t q1, q2;
static QueueSetHandle_t qset;
...
// Some init function
q1 = xQueueCreate(1, sizeof(uint32_t));
q2 = xQueueCreate(1, sizeof(uint32_t));
xQueueAddToSet(q1, qset);
xQueueAddToSet(q2, qset);
...
// Some recever function
while(true) {
QueueHandle_t queue_with_data = (QueueHandle_t)xQueueSelectFromSet(qset, portMAX_DELAY);
xQueueReceive(queue_with_data, ...);
// Do something with data ...
}
Synchronisation
- Binary Sempahores:
SemaphoreHandle_t xSemaphoreCreateBinary(void)
BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore)
BaseType_t xSempahoreGiveFromISR(SempahoreHandle_t xSemaphore, BaseType_t pxHigherPriorityTaskWoken)
BaseType_t xSemaphoreTake(...)
- Counting Sempahores:
- Enable by defining
configUSE_COUNTING_SEMAPHORES
inFreeRTOSConfig.h
xSemaphoreCreateCounting(uxMaxCount, uxInitialCount)
- Enable by defining
- Mutexes:
- Enable by defining
configUSE_MUTEXES
inFreeRTOSConfig.h
- Mutexes are binary semaphores that include a priority inheritance mechanism.
- Not recursive - must use recursive mutexes if you need this.
- Enable by defining
Event Groups
- Event groups allow a task to wait in the Blocked state for a combination of one of more events to occur
- Event groups unblock all the tasks that were waiting for the same event, or combination of events, when the event occurs.
- Useful for
- synchronizing multiple tasks,
- broadcasting events to more than one task,
- allowing a task to wait in the Blocked state for any one of a set of events to occur, and
- allowing a task to wait in the Blocked state for multiple actions to complete.
xEventGroupWaitBits()
to wait for any bit to be set and get a mask of all bits set.xEventGroupSync()
to set a bit and wait for all or a selection of other bits to be set.- The function allows a task to set one or more event bits in an event group, then wait for a combination of event bits to become set in the same event group, as a single uninterruptable operation.
Task Notifications
- Inter-task or ISR-task interaction and synchronisation without a communication object like a semaphore.
- Optional so must set
configUSE_TASK_NOTIFICATIONS
to1
inFreeRTOSConfig.h
. - Much faster than using a queue, semaphore or event group.
- Requires significantly less RAM.
vTaskNotifyGiveFromISR()
Interrupt Management
- Never call a FreeRTOS API function that does not have
FromISR
in its name from an ISR. xHigherPriorityTaskWoken
:- When an API is used that might cause a context switch, the switch cannot happen in
the ISR, thus all interrupt safe API functions have a param
xHigherPriorityTaskWoken
. - Set
xHigherPriorityTaskWoken
to false before the API call, then if it is true after,portYIELD_FROM_ISR()
needs to be called with the value ofxHigherPriorityTaskWoken
. If it is false no context switch is requested, otherwise one is requested.
- When an API is used that might cause a context switch, the switch cannot happen in
the ISR, thus all interrupt safe API functions have a param
- Deferred interrupt processing: An interrupt service routine must record the cause of the interrupt, and clear the interrupt. Any other processing necessitated by the interrupt can often be performed in a task, allowing the interrupt service routine to exit as quickly as is practical.
Software Timers
- Set
configUSE_TIMERS
to1
inFreeRTOSConfig.h
. - Set
configTIMER_TASK_PRIORITY
to desired priority of timer service task. - Set
configTIMER_QUEUE_LENGTH
for max number of unprocessed commands that timer command queue can hold. - Set
configTIMER_TASK_STACK_DEPTH
to define stack size for timer service task. - Timer callback prototype:
void ATimerCallback( TimerHandle_t xTimer )
. - Timer callbacks must NOT enter blocked state!
- All callback execute in context of timer service task, aka "RTOS daemon task".
- APIs:
xTimerCreate
,xTimerStart
,xTimerChangePeriod
...
Memory Protection Unit (MPU)
- Supports static allocation config as well as synamic allocation config.
- Must define
portUSING_MPU_WRAPPERS
to be1
. portNUM_CONFIGURABLE_REGIONS
. Default is1
. Examples seem to set this to3
because as docs says it uses 8 MPU regions, 4 reserved by kernel, 3 for task regions and 1 for task stack. Presumably on devices where MPU can do 16 regions this can just be set higher.xTaskCreateRestricted()
andxTaskCreateRestrictedStatic()
.