Difference between revisions of "Embedded Systems Design II FreeRTOS"

From EdWiki

m (Getting Started with FreeRTOS)
m (Getting Started with FreeRTOS)
Line 11: Line 11:
   <div class="content" id="panel2">
   <div class="content" id="panel2">
     <p>This is the second panel of the basic tab example. This is the second panel of the basic tab example.</p>
     <p>{{EmSys:FreeRTOS - Task Management}}</p>
   <div class="content" id="panel3">
   <div class="content" id="panel3">

Revision as of 06:22, 29 February 2020

Getting Started with FreeRTOS

An Introduction to FressRTOS

FreeRTOS is a real-time kernel (or real-time scheduler) targeting at hard real-time applications.

  • Simple
  • Portable
  • Royalty free
  • Concise
  • Primarily written in C
  • Few assembler functions
  • Thumb mode supported

The Cortex-M3 Port of FreeRTOS

The Cortex-M3 port includes all the standard FreeRTOS features:

  • Pre-emptive or co-operative scheduler operation
  • Very flexible task priority assignment
  • Queues
  • Binary semaphores
  • Counting semaphores
  • Recursive semaphores
  • Mutexes
  • Tick hook functions
  • Idle hook functions
  • Stack overflow checking
  • Trace hook macros

Data Types in FreeRTOS

macro or typedef actual type
portCHAR char
portSHORT short
portLONG long
portFLOAT float
portDOUBLE double
portSTACK_TYPE uint32_t
portBASE_TYPE long
Typically, this is a 32-bit type on a 32-bit architecture,
a 16-bit type on a 16-bit architecture, and
an 8-bit type on an 8-bit architecture.
portBASE_TYPE is generally used for return types
that can take only a very limited range of values,
and for pdTRUE/pdFALSE type Booleans.
UBaseType_t unsigned long
TickType_t TickType_t is the data type used to hold the
tick count value, and to specify times

Variables and Functions Naming

Variables are prefixed with their type:

  • c: for char
  • s: for short
  • l: for long
  • x: for portBASE_TYPE and any other non-standard types (structures, task handles, queue handles, etc.).
  • u: for unsigned
  • p: pointer
  • combinations are possible

If a variable is unsigned, it is also prefixed with a ‘u’. If a variable is a pointer, it is also prefixed with a ‘p’. For example, a variable of type uint8_t will be prefixed with ‘uc’, and a variable of type pointer to char will be prefixed with ‘pc’.

Functions are prefixed with both the type they return, and the file they are defined within. For example:

  • vTaskPrioritySet() returns a void and is defined within task.c.
  • xQueueReceive() returns a variable of type BaseType_t and is defined within queue.c.
  • pvTimerGetTimerID() returns a pointer to void and is defined within timers.c.

File scope (private) functions are prefixed with ‘prv’.

Macro Names

Most macros are written in upper case, and prefixed with lower case letters that indicate where the macro is defined.

Macro Value
pdTRUE 1
pdPASS 1
pdFAIL 0


FreeRTOS is customised using a configuration file called FreeRTOSConfig.h. Every FreeRTOS application must have a FreeRTOSConfig.h header file in its pre-processor include path. FreeRTOSConfig.h tailors the RTOS kernel to the application being built. It is therefore specific to the application, not the RTOS, and should be located in an application directory, not in one of the RTOS kernel source code directories.

  • Constants that start with the text “config” define attributes of the kernel, or include or exclude features of the kernel.
  • Constants that start with the text “INCLUDE_” are used to included or excluded FreeRTOS API functions from the application.

Some important fields/features:

  • configUSE_PREEMPTION: This is set to 1 if the preemptive kernel is desired.
  • configUSE_IDLE HOOK: An idle task hook will execute a function during each cycle of the idle task.
  • configUSE_TICK HOOK: A tick hook function will execute on each RTOS tick interrupt if this value is set to 1.
  • configTICK_RATE HZ: This is the frequency at which the RTOS tick will operate.
  • configMAX_PRIORITIES: The total number of priority levels that can be assigned when prioritizing a task.
  • configUSE_COUNTING_SEMAPHORES: This is set to 1 if counting semaphores are required.
  • configUSE_MUTEXES: This is set to 1 if mutexes are needed. Priority inheritance will then be enforced.
  • etc...

Resources Used By FreeRTOS

FreeRTOS makes use of SysTick, PendSV, and SVC interrupts. These interrupts are not available for use by the application. FreeRTOS has a very small footprint. A typical kernel build will consume approximately 6KB of Flash space and a few hundred bytes of RAM. Each task also requires RAM to be allocated for use as the task stack.

Task Management

Tasks in FreeRTOS

  • With FreeRTOS, an application can be structured as a set of autonomous tasks.
  • Each task executes within its own context (e.g., stack) with no coincidental dependency on other tasks.
  • The scheduler is responsible for starting, stoping, swapping in, and swapping out tasks.

Tasks Functions

Tasks are implemented as C functions. The prototype of a task function must return void and take a void pointer parameter. A task will typically execute indefinitely in an infinite loop:

  • must never terminate by attempting to return to its caller
  • If required, a task can delete itself prior to reaching the function end.

A single task function definition can be used to create any number of tasks:

  • Each created task is a separate execution instance
  • Each created task has its own stack
  • Each created task has its own copy of any automatic variables defined within the task itself.

The structure of a typical task function:

void vTaskFunction(void *pvParameters)
    int iVariable = 0;
     * Each instance of this task function will have its own copy of the iVariable.
     * Except that if the variable was declared static – in which case only one copy of the variable
     * would exist and would be shared by all created instance.
    /* A task will normally be implemented as an infinite loop. */
    while(1) {
        ;      /* The code to implement the task functionality will go here. */
     * Should the task implementation ever break out of the above loop then the task
     * must be deleted before reaching the end of this function. The NULL parameter 
     * passed to the  vTaskDelete() function indicates that the task to be deleted is the
     * calling (this) task.
     vTaskDelete( NULL );

Task States

An application can consist of many tasks. Only one task of the application can be executed at any given time on the microcontroller (single core). Thus, a task can exist in one of two states:

  • Running or
  • Not Running.

Only the scheduler can decide which task should enter the Running state. A task is said to have been “switched in” or “swapped in” when transitioned from the Not Running to the Running state, (“switched out” or “swapped out”) when transitioned from the Running state to the Not Running state).

The scheduler is responsible for managing the processor context:

  • Registers values
  • Stack contents

Task States and Transitions

Freertos task states.png
  • Running state
    The processor is executing its code.
  • Not Running state
    The task is dormant, its status having been saved ready for resuming execution the next time
  • Scheduler is the only entity that can switch a task in and out a running state.

Creating a Task

A task can be created by calling xTaskCreate() API

portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode,
			   const signed portCHAR * const pcName,
			   unsigned portSHORT usStackDepth,
			   void *pvParameters,
			   unsigned portBASE_TYPE uxPriority,
			   xTaskHandle *pxCreatedTask );
  • pvTaskCode
    is a pointer to the function that implement the task
  • pcName
    is a descriptive name for the task, not used by FreeRTOS
    configMAX_TASK_NAME_LEN: the application defined constant that defines the maximum length a task name can including the NULL terminator.
  • usStackDepth
    specifies the number of words the stack of this task can hold
    E.g., Cortex-M3 stack is 32 bits wide, if usStackDepth is passed in as 100, 400 bytes of stack space will be allocated (100*4 bytes)
    Size of the stack used by the idle task is defined by configMINIMAL_STACK_SIZE.
  • pvParameters
    is the parameter that can be passed to the task function (pointer to a complex data structure)
  • uxPriority
    is the priority of the task (0 is the lowest priority, configMAX_PRIORITIES-1 is the highest priority)
    Passing a value above (configMAX_PRIOIRTIES -1) will result in the priority being capped the maximum legitimate value.
  • pxCreatedTask
    is the handler of the generated task, which can be used to reference the task within API calls
  • Returned value
    There are two possible return values:
    1. pdTRUE
      when the task was created successfully
      the task could not be created because there was insufficient heap memory available for FreeRTOS to allocate enough RAM to hold the task data structures and stack.

Expanding the "Not Running" State

  • The Blocked state
    A task that is waiting for an event
    • Tasks can enter the Blocked state to wait for two different types of events:
      1. Temporal (time related) events where a delay period expiring or an absolute time being reached
        For example, wait for 10 ms to pass
      2. Synchronization events where the events originate from another task or interrupt
        For example, wait for data to arrive on a queue
    • It is possible for a task to block on a synchronization event with a timeout
      For example, wait for a maximum of 10 ms for data to arrive on a queue
  • The Suspended state
    Tasks in the Suspended state are not available to the scheduler.
    • The only way into the Suspended state is through a call to the vTaskSuspend() API function
    • The only way out through a call to the vTaskResume() or xTaskResumeFromISR() API functions
  • The Ready State
    Tasks that are in the Not Running but are not Blocked or Suspended
    • Tasks are able to run, and therefore ready to run, but not currently in the Running state

Task State Transitions

Freertos task state transitions.png

Using the Blocked state to create a delay

  • The tasks may generate delay using a null loop – polling a counter until it reaches a fixed value
    Waste of processor cycles
  • An efficient method is to create a delay with a call to the vTaskDelay() API function
    • vTaskDelay() places the calling task into the Blocked state for a fixed number of tick interrupts
    • The task in the Blocked state will not use any processing time at all
  • An alternative method is to use the vTaskDelayUntil() API function


void vTaskDelay( portTickType xTicksToDelay ); 
  • xTicksToDelay
    is the number of tick interrupts that the calling task should remain in the Blocked state before being transitioned back into the Ready state.

The constant portTICK_RATE_MS stores the time in milliseconds of a tick, which can be used to convert milliseconds into ticks.


void vTaskDelayUntil(portTickType * pxPreviousWakeTime, portTickType xTicksToDelay ); 
  • pxPreviousWakeTime
    • Holds the time at which the task last left the Blocked state (was ‘woken’ up). This time is used as a reference point to calculate the time at which the task should next leave the Blocked state.
    • The variable pointed to by pxPreviousWakeTime is updated automatically within the vTaskDelayUntil() function and should be initialized by the application code first.
  • xTicksToDelay
    vTaskDelayUntil() is normally being used to implement a task that executes periodically; the frequency being set by this value which is specified in ‘ticks’

This is the third panel of the basic tab example. This is the third panel of the basic tab example.

This is the fourth panel of the basic tab example. This is the fourth panel of the basic tab example.