vTaskDelay() not giving consistent times

mattbudd wrote on Friday, June 06, 2008:

I have a problem with vTaskDelay. What I want to do is perform an action on a regular task once every tick, and then every say 100 ticks (1 second in my config) have a periodic task wake up and report on the status of the regular task. Here is my code:

//--------------------------------------------------------------
portTASK_FUNCTION_PROTO(regularTask, ppvParameters);
portTASK_FUNCTION_PROTO(periodicTask, ppvParameters);

static volatile unsigned int m_iCounter = 0;

void CreateTasks(void)
{
    xTaskCreate(regularTask, "reg", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
    xTaskCreate(periodicTask, "per", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, NULL);
}

portTASK_FUNCTION(regularTask, ppvParameters)
{
    while (1)
    {
        m_iCounter++;
        vTaskDelay(1);
    }
}

portTASK_FUNCTION(periodicTask, ppvParameters)
{
    while (1)
    {
        vTaskDelay(1000 / portTICK_RATE_MS);
        CSLog("counter = %d, tickcount = %d", m_iCounter, xTaskGetTickCount()); //This just logs to the debug window
    }
}
//--------------------------------------------------------------

So the periodic task is a higher priority, but it doesn’t seem to fire off every 1 second…it takes about 3 or 4 second to fire off. If I take out the “vTaskDelay(1)” in the regular task, it will fire off at the correct speed, but then m_iCounter gets updated more than once per tick. How do I yield the regular task to the next tick…taskYield() seems have the same issue.
Any ideas?

davedoors wrote on Friday, June 06, 2008:

If you just call taskYIELD() then you are not delaying so FreeRTOS will just choose the same task to run again.

If you call vTaskDelay( 1 ) then you are on the limit of the resolution and the period you delay for will depend on where in the current time slice the function is called. This is also very inefficient.

Can you replace regularTask with a tick hook? http://www.freertos.org/a00016.html

mattbudd wrote on Friday, June 06, 2008:

Thanks for your help. Some further comments:

1. So then I would expect that if I called taskYIELD() that is would be the same as having no statement in there at all (since this is the only task (besides the idle task) that is in the ready state), so like you say it would give execution right back to the “regular” task. However, I don’t see that…if I use taskYIELD() it still takes about 4 seconds for my periodic guy to fire and the regular task still fires once per tick.

2. So lets say I simplify the "regular task" like this:
    while (1)
    {
        //Do nothing except sleep
        vTaskDelay(1);
    }
Why do I still see the problem? Why would a task that executes during every tick at lower priority affect the overall time duration of the tick. The periodic task is still waiting 100 ticks, its just that those ticks are taking 4 times as long to happen. And nothing else is going on in the system besides the idle task and the regular task that does nothing except sleep. Does the overhead of switching to a task every tick really lengthen the tick period that much?

3. I can’t use a tick hook, because this problem/code is not really what I am trying to do. It is just a sample that demonstrates the same problem I am having in my much more complicated code. I stripped it down to this ficticious example to make it really simple for people to analyze.

mattbudd wrote on Friday, June 06, 2008:

A updated code listing for the simplified version:

//--------------------------------------------------------------
portTASK_FUNCTION_PROTO(regularTask, ppvParameters);
portTASK_FUNCTION_PROTO(periodicTask, ppvParameters);

void CreateTasks(void)
{
xTaskCreate(regularTask, "reg", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
xTaskCreate(periodicTask, "per", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, NULL);
}

portTASK_FUNCTION(regularTask, ppvParameters)
{
while (1)
{
vTaskDelay(1);
}
}

portTASK_FUNCTION(periodicTask, ppvParameters)
{
while (1)
{
vTaskDelay(1000 / portTICK_RATE_MS);

//ERR: I don’t get here every second…I get here about every 4 seconds. Why?
CSLog(“tickcount = %d”, xTaskGetTickCount());
}
}
//--------------------------------------------------------------