Updated Jul 2025
Symmetric Multiprocessing (SMP) with FreeRTOS
SMP support in the FreeRTOS Kernel enables one instance of
the FreeRTOS kernel to schedule tasks across multiple identical processor cores.
The core architectures must be identical and share the same memory.
Getting Started with FreeRTOS and SMP
The simplest way to get started is to use one of the following pre-configured example projects:
Modifying an Application to use FreeRTOS SMP Functionality
The FreeRTOS API remains substantially the same between single core and SMP versions except for these additions. Therefore, an application written for the FreeRTOS single core version should compile with the SMP version with minimal to no effort. However, there may be some functional issues, as some assumptions which were true for single core applications may no longer be true for multi-core applications.
One such common assumption is that a lower priority task cannot run while a higher priority task is running. While this was true on a single core, it is no longer true for multi-cores, as multiple tasks can be running simultaneously. If the application relies on relative task priorities to provide mutual exclusion, it may observe unexpected results in a multi-core environment. The application writer has couple of options to address this:
-
The best option is to update the application so that it does not rely on task priorities and uses synchronization primitives instead.
-
Another option is to pin all the tasks which must not be running simultaneously to one core using the
API.vTaskCoreAffinitySet -
Another option is to define
toconfigRUN_MULTIPLE_PRIORITIESwhich ensures that multiple tasks will run simultaneously only if they have the same priority. Note that this may result in under utilization and put some cores to idle when they could be used to run other low priority tasks.0
One other common assumption is that ISRs cannot run simultaneously with each other or with other tasks. This is no longer true in a multi-core environment and the application writer needs to ensure proper mutual exclusion while accessing data shared between tasks and ISRs. The macros
taskENTER_CRITICAL_FROM_ISR()
taskEXIT_CRITICAL_FROM_ISR()
taskENTER_CRITICAL()
taskEXIT_CRITICAL()
SMP Specific APIs
These additional APIs are available to the FreeRTOS-SMP kernel:
vTaskCoreAffinitySet
1void vTaskCoreAffinitySet( const TaskHandle_t xTask, UBaseType_t uxCoreAffinityMask );
configUSE_CORE_AFFINITY
1
Sets the core affinity mask for a task, i.e. the cores on which a task can run.
Parameters:
-
- The handle of the task that the core affinity mask is for. PassingxTaskwill set the core affinity mask for the calling task.NULL
-
- A bitwise value that indicates the cores on which the task can run. Cores are numbered fromuxCoreAffinityMaskto0. For example, to ensure that a task can run on coreconfigNUM_CORES - 1and core0, set1touxCoreAffinityMask.0x03
Example Usage:
1/* The function that creates task. */2void vAFunction( void )3{4TaskHandle_t xHandle;5UBaseType_t uxCoreAffinityMask;67 /* Create a task, storing the handle. */8 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &( xHandle ) );910 /* Define the core affinity mask such that this task can only run on core 011 * and core 2. */12 uxCoreAffinityMask = ( ( 1 << 0 ) | ( 1 << 2 ) );1314 /* Set the core affinity mask for the task. */15 vTaskCoreAffinitySet( xHandle, uxCoreAffinityMask );16}
vTaskCoreAffinityGet
1UBaseType_t vTaskCoreAffinityGet( const TaskHandle_t xTask );
configUSE_CORE_AFFINITY
1
Gets the core affinity mask for a task, i.e. the cores on which a task can run.
Parameters:
- - The handle of the task that the core affinity mask is for. PassingxTaskwill get the core affinity mask for the calling task.NULL
Returns:
- The core affinity mask, which is a bitwise value that indicates the cores on
which a task can run. Cores are numbered from to0. For example, if a task can run on coreconfigNUM_CORES - 1and core0, the core affinity mask is1.0x03
Example Usage:
1/* Task handle of the networking task - it is populated elsewhere. */2TaskHandle_t xNetworkingTaskHandle;34void vAFunction( void )5{6TaskHandle_t xHandle;7UBaseType_t uxNetworkingCoreAffinityMask;89 /* Create a task, storing the handle. */10 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &( xHandle ) );1112 /* Get the core affinity mask for the networking task. */13 uxNetworkingCoreAffinityMask = vTaskCoreAffinityGet( xNetworkingTaskHandle );1415 /* Here is a hypothetical scenario, just for the example. Assume that we16 * have 2 cores - Core 0 and core 1. We want to pin the application task to17 * the core that is not the networking task core to ensure that the18 * application task does not interfere with networking. */19 if( ( uxNetworkingCoreAffinityMask & ( 1 << 0 ) ) != 0 )20 {21 /* The networking task can run on core 0, pin our task to core 1. */22 vTaskCoreAffinitySet( xHandle, ( 1 << 1 ) );23 }24 else25 {26 /* Otherwise, pin our task to core 0. */27 vTaskCoreAffinitySet( xHandle, ( 1 << 0 ) );28 }29}
vTaskPreemptionDisable
1void vTaskPreemptionDisable( const TaskHandle_t xTask );
configUSE_TASK_PREEMPTION_DISABLE
1
Disables preemption for a task.
Parameters:
- - The handle of the task for which preemption will be disabled. PassingxTaskdisables preemption for the calling task.NULL
Example Usage:
1void vTaskCode( void *pvParameters )2{3 /* Silence warnings about unused parameters. */4 ( void ) pvParameters;56 for( ;; )7 {8 /* ... Perform some function here. */910 /* Disable preemption for this task. */11 vTaskPreemptionDisable( NULL );1213 /* The task will not be preempted when it is executing in this portion ... */1415 /* ... until the preemption is enabled again. */1617 vTaskPreemptionEnable( NULL );1819 /* The task can be preempted when it is executing in this portion. */20 }21}
vTaskPreemptionEnable
1void vTaskPreemptionEnable( const TaskHandle_t xTask );
configUSE_TASK_PREEMPTION_DISABLE
1
Enables preemption for a task.
Parameters:
- - The handle of the task for which preemption will be enabled. PassingxTaskenables preemption for the calling task.NULL
Example Usage:
1void vTaskCode( void *pvParameters )2{3 /* Silence warnings about unused parameters. */4 ( void ) pvParameters;56 for( ;; )7 {8 /* ... Perform some function here. */910 /* Disable preemption for this task. */11 vTaskPreemptionDisable( NULL );1213 /* The task will not be preempted when it is executing in this portion ... */1415 /* ... until the preemption is enabled again. */16 vTaskPreemptionEnable( NULL );1718 /* The task can be preempted when it is executing in this portion. */19 }20}
SMP Specific Hook Functions
Minimal Idle Hook Function
The FreeRTOS SMP kernel has two type of Idle tasks:
-
Idle Task - There is the standard Idle task used in single core FreeRTOS applications.
-
Minimal Idle Tasks - There are
Minimal Idle tasks which are run on idle cores and which do nothing.configNUM_CORES - 1
The minimal idle tasks can optionally call an application-defined hook (or callback) function - the minimal idle hook. The minimal idle tasks run at the very lowest priority, so such an idle hook function will only run when there are no tasks of higher priority that are able to run.
The minimal idle hook will only get called if
configUSE_MINIMAL_IDLE_HOOK
1
FreeRTOSConfig.h
1void vApplicationMinimalIdleHook( void );
The minimal idle hook is called repeatedly by the minimal idle tasks as long as any one of them is running. It is paramount that the minimal idle hook function does not call any API functions that could cause it to block.
SMP Specific Configuration Options
These additional configuration options are available to the FreeRTOS-SMP Kernel:
- configNUM_CORES
- configRUN_MULTIPLE_PRIORITIES
- configUSE_CORE_AFFINITY
- configUSE_TASK_PREEMPTION_DISABLE
configNUM_CORES
Sets the number of available processor cores.
configRUN_MULTIPLE_PRIORITIES
In a single core FreeRTOS application, a lower priority task will never run if there is a higher priority task that is able to run. In an SMP FreeRTOS application the RTOS kernel will run as many tasks as there are cores available - so it is possible that a lower priority task will run on one core at the same time as a higher priority task runs on another core. That can cause a problem if your application or library was written for a single core environment, and so makes assumptions about the order in which tasks execute. Therefore configRUN_MULTIPLE_PRIORITIES is provided to control this behaviour.
If
configRUN_MULTIPLE_PRIORITIES
0
configRUN_MULTIPLE_PRIORITIES
1
configUSE_CORE_AFFINITY
Allows the application writer to control which cores a task can run on. If
configUSE_CORE_AFFINITY
1
vTaskCoreAffinitySet
vTaskCoreAffinityGet
configUSE_CORE_AFFINITY
configUSE_TASK_PREEMPTION_DISABLE
In a single core FreeRTOS application the FreeRTOS scheduler can be configured to be either pre-emptive or co-operative. See the definition of configUSE_PREEMPTION. In SMP FreeRTOS application, if
configUSE_TASK_PREEMPTION_DISABLE
1
vTaskPreemptionDisable
vTaskPreemptionEnable