What's new

Set the router clock with a GPS receiver for under $70

  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

My latest update is to use Arduino Nano with a real-time clock. So I follow this project with some tweaks.

Soon, it all goes into a little black box.
fk625i.jpg


In some parts of the world, they arrest you for bringing it to class.
28qx5sg.jpg


Specifically, I have these pieces here:
  • Arduino Nano (CH341 UART) microcontroller
  • DS3231 realtime clock w/backup lithium battery
  • 1602A LCD liquid crystal, blue 16x2 characters
  • RY825AI GPS receiver module
  • Green LED to monitor the GPS fix
  • 10-kOhm resistor to protect a digital pin
  • 330-Ohm resistor to regulate power on green LED
  • 10uF electrolytic capacitor to disable the auto-reset of Nano
  • 10-kOhm potentiometer to adjust LCD brightness
  • CAT6 cable for GPS connection
  • USB cable for router connection

How to wire the Arduino Nano for GPS.
w6xv2b.png

SOURCE: http://geekistuff.blogspot.de/2014/06/advance-u-blox-neo-6m-gps-module.html


My Arduino sketch is approximately 900 lines C++ code, to perform this functions:
  • Sync the RTC time with GPS time on PPS pulse every 5 minutes.
  • Update the LCD display in local time. Support daylight saving time for US and EU regions.
  • Has command to get the RTC time via USB serial.
  • Has command to set the RTC time via USB serial.
  • Has command to change the timezone of the LCD display via USB serial.

Here's example code to sync the router's clock with the current time of the RTC via USB serial. You must enable the CH341 UART driver in the kernel configuration of the Asuswrt-Merlin firmware.

/jffs/scripts/wan-start
Code:
#!/bin/sh

# set the system clock from the RTC
if [ ! -e /dev/ttyUSB0 ]; then
  /sbin/lsmod | /bin/grep -e "ch341" > /dev/null 2>&1 || /sbin/modprobe ch341
  N=1
  while [ $N -lt 30 ]; do
    if [ -e /dev/ttyUSB0 ]; then
      /bin/echo R>/dev/ttyUSB0 && read -t 2 RTC</dev/ttyUSB0 && RTC=${RTC%$'\r'} && /usr/bin/logger -t $(/usr/bin/basename $0) "custom script setting system clock to $(/bin/date -u -d $RTC)" && /bin/date -u -s $RTC
      break
    else
      let N++
      /bin/sleep 1
    fi
  done

  if [ $N -ge 30 ]; then
    /bin/touch /dev/ttyUSB0 #reserved
  fi
else
  /bin/echo R>/dev/ttyUSB0 && read -t 2 RTC</dev/ttyUSB0 && RTC=${RTC%$'\r'} && /usr/bin/logger -t $(/usr/bin/basename $0) "custom script RTC time is $(/bin/date -u -d $RTC)"
fi
 
Last edited:
I've heard Arduino on multiple occasions. It's my first time seeing a photo of the actual hardware. Looks like a DIP chip...maybe the size of a 8086 CPU?
 
maybe the size of a 8086 CPU?
The "Nano" is an ATmega328P 16 MHz 8-bit microcontroller. There is no operating system. The program has one main loop. This unit is about the size of my little "pinky" finger, from the knuckle to the tip.

See all the Arduino models here:
https://www.arduino.cc/en/Main/Products

I briefly noticed a Github project that runs an NTP server on an Arduino "Mega" microcontroller. Not sure about the performance.

The Arduino "Yun" runs OpenWRT/Linux but that's overkill for our simple clock. The "Yun" model is similar to a Raspberry Pi because it runs Linux.
 
The "Nano" is an ATmega328P 16 MHz 8-bit microcontroller. There is no operating system. The program has one main loop. This unit is about the size of my little "pinky" finger, from the knuckle to the tip.

That's smaller than a 8086..
i8086.jpg
 
And it's important to note the major difference, that a microcontroller is an entire computer on a chip, while the 8086 is only the CPU piece.

You're right. The form factor of Arduino Nano looks nostalgic to me :rolleyes:
 
There is another alternative to GPS. In some countries they use radio to adjust time for clocks to account for daylight savings and it requires less CPU since it only needs to receive and set data rather than calculate through GPS.
 
In some countries they use radio to adjust time for clocks
DCF77 is a German longwave time signal and standard-frequency radio station
https://en.wikipedia.org/wiki/DCF77

WWVB is a NIST time signal radio station near Fort Collins, Colorado
https://en.wikipedia.org/wiki/WWVB

NIST Radio Station WWVB
http://www.nist.gov/pml/div688/grp40/wwvb.cfm

Synchronizing time with DCF77 and MSF60
http://www.compuphase.com/mp3/h0420_timecode.htm

The Arduino - CMMR-6P-60 "Almost Accurate Clock"
http://duinolab.blogspot.com/2009/06/arduino-cmmr-6p-60-almost-accurate.html

C-MAX CMMR-6P-60 WWVB 60kHz Receiver
http://duinolab.blogspot.com/2009/05/c-max-cmmr-6p-60-wwvb-60khz-receiver.html

Arduino and atomic clock (WWVB) receiver
http://forum.arduino.cc/index.php?topic=14946.0
 
This is for educational and informational purposes about the u-blox based GPS. For instance, the REYAX GPS module has a u-blox chip inside. This tells you how to configure it over the serial port.

The NEMA sentence for date/time is GxZDA. This is all you need for clock synchronization. Turn off all other NEMA sentences. By default, the GPS is configurated to generate NEMA sentences that report your geographical location. These are not needed for clock synchronization. If you have too many NEMA sentences turned on, it could take longer than 1 second to receive everything at 9600 baud.

The REYAX GPS modules have a u-blox GPS chip in them. U-blox uses their own protocol called UBX to configure the GPS. The UBX command sequences may be used to turn on or off specific NEMA sentences. These UBX command sequences may be auto-generated using the u-blox u-center application for Windows or Mac, here: View -> Messages View -> UBX -> CFG -> MSG. If your REYAX GPS module has flash memory then you don't really need to do this. Otherwise, you must make the configuration settings changes each time the unit is powered on.

Here's examples of how to control which NEMA sentences get generated for u-blox based GPS receivers. Again, all you really need is the GxZDA sentence for clock synchronization.
Code:
##########################################################################################
# Turn off NEMA sentences (u-blox UBX protocol)

# Disable: NEMA GxGGA
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x00\x00\x00\x00\x00\x00\x00\xFF\x23" > /dev/ttyUSB0

# Disable: NEMA GxGLL
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x01\x00\x00\x00\x00\x00\x00\x00\x2A" > /dev/ttyUSB0

# Disable: NEMA GxGSA
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x02\x00\x00\x00\x00\x00\x00\x01\x31" > /dev/ttyUSB0

# Disable: NEMA GxGSV
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x03\x00\x00\x00\x00\x00\x00\x02\x38" > /dev/ttyUSB0

# Disable: NEMA GxRMC
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x04\x00\x00\x00\x00\x00\x00\x03\x3F" > /dev/ttyUSB0

# Disable: NEMA GxVTG
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x05\x00\x00\x00\x00\x00\x00\x04\x46" > /dev/ttyUSB0

# Disable: NEMA GxGRS
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x06\x00\x00\x00\x00\x00\x00\x05\x4D" > /dev/ttyUSB0

# Disable: NEMA GxGST
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x07\x00\x00\x00\x00\x00\x00\x06\x54" > /dev/ttyUSB0

# Disable: NEMA GxZDA
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x08\x00\x00\x00\x00\x00\x00\x07\x5B" > /dev/ttyUSB0

# Disable: NEMA GxGBS
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x09\x00\x00\x00\x00\x00\x00\x08\x62" > /dev/ttyUSB0

# Disable: NEMA GxDTM
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x0A\x00\x00\x00\x00\x00\x00\x09\x69" > /dev/ttyUSB0

# Disable: NEMA GxGNS
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x0D\x00\x00\x00\x00\x00\x00\x0C\x7E" > /dev/ttyUSB0

# Disable: NEMA GxTHS
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x0E\x00\x00\x00\x00\x00\x00\x0D\x85" > /dev/ttyUSB0

# Disable: NEMA GxVLW
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x0F\x00\x00\x00\x00\x00\x00\x0E\x8C" > /dev/ttyUSB0

##########################################################################################
# Turn on NEMA sentences (u-blox UBX protocol)

# Enable: NEMA GxGGA
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x00\x01\x01\x01\x01\x01\x00\x04\x37" > /dev/ttyUSB0

# Enable: NEMA GxGLL
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x01\x01\x01\x01\x01\x01\x00\x05\x3E" > /dev/ttyUSB0

# Enable: NEMA GxGSA
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x02\x01\x01\x01\x01\x01\x00\x06\x45" > /dev/ttyUSB0

# Enable: NEMA GxGSV
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x03\x01\x01\x01\x01\x01\x00\x07\x4C" > /dev/ttyUSB0

# Enable: NEMA GxRMC
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x04\x01\x01\x01\x01\x01\x00\x08\x53" > /dev/ttyUSB0

# Enable: NEMA GxVTG
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x05\x01\x01\x01\x01\x01\x00\x09\x5A" > /dev/ttyUSB0

# Enable: NEMA GxGRS
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x06\x01\x01\x01\x01\x01\x00\x0A\x61" > /dev/ttyUSB0

# Enable: NEMA GxGST
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x07\x01\x01\x01\x01\x01\x00\x0B\x68" > /dev/ttyUSB0

# Enable: NEMA GxZDA
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x08\x01\x01\x01\x01\x01\x00\x0C\x6F" > /dev/ttyUSB0

# Enable: NEMA GxGBS
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x09\x01\x01\x01\x01\x01\x00\x0D\x76" > /dev/ttyUSB0

# Enable: NEMA GxDTM
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x0A\x01\x01\x01\x01\x01\x00\x0E\x7D" > /dev/ttyUSB0

# Enable: NEMA GxGNS
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x0D\x01\x01\x01\x01\x01\x00\x11\x92" > /dev/ttyUSB0

# Enable: NEMA GxTHS
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x0E\x01\x01\x01\x01\x01\x00\x12\x99" > /dev/ttyUSB0

# Enable: NEMA GxVLW
/usr/bin/printf "\xB5\x62\x06\x01\x08\x00\xF0\x0F\x01\x01\x01\x01\x01\x00\x13\xA0" > /dev/ttyUSB0


HOWTO: Use the u-center application to generate you own UBX command sequences for a u-blox based GPS
3136gio.jpg
 
Last edited:
This is a fun thread - I've got a couple of Pharos iGPS 500 USB modules that'll output NMEA stanzas - one I use with my WiFi toolkit for position and time tracking, but I've got a spare - it's a SIRF III chip, which acquires pretty quick on a cold start as long as the almanac is current, otherwise, it'll take about 12 minutes to locate enough SV's to get a 3D fix, but once it updates the internal almanac, restarts are fast...

Pretty easy to configure with gpsd - didn't have to tweak anything on the build, just updated the config file for NMEA at 4800bps and it was good to go...

They're easy to come by on eBay and the list from Craig.. as they were used with MS Streets and Trips package as the bundled GPS unit - that's why on the second hand market they're pretty cheap...

They don't do Glonass or BeiDu, but if I recall, they might support WAAS (I know many Garmin's do)...

This thread sent me on an archaeological dig through my boxes of e-junk (about half of it becomes useful again!) to find my own Pharos iGPS 500. I'm pretty sure it does support WAAS. PPS remains a bit of a mystery - the SIRF III did output PPS, the included USB to serial module is in fact a Prolific PL2303HX, and the GPS 500 has 7 pins... so, maybe? Amazingly nobody has posted a pinout for these things (that I can find)
 
Last edited:
kvic and ASAT: can you explain the factor of 10 difference in offset (~100 us ASAT vs ~1 ms kvic)?

Any results from the Raspberry Pi? That seems like it has the potential for 10-100 us offsets with the direct PPS connection and the possibility to strip a lot of overhead from the Pi.
 
kvic and ASAT: can you explain the factor of 10 difference in offset (~100 us ASAT vs ~1 ms kvic)?

Any results from the Raspberry Pi? That seems like it has the potential for 10-100 us offsets with the direct PPS connection and the possibility to strip a lot of overhead from the Pi.

The better precision is simply contributed by a higher precision reference clock in ASAT's case. The 'ms' precision is very good enough for a home router IMO. But if people can achieve better with a GPS, why not.. :)

The bigger problem of sourcing from network time server is fluctuation in the offset. Variation in network latency can move offset from 1ms range to 10ms or even higher. That's no good. Hence, QoS to give priority to NTP packets are recommended. GPS as the reference clock won't have such issue as it is agnostic to network latency.

I believe a Raspberry Pi won't do any better...
 
The better precision is simply contributed by a higher precision reference clock in ASAT's case. The 'ms' precision is very good enough for a home router IMO. But if people can achieve better with a GPS, why not.. :)

The bigger problem of sourcing from network time server is fluctuation in the offset. Variation in network latency can move offset from 1ms range to 10ms or even higher. That's no good. Hence, QoS to give priority to NTP packets are recommended. GPS as the reference clock won't have such issue as it is agnostic to network latency.

I believe a Raspberry Pi won't do any better...

Connection bitrate is important because of the possible jitter encountered when transmitting an MTU-sized packet. For example, my connection takes ~20ms to send a ~1500 byte packet. It seems like NTP can account for occasional worst-case scenarios, but a higher bitrate (or a mostly idle, lower bitrate?) connection prevails.

There's also tick-rate, which usually maxes at 1000Hz on most Unix-based systems.

I don't understand NTP at all, so... maybe these factors are uninfluential.
 
Connection bitrate is important because of the possible jitter encountered when transmitting an MTU-sized packet. For example, my connection takes ~20ms to send a ~1500 byte packet. It seems like NTP can account for occasional worst-case scenarios, but a higher bitrate (or a mostly idle, lower bitrate?) connection prevails.

Interesting point...I haven't particularly considered the time of putting a packet to wire. Putting it in the framework of NTP protocol it doesn't matter though.

Like all well made tools, people before us incorporated wisdom into the NTP protocol which I found interesting. In its simple form, it's like this:
  • sender stores a timestamp (A) on a request packet, and sends the request to time server
  • time server receives the request packet, copy the payload and stores a second timestamp (B) on the reply, and sends out.
  • sender receives the reply, and stores a third timestamp (C). Offset between the sender's clock and timeserver's clock are calculated based on the three timestamps.
Note that A and C are local time of sender. B is local time of time server. Calculations will eliminate the network latency between them _as long as_ both ways are roughly equally delayed.
 
...
Calculations will eliminate the network latency between them _as long as_ both ways are roughly equally delayed.

That's exactly my point. With my 640Kbit connection, an NTP packet could take less than 1ms to be on the wire, or if an MTU-sized packet was currently being transmitted, the delay could be 18.75ms more. (This is assuming that NTP is given max priority). Considering that my current NTP peer has a 48ms average delay, the possibility of a ~20ms jitter is significant. Edit: Oops... I meant that if the additional ~20ms delay were to happen, it's effect would be significant, not that the possibility of it happening is significant (since it's rather dependant on my actions).

From http://www.ntp.org/ntpfaq/NTP-s-algo.htm#Q-ACCURATE-CLOCK
In addition the quality of network connection also influences the final accuracy. Slow and non predictable networks with varying delays are very bad for good time synchronization.

With 10Mbit & above the worst-case delay caused by an MTU-sized packet begins to creep below 1ms.
 
Last edited:
Considering that my current NTP peer has a 48ms average delay, the possibility of a ~20ms jitter is significant. Edit: Oops... I meant that if the additional ~20ms delay were to happen, it's effect would be significant, not that the possibility of it happening is significant (since it's rather dependant on my actions).

A + offset + delay1 = B .... (1)
B - offset + delay2 = C .... (2)

Re-arranging eqn (1) & (2), we get if delay1=delay2:
  • offset = (2B - A - C) / 2
If delay1 != delay2, we get:
  • offset = (2B - A - C) / 2 + (delay2 - delay1) / 2
Syncing the clock enough number of times, we can minimise the error from the term (delay2 - delay1) / 2. A stable network connection (including the time NIC putting a packet to wire) between the sender and the time server shall yield a higher quality constant term (delay2 - delay1)/2...
 
A + offset + delay1 = B .... (1)
B - offset + delay2 = C .... (2)

Re-arranging eqn (1) & (2), we get if delay1=delay2:
  • offset = (2B - A - C) / 2
If delay1 != delay2, we get:
  • offset = (2B - A - C) / 2 + (delay2 - delay1) / 2
Syncing the clock enough number of times, we can minimise the error from the term (delay2 - delay1) / 2. A stable network connection (including the time NIC putting a packet to wire) between the sender and the time server shall yield a higher quality constant term (delay2 - delay1)/2...

(I don't understand your math, so I could be confusing what you are saying.) I think you are forgetting queuing latency. No packet is instantly put on the wire (what I think you are calling the "offset"). What you call "delay" is transmission + propogation latency? https://en.m.wikipedia.org/wiki/End-to-end_delay#Delay_components

I am saying, in concert with the NTP FAQ, is that low-bitrates and the resulting variance between best-case & worst-case latency can massively effect NTP's accuracy.

(My guess at why the problem I outline exists): NTP creates the time-stamped packet but then hands off the packet to the NIC queue, which (as I have explained) may experience worst-case delay, and said packet cannot account for this delay since NTP cannot modify a packet passed to to the NIC.
 
He's filtering out the transients...

I was more implying that my math education is not even high-school level (and the current time is past midnight). I didn't really mean to criticize him.

Transients = other possible factors?
 
(I don't understand your math, so I could be confusing what you are saying.) I think you are forgetting queuing latency. No packet is instantly put on the wire (what I think you are calling the "offset"). What you call "delay" is transmission + propogation latency? https://en.m.wikipedia.org/wiki/End-to-end_delay#Delay_components

delay1 (and delay2) is the delay between two timestamps, A and B in this case i.e the request trip (delay2 will between B and C..the reply trip). Think of it as the end-to-end delay from your wiki..

I am saying, in concert with the NTP FAQ, is that low-bitrates and the resulting variance between best-case & worst-case latency can massively effect NTP's accuracy.

If we substitute delay1 and delay2 with components of end-to-end delay from your wiki, take calculus...then we are able to do some analysis on the effect of different delay components...

I think that's not particularly interesting. The thing on the good side is that the delay portion in the final result of the offset formula is half of difference of two delays i.e. (delay2 - delay1)/2.

From there, we could see that the absolute magnitude of e.g. transmission delay or propagation delay etc do not imply its magnitude of effect on the accuracy of estimating the offset. It's the variation that matters more...

So if we take enough number of clock sync, effect of (delay2 - delay2)/2 will be minimised...at least we can get a more accurate estimation of the effect of the delays..
 

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top