A GPS disciplined clock
Dependencies: net lpc1768 crypto clock web log
gps/pps.c@84:baec7c1f5618, 2019-11-18 (annotated)
- 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?
User | Revision | Line number | New 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 | } |