# 3. Using delays

In this tutorial, we will illustrate the need for an OS-aware waiting mechanism in the tasks. Let-us compare the effect of using of the vTaskDelay() OS function to a stupid delay implementation using the usual loop-counting idea.

/*
*	Task1 toggles LED every 30ms
*/
{
while(1)
{
BSP_LED_Toggle();
}
}

/*
*	Task2 sends a message to console every 100ms
*/
{
uint16_t 	count;
uint32_t	i;

count = 0;

while(1)
{
count++;

// Let us try a stupid delay
for(i=0; i<1000000; i++);
}
}

Save all , build , start the debugger  et run the application. You'll get the console message:

but no blinking LED. Why is that?

Only you know that the counting loop is there for a delay. The OS scheduler just considers this is something the task has to do. Since the never ending loop of Task_2 never pauses, and because Task_2 is of highest priority, there is no chance for Task_1 to ever execute.

Below is the trace properties after several seconds of recording. Only 40 events have been captured, for a total duration of 75µs. How come?

The time line provides an explanation: startup events are first recorded, as expected. Then Task_2 is started. From this point, no kernel event never occurs because Task_2 never stops. There's nothing left to record, and there is even no evidence of a Task_1 waiting somewhere...

/*
*	Task1 toggles LED every 30ms
*/
{
uint32_t	i;

while(1)
{
BSP_LED_Toggle();

// Let us try the stupid delay here, now.
for(i=0; i<100000; i++);
}
}

/*
*	Task2 sends a message to console every 100ms
*/
{
uint16_t 	count;

count = 0;

while(1)
{
count++;
}
}

This time, the application seems to work fine, both processes are executed as expected. Nevertheless, looking at the execution trace, on can see that Task_1 takes more than 90% of the CPU time... for blinking a LED (what a shame)! And it only works because Task_1 has the lowest priority level. Any task with a priority level lower than the one of Task_1 would never execute.

As a conclusion, this little experiment clearly shows that you need, somewhere in every task loop, an OS aware waiting mechanism, otherwise there is no CPU time left to execute other tasks. When the task only need to wait for a known amount of time, vTaskDelay(), or vTaskDelayUntil() must be used, instead of any other non-OS delay functions.

When the task needs to wait an unknown time, for something to happen, say an event coming from other tasks, or from an external input, then other kernel objects are used. This includes semaphores, message queues, events, timers...

 Commit name "Wrong delay"  Push onto Gitlab

Stay tuned!