A Task Manager with Delays

Ron Kreymborg



The article describing the TaskR task manager provides the details on how it works. The TaskR2 module is an extension of this that provides programmable delays prior to the task being run. In the solely event based environment of TaskR, only an event such as an interrupt could start a process. By providing a delay that must elapse before the task runs, TaskR2 essetially defines the completion of the delay as an event in itself.

The addition of delays adds one more data structure to the existing pending task list and queue link structures. Expressed as a structure, this is now

struct {
   void          (*Task[MAX_TASKS])(void);
   DELAY_TYPE    delay;
   BYTE          next;
}

In the ever present embedded systems design goal of saving ram space, both standard and delayed queued tasks share the same structure. A new function called QueDelay is provided for putting a task on the delay queue. The definition is:

void QueDelay(void (*TaskName)(), DELAY_TYPE delay)

The delay is defined as an elapsed number of system clock ticks, and consequently depends on the particular implementation. It is usual to define the clock period so it is an even divisor of one second, and so can do double duty as a real time clock source. The maximum delay time will of course depend on the type of the delay variable. Here it is shown as a DELAY_TYPE, defined in the header as an unsigned integer, good for around 65,000 ticks. Define it as a long if your application needs delays longer than this. If 256 ticks wll be enough, then use a BYTE.

Having a delay facility means you can now schedule tasks independent of external events. For example, an AtoD sampling task may need to run every 500 mSec. In this case the task is initially scheduled after TaskR2 has been initialised and before the Despatch loop is entered. eg:

   InitTaskR2();
   QueTask(Task_ADconverter);
   while (1)
   {
      Despatch();
   }

The Task_ADconverter task will run when Despatch is called. This function would look like:

void Task_ADconverter(void)
{
   // Take an A to D sample
   //
   (all the necessary code to do this)

   QueDelay(Task_ADconverter, 500);
}

As mentioned earlier, the new function QueDelay puts the passed task on the delay queue rather than the ready queue. Only after this many clock ticks have occurred will the task be moved from the delay queue to the ready queue. So the task re-schedules itself to run 500 ticks later.

The technique can also be used to insert necessary delays during initialisation or elsewhere. Given the design requirement discussed in the TaskR article that no task should run longer than the tick period, you can be assured that any delay will have at least clock tick resolution.