Andrew Boyson / clock

Dependents:   oldheating gps motorhome heating

Committer:
andrewboyson
Date:
Tue Jul 04 15:04:26 2017 +0000
Revision:
5:a3e37ce4975d
Parent:
4:095dfd4a316b
Child:
6:d8a6235486b7
Better saved the ppb state

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 4:095dfd4a316b 1 #include "mbed.h"
andrewboyson 4:095dfd4a316b 2 #include "rtc.h"
andrewboyson 4:095dfd4a316b 3 #include "time.h"
andrewboyson 4:095dfd4a316b 4 #include "settings.h"
andrewboyson 0:33686e88f09a 5
andrewboyson 0:33686e88f09a 6 #define ONE_BILLION 1000000000
andrewboyson 0:33686e88f09a 7
andrewboyson 0:33686e88f09a 8 #define COUNT_PER_TICK 96000000
andrewboyson 0:33686e88f09a 9
andrewboyson 0:33686e88f09a 10 static int64_t nsTickCount;
andrewboyson 0:33686e88f09a 11 static int64_t nsFreqCount;
andrewboyson 0:33686e88f09a 12 static int64_t nsTimeCount;
andrewboyson 5:a3e37ce4975d 13 static bool nsCountIsSet = false;
andrewboyson 5:a3e37ce4975d 14 bool TickIsSet() { return nsCountIsSet; }
andrewboyson 5:a3e37ce4975d 15 void TickSet(int64_t extClock)
andrewboyson 5:a3e37ce4975d 16 {
andrewboyson 5:a3e37ce4975d 17 nsTickCount = 0;
andrewboyson 5:a3e37ce4975d 18 nsFreqCount = 0;
andrewboyson 5:a3e37ce4975d 19 nsTimeCount = extClock;
andrewboyson 5:a3e37ce4975d 20 LPC_TIM1->TCR = 2; // 21.6.2 Timer Control Register - Reset TC and PC.
andrewboyson 5:a3e37ce4975d 21 LPC_TIM1->TCR = 1; // 21.6.2 Timer Control Register - Enable TC and PC.
andrewboyson 5:a3e37ce4975d 22 nsCountIsSet = true;
andrewboyson 5:a3e37ce4975d 23 }
andrewboyson 0:33686e88f09a 24
andrewboyson 5:a3e37ce4975d 25 int32_t slew = 0; //ns - up to +/- 2.147s of slew
andrewboyson 5:a3e37ce4975d 26 int32_t TickGetSlew() { return slew; }
andrewboyson 5:a3e37ce4975d 27 void TickSetSlew(int32_t value) { slew = value; }
andrewboyson 5:a3e37ce4975d 28
andrewboyson 5:a3e37ce4975d 29 int32_t ppb = 0;
andrewboyson 5:a3e37ce4975d 30 int32_t TickGetPpb () { return ppb; }
andrewboyson 5:a3e37ce4975d 31 void TickSetPpb (int32_t value) { ppb = value; LPC_RTC->GPREG0 = ppb; }
andrewboyson 5:a3e37ce4975d 32 void TickAddPpb (int32_t value) { ppb += value; LPC_RTC->GPREG0 = ppb; }
andrewboyson 0:33686e88f09a 33
andrewboyson 0:33686e88f09a 34 #define CLOCK_TIC 0
andrewboyson 0:33686e88f09a 35 #define CLOCK_INT 1
andrewboyson 0:33686e88f09a 36 #define CLOCK_ABS 2
andrewboyson 0:33686e88f09a 37
andrewboyson 0:33686e88f09a 38 static void tick(void) //Called from main if the timer has overflowed
andrewboyson 0:33686e88f09a 39 {
andrewboyson 0:33686e88f09a 40 //Reset the timer interrupt
andrewboyson 0:33686e88f09a 41 LPC_TIM1->IR |= 1;
andrewboyson 0:33686e88f09a 42
andrewboyson 0:33686e88f09a 43 //reset the tick timer
andrewboyson 0:33686e88f09a 44 LPC_TIM1->TCR = 2; // 21.6.2 Timer Control Register - Reset TC and PC.
andrewboyson 0:33686e88f09a 45 LPC_TIM1->TCR = 1; // 21.6.2 Timer Control Register - Enable TC and PC
andrewboyson 0:33686e88f09a 46
andrewboyson 0:33686e88f09a 47 //Calculate the new counts
andrewboyson 0:33686e88f09a 48 nsTickCount += ONE_BILLION;
andrewboyson 5:a3e37ce4975d 49 nsFreqCount += ppb;
andrewboyson 5:a3e37ce4975d 50 nsTimeCount += slew;
andrewboyson 0:33686e88f09a 51
andrewboyson 0:33686e88f09a 52 //Feedback the amount slewed
andrewboyson 5:a3e37ce4975d 53 slew = 0;
andrewboyson 0:33686e88f09a 54 }
andrewboyson 0:33686e88f09a 55 static volatile int64_t nsTickSnapshot;
andrewboyson 0:33686e88f09a 56 static volatile int64_t nsFreqSnapshot;
andrewboyson 0:33686e88f09a 57 static volatile int64_t nsTimeSnapshot;
andrewboyson 0:33686e88f09a 58 static volatile int32_t timerSnapshot;
andrewboyson 0:33686e88f09a 59
andrewboyson 0:33686e88f09a 60 void TickSaveSnapshotI()
andrewboyson 0:33686e88f09a 61 {
andrewboyson 0:33686e88f09a 62 timerSnapshot = LPC_TIM1->TC;
andrewboyson 0:33686e88f09a 63 nsTickSnapshot = nsTickCount;
andrewboyson 0:33686e88f09a 64 nsFreqSnapshot = nsFreqCount;
andrewboyson 0:33686e88f09a 65 nsTimeSnapshot = nsTimeCount;
andrewboyson 0:33686e88f09a 66 }
andrewboyson 0:33686e88f09a 67 void TickRetrieveSnapshot(int64_t* pNsInt, int64_t* pNsAbs)
andrewboyson 0:33686e88f09a 68 {
andrewboyson 0:33686e88f09a 69 int64_t fraction = ((int64_t)timerSnapshot << 32) / COUNT_PER_TICK;
andrewboyson 0:33686e88f09a 70 int64_t nsFraction;
andrewboyson 0:33686e88f09a 71
andrewboyson 0:33686e88f09a 72 int64_t nsBase = nsTickSnapshot;
andrewboyson 0:33686e88f09a 73 int64_t nsPerTick = ONE_BILLION;
andrewboyson 0:33686e88f09a 74
andrewboyson 0:33686e88f09a 75 nsBase += nsFreqSnapshot;
andrewboyson 5:a3e37ce4975d 76 nsPerTick += ppb;
andrewboyson 0:33686e88f09a 77 nsFraction = (nsPerTick * fraction) >> 32;
andrewboyson 0:33686e88f09a 78 *pNsInt = nsBase + nsFraction;
andrewboyson 0:33686e88f09a 79
andrewboyson 0:33686e88f09a 80 nsBase += nsTimeSnapshot;
andrewboyson 5:a3e37ce4975d 81 nsPerTick += slew;
andrewboyson 0:33686e88f09a 82 nsFraction = (nsPerTick * fraction) >> 32;
andrewboyson 0:33686e88f09a 83 *pNsAbs = nsBase + nsFraction;
andrewboyson 0:33686e88f09a 84 }
andrewboyson 0:33686e88f09a 85 static int64_t getClock(char index)
andrewboyson 0:33686e88f09a 86 {
andrewboyson 0:33686e88f09a 87 //Get the base and fractional values while protected from a tick interrupt
andrewboyson 0:33686e88f09a 88 __disable_irq();
andrewboyson 0:33686e88f09a 89 int64_t nsBase = nsTickCount;
andrewboyson 0:33686e88f09a 90 int64_t nsPerTick = ONE_BILLION;
andrewboyson 0:33686e88f09a 91 if (index >= CLOCK_INT)
andrewboyson 0:33686e88f09a 92 {
andrewboyson 0:33686e88f09a 93 nsBase += nsFreqCount;
andrewboyson 5:a3e37ce4975d 94 nsPerTick += ppb;
andrewboyson 0:33686e88f09a 95 }
andrewboyson 0:33686e88f09a 96 if (index >= CLOCK_ABS)
andrewboyson 0:33686e88f09a 97 {
andrewboyson 0:33686e88f09a 98 nsBase += nsTimeCount;
andrewboyson 5:a3e37ce4975d 99 nsPerTick += slew;
andrewboyson 0:33686e88f09a 100 }
andrewboyson 0:33686e88f09a 101 int32_t count = LPC_TIM1->TC;
andrewboyson 0:33686e88f09a 102 __enable_irq();
andrewboyson 0:33686e88f09a 103
andrewboyson 0:33686e88f09a 104 //Now calculate everything
andrewboyson 0:33686e88f09a 105 int64_t fraction = ((int64_t)count << 32) / COUNT_PER_TICK;
andrewboyson 0:33686e88f09a 106 int64_t nsFraction = (nsPerTick * fraction) >> 32;
andrewboyson 0:33686e88f09a 107
andrewboyson 0:33686e88f09a 108 //Return the base plus the fractional part
andrewboyson 0:33686e88f09a 109 return nsBase + nsFraction;
andrewboyson 0:33686e88f09a 110
andrewboyson 0:33686e88f09a 111 }
andrewboyson 0:33686e88f09a 112 int64_t TickGetTic() {return getClock(CLOCK_TIC); }
andrewboyson 0:33686e88f09a 113 int64_t TickGetInt() {return getClock(CLOCK_INT); }
andrewboyson 0:33686e88f09a 114 int64_t TickGetAbs() {return getClock(CLOCK_ABS); }
andrewboyson 0:33686e88f09a 115
andrewboyson 0:33686e88f09a 116 int TickInit(void)
andrewboyson 0:33686e88f09a 117 {
andrewboyson 0:33686e88f09a 118 nsTickCount = 0;
andrewboyson 0:33686e88f09a 119 nsFreqCount = 0;
andrewboyson 0:33686e88f09a 120 nsTimeCount = 0;
andrewboyson 0:33686e88f09a 121
andrewboyson 5:a3e37ce4975d 122 ppb = LPC_RTC->GPREG0; //This is saved each time Tickppb is updated
andrewboyson 5:a3e37ce4975d 123 slew = 0;
andrewboyson 5:a3e37ce4975d 124 nsCountIsSet = false;
andrewboyson 0:33686e88f09a 125
andrewboyson 0:33686e88f09a 126 LPC_SC->PCLKSEL0 &= ~0x20; // 4.7.3 Peripheral Clock Selection - PCLK_peripheral PCLK_TIMER1 01xxxx = CCLK - reset bit 5
andrewboyson 0:33686e88f09a 127 LPC_SC->PCLKSEL0 |= 0x10; // set bit 4
andrewboyson 0:33686e88f09a 128 LPC_SC->PCONP |= 4; // 4.8.9 Power Control for Peripherals register - Timer1 Power On
andrewboyson 0:33686e88f09a 129 LPC_TIM1->TCR = 2; // 21.6.2 Timer Control Register - Reset TC and PC.
andrewboyson 0:33686e88f09a 130 LPC_TIM1->CTCR = 0; // 21.6.3 Count Control Register - Timer mode
andrewboyson 0:33686e88f09a 131 LPC_TIM1->PR = 0; // 21.6.5 Prescale register - Don't prescale 96MHz clock (divide by PR+1).
andrewboyson 0:33686e88f09a 132 LPC_TIM1->MR0 = COUNT_PER_TICK; // 21.6.7 Match Register 0 - Match count
andrewboyson 0:33686e88f09a 133 LPC_TIM1->MCR = 1; // 21.6.8 Match Control Register - interrupt on match
andrewboyson 0:33686e88f09a 134 LPC_TIM1->TCR = 1; // 21.6.2 Timer Control Register - Enable TC and PC
andrewboyson 0:33686e88f09a 135
andrewboyson 0:33686e88f09a 136 NVIC_SetVector(TIMER1_IRQn, (uint32_t)&tick);
andrewboyson 0:33686e88f09a 137 NVIC_EnableIRQ(TIMER1_IRQn);
andrewboyson 0:33686e88f09a 138
andrewboyson 0:33686e88f09a 139 return 0;
andrewboyson 0:33686e88f09a 140 }