Andrew Boyson / clock

Dependents:   oldheating gps motorhome heating

Committer:
andrewboyson
Date:
Fri Oct 18 12:33:56 2019 +0000
Revision:
69:4e48d3859b87
Parent:
57:4daf2e423b27
Child:
70:d04775a75597
Changed clkgovsync routines to accept an offset time in seconds rather than an absolute time.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 47:fd2af868c10a 1 #include <stdlib.h>
andrewboyson 47:fd2af868c10a 2 #include <stdbool.h>
andrewboyson 47:fd2af868c10a 3
andrewboyson 54:a3c018ceca77 4 #include "log.h"
andrewboyson 54:a3c018ceca77 5 #include "clktime.h"
andrewboyson 54:a3c018ceca77 6 #include "clk.h"
andrewboyson 54:a3c018ceca77 7 #include "clkutc.h"
andrewboyson 57:4daf2e423b27 8 #include "time64.h"
andrewboyson 47:fd2af868c10a 9
andrewboyson 47:fd2af868c10a 10 #define GPREG0 (*((volatile unsigned *) 0x40024044))
andrewboyson 47:fd2af868c10a 11
andrewboyson 47:fd2af868c10a 12 volatile int32_t slew = 0; //ns - up to +/- 2.147s of slew
andrewboyson 47:fd2af868c10a 13 volatile int32_t ppb = 0; //This gets set to the last recorded ppb in TickInit
andrewboyson 47:fd2af868c10a 14
andrewboyson 47:fd2af868c10a 15 int32_t ClkGovGetSlew() { return slew; }
andrewboyson 47:fd2af868c10a 16 int32_t ClkGovGetPpb() { return ppb; }
andrewboyson 47:fd2af868c10a 17
andrewboyson 47:fd2af868c10a 18 void ClkGovSetSlew(int32_t value) { slew = value; }
andrewboyson 47:fd2af868c10a 19 void ClkGovSetPpb (int32_t value) { ppb = value; GPREG0 = ppb; }
andrewboyson 47:fd2af868c10a 20 void ClkGovInit()
andrewboyson 47:fd2af868c10a 21 {
andrewboyson 47:fd2af868c10a 22 ppb = GPREG0;
andrewboyson 47:fd2af868c10a 23 }
andrewboyson 47:fd2af868c10a 24
andrewboyson 47:fd2af868c10a 25 //Clock limits
andrewboyson 53:2605da6cf1c7 26 int ClkGovFreqDivisor = 10;
andrewboyson 53:2605da6cf1c7 27 int ClkGovFreqChangeMaxPpb = 1000;
andrewboyson 53:2605da6cf1c7 28 int ClkGovFreqSyncedLimPpb = 1000;
andrewboyson 53:2605da6cf1c7 29 int ClkGovFreqSyncedHysPpb = 100;
andrewboyson 53:2605da6cf1c7 30 int ClkGovSlewDivisor = 10;
andrewboyson 53:2605da6cf1c7 31 int ClkGovSlewChangeMaxMs = 10;
andrewboyson 53:2605da6cf1c7 32 int ClkGovSlewSyncedLimNs = 10000000;
andrewboyson 53:2605da6cf1c7 33 int ClkGovSlewSyncedHysNs = 1000000;
andrewboyson 53:2605da6cf1c7 34 int ClkGovSlewOffsetMaxSecs = 3;
andrewboyson 47:fd2af868c10a 35
andrewboyson 47:fd2af868c10a 36 bool ClkGovTrace = false;
andrewboyson 47:fd2af868c10a 37
andrewboyson 47:fd2af868c10a 38 bool ClkGovIsReceivingTime = false; //This is set from the external source of time
andrewboyson 47:fd2af868c10a 39 bool ClkGovTimeIsSynced = false;
andrewboyson 47:fd2af868c10a 40 bool ClkGovRateIsSynced = false;
andrewboyson 47:fd2af868c10a 41 bool ClkGovIsSynced() { return ClkGovRateIsSynced && ClkGovTimeIsSynced; }
andrewboyson 47:fd2af868c10a 42
andrewboyson 57:4daf2e423b27 43 static void setSyncedTime(clktime diff)
andrewboyson 47:fd2af868c10a 44 {
andrewboyson 57:4daf2e423b27 45 clktime absDiff = llabs(diff);
andrewboyson 57:4daf2e423b27 46 clktime limit = ClkGovSlewSyncedLimNs;
andrewboyson 57:4daf2e423b27 47 clktime hysterisis = ClkGovSlewSyncedHysNs;
andrewboyson 47:fd2af868c10a 48
andrewboyson 47:fd2af868c10a 49 if (absDiff < limit - hysterisis)
andrewboyson 47:fd2af868c10a 50 {
andrewboyson 47:fd2af868c10a 51 if (!ClkGovTimeIsSynced) LogTimeF("Time sync acquired\r\n");
andrewboyson 47:fd2af868c10a 52 ClkGovTimeIsSynced = true;
andrewboyson 47:fd2af868c10a 53 }
andrewboyson 47:fd2af868c10a 54 if (absDiff > limit + hysterisis)
andrewboyson 47:fd2af868c10a 55 {
andrewboyson 69:4e48d3859b87 56 if (ClkGovTimeIsSynced) LogTimeF("Time sync lost (difference = %+lld)\r\n", diff);
andrewboyson 47:fd2af868c10a 57 ClkGovTimeIsSynced = false;
andrewboyson 47:fd2af868c10a 58 }
andrewboyson 47:fd2af868c10a 59 }
andrewboyson 57:4daf2e423b27 60 static void setSyncedRate(clktime diff)
andrewboyson 47:fd2af868c10a 61 {
andrewboyson 47:fd2af868c10a 62
andrewboyson 57:4daf2e423b27 63 clktime absDiff = llabs(diff);
andrewboyson 57:4daf2e423b27 64 clktime limit = ClkGovFreqSyncedLimPpb;
andrewboyson 57:4daf2e423b27 65 clktime hysteresis = ClkGovFreqSyncedHysPpb;
andrewboyson 47:fd2af868c10a 66
andrewboyson 52:333a0822a06d 67 if (absDiff < limit - hysteresis)
andrewboyson 47:fd2af868c10a 68 {
andrewboyson 47:fd2af868c10a 69 if (!ClkGovRateIsSynced) LogTimeF("Rate sync acquired\r\n");
andrewboyson 47:fd2af868c10a 70 ClkGovRateIsSynced = true;
andrewboyson 47:fd2af868c10a 71 }
andrewboyson 52:333a0822a06d 72 if (absDiff > limit + hysteresis)
andrewboyson 47:fd2af868c10a 73 {
andrewboyson 47:fd2af868c10a 74 if ( ClkGovRateIsSynced) LogTimeF("Rate sync lost\r\n");
andrewboyson 47:fd2af868c10a 75 ClkGovRateIsSynced = false;
andrewboyson 47:fd2af868c10a 76 }
andrewboyson 47:fd2af868c10a 77 }
andrewboyson 47:fd2af868c10a 78
andrewboyson 57:4daf2e423b27 79 static void setSlew(clktime diff)
andrewboyson 47:fd2af868c10a 80 {
andrewboyson 57:4daf2e423b27 81 clktime toAdd = -diff / ClkGovSlewDivisor;
andrewboyson 52:333a0822a06d 82 int32_t slewMaxTicks = ClkGovSlewChangeMaxMs << CLK_TIME_ONE_MS_ISH_SHIFT;
andrewboyson 47:fd2af868c10a 83
andrewboyson 47:fd2af868c10a 84 if (toAdd > slewMaxTicks) toAdd = slewMaxTicks;
andrewboyson 47:fd2af868c10a 85 if (toAdd < -slewMaxTicks) toAdd = -slewMaxTicks;
andrewboyson 47:fd2af868c10a 86
andrewboyson 47:fd2af868c10a 87 slew = toAdd;
andrewboyson 47:fd2af868c10a 88
andrewboyson 47:fd2af868c10a 89 if (ClkGovTrace) LogTimeF("Sync setSlew diff %lld gives slew %lld gives TickSlew %ld\r\n", diff, toAdd, slew);
andrewboyson 47:fd2af868c10a 90 }
andrewboyson 57:4daf2e423b27 91 static void adjustPpb(clktime diff)
andrewboyson 47:fd2af868c10a 92 {
andrewboyson 57:4daf2e423b27 93 clktime toAdd = diff / ClkGovFreqDivisor;
andrewboyson 53:2605da6cf1c7 94 int32_t maxAdd = ClkGovFreqChangeMaxPpb;
andrewboyson 47:fd2af868c10a 95
andrewboyson 47:fd2af868c10a 96 if (toAdd > maxAdd) toAdd = maxAdd;
andrewboyson 47:fd2af868c10a 97 if (toAdd < -maxAdd) toAdd = -maxAdd;
andrewboyson 47:fd2af868c10a 98
andrewboyson 47:fd2af868c10a 99 ClkGovSetPpb(ppb - toAdd);
andrewboyson 47:fd2af868c10a 100
andrewboyson 47:fd2af868c10a 101 if (ClkGovTrace) LogTimeF("Sync setPpb diff %lld gives toAdd %lld gives TickPpb %ld\r\n", diff, toAdd, ppb);
andrewboyson 47:fd2af868c10a 102 }
andrewboyson 47:fd2af868c10a 103
andrewboyson 57:4daf2e423b27 104 static clktime lastIntClock = -1; //-1 indicates invalid value. 0 is a valid value.
andrewboyson 57:4daf2e423b27 105 static clktime lastExtClock = -1;
andrewboyson 57:4daf2e423b27 106 static void reset(clktime thisExtClock)
andrewboyson 47:fd2af868c10a 107 {
andrewboyson 47:fd2af868c10a 108 ClkTimeSet(thisExtClock);
andrewboyson 47:fd2af868c10a 109 ClkGovSetPpb(0);
andrewboyson 47:fd2af868c10a 110 lastIntClock = 0;
andrewboyson 47:fd2af868c10a 111 lastExtClock = 0;
andrewboyson 47:fd2af868c10a 112 }
andrewboyson 47:fd2af868c10a 113
andrewboyson 57:4daf2e423b27 114 static void sync(clktime thisExtClock)
andrewboyson 47:fd2af868c10a 115 {
andrewboyson 47:fd2af868c10a 116
andrewboyson 47:fd2af868c10a 117 if (!ClkTimeIsSet()) //Cold start - only ever true if the RTC was not set.
andrewboyson 47:fd2af868c10a 118 {
andrewboyson 47:fd2af868c10a 119 LogTimeF("Sync - cold start of clock so resetting\r\n");
andrewboyson 47:fd2af868c10a 120 reset(thisExtClock);
andrewboyson 47:fd2af868c10a 121 return;
andrewboyson 47:fd2af868c10a 122 }
andrewboyson 47:fd2af868c10a 123
andrewboyson 47:fd2af868c10a 124 //Get the time at the time of the interrupt
andrewboyson 57:4daf2e423b27 125 clktime thisIntClock;
andrewboyson 57:4daf2e423b27 126 clktime thisAbsClock;
andrewboyson 47:fd2af868c10a 127 ClkTimesGetFromSnapshot(&thisIntClock, &thisAbsClock);
andrewboyson 47:fd2af868c10a 128
andrewboyson 47:fd2af868c10a 129 //Calulate the time error
andrewboyson 57:4daf2e423b27 130 clktime absDiff = thisAbsClock - thisExtClock;
andrewboyson 57:4daf2e423b27 131 if (llabs(absDiff) > ((clktime)ClkGovSlewOffsetMaxSecs << CLK_TIME_ONE_SECOND_SHIFT))
andrewboyson 47:fd2af868c10a 132 {
andrewboyson 52:333a0822a06d 133 LogTimeF("Sync - offset is greater than %d seconds so resetting\r\n", ClkGovSlewOffsetMaxSecs);
andrewboyson 47:fd2af868c10a 134 reset(thisExtClock);
andrewboyson 47:fd2af868c10a 135 return;
andrewboyson 47:fd2af868c10a 136 }
andrewboyson 47:fd2af868c10a 137 setSlew(absDiff);
andrewboyson 47:fd2af868c10a 138 setSyncedTime(absDiff);
andrewboyson 47:fd2af868c10a 139
andrewboyson 47:fd2af868c10a 140 //Calculate the rate error
andrewboyson 47:fd2af868c10a 141 if (lastExtClock > -1)
andrewboyson 47:fd2af868c10a 142 {
andrewboyson 57:4daf2e423b27 143 clktime extPeriod = thisExtClock - lastExtClock;
andrewboyson 47:fd2af868c10a 144
andrewboyson 57:4daf2e423b27 145 clktime intPeriod = thisIntClock - lastIntClock;
andrewboyson 57:4daf2e423b27 146 clktime periodDiff = intPeriod - extPeriod;
andrewboyson 47:fd2af868c10a 147
andrewboyson 57:4daf2e423b27 148 clktime ppbDiff;
andrewboyson 47:fd2af868c10a 149 if (extPeriod == CLK_TIME_ONE_SECOND) ppbDiff = periodDiff; //This saves a 64bit shift and division for PPS
andrewboyson 47:fd2af868c10a 150 else ppbDiff = (periodDiff << CLK_TIME_ONE_SECOND_SHIFT) / extPeriod;
andrewboyson 47:fd2af868c10a 151
andrewboyson 47:fd2af868c10a 152 adjustPpb(ppbDiff);
andrewboyson 47:fd2af868c10a 153 setSyncedRate(ppbDiff);
andrewboyson 47:fd2af868c10a 154 }
andrewboyson 47:fd2af868c10a 155
andrewboyson 47:fd2af868c10a 156 //Save last values
andrewboyson 47:fd2af868c10a 157 lastIntClock = thisIntClock;
andrewboyson 47:fd2af868c10a 158 lastExtClock = thisExtClock;
andrewboyson 47:fd2af868c10a 159 }
andrewboyson 57:4daf2e423b27 160 void ClkGovSyncPpsI()
andrewboyson 54:a3c018ceca77 161 {
andrewboyson 57:4daf2e423b27 162 ClkTimeSaveSnapshot();
andrewboyson 57:4daf2e423b27 163 }
andrewboyson 69:4e48d3859b87 164 void ClkGovSyncPpsZ(time64 offset)
andrewboyson 54:a3c018ceca77 165 {
andrewboyson 57:4daf2e423b27 166 clktime time;
andrewboyson 54:a3c018ceca77 167 time = ClkNowTai();
andrewboyson 69:4e48d3859b87 168 time += (clktime)offset << CLK_TIME_ONE_SECOND_SHIFT;
andrewboyson 69:4e48d3859b87 169 time += 1ULL << (CLK_TIME_ONE_SECOND_SHIFT - 1); //Add half a second so as to round to nearest rather than round down
andrewboyson 69:4e48d3859b87 170 time >>= CLK_TIME_ONE_SECOND_SHIFT;
andrewboyson 69:4e48d3859b87 171 time <<= CLK_TIME_ONE_SECOND_SHIFT;
andrewboyson 54:a3c018ceca77 172 sync(time);
andrewboyson 54:a3c018ceca77 173 }
andrewboyson 54:a3c018ceca77 174
andrewboyson 57:4daf2e423b27 175 void ClkGovSyncTime(clktime time)
andrewboyson 57:4daf2e423b27 176 {
andrewboyson 57:4daf2e423b27 177 ClkTimeSaveSnapshot();
andrewboyson 57:4daf2e423b27 178 sync(time);
andrewboyson 57:4daf2e423b27 179 }