[uCsimm] rtc and processor maintained clock

From: Bob (rhl@diamond.demon.co.uk)
Date: Wed Jan 26 2000 - 14:59:48 EST


Hi All

We have an application which requires accurate timing in the short term,
little on no drift within say 5 minutes. The ucsimm seems a good
starting point and we have one which is working fine, I think. We have
been doing some timing tests and it appears that the processor
maintained clock is running approx 7% slower than real time and the rtc
on the ucsimm. That is the processor maintained clock is loosing 7
seconds in every 100.

The attached test program shows this and verifies the results we were
getting when compared to another processor / real clock.
Run as <rtctest> and it reports the current values of the processor
maintained clock and the rtc.
Run as <rtctest MMDDhhmmYY> and it sets the processor clock and the rtc
pretty much at the same time so the divergence can then be seen after 60
to 100 secs.

We have looked around all the init code and the various timers appear to
be setup ok. We are running a pre1 kernel. One interesting fact come
to light is the cpuspeed reported in /proc/cpuinfo is only 15.2MHz
rather than the 16.5ishMHz that is supposed to be running. We have not
changed any of the PLL settings. This difference is in the order of the
7% we are looking for, so somewhere in the kernel timing code or timer
setup stuff something must be awry. The fact that the onboard rtc is
maintaining real time indicates that the 32kHz xtal is near enough the
correct frequency.

Help!! Any ideas where to look?

Bob Lees


/*
 * Real Time Clock Driver Test/Example Program for ucsimm
 *
 * Copyright (C) 2000, Bob Lees.
 *
 * Released under the GNU General Public License, version 2,
 * included herein by reference.
 *
 */

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <linux/config.h>
#include <asm/MC68EZ328.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

int daysInMonthNLY[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int daysInMonthLY[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char *monInYear[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

int main(int argc, char **argv) {

#ifdef CONFIG_UCSIMM

  struct tm tm;
  time_t t;
  unsigned long temp = 0;
  struct timeval tv;
  long dayInYear = 0, i = 0, tempd;
  char *month;

  if (argc == 2) {
    /* enable rtc with default crystal */
    if ((RTCCTL & RTCCTL_EN) != RTCCTL_EN) {
      RTCCTL = RTCCTL_EN;
      printf("enabling rtc\n");
    }
    /* hhmm */
    if (strlen(argv[1]) != 10) {
      printf("usage: rtctest MMDDhhmmYY\n");
      printf("Version 1.0\n");
      return 0;
    }
    memset(&tm, 0, sizeof(tm));
    tm.tm_isdst = 0;
    tm.tm_sec = 0;
    tm.tm_min = (argv[1][6]-'0')*10+(argv[1][7]-'0');
    if (tm.tm_min > 59) {
      printf("minutes must be between 0 and 59, not %d\n", tm.tm_min);
      exit (1);
    }
    tm.tm_hour = (argv[1][4]-'0')*10+(argv[1][5]-'0');
    if (tm.tm_hour > 23) {
      printf("hours must be between 0 and 23, not %d\n", tm.tm_hour);
      exit (1);
    }
    tm.tm_mday = (argv[1][2]-'0')*10+(argv[1][3]-'0');
    if (tm.tm_mday < 1 || tm.tm_mday > 31) {
      printf("day must be between 1 and 31ish, well 28ish for Feb and 30 for others, not %d\n", tm.tm_mday);
      exit (1);
    }
    tm.tm_mon = (argv[1][0]-'0')*10+(argv[1][1]-'0');
    if (tm.tm_mon < 1 || tm.tm_mon > 12) {
      printf("month must be between 1 and 12, not %d\n", tm.tm_mon);
      exit (1);
    }
    tm.tm_mon -= 1;
    tm.tm_year = (argv[1][8]-'0')*10+(argv[1][9]-'0');
    if (tm.tm_year < 90) tm.tm_year += 100;
    t = mktime(&tm);
    tv.tv_sec = t;
    tv.tv_usec = 0;
    settimeofday(&tv, NULL);
    temp = tm.tm_sec + (tm.tm_min << RTCTIME_MINUTES_SHIFT) + (tm.tm_hour << RTCTIME_HOURS_SHIFT);
    RTCTIME = temp;
    tempd = DAYR & 0xfe00;
    if (tm.tm_year % 4 == 0) { /* I know this isn't perfect but it'll do for now */
      for (i = 0; i < tm.tm_mon; i++) {
        dayInYear += daysInMonthLY[i];
      }
    } else {
      for (i = 0; i < tm.tm_mon; i++) {
        dayInYear += daysInMonthNLY[i];
      }
    }
    dayInYear += tm.tm_mday;
    if (tm.tm_year % 4 == 0) { /* I know this isn't perfect but it'll do for now */
      for (i = 0; i < 12; i++) {
        dayInYear -= daysInMonthLY[i];
        if (dayInYear < 0) {
          dayInYear += daysInMonthLY[i];
          break;
        }
      }
    } else {
      for (i = 0; i < 12; i++) {
        dayInYear -= daysInMonthNLY[i];
        if (dayInYear < 0) {
          dayInYear += daysInMonthNLY[i];
          break;
        }
      }
    }
    DAYR = tempd + (dayInYear & DAYR_DAYS_MASK);
    time(&t);
  } else {
    temp = RTCTIME;
    dayInYear = DAYR & DAYR_DAYS_MASK;
    time(&t);
    /* I know this bit only works for leap years :) */
    for (i = 0; i < 12; i++) {
      dayInYear -= daysInMonthLY[i];
      if (dayInYear < 0) {
        dayInYear += daysInMonthLY[i];
        break;
      }
    }
  }
  month = monInYear[i];
  printf("tod - from processor maintained clock %s", ctime(&t));
  printf("rtc - from rtc hardware clock day %s %.2d %.2d:%.2d:%.2d\n",
         month,
         dayInYear,
         (temp & RTCTIME_HOURS_MASK) >> RTCTIME_HOURS_SHIFT,
         (temp & RTCTIME_MINUTES_MASK) >> RTCTIME_MINUTES_SHIFT,
         (temp & RTCTIME_SECONDS_MASK) >> RTCTIME_SECONDS_SHIFT);

#endif /* CONFIG_UCSIMM */

}

This message resent by the ucsimm@uclinux.com list server http://www.uClinux.com/



This archive was generated by hypermail 2b30 : Sun Apr 07 2002 - 00:01:34 EST