A GPS disciplined clock

Dependencies:   net lpc1768 crypto clock web log

Committer:
andrewboyson
Date:
Sun Jan 28 14:41:59 2018 +0000
Revision:
0:67724a462d86
Child:
1:1c4013b67497
Updated libraries

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 0:67724a462d86 1 #include <stdint.h>
andrewboyson 0:67724a462d86 2 #include <stdbool.h>
andrewboyson 0:67724a462d86 3 #include <stdio.h>
andrewboyson 0:67724a462d86 4
andrewboyson 0:67724a462d86 5 #include "log.h"
andrewboyson 0:67724a462d86 6 #include "defs.h"
andrewboyson 0:67724a462d86 7 #include "nmea.h"
andrewboyson 0:67724a462d86 8 #include "sync.h"
andrewboyson 0:67724a462d86 9 #include "timer.h"
andrewboyson 0:67724a462d86 10 #include "led.h"
andrewboyson 0:67724a462d86 11
andrewboyson 0:67724a462d86 12 #define GPS_ENABLE_MASK_0 (1UL << 24)
andrewboyson 0:67724a462d86 13 #define GPS_FIX_MASK_0 (1UL << 23)
andrewboyson 0:67724a462d86 14 #define GPS_PPS_MASK_0 (1UL << 17)
andrewboyson 0:67724a462d86 15
andrewboyson 0:67724a462d86 16 #define CONFIDENCE_OK 60
andrewboyson 0:67724a462d86 17 #define MIN_MS_SINCE_PULSE 150
andrewboyson 0:67724a462d86 18
andrewboyson 0:67724a462d86 19 #define BUCKET_COUNT 20
andrewboyson 0:67724a462d86 20 uint32_t buckets[BUCKET_COUNT] = {0};
andrewboyson 0:67724a462d86 21
andrewboyson 0:67724a462d86 22 void GpsBucketsAsString(int size, char *text)
andrewboyson 0:67724a462d86 23 {
andrewboyson 0:67724a462d86 24 char* p = text;
andrewboyson 0:67724a462d86 25 for (int i = 0; i < BUCKET_COUNT; i++)
andrewboyson 0:67724a462d86 26 {
andrewboyson 0:67724a462d86 27 if (p - text < size - 20)
andrewboyson 0:67724a462d86 28 {
andrewboyson 0:67724a462d86 29 p += sprintf(p, "%d\r\n", buckets[i]);
andrewboyson 0:67724a462d86 30 }
andrewboyson 0:67724a462d86 31 }
andrewboyson 0:67724a462d86 32 *p = 0;
andrewboyson 0:67724a462d86 33 }
andrewboyson 0:67724a462d86 34
andrewboyson 0:67724a462d86 35
andrewboyson 0:67724a462d86 36 static int confidence = 0;
andrewboyson 0:67724a462d86 37 bool GpsStable = false;
andrewboyson 0:67724a462d86 38 static time_t gpsTime = 0;
andrewboyson 0:67724a462d86 39 static uint32_t msTimer;
andrewboyson 0:67724a462d86 40 static volatile bool hadPulse;
andrewboyson 0:67724a462d86 41
andrewboyson 0:67724a462d86 42 __irq void GpsPpsHandler()
andrewboyson 0:67724a462d86 43 {
andrewboyson 0:67724a462d86 44 LPC_GPIOINT->IO0IntClr = GPS_PPS_MASK_0;
andrewboyson 0:67724a462d86 45 SyncPpsI();
andrewboyson 0:67724a462d86 46 hadPulse = true;
andrewboyson 0:67724a462d86 47 }
andrewboyson 0:67724a462d86 48
andrewboyson 0:67724a462d86 49 void pulseN(int ms)
andrewboyson 0:67724a462d86 50 {
andrewboyson 0:67724a462d86 51 int missed = (ms + 500) / 1000;
andrewboyson 0:67724a462d86 52 int ppsOffset = ms % 1000;
andrewboyson 0:67724a462d86 53
andrewboyson 0:67724a462d86 54 gpsTime += missed;
andrewboyson 0:67724a462d86 55
andrewboyson 0:67724a462d86 56 if (ppsOffset != 999 && ppsOffset != 0)
andrewboyson 0:67724a462d86 57 {
andrewboyson 0:67724a462d86 58 LogTimeF("GPS %4d ms PPS interval is not 999 or 000 ms - sync disabled\r\n", ms);
andrewboyson 0:67724a462d86 59 confidence = 0;
andrewboyson 0:67724a462d86 60 }
andrewboyson 0:67724a462d86 61
andrewboyson 0:67724a462d86 62 if (confidence == CONFIDENCE_OK) SyncPpsN(gpsTime);
andrewboyson 0:67724a462d86 63
andrewboyson 0:67724a462d86 64 }
andrewboyson 0:67724a462d86 65 void GpsNmeaTimeReceived(time_t nmeaTime, int nmeaMs)
andrewboyson 0:67724a462d86 66 {
andrewboyson 0:67724a462d86 67 //Ignore time messages if the module is not ready or has no fix
andrewboyson 0:67724a462d86 68 if (!NmeaHaveFix) return;
andrewboyson 0:67724a462d86 69 if (NmeaModuleReadiness != NMEA_READY) return;
andrewboyson 0:67724a462d86 70
andrewboyson 0:67724a462d86 71 //Get the time of the message relative to the last pulse
andrewboyson 0:67724a462d86 72 int ms = TimerSinceMs(msTimer);
andrewboyson 0:67724a462d86 73
andrewboyson 0:67724a462d86 74 //Add time to bins to allow display of distribution
andrewboyson 0:67724a462d86 75 int bucket = ms * BUCKET_COUNT / 1000;
andrewboyson 0:67724a462d86 76 if (bucket < BUCKET_COUNT) buckets[bucket]++;
andrewboyson 0:67724a462d86 77
andrewboyson 0:67724a462d86 78 //Check for non zero ms in NMEA
andrewboyson 0:67724a462d86 79 if (nmeaMs) LogTimeF("GPS %4d ms NMEA time has non zero ms = %d\r\n", ms, nmeaMs);
andrewboyson 0:67724a462d86 80
andrewboyson 0:67724a462d86 81 //Ignore time messages which have probably overflowed from a previous pulse
andrewboyson 0:67724a462d86 82 if (ms < MIN_MS_SINCE_PULSE)
andrewboyson 0:67724a462d86 83 {
andrewboyson 0:67724a462d86 84 LogTimeF("GPS %4d ms NMEA time message ignored as received before %d ms\r\n", ms, MIN_MS_SINCE_PULSE);
andrewboyson 0:67724a462d86 85 return;
andrewboyson 0:67724a462d86 86 }
andrewboyson 0:67724a462d86 87
andrewboyson 0:67724a462d86 88 //Handle the time message
andrewboyson 0:67724a462d86 89 if (gpsTime == nmeaTime)
andrewboyson 0:67724a462d86 90 {
andrewboyson 0:67724a462d86 91 confidence++;
andrewboyson 0:67724a462d86 92 if (confidence > CONFIDENCE_OK) confidence = CONFIDENCE_OK;
andrewboyson 0:67724a462d86 93 }
andrewboyson 0:67724a462d86 94 else
andrewboyson 0:67724a462d86 95 {
andrewboyson 0:67724a462d86 96 confidence = 0;
andrewboyson 0:67724a462d86 97 if (gpsTime) LogTimeF("GPS %4d ms NMEA time differs by %+d seconds so corrected pps count - sync disabled\r\n", ms, nmeaTime - gpsTime);
andrewboyson 0:67724a462d86 98 else LogTimeF("GPS %4d ms not set so setting pps count to NMEA time - sync disabled\r\n", ms, nmeaTime - gpsTime);
andrewboyson 0:67724a462d86 99 gpsTime = nmeaTime;
andrewboyson 0:67724a462d86 100 }
andrewboyson 0:67724a462d86 101 }
andrewboyson 0:67724a462d86 102 void GpsMain()
andrewboyson 0:67724a462d86 103 {
andrewboyson 0:67724a462d86 104 NmeaMain();
andrewboyson 0:67724a462d86 105
andrewboyson 0:67724a462d86 106 //Disable syncing until Nmea module is ready
andrewboyson 0:67724a462d86 107 if (NmeaModuleReadiness != NMEA_READY) confidence = 0;
andrewboyson 0:67724a462d86 108
andrewboyson 0:67724a462d86 109 //Handle the arrival of a pulse
andrewboyson 0:67724a462d86 110 int ms = TimerSinceMs(msTimer);
andrewboyson 0:67724a462d86 111 bool pulseIsStopped = ms > 1000;
andrewboyson 0:67724a462d86 112 if (hadPulse)
andrewboyson 0:67724a462d86 113 {
andrewboyson 0:67724a462d86 114 msTimer = TimerNowCount();
andrewboyson 0:67724a462d86 115 pulseN(ms);
andrewboyson 0:67724a462d86 116 hadPulse = false;
andrewboyson 0:67724a462d86 117 pulseIsStopped = false; //This gets the signal 1 scan before the ms is reset
andrewboyson 0:67724a462d86 118 }
andrewboyson 0:67724a462d86 119
andrewboyson 0:67724a462d86 120 //Check pulses are arriving
andrewboyson 0:67724a462d86 121 static bool pulseWasStopped = false;
andrewboyson 0:67724a462d86 122 if ( pulseIsStopped) confidence = 0;
andrewboyson 0:67724a462d86 123 if ( pulseIsStopped && !pulseWasStopped) LogTimeF("GPS %4d ms PPS pulses have stopped - sync disabled\r\n", ms);
andrewboyson 0:67724a462d86 124 if (!pulseIsStopped && pulseWasStopped) LogTimeF("GPS %4d ms PPS pulses have started\r\n", ms);
andrewboyson 0:67724a462d86 125 pulseWasStopped = pulseIsStopped;
andrewboyson 0:67724a462d86 126
andrewboyson 0:67724a462d86 127
andrewboyson 0:67724a462d86 128 //Record any fix quality changes
andrewboyson 0:67724a462d86 129 static bool lastHaveFix = false;
andrewboyson 0:67724a462d86 130 if (!NmeaHaveFix) confidence = 0;
andrewboyson 0:67724a462d86 131 if ( NmeaHaveFix && !lastHaveFix) LogTimeF("GPS %4d ms NMEA fix acquired\r\n", ms);
andrewboyson 0:67724a462d86 132 if (!NmeaHaveFix && lastHaveFix) LogTimeF("GPS %4d ms NMEA fix lost - sync disabled\r\n", ms);
andrewboyson 0:67724a462d86 133 lastHaveFix = NmeaHaveFix;
andrewboyson 0:67724a462d86 134
andrewboyson 0:67724a462d86 135 //Settle time after disruption
andrewboyson 0:67724a462d86 136 GpsStable = confidence == CONFIDENCE_OK;
andrewboyson 0:67724a462d86 137 static bool lastStable = false;
andrewboyson 0:67724a462d86 138 if ( GpsStable && !lastStable) LogTimeF("GPS %4d ms stable - sync enabled\r\n", ms);
andrewboyson 0:67724a462d86 139 lastStable = GpsStable;
andrewboyson 0:67724a462d86 140 }
andrewboyson 0:67724a462d86 141 void GpsInit()
andrewboyson 0:67724a462d86 142 {
andrewboyson 0:67724a462d86 143 msTimer = TimerNowCount();
andrewboyson 0:67724a462d86 144 NmeaInit();
andrewboyson 0:67724a462d86 145
andrewboyson 0:67724a462d86 146 LPC_GPIO0->FIODIR |= GPS_ENABLE_MASK_0; //Set the enable pin direction to 1 == output
andrewboyson 0:67724a462d86 147 LPC_GPIO0->FIOCLR = GPS_ENABLE_MASK_0; //Set the enable to low to reset the GPS
andrewboyson 0:67724a462d86 148 while (TimerSinceMs(msTimer) < 10) __nop();
andrewboyson 0:67724a462d86 149 LPC_GPIO0->FIOSET = GPS_ENABLE_MASK_0; //Set the enable to high
andrewboyson 0:67724a462d86 150
andrewboyson 0:67724a462d86 151 LPC_GPIOINT->IO0IntEnR |= GPS_PPS_MASK_0; //Set the PPS pin to be interrupt on rise
andrewboyson 0:67724a462d86 152 NVIC->ISER[0] |= 1 << 21; //6.5.1 bit1 == Interrupt set enable for EINT3. It MUST be enabled even for GPIO interrupts - I checked.
andrewboyson 0:67724a462d86 153 }