Microsecond Level Synced Clock

Status
Not open for further replies.
Sorry, still no code that will run out of the box. If you have questions about how the parts integrate in to the missing code and the variables I may have left out, ask. Because of my CFS, I don't have the time to spend separating out the relevant code properly and do everything else I need to do by the end of the week. There will be more variables without definition in this code. I also don't have any analysis code trying to find temperature based clock adjustments yet. I do have it under a raw fine tune mode, and it can keep +/-1.5 clock RTC prescale counter ticks with some times being within +/- 0.5 ticks. I plan on dumping the data to a file so I can process it with a few different algorithms and see what works best. I'd like to come up with a curve that can have a couple coefficients to tune it to a specific MCU. Furthermore I'm going to try to make it so it can self calibrate via the GPS PPS. I only use the GPS for time information.

I have the code for coarse slewing of theTeensy RTC time to within reason in the GPS PPS interrupt code. I'm going to move that to threadTADC so it is all in one spot. There is a lot of other code I need to refactor. The RTC PPS interrupt will get the code that sets up my 120Hz tick used for timing the LED updates.

fti is an unsigned 8 bit value, it rolls over to 0 after 255... It could never have pointed outside the array when the array was 256 entries long. Hence the reason I made the array that long. I now have only 16 array entries in each array, and use "fti &= 0x0F;" to roll it over. I shortened the array so multiple entries with similar ICC values won't be in the arrays.

The 1F super capacitor powered the Teensy RTC for over 36 hours when I was off to see the doc. Longest off period sofar.

Average of 179998217 ICC ticks per second for over 68000 seconds. A min of 179998091, and max of 179998357, are only for the last few hours of the time period. The rest had scrolled out of the monitor window buffer. The clock crystal speed does change with temperature. I'm now outputting the last temperature read with my averages info lines. I need to setup writing to the log file on the SD card. I want to pre allocate a large file, then write blocks to it so the index doesn't need constant update of the file allocation tables. Otherwise, I am to the point where the file is opened and ready for writing.

Includes, defines, and variables.
Code:
// threading library
#include <TeensyThreads.h>

// For SD card access
#include <SD.h>
#include <SPI.h>

// GPS
#include <time.h>
#include <TimeLib.h>
#include <TinyGPS.h>

TinyGPS gps;

#define SerialGPS Serial1
#define GPS_PPS_Pin 20

// Offset hours from gps time (UTC)
const int offset = 0; // hours east or west of UTC

volatile uint32_t teensyTimeSet = 0, intCount = 0, setCount = 0;

// file write thread variables
File logFile;
#define logFileBufSize (uint32_t)0x00008000
#define logFileBufWriteSize 4096
volatile uint32_t logFileBufHead = 0;
volatile uint32_t firstTime = 0;
volatile uint32_t logFileBufTail = 0;
volatile uint32_t lfOK = 0, sdOK = 0, SyncProviderSet = 0;

// for the SD card library
const int chipSelect = BUILTIN_SDCARD;

// large data structures
char logFileBuf[logFileBufSize] = {0};
char strBuf[1024]; // for string buffer use, ***FIXME*** should make own for each thread. Could be shorter too.

// time adjustment data collection related 
#define tcrCal(__r__,__a__) (uint32_t)(((uint32_t)__r__<<8) | ((uint32_t)0x000000ff & ((int8_t) __a__)))
#define FTM_ICC_diff  2048 // # of instruction cycles the Teensy RTC will be after the GPS PPS.
#define FOSC 180000000
#define FOSCh 180032768
#define FOSCl 179967232
volatile uint32_t gfti, tfti; // = last index into array set.
volatile uint32_t lastTemp = 0;
volatile uint8_t fineTuneModeSecSkip = 0;
volatile int8_t fineTuneModePrescaleAdjust = 0;
volatile int8_t fineTuneMode = false;
volatile int8_t fineTuneModeNew = false;
volatile int32_t iccAvg = 179998217; // based on 68521 time periods ***FIXME*** should be updated with a MCU PPS time value as soon as possible. Averages then can be applied as they are generated.
struct fineTuneStruct {
  int32_t s;    // seconds
  uint32_t p;   // prescale
  uint32_t icc; // instruction cycle counter
  uint32_t t;   // temperature
  uint8_t processed, fineTuneMode;
} gFineTune[16] = {{0, 0, 0, 0, 0}},
tFineTune[16] = {{0, 0, 0, 0, 0}};
These initializations are pulled from setup().
Code:
  /* start CPU counter */
  ARM_DEMCR |= ARM_DEMCR_TRCENA;
  ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;

  for (int i = 0; i < 16; i++) {
    gFineTune[i].s = 0;
    gFineTune[i].p = 0;
    gFineTune[i].icc = 0;
    gFineTune[i].t = 0;
    gFineTune[i].processed = true;
    gFineTune[i].fineTuneMode = false;
    tFineTune[i].s = 0;
    tFineTune[i].p = 0;
    tFineTune[i].icc = 0;
    tFineTune[i].t = 0;
    tFineTune[i].processed = true;
    tFineTune[i].fineTuneMode = false;
  }

  // set the Time library to use Teensy 3.0's RTC to keep time
  if (0 == (0x00000001 & RTC_SR)) {
    setSyncProvider(getTeensy3Time);
    SyncProviderSet = 1;
    Serial.println("RTC Sync Setup.");
  } else {
    SyncProviderSet = 0;
    Serial.println("RTC not synced!");
  }

  // GPS
  SerialGPS.setTX(5);
  SerialGPS.setRX(21);
  SerialGPS.begin(9600, SERIAL_8N1);

  // setup pin for PPS signal
  pinMode(GPS_PPS_Pin, INPUT);

  // setting up the Teensy RTC PPS interrupt.
  RTC_IER |= 0x10;  // set the TSIE bit (Time Seconds Interrupt Enable)
  NVIC_ENABLE_IRQ(IRQ_RTC_SECOND);

  if (timeStatus() != timeSet) {
    if (pr) Serial.println("Unable to sync with the RTC");
  } else {
    if (pr) Serial.println("Teensy 3 RTC has set the system time");
  }

  // setup for reading internal temperature
  analogReference(INTERNAL);
  analogReadResolution(16);
  analogReadAveraging(16);
#define StartThread(__t__,__s__,__id__,__ic__,__n__) {__ic__ = 0;\
    if(!(__id__ = threads.addThread(__t__, 1, __s__))) {\
      if(pr) Serial.printf("ERROR failed to start %s.\n",__n__);\
    } else {\
      if(pr) Serial.printf("OK started %d %s.\n", __id__,__n__);\
    }\
  }

  StartThread(threadSerialGPS, 4096, XXX, XXX, "threadSerialGPS");
  StartThread(threadTADC, 4096, XXX, XXX, "threadTADC");

  // start interrupt routines.
  attachInterrupt(GPS_PPS_Pin, gpsPPS_isr, RISING);
This is the routine that gathers the ICC values when the Teensy RTC PPS interrupt happens.
Code:
void rtc_seconds_isr() { //formerly rtcPps_interrupt
  uint32_t s, p, icc;
  static uint8_t fti;
  // get the current time
  icc = ARM_DWT_CYCCNT;
  s = RTC_TSR;
  p = RTC_TPR;
  while ((p != RTC_TPR) || (s != RTC_TSR)) {
    s = RTC_TSR;
    p = RTC_TPR;
  }

  // save data into the array
  fti++;
  fti &= 0x0f;
  tFineTune[fti].s = s;
  tFineTune[fti].p = p;
  tFineTune[fti].icc = icc;
  tFineTune[fti].t = lastTemp;
  tFineTune[fti].processed = false;
  tFineTune[fti].fineTuneMode = fineTuneMode;
  tfti = fti;
}
GPS version, the version that existed from the start. The Teensy one is only recent after I found out about the instruction cycle counter. In both routines I only store raw data. No conversions until it is needed.
Code:
// The GPS PPS interrupt code. 
void gpsPPS_isr() {
  uint32_t s, p, pOr, icc;
  static uint8_t fti = 0;

  // get the current time
  icc = ARM_DWT_CYCCNT;
  p = RTC_TPR;
  s = RTC_TSR;
  while ((p != RTC_TPR) || (s != RTC_TSR)) {
    s = RTC_TSR;
    p = RTC_TPR;
  }

  // I do some time critical code here to setup and resynchronize a periodic timer for the 120HZ LED string refresh rate. I should move it to the Teensy PPS ISR. Then a lot of code to handle the lack of GPS PPS can be evaporated.

  // save data into the array after we are not time critical.
  fti++;
  fti &= 0x0f;
  gFineTune[fti].s = s;
  gFineTune[fti].p = p;
  gFineTune[fti].icc = icc;
  gFineTune[fti].t = lastTemp; // c = -0.00825*t +351.15;
  gFineTune[fti].processed = false;
  gFineTune[fti].fineTuneMode = fineTuneMode;
  gfti = fti;
  lastRTC_TPR = p;

  intCount++; // just a counter tracking how many times this interrupt is called.

  // When the clocks are close enough, then go to fine tune mode.
  if ((p <= 1) || (p >= (uint32_t)0x00007ffe)) { // fine tune zone
    if (fineTuneMode == true) return;
    fineTuneMode = true;
    fineTuneModeNew = true;
    if (fineTuneModePrescaleAdjust > 0) {
      RTC_TCR = tcrCal(fineTuneModeSecSkip, fineTuneModePrescaleAdjust);
    }
    return;
  }

  // ***FIXME*** move all tic adjustment to thread.

  if ((fineTuneMode == true) && ((p <= 8) || (p >= (uint32_t)0x00007ff7))) { // fine tune zone
    // do nothing but give time for fine tune mode to settle.
    return;
  }
  // assume fine tune mode failed, and go back into fast slewing.
  // calculate new fast slew adjustment
  fineTuneMode = false;
  fineTuneModeNew = false;
  if (p >= (uint32_t)16384) {
    // high value ones
    if (p >= (uint32_t)(0x00007ffb)) {
      RTC_TCR = tcrCal(0, +1);
      return;
    } else if (p >= (uint32_t)(0x00007f00)) {
      RTC_TCR = tcrCal(0, +((0x00000100 - (p - (0x00007f00))) / 3 + 1));
      return;
    } else {
      RTC_TCR = tcrCal(0, +127);
      return;
    }
  } else {
    // low value ones
    if (p <= (uint32_t)4) {
      RTC_TCR = tcrCal(0, -1);
      return;
    } else if (p <= (uint32_t)0x000000ff) {
      RTC_TCR = tcrCal(0, -(p / 3 + 1));
      return;
    } else {
      RTC_TCR = tcrCal(0, -127);
      return;
    }
  }
  // should not get here.
}
This routine is only called by the thread that does the debug monitoring of the system, thus it can directly output to Serial. I should change it to using the data logging file. Average, high, and low instruction cycle counter ticks per second should be tracked. Needs to be called once a second so it can catch the near buffer full condition and average the entries. It should also track average, high, and low temperatures for the time period. The processor clock does change some due to temperature.
Code:
void avgFineTune(const time_t tt) {
  static int avgDone = false;
  uint32_t lgfti;
  
  lgfti = gfti;
  //
  if ((lgfti >= 14) && (avgDone == false)) {
    int64_t iccAccum; 
    uint32_t secAccum;
    int32_t loc_iccAvg;
    static int64_t lt_iccAccum;
    static uint32_t lt_secAccum;
    iccAccum = 0;
    secAccum = 0;
    // average them
    for (int c = 0; c < 16; c++) {
      if ((gFineTune[c].s > 0) && (gFineTune[(c - 1) % 0x000f].s > 0)) {
        if (gFineTune[c].s > gFineTune[(c - 1) % 0x000f].s) {
          // sec = gFineTune[c].s - gFineTune[(c-1)%0x000f].s;
          if (((gFineTune[c].icc - gFineTune[(c - 1) % 0x000f].icc) /
               (gFineTune[c].s - gFineTune[(c - 1) % 0x000f].s) <= 181800000) &&
              ((gFineTune[c].icc - gFineTune[(c - 1) % 0x000f].icc) /
               (gFineTune[c].s - gFineTune[(c - 1) % 0x000f].s) >= 178200000)
             ) {
            iccAccum += gFineTune[c].icc - gFineTune[(c - 1) % 0x000f].icc;
            secAccum += gFineTune[c].s - gFineTune[(c - 1) % 0x000f].s;
            //Serial.printf(" icc.%lu.%04u.%d\n", iccAccum / (secAccum), (secAccum),c);
          }
        }
      }
    }
    loc_iccAvg = iccAccum / secAccum;
    if((FOSCl < loc_iccAvg) && (FOSCh >= loc_iccAvg)) {
      lt_iccAccum += iccAccum;
      lt_secAccum += secAccum;
      iccAvg = lt_iccAccum / lt_secAccum;
    }
    
    Serial.printf("ICCA,%2u:%02u:%02u", hour(tt), minute(tt), second(tt));
    Serial.printf(",%4u/%02u/%02u", year(tt), month(tt), day(tt));
    Serial.printf(",temp,%f", -0.00825f * lastTemp + 351.15f);
    Serial.printf(",icc,%lu,%04lu,lt,%lu,%06lu\n", loc_iccAvg, secAccum, iccAvg, lt_secAccum);
    avgDone = true;
  } else {
    if (lgfti < 4)
      avgDone = false;
  }
}
Some routines I call.
Code:
// Copies the string in the global string buffer over to the logfile output buffer.
void logFileStrBuf(int c) {
  for (uint32_t x = 0; ((x < 1024) && (x < c)); x++) {
    // check if overrun of buffer
    if (logFileBufHead != ((logFileBufTail - 1) & (logFileBufSize - 1))) {
      logFileBuf[logFileBufHead++] = strBuf[x];
      if (logFileBufHead >= logFileBufSize)
        logFileBufHead = 0;
    } else {
      // buffer overflow error.
      // what to do? put a newline char? Nothing?
    }
  }
}

// takes a position in the GPS fine tune array (gFineTune) and one in the Teensy fine tune array (tFineTune) and calculates the difference between them. It uses 64 bit ints, but I later figured out a way to do it in 32 bit ints, but haven't changed the code yet. It is a subroutine because I initially had multiple places where it was called.
inline int32_t iccDiff(int ig, int it) {
  if(gFineTune[ig].icc < gFineTune[(ig-1) & 0x000f].icc) {
    // handle overflow of gFineTune
    if(tFineTune[it].icc < tFineTune[(it-1) & 0x000f].icc) {
      // handle overflow of tFineTune also
      return (int32_t)(((int64_t)gFineTune[ig].icc + 0x00000000ffffffff) - 
                         ((int64_t)tFineTune[it & 0x000f].icc + 0x00000000ffffffff) - FTM_ICC_diff);
    } else {
      // handle overflow of gFineTune but not tFineTune
      return (int32_t)(((int64_t)gFineTune[ig].icc + 0x00000000ffffffff) - 
                         ((int64_t)tFineTune[it & 0x000f].icc) - FTM_ICC_diff);
    }
  } else if(tFineTune[it].icc < tFineTune[(it-1) & 0x000f].icc) {
    // handle overflow of tFineTune
      return (int32_t)(((int64_t)gFineTune[ig].icc) - 
                         ((int64_t)tFineTune[it & 0x000f].icc + 0x00000000ffffffff) - FTM_ICC_diff);
  } else { // neither overflowed
    return gFineTune[ig].icc - tFineTune[it & 0x000f].icc - FTM_ICC_diff;
  }
  // should not make it here
  return(0x7fffffff);
}
This is the thread that captures and writes out the data for calculating the fine tune adjustments. Note, at this point I'm writing the output data buffer to Serial rather than a file on the SD card. It would be easy to write to the SD card. Note: zero is not zero, it really is FTM_ICC_diff. it is an offset used to keep the GPS PPS interrupt, and the Teensy RTC PPS interrupts from going after the same time slot. Yes, this means the Teensy RTC lags the GPS RTC by FTM_ICC_diff instruction cycles. Is it needed? I don't know.
Code:
void threadTADC(int arg) {
  uint32_t p1TCR, p2TCR, lastTSR;
  uint32_t cTSR, cTCR, c;
  static int8_t lastitFineTuneOffset = 0;
  int32_t ftdiff;
  static int32_t lastftdiff[8] = {0};

#define lastftdiff_push(__v__) {for(int x = 0; x < 7; x++) lastftdiff[x+1] = lastftdiff[x]; \
                                lastftdiff[0] = __v__;}
#define find_high_to_low(__r__) {__r__ = 0; for(int x = 7; x > 0; x--)\
                               if((FTM_ICC_diff != lastftdiff[x]) && (FTM_ICC_diff != lastftdiff[x-1]) &&\
                                   (lastftdiff[x] < lastftdiff[x-1])) __r__ = x;}
#define find_low_to_high(__r__) {__r__ = 0; for(int x = 7; x > 0; x--)\
                               if((FTM_ICC_diff != lastftdiff[x]) && (FTM_ICC_diff != lastftdiff[x-1]) &&\
                                   (lastftdiff[x] > lastftdiff[x-1])) __r__ = x;}
#define find_pos_to_neg(__r__) {__r__ = 0; for(int x = 7; x > 0; x--)\
                               if((lastftdiff[x-1] < FTM_ICC_diff) && (lastftdiff[x] > FTM_ICC_diff)) __r__ = x;}
#define find_neg_to_pos(__r__) {__r__ = 0; for(int x = 7; x > 0; x--)\
                               if((lastftdiff[x-1] > FTM_ICC_diff) && (lastftdiff[x] < FTM_ICC_diff)) __r__ = x;}
#define count_pos(__r__) {__r__ = 0; for(int x = 0; x < 8; x++)\
                         if(lastftdiff[x] > FTM_ICC_diff) __r__++;}
#define count_neg(__r__) {__r__ = 0; for(int x = 0; x < 8; x++)\
                         if(lastftdiff[x] < FTM_ICC_diff) __r__++;}

  // code to gather and output data for time adjustment calculations while trying to keep the RTC within 1/32768th of a second of the offset (FTM_ICC_diff) from GPS RTC PPS output.
  p1TCR = 0;
  p2TCR = 0;
  countMVT = 0;
  acumMVT = 0;
  lastTSR = RTC_TSR;
  while(1) {
    while(fineTuneMode == true) {
      threadTADCCount++;
      if(fineTuneModeNew == true)
        for(int x = 0; x < 8; x++)
          lastftdiff[x] = FTM_ICC_diff;
 
      //c = sprintf(strBuf, "gft%d:",c);
      //logFileStrBuf(c);
      // check for fine correction zone // c = -0.00825*t +351.15;
      for (int ig = 0; ig < 16; ig++) {
        // properly get mv temperature
        acumMVT += lastTemp = analogRead(70);
        countMVT++;
        if ((gFineTune[ig].fineTuneMode == true) && (gFineTune[ig].processed == false)) {
          //
          int eit = lastitFineTuneOffset + 16;
          char *ws;
          ws = "nop";
          for (int it = lastitFineTuneOffset - 1; it < eit; it++) {
            if ((tFineTune[it & 0x000f].processed == false) && (tFineTune[it & 0x000f].fineTuneMode == true) && 
                ((tFineTune[it & 0x000f].s <= gFineTune[ig].s+1) && (tFineTune[it & 0x000f].s >= gFineTune[ig].s-1))
               ) { // seconds ok
              ftdiff = iccDiff(ig,it);
              if((ftdiff < (60000-FTM_ICC_diff)) && (ftdiff > -(60000+FTM_ICC_diff))) { // ftdiff ok   
                // Calculate new adjustment
                // --------------------------------------------------------------------------
                // --------------------------------------------------------------------------
                // --------------------------------------------------------------------------
                int ptn, ntp, pos, neg;
                if((RTC_TCR & 0xff000000) != 0) {
                  //
                  ws = "RTC_TCR skip";
                } else {
                  if((ftdiff > (FTM_ICC_diff+90000)) || (ftdiff < (FTM_ICC_diff-90000))) {
                    for(int x = 0; x < 8; x++) // zero
                      lastftdiff[x] = FTM_ICC_diff;
                  } else {
                    lastftdiff_push(ftdiff);
                  }
                  count_pos(pos);
                  count_neg(neg);
                  if((0 != neg) && (0 != pos)) {
                    // change in positive to negative or negastive to positive.
                    find_pos_to_neg(ptn);
                    find_neg_to_pos(ntp);
                    if(ptn < ntp) {
                      RTC_TCR = tcrCal(1,-1);
                      ws = "tcrCal(1 -1) ptn < ntp";
                    } else {
                      RTC_TCR = tcrCal(1,+1);
                      ws = "tcrCal(1 +1) ptn > ntp";
                    }
                  } else if (0 != pos) {
                    // positive values only
                    if((lastftdiff[0] != FTM_ICC_diff) && (lastftdiff[1] != FTM_ICC_diff)) {
                      if (lastftdiff[0] > lastftdiff[1]) {
                        if(lastftdiff[0] > (FTM_ICC_diff + 2048)) {
                          RTC_TCR = tcrCal(0,-1); // need to swap directions.
                          ws = "tcrCal(0 -1) 1.1";
                        } else {
                          RTC_TCR = tcrCal(1,-1); // need to swap directions.
                          ws = "tcrCal(1 -1) 1.2";
                        }
                      } else {
                        //RTC_TCR = tcrCal(0,+1); // need to stay the same direction
                        ws = "stay same    2";
                      }
                    }
                  } else if (0 != neg) {
                    // negative values only
                    if((lastftdiff[0] != FTM_ICC_diff) && (lastftdiff[1] != FTM_ICC_diff)) {
                      if (lastftdiff[0] < lastftdiff[1]) {
                        if (lastftdiff[0] < (FTM_ICC_diff - 2048)) {
                          RTC_TCR = tcrCal(0,+1); // need to swap directions.
                          ws = "tcrCal(0 +1) 3.1";
                        } else {
                          RTC_TCR = tcrCal(1,+1); // need to swap directions.
                          ws = "tcrCal(1 +1) 3.2";
                        }
                      } else {
                        //RTC_TCR = tcrCal(0,-1); // need to stay the same direction
                        ws = "stay same    4";
                      }
                    }
                  } else {
                    // all zero
                    // Stay the same
                    ws = "stay same 000";
                  }
                }
                lastitFineTuneOffset = it & 0x000f; // found an offse3t that is good, update it // (int32_t)gFineTune[ig].icc - tFineTune[it & 0x00ff].icc,
                c = sprintf(strBuf, 
    "FineTune,%4lu/%02lu/%02lu,%02lu:%02lu:%02lu,%6.2f,%l10u,%10lu,%10ld,%08lx,%08lx,%3ld,%s\n",
                            year(lastTSR), month(lastTSR), day(lastTSR),
                            hour(lastTSR), minute(lastTSR), second(lastTSR),
                            -0.00825f * gFineTune[ig].t + 351.15f,
                            gFineTune[ig].icc,
                            tFineTune[it & 0x000f].icc,
                            ftdiff + FTM_ICC_diff, 
                            p2TCR, RTC_TCR, (int32_t)(lastRTC_TPR > 16000 ? lastRTC_TPR - 32768 : lastRTC_TPR),
                            ws
                           );
                tFineTune[it & 0x000f].processed = true;
                gFineTune[ig].processed = true;
                logFileStrBuf(c);
                ws = "nop";
                fineTuneModeNew = false;
              } // ftdiff ok
            } //seconds OK
          } // for it
        }
      } // for ig
      // check and wait until we increment seconds.
      while ((fineTuneMode == true) && (lastTSR == (cTSR = RTC_TSR))) {
        threadTADCAct2++;
        
        // properly get time compensation register
        cTCR = RTC_TCR;
        p2TCR = p1TCR;
        p1TCR = cTCR;
        
        // properly get mv temperature
        acumMVT += lastTemp = analogRead(70);
        countMVT++;
        
        PostLed1L();
        threads.yield(); // sleep for now
        PostLed1H();
      }
      lastTSR = RTC_TSR;
      countMVT = 0;
      acumMVT = 0;
    }
    while (fineTuneMode == false) {
      threadTADCCount++;
  
      // check and wait until we increment seconds.
      while ((fineTuneMode == false) && (lastTSR == (cTSR = RTC_TSR)) ){
        threadTADCAct2++;
        
        // properly get time compensation register
        cTCR = RTC_TCR;
        p2TCR = p1TCR;
        p1TCR = cTCR;
        
        // properly get mv temperature
        acumMVT += lastTemp = analogRead(70);
        countMVT++;
  
        PostLed1L();
        threads.yield();
        PostLed1H();
      }
      lastTSR = RTC_TSR;
      // write data out
      c = sprintf(strBuf, 
       "Coarse   ,%4lu/%02lu/%02lu,%02lu:%02lu:%02lu,%10lu,%6.2f,%10lu,%10lu,%10ld,%10ld,%08lx,%08lx,%6ld\n",
                  year(lastTSR), month(lastTSR), day(lastTSR),
                  hour(lastTSR), minute(lastTSR), second(lastTSR),
                  0,
                  -0.00825f * lastTemp + 351.15f,
                  0,
                  0,
                  0, 0,
                  p2TCR, p1TCR, (int32_t)(lastRTC_TPR > 16000 ? lastRTC_TPR - 32768 : lastRTC_TPR)
                 );
      countMVT = 0;
      acumMVT = 0;
      threads.yield(); // sleep for now
    }
  }
}
GPS service thread. Only talks to the GPS. Will set the time if off.
Code:
void threadSerialGPS(int arg) {
  while (1) {
    threadSerialGPSCount++;
    while (SerialGPS.available()) {
      if (gps.encode(SerialGPS.read())) { // process gps messages
        // when TinyGPS reports new data...
        unsigned long age;
        struct tm gt, *rt;
        int tc_year;
        int32_t crtc;
        uint8_t tc_mon, tc_mday, tc_hour, tc_min, tc_sec, Hundredths;
        gps.crack_datetime(&tc_year, &tc_mon, &tc_mday, &tc_hour, &tc_min, &tc_sec, &Hundredths, &age);
        crtc = RTC_TSR;
        while (crtc != (int32_t)RTC_TSR) crtc = RTC_TSR;
        rt = gmtime(&crtc - (offset * SECS_PER_HOUR)); /////// - (offset * SECS_PER_HOUR);
        gt.tm_sec  = tc_sec;
        gt.tm_min  = tc_min;
        gt.tm_hour = tc_hour;
        gt.tm_mday = tc_mday;
        gt.tm_mon  = tc_mon;
        gt.tm_year = tc_year;
        if ((teensyTimeSet == 0) && (age < 55) && (
              (gt.tm_sec  != rt->tm_sec)  ||
              (gt.tm_min  != rt->tm_min)  ||
              (gt.tm_hour != rt->tm_hour) ||
              (gt.tm_mday != rt->tm_mday) ||
              (gt.tm_mon  != rt->tm_mon)  ||
              (gt.tm_year != rt->tm_year)
            )) {
          RTC_TCR = 0; // set compensation register to none.
          // set the Time to the latest GPS reading
          // just set the library RTC to get leap seconds handled
          setTime(tc_hour, tc_min, tc_sec, tc_mday, tc_mon, tc_year);
          adjustTime(offset * SECS_PER_HOUR);
          Teensy3Clock.set(1 + now()); // Add one second because we are after the seconds tick
          firstTime = RTC_TSR;
          avgcnt = 0;
          avgacu = 0;
          while (avgcnt + avgacu != 0) {
            avgcnt = 0;
            avgacu = 0;
          }
          setCount++;
          teensyTimeSet = 1;
          timeWasReset = 1;
          lastage = age;
        }
      }
    }
    threads.delay(20);
  }
}
 
Status
Not open for further replies.
Back
Top