In article <9210072046.AA01...@coyote.draper.com>, l...@draper.com (Carl Lacy) writes:
> I am in need of accurate timing on a MVME167. The TOD clock, a MK48TO8,
> has a quanta of only 1 sec. The MVME manual notes a "tick timer 1 and 2
> counter" on the VMEchip2, and a "TIC timer 1 and 2 counter" on the PCCchip2,
> so I was wondering if anyone might have packaged routines for managing these?
Below is a package which should meet your needs. This uses
unix standard gettimeofday, settimeofday, and adjtime. Accurate
to 1 microseconds. Calls to gettimeofday without a timezone
take about 5.5 microseconds. This package works with the NTP
packages available for VxWorks (see archives).
--
Eric L. Schott, HRB Systems, Inc. 814/238-4311 e...@icf.hrb.com
"As we acquire more knowledge, things do not become more comprehensible
but more mysterious." Albert Schweitzer, "Paris Notes"
---------------------------------------------------------------------------
/*
* (U) The Timer_Library provides gettimeofday and
* settimeofday functionality for the MVME167 card. This library
* has been extended to support NTP. Therefore, this 167 can be
* closely synchronized with other CPUs on the network. See the
* VxWorks NTP documentation for further details.
*
* (U) The functions within the Timer_Library software are
* called as needed based on their prototypes as found in
* Prototypes.h.
*
* (U) The TOD_Init routine MUST be called AFTER the clock
* has been set or reset (via sysClkRateSet).
*
*/
#include <vxWorks.h>
#include <sysLib.h>
#include <intLib.h>
#include <68k/iv.h>
#include <stdioLib.h>
#include <string.h>
#include <limits.h>
#include <wdLib.h>
#define J68KTIM_USEC_PER_SEC 1000000
/*
*. (U) Number of microseconds per second
*.
*.
*/
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
};
struct timezone {
int tz_minuteswest; /* minutes west of Greenwich */
int tz_dsttime; /* type of dst correction */
};
#define DST_NONE 0 /* not on dst */
#define DST_USA 1 /* USA style dst */
#define DST_AUST 2 /* Australian style dst */
#define DST_WET 3 /* Western European dst */
#define DST_MET 4 /* Middle European dst */
#define DST_EET 5 /* Eastern European dst */
#define DST_CAN 6 /* Canada */
#define DST_GB 7 /* Great Britain and Eire */
#define DST_RUM 8 /* Rumania */
#define DST_TUR 9 /* Turkey */
#define DST_AUSTALT 10 /* Australian style with shift in 1986 */
#define ITIMER_REAL 0
#define ITIMER_VIRTUAL 1
#define ITIMER_PROF 2
struct itimerval {
struct timeval it_interval; /* timer interval */
struct timeval it_value; /* current value */
};
/*
* Local Commons and Data Items
*/
#define VMECHIP2_BASE_ADRS 0xfff40000
#include <drv/vmechip2.h>
/*
*. (U) Define the VMEchip2 registers
*/
#define TIMEOUTCR_PA_MASK 0xff
/*
*. (U) Mask for Prescaler Ajdust in Prescaler Control
*. Register of VMEchip2.
*/
#define TIMEOUTCR_PA_25_MHZ 0xe7
/*
*. (U) Prescaler Ajdust for our 68040 speed.
*/
#define TIMERCR_TT1_OVF_SHIFT (4)
/*
*. (U) Tick Timer Control Register overflow counter.
*/
#define TIMERCR_TT1_OVF (0xf << TIMERCR_TT1_OVF_SHIFT)
/*
*. (U) Tick Timer Control Register overflow counter.
*/
#define IOCR_VBR0_SHIFT (28 - 4)
/*
*. (U) Mask for VMEchip2 interrupt vector selection.
*/
#define IOCR_VBR1_SHIFT (24 - 4)
/*
*. (U) Mask for VMEchip2 interrupt vector selection.
*/
#define IOCR_VBR0_MASK 0xf0000000
/*
*. (U) Mask for VMEchip2 interrupt vector selection.
*/
#define IOCR_VBR1_MASK 0x0f000000
/*
*. (U) Mask for VMEchip2 interrupt vector selection.
*/
#define ADJTIME_MAX ((INT_MAX / J68KTIM_USEC_PER_SEC) - 1)
/*
*. (U) Maximum time to adjust clock.
*/
unsigned int hz;
/*
*. (U) sysclock interrupt rate per seconds. This is
*. global for NTP.
*.
*. Units: interrupts per seconds
*. Accuracy: N/A
*. Precision: N/A
*. Range: N/A
*. Default: TRUE or FALSE
*/
unsigned int tick;
/*
*. (U) Number of microseconds in clock tick. This is
*. global for NTP.
*.
*. Units: microseconds
*. Accuracy: N/A
*. Precision: N/A
*. Range: N/A
*. Default: N/A
*/
volatile int tickadj = 500;
/*
*. (U) Number of microseconds to adjust time of day clock
*. every adjustment interval (one second). This is
*. global for NTP.
*.
*. Units: microseconds
*. Accuracy: N/A
*. Precision: N/A
*. Range: 1 - 250,000 (1/4 s)
*. Default: 500
*/
LOCAL int adj_time = 0;
/*
*. (U) How much time to adjust timeofday clock
*.
*. Units: microseconds
*. Accuracy: N/A
*. Precision: N/A
*. Range: +/- ADJTIME_MAX
*. Default: Zero
*/
LOCAL int timerInitCalled=FALSE;
/*
*. (U) Indicates if timer initialized.
*.
*. Units: Boolean
*. Accuracy: N/A
*. Precision: N/A
*. Range: N/A
*. Default: TRUE or FALSE
*/
LOCAL long currentSecond=0;
/*
*. (U) This is the current second past Epoch. However,
*. the concept of Epoch is muddied here since we have no
*. guarantee settimeofday has been called to set the
*. seconds based upon Jan 1, 1970. Most likey, Epoch is
*. time since the board last booted.
*.
*. Units: seconds
*. Accuracy: one second
*. Precision: N/A
*. Range: N/A
*. Default: N/A
*/
LOCAL struct timezone currentZone = {5*60,DST_USA};
/*
*. (U) Current time zone. Must be set by settimeofday
*. for the value to be valid.
*.
*. Units: N/A
*. Accuracy: N/A
*. Precision: N/A
*. Range: N/A
*. Default: Eastern timezone, USA DST
*/
LOCAL WDOG_ID adjust_wd_timer;
/*
*. (U) When doing an adjustment of the time of day clock,
*. it is simplest if the adjustment is made in the middle
*. of a second. This means if we either add or subtract
*. from the microseconds in a second, we do not have to
*. worry about the time rolling over into another second.
*. We use this timer to create an interrupt at near the
*. one-half second interval.
*.
*. Units: N/A
*. Accuracy: N/A
*. Precision: N/A
*. Range: N/A
*. Default: N/A
*/
LOCAL unsigned int adjust_wd_ticks;
/*
*. (U) Number of ticks to wait to call adjustment routine.
*.
*. Units: VxWorks ticks
*. Accuracy: N/A
*. Precision: N/A
*. Range: N/A
*. Default: N/A
*/
/********************* Adjust_Clock ***********************
*
* (U) Adjust_Clock adjusts the time of day clock.
*
* (U) Adjust_Clock adjusts the time of day clock. This
* routine should be called at the 1/2 second interval if there
* is an adjustment to be made. It adds/subtracts the adjustment
* interval from the VMECHIP2 timer.
*
* (U) The calling parameters for this routine are:
*
*/
LOCAL void Adjust_Clock
(
int parameter
/*
*. (U) Unused VxWorks parameter.
*.
*. Type: Input
*. Units: N/A
*. Accuracy: N/A
*. Precision: N/A
*. Range: N/A
*.
*/
)
{
int cur_adj;
/*
*. (U) Amount to adjust clock in current second.
*.
*. Units: Microseconds
*. Accuracy: N/A
*. Precision: N/A
*. Range: 0 -> +/- tickadj
*.
*/
volatile int *ireg;
/*
*. (U) points to hardware register
*.
*. Units: N/A
*. Accuracy: N/A
*. Precision: N/A
*. Range: N/A
*.
*/
cur_adj = max(min(adj_time,tickadj),-tickadj); /* Calc adjustment */
if (cur_adj != 0) /* if adjustment required */
{
ireg = VMECHIP2_TTCOUNT1;
*ireg += cur_adj;
adj_time -= cur_adj;
}
return;
}
/********************* TOD_Isr ***********************
*
* (U) TOD_Isr is the Time of Day interrupt service routine.
*
* (U) TOD_Isr resets the VMEchip2 microseconds timer and
* maintains the count of seconds past the "Epoch."
*
* (U) The calling parameters for this routine are:
*
*/
LOCAL void TOD_Isr
(
int param
/*
*. (U) Unused intConnect parameter
*.
*. Type: Input
*. Units: N/A
*. Accuracy: N/A
*. Precision: N/A
*. Range: N/A
*.
*/
)
{
volatile int *ireg;
/*
*. (U) points to hardware register
*.
*. Units: N/A
*. Accuracy: N/A
*. Precision: N/A
*. Range: N/A
*.
*/
ireg = VMECHIP2_ICLR; /* Interrupt clear register */
*ireg |=
...
read more »