4

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.

Kamuffel
  • 592
  • 1
  • 6
  • 17

1 Answers1

10

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.

jdc
  • 680
  • 1
  • 8
  • 11
  • 1
    `_delay_ms` is (most probably) AVR implementation for delay. It does not interact with RTOS and calling it will actually block everything for 100ms, if it is called from higest-priority task. Otherwise delay might be even few days (depends on higher priority tasks..). Always use RTOS based delay function. – unalignedmemoryaccess Jul 03 '18 at 06:55
  • @tilz0R Thanks for the additional explanation, which I was exactly looking for. I am aware that vTaskDelay should be used. I was wondering what would happend to the flow of a program if you would use the AVR function `_delay_ms` instead of `vTaskDelay`. – Kamuffel Jul 03 '18 at 11:45
  • `vTaskDelay` will put your task to blocked state for `100ms` and will execute other tasks in the meantime. When `100ms` time passes, task will go back to `runnable` state and scheduler will pick it next time. In case of `_delay_ms`, you don't have this option as _delay_ms runs with for loop and this for loop must be executed by number of cycles. If you switch task in between cycles, you will continue when you are back to this task (if you are ever back). Don't try to use _delay_ms. – unalignedmemoryaccess Jul 03 '18 at 11:47