A question or two about tickless support.

2013-01-30
2013-09-16
  • Travis Griggs

    Travis Griggs - 2013-01-30

    Struggling to get tickless support working for our xmega256a3 port of freertos. Looking around, trying to understand under the hood better, I was surprised to see the following line in vTaskStepTick():

        configASSERT( xTicksToJump <= xNextTaskUnblockTime );

    I don't have configASSERT turned on, but I would think that if I did, that would be raising issues regularly. xTicksToJump is a delta time, but xNextTaskUnblockTime, if I read the code correctly, is an absolute tick time? Did I get that wrong?

    My sleep function, patterned after the documentation example is here: http://nopaste.info/f775342807.html. If anyone sees an obvious problem there, I would love to hear it. The behavior it demonstrates is kind of interesting. For testing, I'm running a simple task loop that delays 2000ms, and then simply toggles a pin I can watch on my scope. Adding some printf's to my function there, it will do the first one correctly, but after I exit it, it immediately reenters, but with a near 65535 value. Which it dutifully waits out, and then gets the next one correct again, and then wrong (long) again, alternating back and forth.

     
  • Richard

    Richard - 2013-01-30

    I was working on something similar just yesterday, but on a SAM4L.  It is working really nicely and the results are quite dramatic.  I will publish the demo soon, but can't say exactly when (things are very busy here).

    I agree with you regarding the assertion.  I think it should be:

    configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );
    

    but will have to consider carefully the overflow case .

    Is your RTC.CNT value equal to your tick period?

    Regards.

     
  • Richard Damon

    Richard Damon - 2013-01-30

    I suspect you actually want configASSERT( xTicksToJump <= (xNextTaskUnblockTime - xTickCount))

    i.e. compare two delta times based on now, this will wrap right (this assumes that xNextTaskUnblockTime is always going to be in the future at this point).

     
  • Richard

    Richard - 2013-01-30

    The next task unblock time is always kept in the same time line as the current tick count.  When the next unblock time reaches the wrap point it is held at the wrap point until the tick catches up with it, then both it and the tick wrap at the same time - at which point the next unblock time is set to its real value.

    I think the idea of the assert is to ensure that the implementation of the sleep function has not slept past the time at which the next task needed to run.  If a task needed to run in 10 ticks time, the sleep function can sleep for 9 or 10 ticks, but must not sleep for 11 ticks (otherwise the task would be late running).

    In this case, xTickCount is the tick count at the time the tick was turned off.  xTicksToJump is the number of tick periods that passed while the tick was turned off.  The two added together equal the time now (the time that xTickCount will get set to), which must not be past the time the next task wanted to run.

    Regards.

     
  • Travis Griggs

    Travis Griggs - 2013-01-30

    Yes the RTC.CNT is in sync with our tick rate. It's basically mibiseconds (1/1024th of a second).

    richardbarry, I'm not following your other response entirely yet, let me restate/ask in hopes of clarifying. xNextTaskUnblockTime is in the same domain as xTickCount. I have configUSE_16_BIT_TICKS set to 1, so my xTickCount will roll from 65535 to 0.

    Does that mean that if my current xTickCount is at 65000, but I have no runnable processes for the next 1000 ticks, that the xNextTaskUnblockTime is set 65355 (or maybe 0?), at which point, it will then set the xNextTaskUnblockTime to the remainder of the time (644 in this example, I think).

    If this is true, I assume that prvGetExpectedIdleTime() is never supposed to return a delta that would be beyond the wrap? Or is there something else going on?

    The other thing that seems really suspect to me, is the dramatic difference between vTaskIncrementTick() and vTaskStepTick() in tasks.c. vTaskIncrementTick is obviously the heart and soul of tick management. It checks for wrap (compare to 0L), manages lists, etc. vTaskStepTick() otoh, just increments xTickCount by delta. No list management or wrap checking, or anything. If I use vTaskStepTick(4) when my current xTickCount is 0xFFFE, I'm going to miss an important bit and all kinds of undefined things are going to happen. The only thing I could see that was preventing that, would be if the above invariants were being preserved, but it means the writer of the sleep function has to help maintain them as well.

    (an aside, it would be nice if there were a #define in Config for how many idle ticks threshold triggers the sleep function, for us 2 is kind of aggressive)

     
  • Richard

    Richard - 2013-01-30

    Does that mean that if my current xTickCount is at 65000, but I have no runnable processes for the next 1000 ticks, that the xNextTaskUnblockTime is set 65355 (or maybe 0?), at which point, it will then set the xNextTaskUnblockTime to the remainder of the time (644 in this example, I think).

    Yes.  If the next unblock time does not wrap from xTickCount the it is set to the true next unblock time.  If it does wrap then it is set to the maximum value that the tick count can be (0xffff in your case).  That will make the kernel do something at that time, which will be just to increment the tick, which will wrap, which will swap the block list with the overflow block list, which will then set the next unblock time to the remainder as you say….if that makes sense.

    If this is true, I assume that prvGetExpectedIdleTime() is never supposed to return a delta that would be beyond the wrap? Or is there something else going on?

    True, because the next unblock time cannot be past the wrap (for the reason just explained, albeit maybe not that well).

    The other thing that seems really suspect to me, is the dramatic difference between vTaskIncrementTick() and vTaskStepTick() in tasks.c. vTaskIncrementTick is obviously the heart and soul of tick management. It checks for wrap (compare to 0L), manages lists, etc. vTaskStepTick() otoh, just increments xTickCount by delta. No list management or wrap checking, or anything. If I use vTaskStepTick(4) when my current xTickCount is 0xFFFE, I'm going to miss an important bit and all kinds of undefined things are going to happen.

    Yes - step tick cannot go past the wrap point.  This is intentional, and for the reason described already in my post here.  So step tick can be simple, and the configASSERT() statement is intended to ensure that this condition is never breached (which in correctly implemented cases it never should be )

    (an aside, it would be nice if there were a #define in Config for how many idle ticks threshold triggers the sleep function, for us 2 is kind of aggressive)

    Agreed.  I would appreciate you adding a feature request in the SourceForge tracker for that so it does not get lost.

    Regards.

     

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks