Close

Ticking accurately with the NEO-6M

A project log for VQB 71 GPS Clock

A tiny version of the GPS Wall Clock

stephen-holdawayStephen Holdaway 08/07/2021 at 01:111 Comment

Like any normal person, I want a desk clock that has sub-millisecond accuracy.

Parsing and immediately displaying time from NMEA messages as they arrive from the GPS module, like GPS Wall Clock originally did, gives a useable-enough value for display, but it's not particularly accurate for a few reasons:

To avoid these delays and uncertainties, the GPS module offers a TIMEPULSE pin that can be used to generate interrupts on our controller at the top of each second with considerable accuracy.

GPS PPS vs serial message timing
Even with a good GPS signal, there's a significant delay between the tick of each second and the serial data containing that time.

How accurate are we talking?

The u-blox documentation claims it's possible to get timing accuracy in the order of nanoseconds with ideal conditions, while accuracy in the order of microseconds is quite achievable:

As a rule of thumb the position should be known with an accuracy of better than 1m for a timing accuracy in the order of nanoseconds. If an accuracy is required only in the order of microseconds, a position accuracy of roughly 300m is sufficient.

Let's not get too carried away though - we're making a display for humans after all, where perception seems to take in the order of tens of milliseconds at best. In practice it will take someone much longer to look at and interpret the display.

Consider that in your day-to-day life, knowing the time to ±1 minute would likely be inconsequential, and ±1 second would be practically imperceptible. I would hazard a guess that the standard deviation of maintained time-keeping devices you encounter is at least 30 seconds, though I can't find anyone who has sampled this, and networked clocks probably tighten this guess up a bit.

I'm happy drawing a line at ±1ms, mainly because digging any deeper yields more and more uncertainty:

Given that I'm using these modules indoors and don't have equipment to verify absolute accuracy anyway, all of this is essentially academic, but it's fun to consider.

Using timepulse (1PPS)

The TIMEPULSE pin on the GPS module generates a rising edge at the top of each second, with a configurable offset in nanoseconds to account for electrical and processing delays. Messages sent by the module always correspond to the previous timepulse, though the documentation only mentions this a few times briefly:

NEO-6M top of second (PPS) vs serial data out (from the Receiver Description and Protocol Specification PDF)
Order of the timepulse and serial data output (u-blox 6 Receiver Description, p27)

To display the time correctly, we'll need to calculate the next time to display when a NMEA "Recommended Minimum" (RMC) message arrives. At the following rising TIMEPULSE edge, this calculated time needs to be displayed. The MAX72xx will immediately update its display when any digit data is written, so the most I can prepare in my case is internally buffering segment data ready for blasting out over SPI.

Due to the reversed wiring of the MAX72xx for common-anode digits on this project, all 8 "digit" registers always need to be written when updating any of the VQB-71 digits, even if only one digit has changed. This might seem like a disadvantage in terms of speed, but a consistent update time is actually better here as it can be compensated away using the module's user configurable timepulse delay setting.

A quick measurement of the delay between timepulse and a complete display update using a logic analyser gives a consistent value of 40.875μS (sampled at 200MHz):

DSView logic analyser screenshot of SPI and timepulse

Configuring this on the GPS module requires sending a UBX protocol command - specifically CFG-TP5. The UBX protocol is binary, but it's well documented by u-blox and doesn't take much code to send commands. The data for my timepulse configuration command looks like this:

UBX protocol CFG-TP5 message data code. See the variable gps_cfg_tp5_data in the main.c in the GitHub repository. Not a code block because Hackaday.io's code rendering is poor

Note that timepulse is only guaranteed to be aligned with the top of each second if "GPS time is locked". As far as I can tell, a lock on GPS time doesn't necessarily require a position fix, but it does require the receiver to have a decent quality signal. NEO-6M modules in their default configuration won't output the timepulse signal unless GPS time is locked, but this can be tweaked using the CFG-TP5 UBX command, as I've done here.

If you don't want to write any code, these GPS modules can be connected to a computer by UART and configured using the u-center tool (Windows only) from u-blox.

Further reading

As mentioned, the official documentation for these modules is very good:

Since writing this article, I've also applied the same timepulse upgrade to the ATTiny-based wall clock - surprisingly managed to make it fit!

Discussions

Andrew wrote 09/25/2021 at 15:33 point

Very cool project. I am using a NEO-6M for time acquisition and MAX7219 for display and I learned a ton from this post. Thanks for sharing!

  Are you sure? yes | no