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.
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:
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.
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.
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.
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"
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).
Update the USB_IRQHandler() function in cdc_main.c as per the image below.