Technique for delaying Multiple functions

Delaying Function Execution

In the FreeRTOS implementation for the LPC1347 I could not find a method to queue functions for execution at some later time. There were functions defined but not implemented to use the system tick, but none that suited our purpose. This required being able to add functions with their parameters to a queue for execution at some given number of ticks later. This short paper describes our solution. While undoubtedly not unique it is a working solution.

A public function called DoDelay is provided that takes as its parameter a message structure that includes the name of the task to run, how many ticks to wait and the required priority, along with an optional parameter to be passed on when the function runs. An example structure is:

typedef struct 
{
   MessageType message; 
   TaskBase* task;
   uint32_t delay; 
   uint16_t priority; 
}  DelayMessageType;

The MessageType can be a simple integer or itself a structure. An example of filling the
DelayMessageType structure and calling the DoDelay function is given here:

DelayMessageType d;
 … d.delay = timerTicks; 
d.task = MotorClass.TimedEvent_StartMotor(); 
d.priority = uxTaskPriorityGet(NULL); 
DelayQueue.DoDelay(&d);

The DoDelay function copies the DelayMessageType structure contents to a local variable, pushes that onto a FreeRTOS queue accessible via xDelayQueHandle, and then exits. The message copy means the original data can be transient.

//----------------------------------------------------------------------------- 
// Receive a request to run a task sometime later. The various details are 
// in the message. Only the delay, function address, and priority are necessary. 
//
void CDelayQueue::DoDelay(DelayMessageType* dp) 
{ 
    DelayMessageType dm; 
    if (uxQueueSpacesAvailable(xDelayQueHandle) < DELAY_QUEUE_SIZE) 
    { 
        // Copy the message to local storage. 
        memcpy((void*)&dm, (void*)dp, sizeof(DelayMessageType)); 
       // Send it to the delay control task. 
       xQueueSendToBack(xDelayQueHandle, &dm, 5000); 
    } 
}

A task called DelayQueueManager runs at a high priority every system tick. It wakes up and peeks at the xDelayQueHandle queue to check for entries. If so it is read until empty with each DelayMessageType being pushed onto a timer queue by the private method InsertDelta. This is repeated until the input queue is empty. The timer queue is organised so the shortest delayed message is always at the start of the queue and all messages are ordered by their time of arrival.

//----------------------------------------------------------------------------- 
// This task runs every clock tick. It first examines the input queue for any 
// contents. If so they (it) are consecutively extracted and put on the task 
// delay queue by the InsertDelta class method. It then calls the TickDelayQueue 
// method to decrement the queue. Any entries that go to zero will be run. 
// 
void CDelayQueue::Task_DelayQueueManager(void* p) 
{ 
    DelayMessageType dm; 
    TaskBase* task; 

    while (true) 
    {
        2
       // Check if there are any new tasks for the delay queue.
       while (uxQueueMessagesWaiting(xDelayQueHandle) > 0)
       {
            // If so extract it from the queue.
           xQueueReceive(xDelayQueHandle, &dm, 0);
          // Add this task to the delay queue.
          if (!DelayQueue.InsertDelta(&dm))
          {
              mDelayQueOverrun++;
         }
       }
      // Now tick the delay queue to check if any are ready to run.
      DelayQueue.TickDelayQueue();
      // Off to sleep again until the next tick.
      vTaskDelay(1);
    }
}

Once the xDelayQueHandle queue is empty another private method called TickDelayQueue is called. If the queue
has contents the timer queue head entry tick count is decremented. If it goes to zero that entry is taken off the timer
queue and the delayed function called with its given parameter. This is repeated until either the queue is empty or
the head tick value is non-zero, at which point the method returns to the task which goes off to sleep for another
tick.

//-----------------------------------------------------------------------------
// Tick the delay queue if it has any contents. Execute any tasks coming off the
// queue in their queue order.
//
void CDelayQueue::TickDelayQueue(void)
{
uint32_t taskOriginalPriority;
DelayEntryType entry;
if (mDelayQueueCount > 0)
{
mDelayQueue[0].ticks--;
while ( (mDelayQueueCount > 0) && (mDelayQueue[0].ticks == 0) )
{
entry = mDelayQueue[0]; // save the task pointer
mDelayQueueCount--; // done with this entry
// Fix up any remaining entries on the delay list.
if (mDelayQueueCount > 0)
{
// The delay list is linear.
memcpy((void*)&mDelayQueue[0], (void*)&mDelayQueue[1], sizeof(DelayEntryType) * mDelayQueueCount);
}
// Unless the task was deleted, the head of the delay list was
// a valid task and the associated delay time his reached zero,
// execute this task at its given priority.
if (entry.task)
{
taskOriginalPriority = uxTaskPriorityGet(NULL);
if (entry.priority <= HIGHEST_PRIORITY)
{
// Use the given task’s priority. vTaskPrioritySet(NULL, entry.priority);
}
(*entry.task)(&entry.message); // run the task
vTaskPrioritySet(NULL, taskOriginalPriority);
}
}
}
}

The only downside of this method it that all delayed tasks must use the same parameter. We have found that using
a structure as that parameter and judicious use of the union keyword in the definition of the structure solves most
problems.

Your post if very hard to read because certain characters are interpreted as formatting tokens.
In this post @hs2 explains how to insert source code in a post.

Another method uses 3 tildes and the letter ‘c’ to insert C source code:

    ~~~c
    /* This it source code. */
    void my_function( int i )
    {
    }
    ~~~

The tildes won’t be visible in the post.
Or use backquotes (``) to write my_function()

1 Like

One thing to look at are Timers. Each timer can be provided with a void* parameter, which it can get with pvTimerGetTimerID(), which could point to your parameter block (and being a void*, you don’t need unions). The one thing this wouldn’t provide is a priority field, as all the timers run inside the same task at a single priority (which also means they shouldn’t block).

If you need full task functionality, then you will need to actually create your own tasks to do this, at the various priorities that you need. Frankly, it sounds like you are largely trying to recreate a new scheduler in your system, which is a lot of work.

You have a lot of description of WHAT you want to do, but not WHY. Your What doesn’t completely line up with what FreeRTOS provides, so implementing it exactly is hard. If we had a better handle on the Why, perhaps we could help better. This sounds like a classic X-Y problem, you want to do X, and have decided that to do X you need to do Y, but are having troubles, so you are asking how to do Y, when you really should have been asking for a way to do X, which is what you REALLY need to get done.

Thanks for those comments. I should have pointed out that I am not asking for help, but presenting a possible solution to the problem I describe, ie no timers in the LPC1347 port and a requirement to queue functions (not tasks) to run at some future time definable in system ticks. This particular solution works well and is already in a product. It would be interesting to see a simpler version.

Do you mean you’ve chosen not to enable software timers in your application (configUSE_TIMERS)? Or do you mean FreeRTOS doesn’t support software timers on your MCU?

I mean I took advantage of the tick hook so I could implement the functionality in the post that my app required. The tick hook gave me 1 mSec resolution for very little overhead.

If you haven’t already reviewed the FreeRTOS function xTimerPendFunctionCall(), it’s worth a look. If nothing else it might be interesting to see the differences.

Many thanks and very interesting. Looking at its description on the FreeRTOS site it would have been what I was after. However there is nothing like it in the LPC1347 port. As I mentioned I am happy with how my solution works, but that function would have saved me some work.

xTimerPendFunctionCall() is core functionality in FreeRTOS, it isn’t Port dependent, it may need an enabling define in FreeRTOSconfig.h

Surprisingly, this function does not exist anywhere in the LPC1347 port I have here, so I am assuming the port to this (now rather old) processor was very early on for FreeRTOS. If anyone knows of a '1347 port that includes the later features I would be very interested.

What version of FreeRTOS are you using, if it is too old, it may predate the adding of that function.

Version is V7.5.3 2013. I did another global search for the name but definitely not there. As I mentioned, my solution above is working, but I’ll go look at the xTimerPendFunctionCall in later versions and see if it could be back-implemented, just in case the implementation would be more efficient.

xTimerPendFunctionCall was added in Version 8.0. Your other option would be to update to a new version, and see if the functions from the port need updates (they often don’t, or are easy to add),

Thanks Richard. This product now out the door, but new one coming up and hope to use the rather new LPC55S16 and will certainly use a later FreeRTOS. Cheers.