
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). This event driven approach means that no CPU time is wasted polling for events that have not occurred.
Priorities are allocated to tasks in accordance to their timing requirements. The stricter the timing requirement the higher the priority (not all priority assignment assessments are that simplistic).
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.
![]() |
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. |
![]() |
The event driven structure ensures that no CPU time is wasted polling for events that have not occurred. Processing is only performed when there is work needing to be done. |
![]() |
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. |
#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:
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 );
}
}
}
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 );
}
}
}
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.
#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 Real Time Engineers Ltd..
See the files license.txt (included in the distribution) and this copyright notice for more information. FreeRTOSTM and FreeRTOS.orgTM are trade marks of Real Time Engineers Ltd..