Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: oldheating gps motorhome heating
clk/clkgov.c@69:4e48d3859b87, 2019-10-18 (annotated)
- 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?
| User | Revision | Line number | New 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 | } |