Feature
An event scheduler for control applications
Event schedulers provide multiple relative and absolute timer services for real-time system applications. They are a valuable part of many computer control systems.
KV Ramakrishnan, DRDO -- EDN, 6/6/1996
An event scheduler is different from a monolithic control loop. A monolithic control loop is split into a set of logical and autonomous processes. The scheduler uses a split architecture. You submit events at one time, and they are executed in the background in a cyclical manner at the specified time. This process allows the foreground task to handle user interaction apart from external hardware-interrupt handling. An event scheduler makes real-time control-system design easy and manageable. It offers a host of benefits in feasibility and planning, scheduling and breaking tasks, testing and tuning the system, and, finally, easy system maintenance. A typical application for an event scheduler is time control; after all, real-time systems manage the precious and essential resource of time.
Systems that use event schedulers include nuclear reactors; chemical plants; and power-distribution, radar, and sonar systems. You use real-time embedded systems for these control applications. An event scheduler can perform the following tasks:
- Actions that are cyclic in nature, such as ring generation;
- Repeating sequences of events, such as waveform generation, in sequential switching on and off;
- Periodic polling, such as keyboard scanning and watchdog functions;
- An event that causes an action;
- Precision delay;
- Validation of pulse width;
- Waiting for an event of indefinite or definite time;
- Turning the status of a flag or variable on or off;
- Checking the health of a communication link and marking its status, such as loop-back checks.
Figure 1 shows the data structure used to implement the event scheduler. Members in the data structure include:
- PoolSize: An integer quantity that indicates the maximum number of timer pools available for reservation.
- CurrentToken: A character used for dynamic token generation. You generate the tokens dynamically to avoid deletion of nonexistent action tasks.
- AssignedToken: A word representing the dynamically generated token assigned to and reserving a pool. When free, or vacant, the token acquires the value FFFFh. You use the AssignedToken for three purposes: to assign a dynamic token, to see that this particular pool is free in the pool-reservation algorithm, and to increment or decrement CounterValue for each timer count. All AssignedTokens acquire the value FFFFh during initialization.
- CounterValue: An incremented or decremented word, dependent on whether you assign the pool to a timer or timed-action-task execution.
- ActionTask: A pointer to ActionTask that you execute for a timed-action task. SubmitTask supplies this pointer.
Timer handler
Almost all contemporary processors provide at least one hardware timer. However, many real-time environments require multiple relative- and multiple absolute-timer services. The hardware may not be able to handle multiple timers and the associated interrupts assigned to them. For accurate and relative time computation, a single timer is best. It is, therefore, necessary to handle control at a central point with the help of a single timer. This timer has "n-timer" pools for independent counting. These pools give the timer the capability of concurrently handling several timer services. All tasks receive any number of required timers. You need to program the timer to periodically issue interrupts to the processor. The dispatcher, or timer handler, always becomes active at every timer-count event detected by the CPU. Once control is given to the timer, the main job of the task dispatcher is to select all submitted tasks that initiate transition of the task from a ready to an active (run) state. The program runs in multiprogramming mode, which means that several processes exist. All submitted tasks are in ready-to-run mode, and, depending upon the countdown value, the task gains control and executes. After execution, this task goes into a nonexistent state. Figure 2 shows the different states of the submitted task. The sequence of operations done by the task dispatcher is as follows: You perform the following initializations before the foreground task takes control. RequestDelay You cannot realize precision time delays with counter loops. The RequestDelay system call provides a precision time delay for the requested amount of timer counts: RequestDelay algorithm Multiple timer services Multiple timer services support StartTimer, StopTimer, RestartTimer, and ElapsedTime system calls. The StartTimer call allows the scheduler to allocate a timer by giving it a token for further manipulations. The timer counter allocates resets and increments for each subsequent timer count. You base other operations with this timer on the token returned by the StartTimer call. An exception is returned if no timer counter is available. StartTimer algorithm You use the StopTimer call not only to stop the timer, but also to free the timer pool and return the current counter value of the specified timer by returning the StartTimer token. StopTimer algorithm The RestartTimer results in the scheduler's resetting the specified counter, using the token returned by the Start Timer. RestartTimer algorithm ElapsedTime returns the current counter value of the specified timer by giving the token returned by StartTimer. ElapsedTime algorithm SubmitTask The scheduler allocates a timer counter and an action-task pointer that you execute at the end of the requested time countdown. You can pass two parameters to this call: the action task and the time unit, or wait time. SubmitTask returns a token used primarily to abruptly withdraw the action task, if necessary, before it gets executed. After you execute this action task, the timer pool is free for further registration. The action task may be recursive in time for periodic or cyclic execution of tasks. For example, you can generate a ringing sound until it is cleared by the operator. Figure 3 shows the GenRing waveform for switching the ringer on and off. The first call to GenRing turns the ringer on and submits a MakeOff task. You execute this task after OnTime, which turns off the ringer. GenRing continues to submit itself while the Clear flag is false, and the process continues until Clear becomes true. WithdrawTask You use the WithdrawTask system call to withdraw a submitted task using SubmitTask. You use the token returned by SubmitTask as a parameter to the WithdrawTask call to identify the parameter. Because the token is unique, you can't withdraw a task that's already executed. When using this mechanism, you cannot accidentally delete a new action task submitted by other tasks and that is present in this pool. WithdrawTask algorithm StopWatch You can use the StopWatch system call to compute the amount of time that elapses until an event makes the given flag true. The call expects three parameters: The call returns the following values: Examples The following examples can coexist in the same application apart from any other monitored event you want to add. These examples offer the possibility of exploring the use of an event scheduler for designing small, real-time, embedded-control systems. Such a system has: You can directly implement almost all activities using
public functions in the EventScheduler program. You can make a task Do Forever
by unconditional submission of the same task, by itself, for the specified
WaitTime. By doing this procedure at the end of the task's execution, the task
is registered again, thereby achieving the Do Forever effect (Listings 1 and 2). The source files for these listings are well-commented (see pg 160). The "*" indicates functions included in the Eventest.plm source file, and "#" indicates public functions in the Event.plm source file. StopWatch example You can use StopWatch to measure pulse width. The function has three parameters. The first is a pointer to a flag. StopWatch measures the time it takes for the flag to become true. An interrupt program or a call-back function can make the flag true. The second parameter is a pointer to the above callback function. If you use interrupt for making the flag true, then this pointer becomes a null-function pointer. The third specifies maximum wait time. This example uses a call-back function, "CheckStatus," and the previously declared variables, "Status" and "Etime." Pseudo code Waveform-generation example This example implements a serial data-transfer machine by converting a byte into asynchronous RS-232C serial format. The protocol assumes no parity, a single stop bit, and 8-bit data at half the rate of the timer counts. The program first makes the Empty flag false, indicating that the transmission is in progress. It then sends 10 bits (1 start bit+8 bits of data+1 stop bit) by submitting 10 tasks. The waveform program gets controls every Timer Count3BaudConstant32 clock intervals. The program uses four local functions to perform serial transmission. Figure 4 shows the waveforms generated when sending the hex character 93 through the machine. How a system copes with I/O depends very much on the nature of the task and the capabilities built into the system's design. Most system designs have to make a compromise among the number of submitted tasks, the time it takes to execute a task, and the maximum number of tasks that are ready to execute at a given timer count. Computation of worst-case task runtime is very important. Before selecting a slot time (timer-programming value), you must be sure that there is sufficient computing power to execute the critical workload in that slot time. If you select the incorrect slot time, the response time may exceed certain deadlines, and the controlled process may fail. You must optimize the slot time for both response time and worst-case task runtime to meet current system response. A long computational action task affects the entire system's response. Of course, you can partition a long task into a series of short ones or shift some processes to the foreground task to alleviate this problem. Author's biography KV Ramakrishnan is a scientist at the microprocessor division of DRDO, Cochin, India. He designs and develops real-time systems for naval applications, including ships, underwater communications, sound-velocity recorders, and health-monitoring systems. Ramakrishnan holds bachelor's degrees in technology and EE and an MS in technology, instrumentation, and control from the Regional Engineering College, Calicut-Kerala.
Dispatcher algorithm Dispatching:Procedure interrupt For all reserved timer pool Do If it is Task Pool Then Do decrement CounterValue If CounterValue zero Then Do Run ActionTask Free Timer Pool End End Else increment CounterValue //timer service End End
RequestDelay:procedure(WaitTime) Token = StartTimer While true if ElapsedTime(Token) > = WaitTime then Do // Requested delay elapsed StopTimer(Token) // free timer return End End End
StartTimer:procedure Search For the Free Timer Pool If Not Found return FFFFh //fail Initialize CounterValue to Zero Compute AssignedToken //for timers return AssignedToken End
StopTimer:procedure(Token) Find Timer Pool for the given Token If Not Found return FFFFh //fail Free Timer Pool return CounterValue End
RestartTimer:procedure(Token) Find Timer Pool for the given Token If Not Found return FFFFh //fail Initialize CounterValue to Zero End
ElapsedTime:procedure(Token) Find Timer Pool for the given Token If Not Found return FFFFh //fail return CounterValue End
GenRing:Procedure MakeRing ON SubmitTask(MakeOff,OnTime) //First Submit call If Not Clear Submit(GenRing,OffTime) //Second Submit call End GenRing MakeOff:procedure MakeRing OFF End MakeOff SubmitTask algorithm SubmitTask:procedure(CallBackFunction,WaitTime) Search For the Free Timer Pool If Not Found return FFFFh //fail Initialize CounterValue to WaitTime Initialize ActionTask to CallBackFunction Compute AssignedToken //for tasks return AssignedToken End
WithdrawTask:procedure(Token) Find Timer Pool for the given Token If Not Found return FFFFh //fail Initialize CounterValue to FFFFh //free timer pool Initialize ActionTask to NULL return True End
StopWatch:procedure(StopFlagPtr, CallbackFunction, MaxWaitTime) StopFlag based StopFlagPtr Token = StartTimer While true Call CallbackFunction if StopFlag then return StopTimer(Token) if MaxWaitTime <> Indefinitely then do if ElapsedTime(Token) > = WaitTime then Do // condition not satisfied StopTimer(Token) //free timer return(0ffffh) End End End End StopWatch
CheckStatus:procedure /* This is a callback function called by StopWatch. This function polls the event and makes the Status flag true. */ Status = input(address) end CheckStatus; // An event occurred. Measure the time Etime = StopWatch(@Status,@CheckStatus,150) if(Etime >150) then call write(@('Pulse Width High$')) else if(Etime <15) then call write(@('Pulse Width Small$')) else // valid pulse, Pulse width is in Etime. // Use for further processing. ... ...













