This article introduces the tasks and scheduling kernel implementation of FreeRTOS.1. Concept of Tasks
In FreeRTOS, a task is the smallest unit of system scheduling and execution. Each task has its own stack space, program counter (PC), registers, and state.
Task Stack Spaceis a contiguous memory area that stores local variables, function call information, and the context of the task when it is switched.

2. Task Creation
1. FreeRTOS creates tasks by calling thexTaskCreatefunction
<span>BaseType_t xTaskCreate( TaskFunction_t pvTaskCode, const char * const pcName, configSTACK_DEPTH_TYPE usStackDepth, void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pxCreatedTask );</span>
|
Parameter Name |
Description |
|
PvTaskCode |
A function pointer pointing to the task entry function, usually the name of a user-defined function |
|
PcName |
A descriptive name for the task (string) |
|
usStackDepth |
Defines the size of the task stack, measured in words |
|
pvParameters |
A void* pointer used to pass configuration information or context |
|
uxPriority |
The priority of the task (0 to configMAX_PRIORITIES-1), where a higher value indicates a higher priority |
|
pxCreatedTask |
An address of a TaskHandle_t pointer, where the handle of the created task will be returned upon successful creation, which is used for subsequent operations on the task |
2. What the kernel does when creating a task
(1) Allocates two spaces in the heap for the task stack and TCB (Task Control Block, which can be understood as the “identity card” for the scheduler to manage tasks)
(2) Initializes the task control block and task stack as shown in the figure below

(3) Adds the task to the ready list: If the scheduler is enabled, the kernel will insert the new task’s TCB into the corresponding ready list (in linked list form) based on the task’s priority, with the new task being inserted at the end of the priority list. If the scheduler is not enabled, its TCB will be added to the suspended ready list, and when the scheduler starts, these tasks will be moved to the actual ready list.
(4) Returns the task handle: Writes the pointer to the newly created task’s TCB (task handle TaskHandle_t) to the location pointed to by pxCreatedTask
3. Task Scheduling
FreeRTOS primarily performs task scheduling through preemptive scheduling and time-slicing.

1. Preemptive Scheduling
When a higher priority task enters the ready state, it immediately interrupts the currently executing task and forces a switch to the higher priority task.
Kernel implementation steps:
(1) When a higher priority task enters the ready state, the kernel triggers a scheduler check to determine if the current task needs to be preempted. FreeRTOS uses the PendSV exception for this.
(2) After the PendSV exception is triggered, the CPU pauses the execution of the current task and enters the PendSV exception service routine. First, it saves the context, with hardware pushing some registers onto the current task’s stack, and the rest pushed manually by software; then the scheduler finds the highest priority using uxTopReadyPriority() and retrieves the first task B from the corresponding ready list. It updates pxCurrentTCB to task B’s TCB. Finally, it removes pxTopOfStack (stack pointer) from the TCB, restores the previously saved registers, pops the registers from task B’s stack, and the CPU’s PC register is restored to the instruction address of task B at the time it was last interrupted, completing the preemption of task B.
(3) The preempted task A transitions from running state to ready state.

2. Time-Slicing Scheduling
For tasks of the same priority, FreeRTOS uses time-slicing scheduling, where each task is allocated a fixed execution time. When the current task’s time slice is exhausted and there are other ready tasks of the same priority, the scheduler forcibly switches to the next task of the same priority. Unlike Linux’s fair scheduling algorithm, FreeRTOS’s time-slicing does not depend on weight. Interested readers can refer to Linux’s scheduling methods.
Linux Process Scheduling
Call me Red Scarf jj, WeChat public account: Embedded in this area, Linux process scheduling and kernel implementation
Key implementation: Hardware timer: the trigger source for time-slice scheduling; the same priority linked list in the ready list: when the time slice is exhausted, the head task moves to the tail of the list; the scheduler’s time-slice check logic.
The time-slice scheduling’s timing trigger source is usually implemented by a hardware timer (such as the SysTick timer of ARM Cortex-M), which functions to:
Generate interrupts at a fixed period (<span>configTICK_RATE_HZ</span>, typically 100~1000Hz), referred to as “system ticks”; each Tick interrupt triggers the scheduler to check: whether there are higher priority tasks ready, and whether a task switch is needed.
Steps for implementing scheduling:
(1) After task A acquires the CPU and starts executing, assuming the system tick timer generates a SysTick interrupt every 1ms, each interrupt triggers the<span>xTaskIncrementTick()</span>function, which updates the global tick count of the system (<span>xTickCount</span>).
(2) When task A completes a time slice, the<span>xTaskIncrementTick()</span>function checks if there are other ready tasks with the same priority as the currently running task. If so, it marks “scheduling needed”.
(3) Triggers the PendSV exception, and the subsequent process is the same as described above.