A GPS disciplined clock

Dependencies:   net lpc1768 crypto clock web log

Committer:
andrewboyson
Date:
Mon Nov 18 08:51:46 2019 +0000
Revision:
84:baec7c1f5618
Parent:
81:a1de28caf11a
Child:
86:7959accd9679
Updated LPC1768 library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 4:108157115360 1 #include <stdbool.h>
andrewboyson 4:108157115360 2 #include <time.h>
andrewboyson 4:108157115360 3
andrewboyson 4:108157115360 4 #include "log.h"
andrewboyson 24:6f3e53833e62 5 #include "clkgov.h"
andrewboyson 77:4e3925cbb1d8 6 #include "mstimer.h"
andrewboyson 14:1bce51823be0 7 #include "hrtimer.h"
andrewboyson 4:108157115360 8 #include "gpio.h"
andrewboyson 4:108157115360 9 #include "bitband.h"
andrewboyson 34:d9586fc921dc 10 #include "gps.h"
andrewboyson 4:108157115360 11
andrewboyson 4:108157115360 12 #define IO0INTENR_ADDR 0x40028090
andrewboyson 4:108157115360 13 #define IO0INTCLR_ADDR 0x4002808C
andrewboyson 4:108157115360 14 #define ISER0_ADDR 0xE000E100
andrewboyson 4:108157115360 15
andrewboyson 4:108157115360 16 #define FIX_PIN FIO0PIN(23)
andrewboyson 4:108157115360 17 #define ENABLE_DIR FIO0DIR(24)
andrewboyson 4:108157115360 18 #define ENABLE_SET FIO0SET(24)
andrewboyson 4:108157115360 19 #define ENABLE_CLR FIO0CLR(24)
andrewboyson 4:108157115360 20 #define PPS_PIN FIO0PIN(17)
andrewboyson 4:108157115360 21 #define PPS_INT_ENR BIT_BAND4(IO0INTENR_ADDR, 17) = 1
andrewboyson 4:108157115360 22 #define PPS_INT_CLR BIT_BAND4(IO0INTCLR_ADDR, 17) = 1
andrewboyson 4:108157115360 23 #define ISER0 *((volatile unsigned *) ISER0_ADDR)
andrewboyson 4:108157115360 24
andrewboyson 79:992d470e0619 25 static volatile uint32_t pulseHr = 0; //Set after a PPS interrupt. Good for accurate interval between two pulses
andrewboyson 79:992d470e0619 26 static volatile uint32_t pulseMs = 0; //Set after a PPS interrupt. Good for comparing between PPS and NMEA
andrewboyson 79:992d470e0619 27 static volatile bool pulseValid = false; //Set after the first PPS interrupt
andrewboyson 79:992d470e0619 28 static volatile bool hadPulse = false; //Set after each PPS interrupt
andrewboyson 79:992d470e0619 29
andrewboyson 79:992d470e0619 30 int PpsMsSinceLastPulse = 0; //Calculated after a pulse from pulseHr
andrewboyson 79:992d470e0619 31 uint32_t PpsLastPulseMs = 0; //Copied after a pulse from pulseMs
andrewboyson 79:992d470e0619 32 bool PpsLastPulseIsSet = false; //Copied after a pulse from pulseValid
andrewboyson 4:108157115360 33
andrewboyson 79:992d470e0619 34 void PpsHandler() //Called by a PPS interrupt
andrewboyson 79:992d470e0619 35 {
andrewboyson 79:992d470e0619 36 PPS_INT_CLR;
andrewboyson 79:992d470e0619 37 ClkGovSyncPpsI();
andrewboyson 79:992d470e0619 38 pulseHr = HrTimerCount();
andrewboyson 79:992d470e0619 39 pulseMs = MsTimerCount;
andrewboyson 79:992d470e0619 40 pulseValid = true;
andrewboyson 79:992d470e0619 41 hadPulse = true;
andrewboyson 79:992d470e0619 42 }
andrewboyson 77:4e3925cbb1d8 43
andrewboyson 36:2983e45eeb49 44 #define CONFIDENCE_OK 10
andrewboyson 45:3b70941589af 45 #define TIMEOUT_MS 1000
andrewboyson 4:108157115360 46
andrewboyson 4:108157115360 47 static int confidence = 0;
andrewboyson 78:8a29cad1b131 48 static void confidenceReset()
andrewboyson 78:8a29cad1b131 49 {
andrewboyson 78:8a29cad1b131 50 if (confidence == CONFIDENCE_OK) GpsLog("PPS is not stable\r\n");
andrewboyson 78:8a29cad1b131 51 confidence = 0;
andrewboyson 78:8a29cad1b131 52 }
andrewboyson 78:8a29cad1b131 53 static void confidenceIncrease()
andrewboyson 78:8a29cad1b131 54 {
andrewboyson 78:8a29cad1b131 55 if (confidence == CONFIDENCE_OK) return;
andrewboyson 78:8a29cad1b131 56 confidence++;
andrewboyson 78:8a29cad1b131 57 if (confidence == CONFIDENCE_OK) GpsLog("PPS is stable\r\n");
andrewboyson 78:8a29cad1b131 58 }
andrewboyson 35:a535b65203a9 59 bool PpsIsStable() { return confidence == CONFIDENCE_OK; }
andrewboyson 34:d9586fc921dc 60
andrewboyson 36:2983e45eeb49 61 static bool pulseWasStopped = true;
andrewboyson 36:2983e45eeb49 62 static void checkForPulsesStoppingAndStarting()
andrewboyson 34:d9586fc921dc 63 {
andrewboyson 36:2983e45eeb49 64 if (PpsMsSinceLastPulse > TIMEOUT_MS)
andrewboyson 4:108157115360 65 {
andrewboyson 34:d9586fc921dc 66 if (!pulseWasStopped)
andrewboyson 34:d9586fc921dc 67 {
andrewboyson 78:8a29cad1b131 68 GpsLog("PPS pulses have stopped\r\n");
andrewboyson 34:d9586fc921dc 69 pulseWasStopped = true;
andrewboyson 34:d9586fc921dc 70 }
andrewboyson 78:8a29cad1b131 71 confidenceReset();
andrewboyson 4:108157115360 72 }
andrewboyson 34:d9586fc921dc 73 if (hadPulse)
andrewboyson 34:d9586fc921dc 74 {
andrewboyson 80:6a4e8d12d20f 75 static bool prevPulseValid = false;
andrewboyson 34:d9586fc921dc 76 if (pulseWasStopped)
andrewboyson 34:d9586fc921dc 77 {
andrewboyson 80:6a4e8d12d20f 78 if (prevPulseValid) GpsLog("PPS pulses have restarted after %d ms\r\n", PpsMsSinceLastPulse);
andrewboyson 80:6a4e8d12d20f 79 else GpsLog("PPS pulses have started\r\n");
andrewboyson 34:d9586fc921dc 80 pulseWasStopped = false;
andrewboyson 34:d9586fc921dc 81 }
andrewboyson 80:6a4e8d12d20f 82 prevPulseValid = pulseValid;
andrewboyson 34:d9586fc921dc 83 }
andrewboyson 4:108157115360 84 }
andrewboyson 34:d9586fc921dc 85
andrewboyson 35:a535b65203a9 86 static void buildConfidence()
andrewboyson 34:d9586fc921dc 87 {
andrewboyson 79:992d470e0619 88 static uint32_t prevPulseHr = 0;
andrewboyson 79:992d470e0619 89 static bool prevPulseValid = false;
andrewboyson 79:992d470e0619 90 if (prevPulseValid)
andrewboyson 34:d9586fc921dc 91 {
andrewboyson 79:992d470e0619 92 uint32_t hrSinceLastPulse = pulseHr - prevPulseHr;
andrewboyson 84:baec7c1f5618 93 uint32_t msSinceLastPulse = hrSinceLastPulse / HR_TIMER_COUNT_PER_MS;
andrewboyson 35:a535b65203a9 94 uint32_t msSinceLastPulseMod1000 = msSinceLastPulse % 1000;
andrewboyson 35:a535b65203a9 95
andrewboyson 35:a535b65203a9 96 if (msSinceLastPulseMod1000 == 999 || msSinceLastPulseMod1000 == 000)
andrewboyson 34:d9586fc921dc 97 {
andrewboyson 78:8a29cad1b131 98 confidenceIncrease();
andrewboyson 34:d9586fc921dc 99 }
andrewboyson 34:d9586fc921dc 100 else
andrewboyson 34:d9586fc921dc 101 {
andrewboyson 78:8a29cad1b131 102 GpsLog("PPS interval %03d is not 999 or 1000 ms\r\n", msSinceLastPulse);
andrewboyson 78:8a29cad1b131 103 confidenceReset();
andrewboyson 34:d9586fc921dc 104 }
andrewboyson 35:a535b65203a9 105 }
andrewboyson 79:992d470e0619 106 prevPulseHr = pulseHr;
andrewboyson 79:992d470e0619 107 prevPulseValid = pulseValid;
andrewboyson 36:2983e45eeb49 108 }
andrewboyson 34:d9586fc921dc 109
andrewboyson 4:108157115360 110 void PpsMain()
andrewboyson 4:108157115360 111 {
andrewboyson 36:2983e45eeb49 112 //Wait for 100ms after the start up in order to ignore initial glitches on the PPS line
andrewboyson 36:2983e45eeb49 113 static bool afterStartup = false; //Need to store the timeout as hr timer rolls over every 44 seconds
andrewboyson 35:a535b65203a9 114 if (HrTimerCount() > HR_TIMER_COUNT_PER_SECOND / 10) afterStartup = true;
andrewboyson 36:2983e45eeb49 115 if (!afterStartup)
andrewboyson 35:a535b65203a9 116 {
andrewboyson 36:2983e45eeb49 117 hadPulse = false; //Cancel the pulse
andrewboyson 36:2983e45eeb49 118 return;
andrewboyson 35:a535b65203a9 119 }
andrewboyson 36:2983e45eeb49 120
andrewboyson 36:2983e45eeb49 121 checkForPulsesStoppingAndStarting(); //Do this before storing PPsMsSinceLastPulse to allow log to show when they started not zero
andrewboyson 36:2983e45eeb49 122
andrewboyson 79:992d470e0619 123 PpsMsSinceLastPulse = HrTimerSinceMs(pulseHr);
andrewboyson 80:6a4e8d12d20f 124 PpsLastPulseMs = pulseMs;
andrewboyson 80:6a4e8d12d20f 125 PpsLastPulseIsSet = pulseValid;
andrewboyson 36:2983e45eeb49 126
andrewboyson 36:2983e45eeb49 127 if (hadPulse)
andrewboyson 36:2983e45eeb49 128 {
andrewboyson 36:2983e45eeb49 129 buildConfidence();
andrewboyson 36:2983e45eeb49 130 GpsHadPps();
andrewboyson 36:2983e45eeb49 131 }
andrewboyson 36:2983e45eeb49 132
andrewboyson 35:a535b65203a9 133 hadPulse = false;
andrewboyson 4:108157115360 134 }
andrewboyson 4:108157115360 135
andrewboyson 4:108157115360 136 void PpsInit()
andrewboyson 4:108157115360 137 {
andrewboyson 81:a1de28caf11a 138 GpsLog("PPS reset\r\n");
andrewboyson 81:a1de28caf11a 139 confidenceReset();
andrewboyson 36:2983e45eeb49 140 ENABLE_SET; //Set the enable to high
andrewboyson 4:108157115360 141 ENABLE_DIR = 1; //Set the enable pin direction to 1 == output
andrewboyson 4:108157115360 142 PPS_INT_ENR; //Set the PPS pin to be interrupt on rise
andrewboyson 4:108157115360 143 ISER0 |= 1 << 21; //6.5.1 bit1 == Interrupt set enable for EINT3. It MUST be enabled even for GPIO interrupts - I checked.
andrewboyson 4:108157115360 144 }