This is the user manual for the Precision Clock Mk IV. See also the assembly instructions for the kit and the project page about its development.
Connect a GPS antenna to the SMA connector, and power the clock via the USB cable.
For a cold start, with no coin cell or if it's just been fitted, the clock will show approximate UTC time until it finds a full GPS fix. Once it gets a fix, it should update to show local time with full precision.
The colons will only illuminate if it has a full GPS fix (PPS active). If it loses its fix, the colons will stop blinking. After 1000 seconds (about 15 minutes) without a fix, the milliseconds digit will go blank, and after 10000 seconds the centiseconds digit will go blank.
In other words, the tolerance of the current time display is shown by the amount of precision on the display. The time is only right to within a millisecond if the millisecond digit is ticking.
All configuration of the clock is done via the USB port, which enumerates as both a mass storage device, and a serial port. The mass storage device contains a file called config.txt
which should be fairly self explanatory.
You can find a fresh (template) copy of the file here.
The file contains a list of parameters in key = value
format, with lines beginning with #
ignored. The on/off values are relaxed about syntax (you can either specify 0/1, on/off, enabled/disabled) and it's case insensitive.
Any config listed in the file can also be sent via USB-serial. If you enable a mode this way, it will immediately switch to that display mode. There is one special command via serial not available in the config file: reboot
.
There are lots of different modes, so to keep things simple most of them are disabled by default.
There are just two buttons on the clock, and these cycle back and forth through the enabled modes.
MODE_SHOW_TZ_NAME | Attempt to display the IANA timezone name on the 7-segment display, such as Europe/London, etc. This is usually somewhat illegible, particularly as it can't display the "m" in America, but it's enough to confirm the auto-timezone is working (or, if you've overriden it via the config, the zone override is working). |
MODE_SHOW_OFFSET | Display the UTC offset of the current local time. This overrides the whole display. Naturally it would have been nice to have an additional four or five digits on the display to show this all the time, but it would have made the clock even wider! |
Date formats | |
---|---|
MODE_ISO8601_STD | YYYY-MM-DD Standard ISO8601 / RFC3339. |
MODE_ISO_Ordinal | YYYY-DDD ISO8601 ordinal (day of year) |
MODE_ISO_WEEK | YYYY-Www-d ISO week date. The ISO week-numbering year is slightly offset to the Gregorian year. On the 7-segment display, the W is poorly rendered, but hopefully unambiguous. |
MODE_UNIX | Unix timestamp, in decimal; the number of non-leap seconds that have elapsed since 00:00:00 UTC on 1 January 1970. |
MODE_JULIAN_DATE | Julian Date. The number of days (plus fraction) since the Julian period epoch. Not that the date display of the clock is only updated once per second. |
MODE_MODIFIED_JD | Modified Julian Date (Julian Date minus 2400000.5). An easier to manage version of Julian Date that drops the first two digits and increments at midnight instead of noon. Note that the fraction is approximate: the date display of the clock is latched at the start of the UTC second, not the fractional increments of MJD. |
MODE_WEEKDAY | Show weekday, within the limitations of the 7-segment displays. "M" and "W" are rendered poorly. |
Special modes | |
MODE_STANDBY | Turn off the whole display. This mode can be useful if you want to reduce power consumption but keep the clock/GPS module fully powered. If you're running the clock from a USB battery bank, you may have to activate a mode on the battery to keep it supplying power when the current has dropped to almost nothing. |
MODE_TEXT | Generic text display. The text displayed is loaded via the TEXT= command. As with all the commands, this can be sent via the USB-serial interface, so it could even be used to implement a custom date format handled by an external script.Currently, only one decimal point may be illuminated at a time. This will be fixed in a later firmware version. |
MODE_COUNTDOWN | Turn the clock into a high-precision countdown timer, showing the number of days, hours, minutes, and seconds until the epoch specified by COUNTDOWN_TO . With the current firmware, the epoch must be specified as a UTC timestamp in ISO8601 format, with the T in the middle, no fractional seconds, and the trailing Z.E.g. 2023-05-06T23:00:00Z |
Debug modes | |
MODE_FIRMWARE_CRC | Display the CRC of the loaded firmware images, in hexadecimal. This enables two separate display modes, one for each firmware image, with the values preceded by a t and a d for the time and date sides of the clock respectively. |
MODE_DEBUG_BRIGHTNESS | Shows input and output values of DAC/ADC. The separate command brightness= can be used in conjunction, more info further down this page. |
MODE_DEBUG_RTC | Show remainder of RTC calibration after 63 second period, added purely to aid with the implementation. |
MODE_SATVIEW | List number of GPS/GLONASS satellites in view. Note that this is just the number of satellites, not their signal strength, but gives a very basic idea of whether the GPS module and antenna are working. |
The timezone is detected automatically from the GPS position. If you want to display a specific timezone instead, use this parameter. You will need to use the exact IANA timezone string, case sensitive.
ZONE_OVERRIDE = America/New_York
Comment out the line to leave it automatic. For UTC display, use:
ZONE_OVERRIDE = Etc/UTC
It's also possible, for debug purposes, to send a fake GPS coordinate with fake_longitude =
and fake_latitude =
commands. To disable this, set both coordinates to exactly zero.
When connected to the USB serial device, in addition to typing commands, the clock will (by default) output the NMEA strings it's receiving from the GPS module. This generally appears as a wall of text. If you want to use this as a time source, you will also need to wire up a connection to the PPS output of the module. I did experiment with sending PPS via DCD over USB state commands, but the jitter was sometimes several milliseconds, which defeated the purpose.
You can filter the output by using the NMEA = RMC
command, which shows only the RMC message. You can also turn it off with NMEA = off
or re-enable full output with NMEA = all
This is the speed of the display refresh, in Hertz, from 1000 to 100000. The default is 20000, and unless you're using the clock for high-speed photography there's generally no need to change it. At below 20kHz, there's a potential risk of electroacoustic effects, though I haven't noticed anything in practice. At higher speeds, there's a potential for electromagnetic interference, though again this hasn't been measured.
The display is split into four matrices of 5 digits each. The number given here is the refresh rate of the display – the clock frequency of the matrix will be five times this number. Note the specified frequency is only a target, the exact frequency will be a division of processor clock speed. At high values, there's a chance the date and time sides of the display will be slightly different frequencies.
MATRIX_FREQUENCY = 20000
For the previous generation of clock, some people complained about the blinking colons, so for this one I made sure to be able to customise the animation. Remember that the colons carry information: if they stop blinking it means the GPS fix has been lost.
Currently supported modes are: slowfade, heartbeat, sawtooth, alt_sawtooth, toggle, solid. More animations may be added at a later date.
COLON_MODE = heartbeat
The dynamic precision disables the last digits of the clock to reflect situations with reduced accuracy. The assumption is that the onboard TCXO keeps time to within 1ppm. That may not be entirely true, or you may simply have trust issues about it, or you may want to replace the oscillator with a different 10MHz source. You can change the tolerances for the dynamic precision in the config file.
Tolerance_time_1ms = 1000 Tolerance_time_10ms = 10000
The deciseconds digit is only disabled if the clock has been powered off and the last RTC calibration was more than this many seconds ago.
Tolerance_time_100ms = 100000
A nonlinear mapping between the light sensor and the display voltage is possible. A special display mode, MODE_DEBUG_BRIGHTNESS will plot the exact values at the ADC and the DAC. You can use this, in conjunction with the brightness curve GUI, to set up the brightness curve to work with different LEDs or light sensors.
While debugging, it can be useful to use the command brightness = n
where n
can be either a floating point between 0.0 and 1.0, or the integer value up to 4095. If sent via the USB serial, it immediately disables the brightness curve and updates the display to that brightness. This can also be useful if you are trying to film the clock, and want to lock it to a fixed brightness.
Periodically the timezone and map data may need to be updated. You can find the latest versions in the github repo here. I may also do a github release with a zip download later.
Simply copy the relevant files (tzrules.bin and tzmap.bin) onto the mass storage device. The process will be quite slow, as the clock gives priority to the display stability over the USB interrupts. (This was a conscious decision, knowing it would make copying files slower, but it's worth it to ensure the display doesn't jitter during the transfer!)
For firmware updates, copy the relevant files onto the device (fwt.bin and fwd.bin). You can trigger the update immediately by ejecting the USB device, or you can disconnect and re-connect the clock, it will update at the next power on.
In all cases, you'll want to overwrite the existing files on the disk. The clock looks for those specific filenames.
The last few bytes of each firmware image have information about them. You can view this with a hex editor or hexdump utility.
$ hd fwt.bin | tail 00018420 43 49 49 00 00 00 00 00 00 00 00 00 00 00 00 00 |CII.............| 00018430 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00018440 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00018450 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 0002ffc0 42 75 69 6c 64 20 32 30 32 34 2d 30 35 2d 32 39 |Build 2024-05-29| 0002ffd0 54 30 30 3a 31 38 3a 35 30 20 56 65 72 73 69 6f |T00:18:50 Versio| 0002ffe0 6e 20 30 2e 30 2e 30 20 00 00 00 00 00 00 00 00 |n 0.0.0 ........| 0002fff0 00 00 00 00 00 00 00 00 00 00 00 00 e2 ea 8a a2 |................| 00030000
The last four bytes are the CRC.
The format of the storage is very important. If the device gets corrupted, don't simply re-format the drive with the default options. The memory must be formatted FAT12 or FAT16, with block size of 4096 (not 512).
I have provided a bash script that formats the drive correctly and copies the relevant files onto it, but if you're unsure, the safest option is to download a prepared disk image and use a disk imaging utility.
There are more notes about setting up the flash memory here.
The CR2032 coin cell provides a battery backup to both the GPS module and the RTC. The cell should last a few years.
When the cell becomes empty, the RTC will eventually stop ticking. At that point, there may still be enough voltage to sustain the non-volatile RAM, so at the next power-on the clock will initially show a time that may be several hours or days in the past. If this happens, it's a signal that you need to replace the coin cell.
It should be possible to detect the cell voltage via the ADC, so in a future firmware update it will periodically check the cell voltage and provide a warning when it gets low.
Replacing the coin cell is difficult, I deliberately chose a very secure holder as I originally envisioned the clock functioning as a clapperboard and didn't want it to be shaken loose. The easiest method is to insert a spudger or screwdriver under the coin cell and twist it while pulling back the gold tab with a fingernail. Don't be too forceful or you might rip the whole coin cell holder off the PCB.
If the clock hangs, an error code will display, consisting of a letter and number.
Bootloader errors | ||
---|---|---|
b0 Error | ERR_FATFS | Unable to mount / FATFS failure |
b1 Error | ERR_FS_IMG_CRC_INVALID | fwt.bin image on file system fails CRC check |
b2 Error | ERR_INVALID_NO_FW | Loaded firmware image is invalid and no replacement found in file system |
b3 Error | ERR_ERASE_FAILED | Flash page erase failed |
b4 Error | ERR_WRITE_INVALID | Data written to flash didn't match data read back |
b5 Error | ERR_WRITE_FAILED | Write data to flash returned failure |
b9 Error | ERR_UNKNOWN | Unknown (other bootloader failure) |
Chainloader errors | ||
d1 Error | ERR_FS_IMG_CRC_INVALID | fwd.bin image on file system fails CRC check |
d2 Error | ERR_DATE_DEAD | No response from date side (check hinge cable) |
d3 Error | ERR_GET | Date side system loader error |
d4 Error | ERR_UNEXPECTED_TIMEOUT | Date side system loader error |
d5 Error | ERR_VERSION | Date side system loader error |
d6 Error | ERR_ERASE_FAILED | Date side system loader error |
d7 Error | ERR_WRITE_PAGE | Date side system loader error |
d8 Error | ERR_WRITE | Date side system loader error |
d9 Error | ERR_GO_FAILED | Date side system loader error |
There are test pads on both circuit boards to connect an ST-link adapter if you wish to develop custom firmware for the clock. You can either connect to these with a pogo jig (I have a clothes-peg style one) or surface-mount solder header pins to them. They are positioned so that they won't interefere with each other when the clock is folded.
One thing to note is that the date side of the clock uses the SWD pins as part of its display matrix. In order to connect, you can signal the firmware to not disable the SWD interface by holding down one of the buttons during power-up.