Tics Realtime -----


 
Home Services Products Tutorials Contact Us
- - - - -

Different Timing Mechanisms and How They are Used

This article presents various types of timing mechanisms that are found in most real-time systems and the applicability of each.

The Basic Types of Timers

Most real-time kernels provide some or all of the following types of timing mechanisms.
  1. A pause function (also known as sleep or delay).
  2. A one-shot timer.
  3. A periodic timer (also known as a continuous timer).
  4. Time-slicing (also known as time-sharing, although the term time-sharing is more properly applied to multi-user environments).
  5. Indirect timing mechanisms.

The Pause Function

pause is used to suspend the active task for a specified number of milliseconds.
+------------------+------------------+------------------+
0               10 ms              20 ms               30 ms
              ^
               
The time line above assumes a system timer tic of 10 milliseconds. That is, every, 10 milliseconds a timer interrupt occurs. Assume that the current time is at the caret as shown above. If a 10 millisecond pause is issued at this point, the kernel determines that the timer should expire on the next timer interrupt, i.e., the 10 ms mark. Note that the actual pause period in this case is quite a bit less than 10 ms.
void taskA(void) 
{
	while (TRUE) {
		pause(10L);
		acquireAndProcessData ();
	}
}
Now consider a pause in a loop as shown above, and assume that the current time "t" is in the time line region described by (0 < t < 10). The first time the pause is issued, an inaccuracy can result because, as described above, the timer will expire on the 10 ms mark, regardless of where in the aforementioned region it is started. Note however, that even if the function call to acquireAndProcessData takes 3 ms, which brings us to the 13 ms mark, the subsequent 10 ms pause will still expire at the 20 ms mark - 10 ms after the first timer expired. This means that as long as the pause is issued sometime before the next timer mark, that the timer will consistently expire at regular 10 ms intervals. Also, it is important to note that the inaccuracy occurs only on the first pause, and furthermore, the inaccuracy is inconsequential because it happens on the first data sample. Note that if the pause in the above code fragment is placed after the function call to acquireAndProcessData, the inaccuracy will be consequential as it can cause an inaccuracy between the first and second sample.

Now consider a pause of 500 ms and assume that the time it takes for acquireAndProcessData to execute is 200 ms. In this situation the actual time between calls to acquireAndProcessData will be about 500 + 200 = 700 ms. What is needed in this case is a timer that will periodically expire each 500 ms, which is what the periodic timer does.

The Periodic Timer

The periodic timer may be more accurate than a pause in certain situations, as described above.
void taskA(void) 
{
	typeData data;
	typeMsg * timer;

	timer = makeTimer(5000L);
	timer->flags |= PERIODIC;
	startTimer(timer);

	while (TRUE) {
		freeMsg(waitMsg(TIMEOUT));
		acquireData(&data);
		processData(&data);
	}
}
Note that the periodic timer is started only once; from then on a TIMEOUT message will be issued approximately every 5000 milliseconds. The periodic timer can be accurate because it is on-going. That is, when the 5000 millisecond timer expires, the timer isr starts another 5000 millisecond timer. Note however, that the periodic timer is not necessarily more accurate than a pause, since timers expire on discrete boundaries as described above.

As an aside, the ultimate in timer accuracy is realized by dedicating a hardware timer to a specific operation, and giving its interrupt top priority. Of course in order to implement this approach your system would need 2 timers (one for the system clock and one for the dedicated operation, unless your application does not need a system clock, in which case, a single timer will do).

There is also a potential problem with the use of periodic timers. If taskA cannot service the TIMEOUT messages fast enough, TIMEOUT messages will backup in taskA's message queue until all message space is exhausted. The point is that TIMEOUT messages will be sent by the timer isr regardless of whether the task can keep up with them or not.

The One-shot Timer

A one-shot timer is a timer that does not suspend the active task; that is after the timer is started, task execution continues. When the timer expires, the task is sent a message named TIMEOUT. The one-shot timer is typically used in situations that require a time-out as shown below.
void taskA(void) 
{
	long timerNum;
	typeMsg * timer;

	while (TRUE) {
		timer = makeTimer(5000L);	
		timerNum = timer->seqNum;	
		startTimer(timer);

		sendRs232("Are you there?");	

		msg = waitMsg(ANY_MSG);	

		switch (msg->msgNum) {

		case TIMEOUT:
			printf("RS232 device is not present\n");
			break;

		case I_AM_HERE:
			printf("RS232 device is present\n");
			cancelTimer(timer, timerNum);
			break;
		}
	}
}
A 5 second (5000 milliseconds) timer is started, and a string is sent over an RS232 line to see if there is a device connected to it. If the device is there, its response will be picked up by the RS232 receive isr which will interpret the response, and send a message named I_AM_HERE to taskA if the device is present and operational. So, once the timer has been started, and the RS232 string sent, one of two things will happen: (a) the RS232 device will respond and an I_AM_HERE message will be sent to taskA by the RS232 receive isr, or (b) the timer will expire and the timer isr will send a message named TIMEOUT to taskA. The waitMsg(ANY_MSG) call waits for the occurrence of any message regardless of its name (message number). Note that if the device is present, the timer must be canceled, otherwise, the unwanted TIMEOUT message will eventually be sent to taskA. It is assumed that a late I_AM_HERE message cannot occur because it is assumed that the 5 second time-out is more than adequate to determine if the device is present. If a late I_AM_HERE message can occur, then it must be handled.

Time-slicing

Time-slicing is seldom used in real-time systems since most real-time systems are event driven. Furthermore, time-slicing implies busy waiting.
void taskA(void)
{
	while (TRUE) {
		if (keyHit()) processKey();
	}
}
Assume that the task shown above was started with time-slicing enabled with a 25 millisecond time-slice. This means that taskA will spin for a full 25 milliseconds checking for a key press, which is a waste of CPU time. It is much more efficient to check the keyboard once every 100 milliseconds or so as shown below.
void taskA(void)
{
	while (TRUE) {
		pause(100L);
		if (keyHit()) processKey();
	}
}
Although we contend that time-slicing can and should always be avoided in real-time systems, the following is presented as an example where time-slicing may be useful. Consider a real-time system with 10 tasks - 5 normal priority tasks and 5 low priority number crunching tasks. Assume that the 5 low priority tasks are in a constant mode of computing data. Although these tasks could cooperate with one another by yielding, this is deemed inconvenient. One solution would be to time-slice the 5 low priority tasks.

For reasons given above, and the fact that time-slicing can cause time-dependent errors, we discourage its use.

Indirect Timing Mechanisms

Kernels may offer various indirect timing mechanisms, but these are typically combinations of the mechanisms already discussed. Consider a kernel call that waits for a message only for a given period of time and then times out. The following code fragment waits up to 1000 ms for a message named BEGIN.
	msg = waitTimedMsg(BEGIN, 1000L);

	if (msg->msgNum == BEGIN) allOk(); else reportError();

	freeMsg(msg);
Message time-out can also be accomplished with a one-shot timer and timer cancellation as shown previously. Furthermore, these indirect timing mechanisms are sometimes lacking in flexibility, and you are better off utilizing the control and flexibility offered by the primitive timing mechanisms.


We welcome comments. Let us know what subjects you would like written up. Send comments to Mike@TicsRealtime.com

Copyright © 2000, Tics Realtime