Search code examples
cmultithreadingschedulingavrfreertos

What is the behavioral difference between vTaskDelay and _delay_ms?


1. Introduction

I cannot seem to find information or a detailed explanation about the behavioral differences between the following functions in a FreeRTOS task:

  • vTaskDelay
  • _delay_ms

2. Code

Suppose you have the following codes:

IdleHook + task creation

Long value = 0;

void vApplicationIdleHook( void ) {
    while(1)
    {
        // empty
    }
}

int main(void)
{
     xTaskCreate(TaskIncrement, (const portCHAR *)"up" , 256, NULL, 2, NULL );
     xTaskCreate(TaskDecrement, (const portCHAR *)"down" , 256, NULL, 1, NULL );

     vTaskStartScheduler();
}

Tasks with vTaskDelay

static void TaskDecrement(void *param)
{
    while(1)
    {
        for(unsigned long i=0; i < 123; i++) {
            //semaphore take
            value--;
            //semaphore give
        }
        vTaskDelay(100);
    }
}

static void TaskIncrement(void *param)
{
    while(1)
    {
        for(unsigned long i=0; i < 123; i++) {
            //semaphore take
            value++;
            //semaphore give
        }
        vTaskDelay(100);
    }
}

Tasks with _delay_ms

static void TaskDecrement(void *param)
{
    while(1)
    {
        for(unsigned long i=0; i < 123; i++) {
            //semaphore take
            value--;
            //semaphore give
        }
        _delay_ms(100);
    }
}

static void TaskIncrement(void *param)
{
    while(1)
    {
        for(unsigned long i=0; i < 123; i++) {
            //semaphore take
            value++;
            //semaphore give
        }
        _delay_ms(100);
    }
}

3. Question

What happens with the flow of the program when the tasks are provided with a vTaskDelay versus _delay_ms?

Note: the two given example tasks have different priorities.


Solution

  • From https://www.freertos.org/Documentation/FreeRTOS_Reference_Manual_V10.0.0.pdf:

    Places the task that calls vTaskDelay() into the Blocked state for a fixed number of tick interrupts. Specifying a delay period of zero ticks will not result in the calling task being placed into the Blocked state, but will result in the calling task yielding to any Ready state tasks that share its priority. Calling vTaskDelay(0) is equivalent to calling taskYIELD().

    I think you get the idea already, but if you have multiple tasks created, then vTaskDelay() will put the running task into the "Blocked" state for the specified number of tick interrupts (not milliseconds!) and allow the task with the next highest priority to run until it yields control (or gets preempted, depending on your FreeRTOS configuration).

    I don't think _delay_ms() is part of the FreeRTOS library. Are you sure it's not a platform specific function? My guess is, if the highest priority task calls _delay_ms(), then it will result in a busy wait. Otherwise, a task with a higher priority may preempt the task that calls _delay_ms() as it is delaying (that is, _delay_ms() will not yield control immediately).

    Perhaps a better summary of the above: in a multitasking application, _delay_ms() is not deterministic.