GPS Clock

A simple desk clock that gets time from GPS

Similar projects worth following
GPS is best known as a ubiquitous, accurate positioning system (obvious from the name), but the way it actually works requires distributing hyper-accurate time information. This makes it possible (and, actually, pretty easy) to make a clock that you never have to set as long as it gets good GPS reception.

Yes, this is way overkill... but GPS is getting so cheap that you might as well.

GPS time information is often precise down to the tens of nano-seconds. But if all you want to do is display time for humans, you probably would be satisfied with 4 orders of magnitude less precision, which is what this design achieves - 200 µs accuracy with 100 ms granularity.

Over the course of the project, the clock has undergone a number of design revisions. The original design paired an ATTiny841 with a MAX6951 display driver. The 6951 connects to up to 8 seven-segment common cathode LED display digits (with decimal). This project is going to use 7 of them (6 large and 1 small for the 10th of a second digit), plus two LEDs for AM and PM, 4 for two colons between the 3 large groups, and a FIX LED from the GPS module. There are also two pushbuttons for parameter setting (timezone, DST config and display brightness).

The GPS module has a bidirectional UART and a PPS output. What complicates things just slightly is that the NMEA timecodes on the serial port describe the current second, meaning they happen just after the PPS signal. The serial codes aren't precise enough to do more than name the current second. Actual timing needs to come from the PPS signal. So the serial data needs to have a second added to it, and the result is stored in a buffer in RAM. The PPS interrupt transfers that buffer to the display chip. For tenths of a second, a timer in the controller is used for interpolation. The correct counting rate is determined by counting how many timer ticks occur between adjacent PPS interrupts and dividing that by 10. The timer runs from the controller's RC oscillator, configured for 8 MHz, with a divide-by-8 prescale - so approximately 1 MHz. The controller has interrupt handlers for timer overflow and input capture (for the PPS). The overflow interrupt increments a high order word, allowing us to keep a 32 bit counter. Even at a 1 MHz counting rate, it takes more than an hour to overflow a 32 bit counter, and that gives us microsecond measurement granularity. The RC oscillator's short term stability should be good enough for the purpose, and its stability beyond 2 seconds is mooted by the way it's being used.

The 6951 chip communicates with SPI. It requires a chip select line to be driven low and then 16 bits of data is clocked in. The write format is 8 bits of address and 8 bits of data. The chip has a bunch of registers inside that allow the display to be fully configured and even dimmed. The chip has a resistor that's used to configure the chip for constant-current for each LED segment to insure correct brightness. The chip's maximum SPI clock speed is over 20 MHz, and the highest SPI rate we can use with an 8 MHz ATTiny is 4 MHz, so we can run it flat out without worry. Our accuracy claim (~200 µs) stems from the fact that a full display update over SPI takes approximately 70 µs start to finish, and that happens in the PPS capture interrupt handler once a second that takes around 100 µs before the display updates commence (we do go to the trouble of updating the least significant digits first so that hopefully most of the time the only actual changes take place much faster). The accuracy of the tenth updates is likely much better, but keep in mind that their timing is estimated via interpolation, so that's based on the stability of the 8 MHz RC oscillator in the controller over τ 2s.

The brains of the clock is an ATTiny841, simply because I have a bunch of them and they have a UART (actually, two). It runs from the internal 8 MHz oscillator. The entire circuit runs from a 3.3 volt supply, so 12 MHz is the maximum frequency that could be used, but that would require adding an external crystal for no other reason (and rearranging the pins to allow the crystal to be connected).

The GPS module is the Skytraq Venus838LPx-T timing module. The board has an edge-mount SMA connector for an external antenna, and passes 5v (or 3.3v selectable with a solder jumper) active antenna power with an AP2331 current...

Read more »


Schematic of v5.0

Adobe Portable Document Format - 82.44 kB - 07/09/2017 at 05:10



EAGLE schematic of v5.0

sch - 411.08 kB - 07/09/2017 at 05:10



EAGLE board file of v5.0

brd - 179.83 kB - 07/09/2017 at 05:10



Schematic of v3.1

Adobe Portable Document Format - 77.68 kB - 06/24/2017 at 19:19



EAGLE schematic of v3.1

sch - 391.44 kB - 06/24/2017 at 19:18


View all 9 files

  • 1 × ATXmega32E5 Microprocessors, Microcontrollers, DSPs / ARM, RISC-Based Microcontrollers
  • 1 × SkyTraq Venus838LPx-T
  • 1 × PAM2305AABADJ Power Management ICs / Switching Regulators and Controllers
  • 1 × TBD62783AFNG
  • 1 × TBD62083AFNG

View all 40 components

  • Errata

    Nick Sayer5 hours ago 0 comments

    The v5 prototypes have shown some reduced sensitivity on the antenna input. The symptom has been S/N numbers in the GPGGA sentences about 10 dB lower than other units show.

    Turns out that the problem is caused by a lack of bypassing on the AP2331. I'm going to add footprints for bypass caps on all future boards, but it appears that just tacking an 0805 or 0603 0.1 µF ceramic cap across the output of the 2331 is a sufficient workaround. Another option is to add an external bias-T if your antenna needs power and open the voltage selection jumper or remove the 0.033 µH bias inductor.

    You can test your own clock by taping the GPS receiver serial output. Use a jumper wire to temporarily tie !RESET to ground on the programming header and watch the S/N numbers compared to the numbers while the controller is running. If there's no difference, then you don't have the symptoms. 

    So far, only the versions with the XMega have shown any issues, and those aren't going to ship before the current inventory is exhausted. 

  • Version 5.0.1

    Nick Sayera day ago 0 comments

    Version 5.0.1 has been built. It replaces the PAM2305 + LDO with a MP2149GJ dual buck regulator. One half of it makes the 3.3 volts for the controller and GPS, the other half makes ~2.3v for the display.

    I'm a bit torn, though. The MP2149GJ is a little pricey in comparison to the older design. I could fairly easily use either a pair of PAM2305 adjustable units or a single adjustable and a single 3.3v fixed (or an LDO - like for v5.0) for less money in terms of the BOM price. But the MP2149GJ reduces the BOM quite a bit - one chip, one inductor twice, one ceramic cap three times, three feedback resistors (one common value between the two sides) instead of (for v5.0) two chips, an inductor, two different pairs of ceramic caps, a third ceramic cap as part of the feedback network and two resistor values.

    I'd still rather have some sort of constant current supply for the LED segments. If I did that, I could feed the TBD62783 from either 3.3v or 5v (depending on the LED Vf), and introduce a current regulator on each of the anode lines. Classically, this would be in the form of a JFET and resistor. But having to do that 8 times with discrete components would be pretty silly.

    There are LED driver chips intended to do the job, but most of them are low-side drain switches, which means that they'd be designed for common anode displays, and most of them use serial input of one form or another instead of parallel. Serial input is nice for saving pins, but I don't really need to save pins - the XMega_E5 has plenty for what we want to do.

  • More on leap second preservation

    Nick Sayer5 days ago 0 comments

    I exchanged some mail with SkyTraq. While I was coding my leap second default update code, I happened to notice that the newer clocks didn't show the leap second error even when powered up without my new code. It turns out that if you preserve VBatt at all then the module will checkpoint the current GPS-UTC offset in flash when Vcc drops. From what I can tell, it's not stored in the same place, since the GPS offset command doesn't return the current value as the "default," but the supercap is preventing the 2 second delta at every power-up after the very first one.

    I asked them how long VBatt must be maintained in order to have this save take place, as the clock doesn't really benefit a lot from preserving the almanac and current time for 45 minutes (with good reception it boots up in 10 seconds instead of 30), but this leap second offset save really is a good thing. If the same effect could be done with a few dozen ms worth of VBatt, then a 1000µF polymer cap instead of a 0.1F supercap would be just as good at 1/3 the price. I haven't gotten an answer from them about this, but will update this log when I do. The good news is that a suitable polymer cap would fit in the same footprint as the supercap, so future designs can pick either option.

  • The Leap Second Fix

    Nick Sayer07/15/2017 at 16:51 0 comments

    One issue with the clock is that when it cold boots the built in count of the current number of leap second can be wrong until GPS updates the receiver, which happens about every 12 minutes.

    It would be ideal if the receiver would update this value whenever it determines that it's wrong. It would only ever do so once the first time the clock starts and once every leap second. But it doesn't currently.

    The fantastic news is that this is an operation that we can manually perform with the SkyTraq binary protocol! I found an application note on the Internet, and have used it to add this functionality to the clock. The clock will ask whether the current leap second delta from GPS is valid or not and whether it differs from the default or not. If it is valid and different, an update command is sent to update the default. This action is performed every hour on the half hour.

    In addition, at startup the date code of the GPS module firmware is now displayed briefly after the display self-test.

    These changes are currently being tested in the v5 clock code, but will be back-ported to all versions of the code.

    This obviates the need for the super capacitor on the board, now that I've just had a run of boards manufactured with it installed.

    In looking over the binary protocol, it appears that there may be another good idea now that we can speak the binary protocol. GPS works on a 1024 week cycle, which is just short of 20 years. If you don't do anything, then when that 20 week cycle elapses, the date will wrap around to the beginning. This is the GPS version of the Y2K bug. SkyTraq worked around this by declaring a "UTC reference date" and commands to set and retrieve it. The idea is that the 1024 week window is forced to include the reference date near the beginning. If you update the reference date, the 1024 week window will slide forward along with time. It's probably a good idea to set this value once a year. The alternative is to connect a PC up to the serial pins while holding the !RESET line of the controller low and execute the reference date setting command yourself (SkyTraq has a Windows program to do this for you).

  • How worthy is the clock?

    Nick Sayer07/10/2017 at 16:08 0 comments

      The Hackaday Prize rules ask for answers to a few specific questions:

      1. What are the challenges the project addresses?
      2. How does the instant project address those challenges?
      3. How does solving those challenges change the world?

      The Global Positioning System was fundamentally designed to solve the problem of navigation - knowing where you were in space (relative to the Earth). But solving that problem fundamentally required distributing hyper-accurate time. And providing accurate timekeeping is a secondary goal of GPS. GPS has been widely used in industry and science as a source of accurate time (and from it accurate frequency references, etc).

      For consumers, so-called "Atomic" clocks are available at premium prices in relatively pedestrian retail stores. Such clocks are actually radio clocks (as are GPS clocks), but their source is the WWVB 60 kHz time signal broadcast from Ft. Collins, CO. This signal is only really available in North America, its availability varies widely, and the accuracy of such clocks depends on that level of availability. The attraction of those clocks largely is that they set themselves and automatically corect for Daylight Savings Time. They typically run on batteries which usually need to be replaced at least annually.

      GPS reception is much more available not only around the world, but in North America it relies merely on line of sight reception from the GPS satellites, which are in orbits that move around. Because of that, continuous GPS coverage is easier to obtain than WWVB (where continuous availability is limited to only a few states surrounding Colorado). Because of this a GPS clock doesn't have to maintain its own accurate timekeeping - it can count on continuous service from the GPS system to tell it the current time.

      WWVB's timecode includes DST status, but only for the US (which is sensible given the fact that its coverage area is limited). GPS does not, but GPS includes the date, which is sufficient for a clock to compute DST on its own. In fact, the GPS clock includes rulesets for the EU, Australia and New Zealand in addition to the US (and you can also turn DST off). Adding additional DST rulesets would simply require adding them to the firmware (the same goes for ruleset changes).

      The idea of a clock that sets itself and displays accurate time without any need for maintenance has been made possible by GPS, but that same facility has not been made available routinely to consumers other than via radio clocks limited to use within a particular region. Every modern smart phone or Internet connected computer can obtain accurate time over the Internet, but using something like that as a simple standalone clock would be swatting a fly with a sledgehammer.

      Everything about the design of this project has been about balancing accuracy against cost. No other product of which I am aware offers a display granularity of 100 ms, an accuracy of under 200 µs, and a price tag under US$150.

  • Draft business plan

    Nick Sayer07/10/2017 at 15:39 0 comments

    This is the draft business plan required for Best Product entries in the Hackaday Prize Best Product category.

    The clock is currently in the Tindie store, and selling for prices that are appropriate for the costs of sourcing the components in the current sales quantities.

    To make the GPS clock a better product, the sales volume needs to go up. With sufficient demand, the assemblies can be sourced in quantities that will drive the prices lower. In particular, with sufficient volume, transitioning from the current laser-cut wood and acrylic case to an injection molded plastic case would dramatically reduce the cost of the enclosure (given enough volume to amortize the tooling costs).

    As a product, the clock has some challenges facing it. The clock requires an external antenna. This is because in general people don't want their clocks to sit where GPS reception is best. An external antenna makes placement of the clock itself less troublesome. But not everyone is going to have (or find) a spot sufficiently good for reception.

    Additionally, the clock is just a clock. It has no functionality other than displaying the current time to within 200 µs. This is a deliberate choice - adding more features to the clock makes the user interface more complicated than it otherwise needs to be (and it's already fairly complicated for a consumer product) and further increases the cost.

    Increasing the sales volume would require increased marketing for the clock, but hopefully in the longer term would be offset by reducing manufacturing costs as the volume went up. The same reductions in cost would allow the price to be reduced.

    But even at its current price, the clock is still offers the highest accuracy:price ratio available anywhere. The clock maintains that accuracy with no maintenance of any kind - it even automatically handles daylight savings time changes. Even without the accuracy, a plug-in clock that set itself and automatically tracked DST would already be worth most of the current price.

  • v5.0 build report

    Nick Sayer07/06/2017 at 23:49 0 comments

    The v5.0 variant boards arrived today and I built one with blue LEDs. The bad news is that blue 7 segment LEDs are hopelessly dim. Even blasting them with on the order of 4.3 volts doesn't make them any brighter (it just makes them a little warmer). To make matters worse, I discovered to my horror that the display module for the 10th-of-a-second digit is wrong, and that nobody makes a blue one that size with the correct pinout. So it's back to red. I'll build one of those (or rip the displays out of this one and replace them) later.

    That said, the multiplexing system works beautifully. The one firmware tweak I needed to make was a short delay (a short _NOP() busy-loop) between turning off the anodes (this would really only happen at maximum brightness - at reduced brightness they would have been off already) and shifting to the next cathode and then presenting the new anode values. This is because the high-side buffer chip has a turn-off spec of 2 µs. Before this there was some ghosting in the display at maximum brightness. Other than that (and the fact that blue LEDs suck), the firmware testing I did in advance paid off handsomely and the clock is indistinguishable from the previous versions.

    The next variant is already designed, but ordering it had to wait for this validation. The big change in that one is to replace the LDO and buck converter with a single dual-buck chip - the MP2149GJ. I'm kinda torn about that, though. It costs more than the combination of PAM2305 and LDO, but it's a net BOM reduction (and it's only one active part instead of two).

    For the purposes of the Hackaday Prize, the BOM listed is the v5.0 design. If the clock makes it to the next round of the Best Product category, the v5.0 design will be the one of which 3 copies will be submitted as prototypes.

  • v5 firmware testing

    Nick Sayer07/04/2017 at 03:00 0 comments

    The v5 prototype boards haven't yet arrived, but I got an opportunity to test the firmware in advance.

    I designed a breakout board for the ATXMega32E5, and they arrived today. After writing the de rigueur LED blink program, I decided to load the code for the v5 GPS clock in and see if I could do some debugging with my oscilloscope.

    That worked out better than I had hoped. By triggering on one cathode line and watching one anode line, I could see the display in action. I found and fixed a few bugs in the code and even characterized the performance. The worst-case display update latency for the "0 tenth" update is about 170 µs, which is inside of the 200 µs spec.

    To prove this, I modified the code to set an unused pin (C7) high at the end of the capture ISR right after the display buffers were filled with the new time. I added another line to clear that pin later in the main loop (after the first NMEA sentence is received). I then triggered the scope on the PPS output from GPS and sampled that unused pin. That measurement is the processing latency for the capture ISR - that is, the time it takes for the display buffers to have the new time copied into them.

    You can see that's around 68 µs. It's a bit jittery, but that's a worst-case.

    But to get the worst-case true display update, you have to assume that you just missed the time-slot for the least significant digit and must wait a full update cycle.

    To verify how long that takes, you simply trigger on one of the cathode lines and measure the time between adjacent rising edges.

    This picture shows activity on one of the anode lines in blue as well. The display update time is, as expected, almost exactly 100 µs - a 10 kHz refresh rate for the display. Again, it's slightly jittery because there are times during the process when interrupts are disabled, and the display update delayed ever so slightly.

    So with that, I've validated the operation of the firmware. The only thing left is to verify that the hardware works and that the display looks acceptable.

  • v4.0 build report

    Nick Sayer06/24/2017 at 02:19 0 comments

    The v4 board went together without any surprises. There were two bugs in the firmware that I had to fix, but in essence the ATXMega32E5 has now been swapped in for the ATTiny841 with no net change in functionality. The big difference, though, is that the update latency, as predicted, has dropped to under 50 µs.

    This sets the stage for the v5 hardware, which has the XMega configured for software display multiplexing as previously described. I haven't ordered that board yet, as I want to insure that the footprints for the two new parts are correct. I'll very likely order boards just as soon as the paper test succeeds.

    The downside of v5 is that the display raster is only going to be 10 kHz instead of the 600 kHz of the MAX6951. This will have some impact on the accuracy because the worst-case display update time has to take the refresh frequency into account. At 10 kHz the amount of time between adjacent "slots" for a particular digit is 100 µs. Increasing the display raster rate requires increasing the interrupt frequency, which risks starving the rest of the code. The 10 kHz refresh rate requires an interrupt rate of 320 kHz (4 brightness levels and 8 digits), which is an interrupt every 100 instructions or so. Worse, the code for the interrupt service routine takes on the order of 50 instructions, so we wind up dedicating about half of the available horsepower just to refreshing the display. Still, the current spec for the clock is a display accuracy of 200 µs, so as long as the display update can occur in less than 100 µs the spec will still be met. But if you really desire the lowest update latency, you'll want to build yourself a v4 unit (I'm not planning on selling them).


    I've added the firmware for the v4 clock to the GitHub repository, as well as the design files and PDF schematic in the files section here.

  • Design progress

    Nick Sayer06/23/2017 at 21:11 0 comments

    The v4.0 boards have arrived and I'll be building one this evening. This board has the XMegaE5 controller paired with the MAX6951. I decided on this intermediate step so that I could have a platform where the display was a known system. I can use that board to pin down the big sweeping architectural changes related to all the other parts of the design and then know that with the next board I just have to debug the software multiplexed display in isolation.

    The proposed 5.0 design will use the TBD62?83AFNG switch chips to isolate the higher power required for the LEDs from the controller. The board will have an LDO and a buck converter, but I swapped their roles relative to the last log entry. The LDO will be a fixed 3.3 volt LDO for the GPS module and controller. The buck converter will be a variable voltage unit to supply just the LEDs.

    The choice of how to supply the LEDs was not an easy one to make. Traditionally, one would want to design a constant current system to insure that the same amount of current was fed through each segment. This would go on the anode driver side, since those are separate. This would require 8 separate current regulators. Adding that functionality to the TBD62783A would be ideal, but that chip is more of a generic switch, so the only other choice would be to duplicate it 8 times.

    Because it's untenable to have 8 separate current limiters, the only other choice is a constant voltage supply. If you look at the Vf / If graph for a typical LED, it usually has a kind of knee at the rated Vf where increasing voltage will result in dramatically increased current. Where you wind up on the vertical part of that slope winds up being kind of a crap shoot, but as long as we stay under the pulsed maximum forward current (which is generally much higher), we should be ok. Since the Vf of our red LEDs is 2.1, the design is for a 2.3 volt supply. With a constant voltage supply, it won't matter how many segments are on at a given moment - all of them will wind up seeing the same voltage and will draw as much current as they will. Using an adjustable voltage regulator will allow the design to be tweaked. In fact, one reason I haven't been able to offer blue displays before now was that the Vf is much higher than for green or red. One potential part has, in fact, a 3.8 volt Vf. This would have been impossible before without changing the design of the board so that the MAX6951 could be powered from the 5 volt rail instead of the 3.3 volt rail, but with this design, it's just a matter of changing the voltage sensing resistor divider (they're whacky expensive though, so don't look for them on the Tindie store anytime soon).

    It's also conceivable that this design could wind up being the way forward for larger format digit displays. Most of the 1-2 inch digit displays use multiple LEDs in series, meaning that they simply have a much higher Vf but the same current requirements. As long as the Vf of the three types of displays (large 7 segment, small 7 segment and discrete dots for colons and AM/PM) have the same Vf value, then that voltage can be produced with either a boost or buck converter from the 5 volt rail with the entirety of the rest of the circuit unchanged.

    We still have to see how this works out in practice, but I am optimistic.

View all 37 project logs

  • 1
    Installing the through-hole parts (LEDs)

    When you get the board, all of the surface mount components will have been installed and programmed.

    First, install the two .56" 7-segment LED modules for the seconds and tens-of-seconds digits. Make sure the modules sit flat against the board. For each module, solder a single lead and double-check that the module is oriented correctly (decimal point on the bottom) and sits flat against the board. Solder the rest of the pins.

  • 2
    Step 2

    Install the small .3" 7-segment LED module in the tenth-of-a-second spot on the right side of the board. For best results, mount the module so that the top edge lines up with the top edge of the larger modules. The easiest way to do this is to insert the module into the holes and then lay the board face down so that both the .56" modules and the .3" module are resting flat on the surface. Done correctly the 10th-of-a-second digit will be up about 1/8" from the surface of the PCB. Solder just one pin on each corner and verify that the module is straight, oriented correctly (again, decimal point at the bottom), and the top lines up with the top of the second digit before soldering the rest of the pins.

  • 3
    Step 3

    Install two 3mm LEDs for the colon between the minutes and seconds. The long lead of each (the cathode) should be towards the top. Install the two LEDs so that they're about 1/8" up from the board - that is, so that their tops are at or just below the top face of the adjacent 7 segment display. To do this, you can use the same trick as for the 10th-of-a-second digit - insert the leads and flip the board over and allow the LEDs to rest against the work surface along with the 7 segment modules. Solder one lead of each and carefully verify that each LED is the same height up from the board and is plumb in both directions (from the top and side). Once both LEDs are positioned correctly, solder the remaining leads and trim the excess lead lengths.

View all 14 instructions

Enjoy this project?



Dmitry Grinberg wrote 11/28/2016 at 23:38 point

FYI,  Page 18 of MAX6951 datasheet ( mentions that is has a character rom so this would count against you much like the rules said hd44870 LCDs' would. Judging by their diagram it is 8 bit address an d8 bit data for a 256 byte total.

  Are you sure? yes | no

Nick Sayer wrote 11/30/2016 at 22:51 point

I will disagree with the assertion that character generation tables in accessory chips should count (be they for 7seg or dot matrix), but in this case, there are 16 symbols made from 7 bits of data - that's only 16 bytes, which still fits. If you're counting the charlieplexing matrix built into the chip... well, I don't know what to say to that except that any accessory chip like this could be implemented either as an array of static gates or as an embedded microcontroller running code in ROM. It's unclear how you'd go about interpreting that under the rules one way or the other. See also:

On a more fundamental level, the GPS receiver module has firmware that can be upgraded too. If that counts, then the whole project is sunk (at least, as an entry in the 1K contest).

In the end, it will be a matter for the judges.

Regardless, I still intend to build it. The feature set I want to have is already larger than 1K anyway. :)

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates