This is a traditional preemptive multitasking solution. It makes full use of the RTOS services with no regard to the resultant memory and processor overhead. There is a simplistic partitioning of the required functionality to a number of autonomous tasks.
A separate task is created for each part of the system that can be identified as being able to exist in isolation, or as having a particular timing requirement.

Tasks will block until an event indicates that processing is required. Events can either be external (such as a key being pressed), or internal (such as a timer expiring).
Priorities are allocated to tasks in accordance to their timing requirements. The stricter the timing requirement the higher the priority.
The highest priority task that is able to execute (is not blocked) is the task guaranteed by the RTOS to get processor time. The kernel will immediately suspend an executing task should a higher priority task become available.
This scheduling occurs automatically, with no explicit knowledge, structuring or commands within the application source code. It is however the responsibility of the application designers to ensure that tasks are allocated an appropriate priority.
When no task is able to execute the idle task will execute. The idle task has the option of placing the processor into power save mode.
The scheduler is configured for preemptive operation. The kernel tick frequency should be set at the slowest value that provides the required time granularity.
![]() |
Simple, segmented, flexible, maintainable design with few interdependencies. |
![]() |
Processor utilisation is automatically switched from task to task on a most urgent need basis with no explicit action required within the application source code. |
![]() |
Power consumption can be reduced if the idle task places the processor into power save (sleep) mode, but may also be wasted as the tick interrupt will sometimes wake the processor unnecessarily. |
![]() |
The kernel functionality will use processing resources. The extent of this will depend on the chosen kernel tick frequency. |
![]() |
This solution requires a lot of tasks, each of which require their own stack, and many of which require a queue on which events can be received. This solution therefore uses a lot of RAM. |
![]() |
Frequent context switching between tasks of the same priority will waste processor cycles. |
This can be a good solution provided the RAM and processing capacity is available. The partitioning of the application into tasks and the priority assigned to each task requires careful consideration.
This example is a partial implementation of the hypothetical application introduced previously. The FreeRTOS.org API is used.
This task implements all the control functionality. It has critical timing requirements and is therefore given the highest
priority within the system:
#define CYCLE_RATE_MS 10
#define MAX_COMMS_DELAY 2
void PlantControlTask( void *pvParameters )
{
portTickType xLastWakeTime;
DataType Data1, Data2;
InitialiseTheQueue();
// A
xLastWakeTime = xTaskGetTickCount();
// B
for( ;; )
{
// C
vTaskDelayUntil( &xLastWakeTime, CYCLE_RATE_MS );
// Request data from the sensors.
TransmitRequest();
// D
if( xQueueReceive( xFieldBusQueue, &Data1, MAX_COMMS_DELAY ) )
{
// E
if( xQueueReceive( xFieldBusQueue, &Data2, MAX_COMMS_DELAY ) )
{
PerformControlAlgorithm();
TransmitResults();
}
}
}
// Will never get here!
}
Referring to the labels within the code fragment above:
A return value of 0 from xQueueReceive() indicates that no data arrived within the specified block period. This is an error condition the task must handle. This and other error handling functionality has been omitted for simplicity.
The embedded WEB server task can be represented by the following pseudo code. This only
utilises processor time when data is available but will take a variable and relatively long time to complete. It is therefore given a low
priority to prevent it adversely effecting the timing of the plant control, RS232 or keypad scanning tasks.
void WebServerTask( void *pvParameters )
{
DataTypeA Data;
for( ;; )
{
// Block until data arrives. xEthernetQueue is filled by the
// Ethernet interrupt service routine.
if( xQueueReceive( xEthernetQueue, &Data, MAX_DELAY ) )
{
ProcessHTTPData( Data );
}
}
}
This is very similar in structure to the embedded WEB server task. It is given a medium priority to ensure it does not adversely effect
the timing of the plant control task.
void RS232Task( void *pvParameters )
{
DataTypeB Data;
for( ;; )
{
// Block until data arrives. xRS232Queue is filled by the
// RS232 interrupt service routine.
if( xQueueReceive( xRS232Queue, &Data, MAX_DELAY ) )
{
ProcessSerialCharacters( Data );
}
}
}
This is a simple cyclical task. It is given a medium priority as it's timing requirements are similar to the RS232 task.
The cycle time is set much faster than the specified limit. This is to account for the fact that it may not get processor time immediately upon request - and once executing may get pre-empted by the plant control task.
#define DELAY_PERIOD 4
void KeyScanTask( void *pvParmeters )
{
char Key;
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
for( ;; )
{
// Wait for the next cycle.
vTaskDelayUntil( &xLastWakeTime, DELAY_PERIOD );
// Scan the keyboard.
if( KeyPressed( &Key ) )
{
UpdateDisplay( Key );
}
}
}
If the overall system timing were such that this could be made the lowest priority task then the call to vTaskDelayUntil() could be removed altogether.
The key scan function would then execute continuously whenever all the higher priority tasks were blocked - effectively taking
the place of the idle task.
This is the simplest of all the tasks.
#define DELAY_PERIOD 1000
void LEDTask( void *pvParmeters )
{
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
for( ;; )
{
// Wait for the next cycle.
vTaskDelayUntil( &xLastWakeTime, DELAY_PERIOD );
// Flash the appropriate LED.
if( SystemIsHealthy() )
{
FlashLED( GREEN );
}
else
{
FlashLED( RED );
}
}
}
NEXT >>> Solution #3: Reducing RAM utilisation
Any and all data, files, source code, html content and documentation included in the FreeRTOS distribution or available on this site are the exclusive property of Richard Barry.
See the files license.txt (included in the distribution) and this copyright notice for more information. FreeRTOSTM and FreeRTOS.orgTM are trade marks of Richard Barry.