VTaskDelayUntil and VTaskResume Problem

chaalar wrote on Tuesday, June 26, 2007:

Hi,

I have strange problem about task resuming/suspending I guess which is related to vTaskDelayUntil function.

I have two tasks, one is running periodically hence using vTaskDelayUntil, and the other one is syncronized to an interrupt. When I receive an interrupt which rarely fires, I suspend other task for some time, do some spi transfer and then resume other task. The problem is that after I resumed other task whole freeRTOS behaves strange. It seems like my periodic task never delays itself anymore, it never gives processor anyway, eventough it has the lowest priority.

I searched the forum but unable to find some clue. My port is SAM7X GCC port, I’m also using version 4.0.0. I couldn’t find any related changes in the changelog, also.

Thanks for your comments.

Best Regards
Caglar Akyuz

jorick23 wrote on Tuesday, June 26, 2007:

Here are some checks you can do:

1. Make sure you have enough stack available for the interrupt.
2. Make sure you are clearing the interrupt correctly prior to exiting the interrupt.  Failure to clear the interrupt will cause the interrupt to be entered again immediately after returning.

davedoors wrote on Tuesday, June 26, 2007:

Are you suspending the task from within the interrupt?  There is a vTaskResumeFromISR() function, but no vTaskSuspendFromISR() equivalent.  You could write one easily enough, or use a different method to suspend the task.

chaalar wrote on Wednesday, June 27, 2007:

Sorry for the lack of information in the original post.

Actually I’m not suspending/resuming from the interrupt context. I’m suspending/resuming in an other task which is also have higher priority. Moreover, I’m suspending/resuming three task. Two of them have no problem with this scheme, but the suspending/resuming third one causes the problem. One note which may worth mentioning is other two tasks are waiting on the queues for an event but this third one does not. Instead, it is uses vTaskDelayUntil to perform its job at every 500 ms. If I don’t suspend/resume this third task everything is ok.

I also double checked the stack sizes, I increased all the stack sizes(for interrupts also) almost two times for each. It didn’t help.

I can also solve this situation in another way, but I’m wondering why this is happening.

Thanks

Caglar Akyuz

davedoors wrote on Wednesday, June 27, 2007:

There is a subtle difference with the way in which suspending your two tasks would work.

If a task is suspended while it is blocked on a queue, when it is then resumed it will continue to be blocked on the queue to wait for the rest of its timeout to expire.

If a task is blocked on a DelayUntil call, when the task is resumed it will leave the DelayUntil call even if its timeout has not expired.

Would this explain the behavior you are seeing?

chaalar wrote on Wednesday, June 27, 2007:

Yes, this is exactly the case, I guess. However, at next loop in the task it should wait again in the vTaskDelayUntil, shouldn’t it?

After resuming, task is running uninterrupted, even vTaskDelayUntil doesn’t work. I’m toggling a pin in this task, before suspend/resume operation, led is blanking at every 500 milliseconds. After suspending/resuming led blinks with a period of ~20 microseconds.

Best Regards
Caglar Akyuz

acehigh1971 wrote on Friday, July 06, 2007:

Hi all.

I’ve run in the same problem some time ago, and now again (in another application).

I run in the same situation which is a lot strange: the task stops blocking on vTaskDelayUntil after it is suspended and resumed, and runs uninterrupted.
You could simply verify this by replacing the call to vTaskDelayUntil with vTaskDelay (Yes, I know it’s not the same but a lot of times it is ok…)

I think Richard Barry should consider this as a problem.

P.S. I use Arm7 with Gcc compiler

embeddedc wrote on Friday, July 06, 2007:

The function will return straight away if it thinks the time you have requested to unblock has already passed.  When this situation occurs simple step into the function to see why it does not block.  Most likely the value in the first parameter to the function has become corrupt.  Stack problem?

acehigh1971 wrote on Monday, July 09, 2007:

Hi all,
I’m doing some debug and the results are the following (not finished yet):

- Not a stack problem. I did a check on stack size and no problem came out, but:

The variable that I pass to vTaskDelayUntil gets incremented by one delay time between the suspend call and the resume call!
When I do the first call to vTaskDelayUntil after resuming that task, it is found that the lastwaketime is greater than the actual tick, so the task never blocks, but keeps increasing the lastwaketime variable.

Now I have to understand why this happens. Any help is accepted.

acehigh1971 wrote on Monday, August 06, 2007:

I decided in the end to remove all the calls to vTaskDelayUntil with vTaskDelay and take into account the error that could derive from this.
Anybody can help me, anyway?

Thanks in advance.

acehigh1971 wrote on Tuesday, August 07, 2007:

Hello all,

After completing the development, I decided to do some debug on vTaskDelayUntil behaviour, to support my previous statements (and to correct some of them).

I wrote a simple task that resembles the following:

static portTASK_FUNCTION( vTESTTASKTask, pvParameters)
{
    (void) pvParameters;
   
    
     xLastWakeTime = xTaskGetTickCount();
    
    for(;:wink:
    {
            uint32_t ciclo;
       
            B = 4567;
           
            for (ciclo=0;ciclo<=1800;ciclo++)
            {
                A = B * ciclo;
            }
           
           
        vTaskDelayUntil(&xLastWakeTime,10/portTICK_RATE_MS);
    }
}

Everything works fine. I preload  the tick count in xLastWakeTime, and, at the end of the operations, I call the vTaskDelayUntil to precisely run again after 10ms.
Note: Without optimisation, the computation cycle lasts some 2ms.

Suppose you have the tick time at 9400, and the xLastWakeTime is put at 9405. The task is now "blocked" waiting for the timer to expire.
The problem arises when another task does a vTaskSuspend on this task. The task goes to "suspend state".

Then the tick timer goes up (eg. to 10000), and I do a call to vTaskResume. the wake time is still set at 9405, but the tick is 10000.
The task now does not block on the timer, and the task runs freely, without blocking on the vTaskDelayUntil call (In every vTaskDelayUntil call, the xLastWakeTime is increased of 10/portTICK_RATE_MS counts per call).
Depending on how fast is the task (how many tick it gets to execute), after a lot of free loops of the task, finally the lastwaketime reaches and overpasses the os ticktime, finally allowing the task to block on the vTaskDelayUntil call.
This causes, obviously, to use all the available processing time, respecting the task priorities, to recover the lost time.

If, after a suspend/resume I would not like this behaviour but a 10 ms constant execution, I see only the following solution:
Reset the xLastWakeTime value to the actual TickTime value, before the vTaskResume call.
Not quite elegant, because the xLastWakeTime must be in this case a global variable.

My question now is this: Is this behaviour intended? Am I doing something wrong? Should this be noted down in the API documentation?
I have seen that is quite usual to
stop the execution of a task by suspending it if needed by another "controller" task, and by resuming it when required again to operate.
The vTaskDelayUntil always falls into this pitfall.
I would really prefer to have the lastwaketime updated automatically in the call to vTaskDelayUntil, so not having the xLastWakeTime variable defined as global.
Is this wrong?

P.S. I haven’t done any consideration on tick timer overflow, I prefer to leave this to the OS writer.

rtel wrote on Tuesday, August 07, 2007:

The behviour you describe is as the intended behaviour - and as you describe the system is doing exactly what you are telling it to do.  If you request that a task wakes at some point in the past then it should not go to sleep.

There was a thread some time back where somebody had the same issue and I think I explained what was going on there.

I don’t think it would be easy to change this behaviour as the task that suspends the blocked task has no knowledge of the blocked tasks state.  Likewise the task that is suspended then resumed has no knowledge that this has happened.  You could add data into the TCB to indicate the situation, but this would be RAM that in most cases would never get used.  Also, you would have to know how to behave when such a situation occurred?  Should the periodic task run immediately when unsuspended, or just have its block time adjusted - and if so to when?  This is very application specific behaviour.

One sledge hammer approach I suppose would be for the periodic task to check its wake time once within its periodic function (in the application code, not in the RTOS code) - and if it sees that it is more than one period behind the current time to assume the situation has occurred and then take action to correct its next wake time.  This way you would only spin round the function once.  The current wake time can be obtained using the xTaskGetTickCount() function.

Regards.

acehigh1971 wrote on Tuesday, August 07, 2007:

Thanks for the quick answer, and for the suggestions (and thanks for the great job on freertos…).
I think that exiting the vTaskDelayUntil call would be the correct point to check for this situation, and correct the wake time for my needs, without having to define the variable as global. The same task is controlling its own wake time.

P.S.: Could a brief note on the docs be inserted, anyway? :slight_smile:

rtel wrote on Tuesday, August 07, 2007:

>P.S.: Could a brief note on the docs be inserted, anyway? :slight_smile:

How is this?

acehigh1971 wrote on Monday, August 13, 2007:

Ah…

This is fine. Thank you Richard.