A simple NTP server using GPS
To make the experience fit your profile, pick a username and tell us what interests you.
We found and based on your interests.
I've created a new ESP32 based version that syncs a DS2131 RTC with a GPS module to within a few microseconds. Its still very much a work in progress. It IS functional :-)
Syncing the DS3231 to the GPS is done with a small high level (level 5) interrupt handler in assembly. This generates a timestamp and offset in microseconds tracking the active edges of the GPS PPS and RTC SQW signals. This data is then fed in to a PID algorithm that will generate an offset value used to speed up and slow down the DS3231 RTC.
The GitHub repository for this version is here
In a second version I'm thinking of using a larger touch LCD display and adding a DS3231 (RTC) disciplined to the GPS 1hz to handle timing. I've been playing with this using an esp32 and tracking the offset time between the GPS and RTCs 1h pulses as input to a PID algorithm and driving the DS3231s aging offset register to sync them.
The biggest issue I have run in to is the GPIO interrupt latency is typically just under 2us with occasional jumps to 10us! I'm currently averaging the last 10 deltas and using that as input for PID as a work around. With this I seem to be able to keep the RTC to within +/- 2us of the GPS 1hz signal.
I'm thinking about trying to use an esp8266 again. I switched to the esp32 because software serial at 9600 baud gave a lot of watchdog resets, not what you want in a time server. Software serial was needed because the esp8266 has only one usable UART and that is used for programming and debug messages. It has a second one but the receive pin is in use by on module flash making it unsuitable for receiving messages from a GPS module.
I've found that its possible to swap the pins used for UART0 to an alternate set of pins and I can connect the GPS there. You can also send debug messages to UART1 since its transmit pin is usable.
I'm interested to see if the GPIO interrupt latency is more consistent than I have found on the ESP32. There the latency varies between 4us and 38us. With wifi connected it tends to be on the higher side. With two cores, wifi using core0 and my app and GIPO interrupts using core1 I expected the ESP32 to be able to respond consistently.
I've moved to an ESP32, and renamed the project. I had too many issues with software serial on the ESP8266 failing to read properly at 9600 baud. Also I'm now using esp-idf instead of Arduino. I've added a small OLED display to show status and current UTC time.
Its running 3 "tasks":
I threw together a quick prototype using a NodeMCU, small oled display and a gps unit. Then spent some time working with the software.
I had seen a number random crashes and found that this was due to power demands from the GPS module so I added a large-ish capacitor nearby.
Since the ESP8266 only has one USART I’m using a software serial implementation. I've still seen some crashes and decoding the stack trace they are happening on the interrupt service routine for this module. A quick look at the modules code shows a WAIT macro that may not be safe in an interrupt service routine,
I'm also using a nice, small NMEA parsing library to parse the GPS messages.
Its responding to ntp requests and syncing with the PPS signal from the GPS unit. I am seeing a few times where the NMEA message from the GPS is parsed after the next second pulse from the GPS. Because I'm validating validating that the time I have is correct with each message I see it time warp back one second then timeworn forward one second a few times a day. I think that the ESP wifi housekeeping functions may sometimes delay the serial parsing. Or that rendering the display could be taking too long to render each second.
While I don't have a GPS module, I do have boards from SynchroClock that have the DS3231 real time clock 1hz routed to a GPIO pin on on the ESP8266. This lets me pretend I have a GPS (and I read the current time from the DS3231).
I used a strategy mentioned by @Nick Sayer, in the comments on one of his projects here, and used the ESP8266 builtin CPU cycle counter, 80Mhz, to interpolate the time between seconds. And it answers queries!
flugelberry$ ntpdate -q -u 192.168.0.29
server 192.168.0.29, stratum 1, offset 0.273729, delay 0.06538
3 Nov 19:39:51 ntpdate[8704]: adjust time server 192.168.0.29 offset 0.273729 sec
EDIT: It turns out that ESP.getCycleCount() is not very consistent. Using this I end up with up with well over 250us of jitter! Maybe something with idle sleep or some other power saving mode? In any case using micros() works much much better with jitter less than 20us!
Create an account to leave a comment. Already have an account? Log In.
That's pretty much what the new (esp32) version does. As long as its within 500ms the OFFSET register in the DS3231 is adjusted to speed up or slow down. Measuring with a scope I never see it off by more than a few microseconds. And when there is a loss of GPS the DS3231 has been tuned (when there was a signal) to have much lower drift, on the order of 0.2ppm.
While it is possible I generally include an DS3231 on any project that is that sensitive to time and use the NTP server to set it periodically. For instance I did that here.
Having done the same thing but on a raspberry pi, I now would like to try something like this, as I am now understanding that smaller self contained systems like this are much easier, and less to fail than with a whole small board computer like a rpi. Are you able to fully configure the instance of NTP with the same options you'd put into the ntp.conf file normally? I had to do some tinkering to get my unit to be a stand alone unit and not still have it polling external NTP internet servers. Had to do that configuration so that I had my two gps sources both were accepted by NTP. (One with an asterisk next to it, the other with a + next to it. SHOWN BELOW.) Just curious about that config. I have a few ESP32 boardfs on the way to meddle with, as well as a couple cheap GPS modules. I am still kicking myself in the ass for not checking aliexpress first and getting the gps modules for about $6 and buying a single GPS module from expensive-ass adafruit for $40, lol!
root@PiTime:~# ntpq -pn
remote refid st t when poll reach delay offset jitter
==============================================================================
*127.127.28.2 .PPS. 0 l 47 64 377 0.000 -0.016 0.001
+127.127.28.0 .GPS. 0 l 46 64 377 0.000 -496.30 23.862
Become a member to follow this project and never miss any updates
Instead of attempting to sync to the exact time "right now", consider changing the rate of your local clock so it tracks the rate of the reference (this is how NTP works). Then you can set the local epoch to match the reference, and Bob's your uncle. Whenever your local time runs fast, don't jam the time back, slow the rate, etc.