Introduction to FreeRTOS Tasks

1. Uses of FreeRTOS

FreeRTOS is generally used in hardware designs where there are certain limitations on RAM size (cost, resources, performance-to-power ratio, etc.). It is one of the most widely used real-time operating systems today. Choosing FreeRTOS for project applications generally considers the following aspects:

  • Real-time (time constraints): Like most RTOS, at each clock tick, ready high-priority tasks will preempt the CPU (FreeRTOS is a real-time scheduler, and projects are built on this kernel to meet hard real-time applications).

  • Determinism (predictability): Tasks are switched between at specified times, completing necessary work within a limited time, and the execution time of low-priority tasks is predictable.

  • Open-source and free: Compared to other paid RTOS, FreeRTOS is open-source and free.

  • RAM usage: FreeRTOS occupies a small amount of RAM (can run with 2K~3K).

  • Task management: Supports both task preemption and time-slicing.

Based on these characteristics, FreeRTOS is widely used in systems with certain real-time requirements and resource limitations, extensively applied in the automotive industry, consumer electronics, network services, and in MCU chips, DSP chips, and customized SOC chips.

2. Task States

Tasks in FreeRTOS are similar to processes in Linux, serving as units for system scheduling and execution in real-time operating systems. For a single-core CPU, at any moment, only one task is executed.

Tasks in FreeRTOS are mainly divided into the following states:

  • Running

The task is currently using the processor to perform corresponding operations, referred to as being in the running state. If the running hardware environment is a single-processor environment, only one task is running at a time.
  • Ready

Ready tasks are those that can be executed but are temporarily not executed due to higher priority or equally prioritized tasks being executed.
  • Blocked

If a task is waiting for a timed cycle or external events/resources, the current task is in a blocked state. A task can enter a blocked state by calling the system-provided vTaskDelay function (or vTaskDelayUntil), setting different system delay cycles to wake up into the Ready state. Additionally, tasks can also enter a blocked state through waiting queues, semaphores, event groups, notifications, or semaphore events, and can set their own blocking time while waiting for these communication resources, with the blocking time set in system ticks as the minimum unit for timeout. Once the timeout period passes, the task automatically switches from Blocked to Ready.
  • Suspended

The suspended state of a task is similar to the blocked state; however, unlike Blocked, a suspended task cannot be awakened by system heartbeat cycles, and the suspended task cannot set a timeout for suspension based on system heartbeat as the minimum unit. A suspended task does not automatically switch from Suspended to Ready; it can only be explicitly commanded to enter or exit the suspended state through vTaskSuspend() and xTaskResume() API calls. While waiting for task communication resources, if the system suspend function is enabled (INCLUDE_vTaskSuspend value is 1) and the waiting time is set to portMAX_DELAY, the task is directly suspended until the resource is satisfied for awakening. Furthermore, a task in the Ready state can explicitly call vTaskSuspend() to enter the Suspended state, but a task in the Ready state means it is waiting for resource satisfaction and will not directly switch to Blocked. The Blocked state is typically entered when a running task discovers that its running resources are insufficient and waits for resources or actively performs a system delay.

The relationship between task states in FreeRTOS can be referenced in the following diagram:

Introduction to FreeRTOS Tasks

3. Task Scheduling

The task scheduling method in FreeRTOS adopts a combination of preemptive scheduling and time-slicing. The system defaults to enabling both methods. Tasks of different priorities use preemptive scheduling, while tasks of equal priority use time-slicing scheduling. By configuring the value of configUSE_TIME_SLICING, one can choose to enable or disable time-slicing. Therefore, FreeRTOS provides a time-sliced preemptive scheduling algorithm when time-slicing is enabled and a non-time-sliced preemptive scheduling algorithm when time-slicing is disabled. Additionally, FreeRTOS provides the taskYIELD() interface for tasks in the running state to enter a blocked state or for running tasks to call for rescheduling.

The task scheduling process in FreeRTOS mainly consists of the task creation phase, the task scheduler startup phase, and the normal operation phase after the task scheduler starts. The following is an example based on the ARM Cortex-M4 series platform.

1. Task Creation Phase

During chip reset, after the BootLoader stage loads the code and enters the main function, after completing the configuration of CPU resources, interrupt resources, and peripheral resources based on the project task planning, FreeRTOS provides two methods for creating tasks and corresponding APIs, for both dynamic task creation and static task creation. Generally, dynamic task creation is most commonly adopted (the explanation here is based on dynamic task creation).

Introduction to FreeRTOS Tasks

Parameters:

  • pxTaskCode: Task implementation function, usually contains an infinite loop statement and has no return value; this function is the entry point for the task. The specific functionality of the task is called and executed in this function.

  • pcName: Task name (cannot exceed the preset configMAX_TASK_NAME_LEN length)

  • usStackDepth: Task stack size (under default conditions, the actual stack size is 4 times usStackDepth)

  • pvParameters: Parameters passed to the task implementation function

  • xPriority: Task priority, ranging from (0 ~ configMAX_PRIORITIES-1). The task priority level in FreeRTOS can be configured through the macro definition value configMAX_PRIORITIES; the higher the xPriority value, the higher the task’s priority. Generally, when creating tasks, the selection of task priority is planned from 0 to configMAX_PRIORITIES-1. (In other RTOS, a smaller value indicates a higher priority).

  • pxCreatedTask: Task handle (TCB task control block), if created successfully, this handle is valid.

Return values:

  • pdPASS: Task creation successful

  • errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY: Insufficient stack, task creation failed

2. Task Scheduler Startup Phase

The FreeRTOS task scheduler startup relies on the SVC interrupt and vTaskStartScheduler function. After the Cortex-M4 series chip completes the initialization of CPU, peripherals, and interrupts, it enters the main function, creates the required tasks for project execution, and calls the vTaskStartScheduler function to start the FreeRTOS task scheduling (as shown in the figure below).

Introduction to FreeRTOS Tasks

During the startup phase of the task scheduler, an idle task is automatically created by default, and the idle task’s priority is set to the system’s lowest priority. The source code will call the prvCheckTasksWaitingTermination function to release the resources of deleted tasks (TCB and task stack) and provide the idle task hook function vApplicationIdleHook for system load calculation. Users can also add monitoring and feedback based on their own projects in this hook function. The entry point for the idle task is portTASK_FUNCTION, with part of the source code shown below:

Introduction to FreeRTOS Tasks

3. Task Scheduling Running Phase

In the FreeRTOS system based on the ARM Cortex-M4 series platform, the systick interrupt, normal external interrupts, SVC, and pendSV interrupts are generally designed with the following priority:

systick interrupt > normal external interrupt > SVC and pendSV interrupt > task (thread)

The SVC interrupt is mostly used during the task scheduler startup phase or for task preemption, serving as a means to start the task scheduler or preempt tasks. After the task scheduler starts, it relies on the systick interrupt for periodic task scheduling (time-slice polling or preemption) and the pendSV interrupt for task context switching and saving. The following diagram illustrates the scheduling of Task A and Task B, interspersed with systick and normal external interrupts.

Introduction to FreeRTOS Tasks

4. Task Stack

The total space size of the FreeRTOS task stack can be configured according to the specific project resources. FreeRTOS plans the total space of the task stack based on the RAM size in the specific project, with the macro definition configTOTAL_HEAP_SIZE determining the total size of the task heap. Each time a new task is created, it requests the corresponding stack space for the newly created task in the total task heap, as shown below.

Introduction to FreeRTOS Tasks

5. Task Monitoring

By configuring both configUSE_TRACE_FACILITY and configUSE_STATS_FORMATTING_FUNCTIONS to 1, the functions prvWriteNameToBuffer(), vTaskList(), and vTaskGetRunTimeStats() enable FreeRTOS task monitoring. This feature can provide feedback on the current task status, task priority, and the maximum remaining stack space of each task in FreeRTOS. The source code of FreeRTOS provides printing of these values using sprintf, with part of the source code shown below:

Introduction to FreeRTOS Tasks

The official demo print result is as follows:

Introduction to FreeRTOS Tasks

Name: Task Name
State: Task State
Priority: Task Priority
Stack: Remaining Stack (can optimize overall RAM space based on this value)

6. Conclusion

The task mechanism of FreeRTOS provides excellent real-time capabilities, while the various configurable options in the native system offer tailored adaptations for different embedded applications. What attracts many manufacturers is that the system is commercially free and open-source. In embedded applications, factors such as power consumption, resources, and cost are often crucial criteria for manufacturers when choosing a system. Currently, in consumer electronics applications, considering power consumption, resources, and costs, some manufacturers adopt a big-core CPU + small-core CPU architecture. The big core often runs general-purpose operating systems (Linux, Android, iOS, etc.), while more and more manufacturers consider deploying FreeRTOS on the small core, adapting it based on different application scenarios. FreeRTOS, being free, open-source, easy to trim, and resource-efficient, presents competitive advantages comparable to other RTOS.

References:

FreeRTOS Official Documentation: https://www.freertos.org/features.html

FreeRTOS Official Code: https://www.freertos.org/a00104.html

Introduction to FreeRTOS Tasks

Leave a Comment

×