grzegorz
grzegorz

Reputation: 340

FreeRTOS vTaskDelayUntil() finishes immediately

I have a problem with vTaskDelayUntil() function not making a delay but finishing immediately. Here is the code:

TickType_t xLastWakeTime = xTaskGetTickCount();
while(1){
    if (xSemaphoreTake(xSemaphoreRS485, portMAX_DELAY) == pdTRUE) {
        printf("S display data %d\n", xTaskGetTickCount());
        sendDisplayData();
        printf("E display data %d\n", xTaskGetTickCount());
        xSemaphoreGive(xSemaphoreRS485);
        printf("W display data %d\n", xLastWakeTime);
        vTaskDelayUntil(&xLastWakeTime, 2000);
    }
}

From this I get following output:

S display data 29928
E display data 30534
W display data 3919
S display data 30534
E display data 31140
W display data 5919
S display data 31140
E display data 31746
W display data 7919
S display data 31746
E display data 32352
W display data 9919

The function sendDisplayData() takes about 670 ms to execute and xTaskGetTickCount() confirms it. Then the task should wait around 1230 ms so the whole iteration could take 2000 ms. But vTaskDelayUntil() finishes immediately. First execution ended at 30534 and the second one starts at 30534 too. Value returned by xTaskGetTickCount() proves there was no delay introduced by vTaskDelayUntil(). I can also see it by frequency of output of sendDisplayData().

The second funny thing is that xLastWakeTime shows totally different values and those values are in fact incremented by 2000. Shouldn't it store similar value as returned by xTaskGetTickCount()?

Upvotes: 3

Views: 5745

Answers (2)

Richard
Richard

Reputation: 3246

As per above, vTaskDelayUntil() will return immediately if the specified wake time is already in the past. Suggest using vTaskDelay() instead.

Upvotes: 2

Clifford
Clifford

Reputation: 93566

In your first iteration xLastWakeTime has value 3919, and you request an increment of 2000, so a delay until 5919, but you have called it at time 30534.

From the documentation of vTaskDelayUntil()

It should be noted that vTaskDelayUntil() will return immediately (without blocking) if it is used to specify a wake time that is already in the past.

Your task spent 26009 ticks (29928 - 3919) blocked on the initial semaphore. Your target 2000 tick increment has long past.

I would suggest the following is nearer at least to what you intended

for(;;)
{
    if (xSemaphoreTake(xSemaphoreRS485, portMAX_DELAY) == pdTRUE)  // Lock
    {
        TickType_t xLastWakeTime = xTaskGetTickCount();
        sendDisplayData();
        xSemaphoreGive(xSemaphoreRS485); // Unlock

        vTaskDelayUntil(&xLastWakeTime, 2000);
}

This will make the loop iteration take 2000 ticks in total including the time taken to execute sendDisplayData() plus the time waiting for the RS485 resource to become available, which is I think what you intended.

Upvotes: 7

Related Questions