Tải bản đầy đủ (.pdf) (5 trang)

O''''Reilly Network For Information About''''s Book part 201 pps

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (21.66 KB, 5 trang )

//
timerList.tick();
//
// Acknowledge the timer interrupt.
//
gProcessor.pPCB->intControl.eoi = EOI_NONSPECIFIC;
//
// Clear the Maximum Count bit (to start the next cycle).
//
gProcessor.pPCB->timer[2].control &= ~TIMER_MAXCOUNT;
} /* Interrupt() */
Of course, the tick method of the TimerList class does most of the work here.
This method is mostly concerned with linked list manipulation and is not very
exciting to look at. Briefly stated, the tick method starts by decrementing the tick
count of the timer at the top of the list. If that timer's count has reached zero, it
changes the state of the software timer to Done and removes it from the timer list.
It also does the same for any timers that are set to expire on the very same tick.
These are the ones at the new head of the list that also have a count of zero.
After creating and starting a software timer, the application programmer can do
some other processing and then check to see if the timer has expired. The waitfor
method is provided for that purpose. This routine will block until the software
timer's state is changed to Done by timerList.tick. The implementation of this
method is as follows:
/******************************************************************
****
*
* Method: waitfor()
*
* Description: Wait for the software timer to finish.
*
* Notes:


*
* Returns: 0 on success, -1 if the timer is not running.
*
******************************************************************
****/
int
Timer::waitfor()
{
if (state != Active)
{
return (-1);
}
//
// Wait for the timer to expire.
//
while (state != Done);
//
// Restart or idle the timer, depending on its type.
//
if (type == Periodic)
{
state = Active;
timerList.insert(this);
}
else
{
state = Idle;
}
return (0);
} /* waitfor() */

One important thing to notice about this code is that the test while (state !=
Done) is not an infinite loop. That's because, as we just learned a few paragraphs
back, the timer's state is modified by timerList.tick, which is called from the
interrupt service routine. In fact, if we were being careful embedded programmers,
we would have declared state as volatile. Doing so would prevent the
compiler from incorrectly assuming that the timer's state is either done or not done
and optimizing away the while loop.
[3]

The final method of the Timer class is used to cancel a running timer. This is easy
to implement because we need only remove the timer from the timer list and
change its state to Idle. The code that actually does this is shown here:
/******************************************************************
****
*
* Method: cancel()
*
* Description: Stop a running timer.
*
* Notes:
*
* Returns: None defined.
*
******************************************************************
****/
void
Timer::cancel(void)
{
//
// Remove the timer from the timer list.

//
if (state == Active)
{
timerList.remove(this);
}
//
// Reset the timer's state.
//
state = Idle;
} /* cancel() */
Of course, there is also a destructor for the Timer class, though I won't show the
code here. Suffice it to say that it just checks to see if the software timer is active
and, if so, removes it from the timer list. This prevents a periodic timer that has
gone out of scope from remaining in the timer list indefinitely and any pointers to
the "dead" timer from remaining in the system.
For completeness, it might be nice to add a public method, perhaps called poll, that
allows users of the Timer class to test the state of a software timer without
blocking. In the interest of space, I have left this out of my implementation, but it
would be easy to add such a routine. It need only return the current value of the
comparison state == Done. However, in order to do this, some technique would
need to be devised to restart periodic timers for which waitfor is never called.
Watchdog Timers
Another type of timer you might hear mentioned frequently in reference to
embedded sy
stems is a watchdog timer. This is a special piece of hardware
that protects the system from software hangs. If present, the watchdog
timer is always counting down from some large number to zero. This
process typically takes a few seconds to complete. In the meantime, it is
possible for the embedded software to "kick" the watchdog timer, to reset
its counter to the original large number. If the counter ever does reach

zero, the watchdog timer will assume that the software is hung. It then
resets the embedded processor and, thus, restarts the software.
This is a common way to recover from unexpected software hangs that
occur after the system is deployed. For example, suppose that your
company's new product will travel into space. No matter how much testing
you do before deployment, the possibility remains that there are
undiscovered bugs lurking in the software and that one or more of these is
capable of hanging the system altogether. If the software hangs, you won't
be able to communicate with it at all, so you can't just issue a reset
command remotely. Instead, you must build an automatic recovery
mechanism into the system. And that's where the watchdog timer comes
in.
The implementation of the watchdog timer "kick" would look just like the
Blinking LED program in this chapter, except that instead of toggling the
LED the watchdog timer's counter would be reset.
Another potential feature of the Timer class is asynchronous callbacks. In other
words, why not allow the creator of a software timer to attach a function to it. This
function could then be called automatically—via timerList.tick —each time that
timer expires. As you read the next section, be sure to think about how different the
Blinking LED program would look if asynchronous callbacks were used instead.
This is one type of application to which asynchronous function calls are
particularly well suited.
7.4 Das Blinkenlights, Revisited
Now that we have the Timer class at our disposal, it is possible to rewrite the
book's very first example to make its timing more precise. Recall that in our
original implementation, we relied on the fact that the length of a "decrement and
compare" operation was fixed for a given processor and speed. We simply took a
guess as to how long that might be and then revised our estimate based on
empirical testing. By utilizing the Timer class, we can simultaneously eliminate
this guesswork and increase the readability of the program.

In the revised Blinking LED program below you will see that we can now simply
start a periodic 500 ms software timer, toggle the LED, and then wait for the timer
to expire before toggling the LED again. In the meantime, we could perform other
processing tasks required by the application at hand.
#include "timer.h"
#include "led.h"
/******************************************************************
****
*
* Function: main()
*
* Description: Blink the green LED once a second.
*
* Notes: This outer loop is hardware-independent. However, it
* calls the hardware-dependent function toggleLed().
*
* Returns: This routine contains an infinite loop.
*
******************************************************************
****/
void
main(void)
{
Timer timer;
timer.start(500, Periodic); // Start a periodic 500 ms timer.
while (1)
{
toggleLed(LED_GREEN); // Toggle the green LED.
// Do other useful work here.
timer.waitfor(); // Wait for the timer to expire.

}
} /* main() */

×