Download FreeRTOS
 

Quality RTOS & Embedded Software

COMMUNITY
WHAT'S NEW
Simplifying Authenticated Cloud Connectivity for Any Device.
Designing an energy efficient and cloud-connected IoT solution with CoAP.
Introducing FreeRTOS Kernel version 11.0.0:
FreeRTOS Roadmap and Code Contribution process.
OPC-UA over TSN with FreeRTOS.

Using FreeRTOS to Improve Run Time Efficiency
Simple updates to change to an event driven structure


The previous example demonstrated how simple it was to convert the stand alone USB example into a new RTOS task for incorporation into the FreeRTOS TCP example. The demonstrated technique was however rather crude, and viewing the executing tasks in the FreeRTOS Eclipse State Viewer plug-in reveals one of the reasons why; one of the TCP related tasks and the Virtual COM / CDC task are each consuming about 50% of the total CPU time available.


Viewing the RTOS task's run-time statistics in the Eclipse plug-in


Both tasks are polling their respective interfaces without ever entering the Blocked state (if a task is in the Blocked state then it is not using any CPU time), so the real time scheduler is sharing processing time between them. This has a number of disadvantages, including:

  1. CPU time is being wasted because the tasks are running even when there is nothing to do. The wasted CPU time could be better utilised by adding more functionality into the application, or the CPU could simply be placed into a low power mode when there was no real processing that needed to be performed.

  2. The tasks have to run at the lowest priority, otherwise they will starve all lower priority tasks of getting any CPU time at all.

  3. The execution pattern and behaviour of the tasks is dependent on the both the hardware speed and other software that is running on the same device.

  4. As the behaviour of the tasks is dependent on other software that is running on the same device the interfaces they implement cannot be classified as exhibiting deterministic behaviour.

The steps on this page show how, through the addition of some simple FreeRTOS primitives, the exact same TCP and USB functionality can be obtained in a system in which the TCP and USB tasks consume a tiny fraction of the available CPU time. The image below shows the task's run time statistics after the modifications have been made. This time nearly all the CPU time is being consumed by the Idle task - which is the task that runs when there are no application tasks that need to run. Implementing an Idle task hook function that places the CPU into a low power state will save a lot of power - using FreeRTOS's tickless idle mode will save a great deal more power.


After the changes, the application has the same functionality, but the Idle task is receiving nnn% of the total run time


Two techniques are demonstrated by the workflow steps below. The first technique is very simple and just places a task into the Blocked state for a fixed period when it has nothing to do. That is effective at reducing the amount of CPU time the task uses, but does not make the task truly event driven. The second technique is more sophisticated as it makes the task truly event driven and maximises responsiveness to real world events - it places the task into the Blocked state until it receives notification from an interrupt that something has happened that requires the task's attention.


Workflow steps:
  1. It is assumed that the workflow steps on the previous pages have already been completed.

    Open the freertos_tcpecho.c source file, and search for a function called vSetupIFTask().

    The function contains a while( 1 ) loop that is monitoring the network's link status, and unless the link status has changed, it has nothing to do. The link status is not going to change very often, so does not need to be polled continuously.

    Add an 'else' part that contains a call to vTaskDelay() to the existing 'if (physts & PHY_LINK_CHANGED)' statement. As shown below the vTaskDelay() call will place the task into the Blocked state for 500ms each time it determines the link status has not changed.


    Delaying the PHY polling task when it has no actions to perform


  2. In the previous step a simple vTaskDelay() call was used to place a task into the Blocked state when it had nothing to do. That technique cannot be used with the USB task because virtual COM / CDC drivers must be very responsive. This time an RTOS semaphore is going to be used to unblock the USB task immediately that the USB task has actions to perform. The USB task is then free to Block on the RTOS semaphore, knowing it will not miss any important events.

    First the RTOS semaphore is declared by adding the following line somewhere in cdc_main.c:

    static xSemaphoreHandle xCDCEventSemaphore;
    				
    Next the RTOS semaphore is created by adding the following line at the start of the task that implements the USB Virtual COM / CDC functionality (note xSemaphoreCreateBinary() is preferred over vSemaphoreCreateBinary() from FreeRTOS V8.0.0).
    vSemaphoreCreateBinary( xCDCEventSemaphore );
    				

    cdc_main.c is now making use of FreeRTOS semaphores, so the following two lines must also be added to the top of the file:

    #include "FreeRTOS.h"
    #include "semphr.h"
    				


    Creating the RTOS semaphore


  3. Now the RTOS semaphore has been created the implementation of the virtual COM task is going to be updated to block on the RTOS semaphore using a call to xSemaphoreTake().

    Add the call to xSemaphoreTake() to the top of the while( 1 ) loop within the implementation of cdc_task() (still in the cdc_main.c source file).


    Updating the USB task's implementation so it blocks on the semaphore


  4. Now the RTOS semaphore has been declared and created, and the task is blocking on the RTOS semaphore, the final edit is to ensure the USB CDC interrupt gives the RTOS semaphore by calling xSemaphoreGiveFromISR() each time it is called. Giving the RTOS semaphore unblocks the USB task to allow the task to perform any processing necessitated by the interrupt.

    Update the USB_IRQHandler() function in cdc_main.c as per the image below.


    Updating the interrupt handler to 'give' the semaphore


  5. Finally, verify that the updated application provides the exact same functionality, but using a fraction of the CPU resources, by building, downloading and executing the example for one last time.


    Typing text into a Tera Term window that is connected to the virtual COM/CDC port



    Receiving ping replies from the LPC1834 target





Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.