This section discusses three example cases of timestamp device drivers (corresponding to the sample code in Example G-1, Example G-2, and Example G-3 respectively).
Example G-1 shows a sample device driver for hardware timers that can be read while enabled. This type of timer is the simplest to configure for timestamp mode, and the device driver code is straightforward. Note the following details:
The timer should be configured for the highest period possible by setting the terminal count to its maximum value (usually 0xfff when counting up, and 0 when counting down).
If programmable, a high-priority interrupt level should be used for boards with a low timer period. This ensures that frequent rollover interrupts are serviced without delay, and that the rollover event is registered in a timely manner with the timestamp callback routine (sysTimestampRoutine).
The sample device driver in Example G-2 illustrates techniques for using a hardware timer that cannot be read while enabled, requires preloading, and counts down. This combination of timer attributes presents several problems for the device driver:
If a timestamp timer cannot be read while enabled, a second correction timer can compensate: use the correction timer to reset the timestamp timer periodically. In this scenario, the second timer runs as a periodic interrupt timer. On each interrupt it resets the first (counting) timer. The counting timer is stopped and read for timestamp values, but never generates an interrupt because it is always reset before reaching its terminal count. However, the correction timer does generate interrupts; because it is not read for timestamp values, it never has time-skew problems. The correction timer ISR resets the counting timer, and then calls the timestamp callback routine (sysTimestampRoutine).
This approach clears the time skew that accumulates in the counting timer between resets. Although a discernible time skew may be present towards the end of the timer period, it is flushed by the reset operation.
Because the counting timer is always reset by the correction timer, the timestamp timer period is really the correction timer period. In the Example G-2 sample code, this period is set by the TS_CORRECTION_PERIOD macro. The value must balance a short period's increased interrupt service rate with a long period's noticeable time skew accumulation.
The chosen period should be based on the amount of time skew that can accumulate, which is related to how often the timestamp facility is called and to the sensitivity of the application using the facility. Our experience is that a correction period of 100 to 150 msec sufficiently satisfies both requirements for most applications.
The timestamp values must increase monotonically. If the timer in use actually counts down, the tick count must be converted to an incrementing value. This is easily done by subtracting the counter value from the reset value (usually 0xfff for a down counter).
If the counter value must be preloaded before the timer can resume counting, three subroutines must perform this action: sysTimestamp( ), sysTimestampLock( ), and sysTimestampEnable( ). The preload operation adds to the time spent with the timer disabled, exacerbating time-skew problems.
After the sysTimestampEnable( )routine enables the counting timer, it may need to delay until the preload value physically gets loaded into the counter. This is an issue for timers that synchronize the preload with a prescaler output transition. If a delay is not inserted, it may be possible for a fast target board to execute the timer preload, return from sysTimestampEnable( ), and call sysTimestamp( ), which stops the timer and specifies a different preload value. This would nullify the sysTimestampEnable( ) reset operation.
Counters that are writable or that have a preload mechanism can compensate for time skew. While the counter is stopped for a read operation, the counter value or the preload value may be adjusted by adding (for an up counter) or subtracting (for a down counter) the number of ticks spent with the timer disabled. The Example G-2 sample code subtracts the TS_SKEW macro (0, by default) from the stopped timestamp counter in an attempt to make up for "lost" time. Note that the adjustment value is not only board-dependent, it is influenced by CPU speed, cache mode, memory speed, and so on. In the default case (TS_SKEW = 0), compiler optimization eliminates the TS_SKEW adjustment.
Example G-3 exhibits a sample device driver that reads the VxWorks system clock timer to obtain the timestamp tick count. This approach is useful if there are no other timers available, and if the system clock timer's counter can be read while enabled.
When the system clock timer is used as the timestamp timer, the usual sysTimestampInt( ) routine cannot be used to service the timer interrupt, because the system clock timer already has an ISR. Thus, the system clock tick can be monitored to provide timestamp rollover information. The sysTimestampConnect( ) routine always returns ERROR because the sysTimestampRoutine callback routine is not used.
Because the system clock is independent of the timestamp facility, the timestamp driver must not disrupt the system clock in any way. Thus, sysTimestampEnable( ) does not reset the timer counter for the system clock. This causes inaccurate timestamp values until the first system clock tick ISR resets the timer counter. For similar reasons, sysTimestampDisable( ) does not physically disable the system clock.
The period of the system clock timer is under the control of the system clock facility, not under the control of the timestamp driver. Thus, the system and the application should not call sysClkRateSet( ) to change the system clock rate once sysTimestampPeriod( ) has been called to determine the timestamp timer period.