Ben Clifford
benc@hawaga.org.uk
Pi doesn't know real time at startup.
Buy a £6 RTC..
1833: Greenwich time ball
>=1926: UK government radio time signals such as MSF
1936: UK speaking clock
>=1979: internet-style protocols such as NTP
>=1983: GPS available for civilian use
Receives UK government MSF time; makes it available over NTP (Network Time Protocol) to my home network (and beyond).
radio receiver -> GPIO pin -> C decoder -> NTP -> ethernet
60kHz radio signal that pulses on and off a few times per second.
Transmitter has 3 on-site atomic clocks
Receiver in commodity clocks and something like this board

Two bits per second - same protocol on carrier wave and on the wire from receiver to Pi GPIO pin
One time stamp per minute
BCD (binary coded decimal): Year (8 bits), Month (5 bits), Day (5 bits), Day of week (3 bits), Hour (6 bits), Minutes (7 bits), Timezone (1 bit), Parity (4 bits)
Seconds are implicit
I wrote this for fun. There are other implementations on the internet.
Language: C
Decodes signal into a time stamp and passes it to ntpd
via a memory buffer.
ntpd takes time signals from several sources,
and makes your computer clock track the best source.
It also makes your clock's time available to other computers elsewhere on the network.
Commonly: point at pool.ntp.org public time servers.
In my case: in addition, look at decoded MSF signal
It's OK but not amazing.
Radio signal is weak and drops out for hours at a time. NTP automatically switches to other (internet based) time sources in this case.
jitter is very high compared to internet based time sources
ntpd cannot estimate latency automatically - handle this by comparing against other (internet based) time sources and putting this in ntpd config file
* memory buffer
system time at time of reading
time according to this time stamp
flag: is this buffer valid? [actually not this - correct it]
effectively recording the error between the system clock and
the time source...
* ntpd
apt-get to install this.
doesn't just blindly reset clock to what our receiver says.
Instead it can track several time servers - for example, this one
and a couple on the internet - and models the accuracy
of those clocks, and picks whichever clock is "best" (for some
definition) to slowly adjust towards (so that we don't get big
jumps in system time).
How to configure ntpd to use a buffer:
[TODO: extract from config]
look at status:
here we can see it knows about the MSF driver, but it has not
chosen to follow it - it's following the one with a *, and
the ones with + are a sort of runner up in the choosing process.
So here it has chosen to track time from my ISP's time server
- which is a stratum 2 server - meaning this ntp daemon will be
stratum 3. This is because wiring messed up and I'm not receiving
any time messages and ntpd has found a better time source.
that's because it's the wrong pi!
$ ntpq -p
remote refid st t when poll reach delay offset jitter
==============================================================================
-81.2.122.172 90.155.53.94 3 u 171 1024 377 0.678 2.521 0.586
+biscay.cqx.ltd. 91.189.89.199 3 u 374 1024 377 31.517 1.844 1.364
SHM(2) .MSF. 0 l - 64 0 0.000 0.000 0.000
*ntp1.aa.net.uk 195.66.241.3 2 u 505 1024 377 11.701 0.845 0.380
-dildano.hawaga. 188.39.213.7 2 u 770 1024 176 17.180 3.570 0.873
+pygar-6.hawaga. 188.39.213.7 2 u 170 1024 377 20.834 1.086 1.341
on the right pi:
npi@faeroe ~ $ ntpq -pn
remote refid st t when poll reach delay offset jitter
==============================================================================
+90.155.53.94 195.66.241.3 2 u 50 64 377 6.345 0.303 1.860
*127.127.28.2 .MSF. 0 l 11 64 167 0.000 -2.587 3.437
+2001:8b0:1638:9 81.2.122.172 2 u 7 64 377 0.829 -2.677 1.756
Go over each column in this.
And on another host, which is syncronised from this:
$ ntpq -p
remote refid st t when poll reach delay offset jitter
==============================================================================
*81.2.122.172 .MSF. 1 u 287 1024 377 1.238 0.437 2.001
+biscay.cqx.ltd. 213.95.200.109 3 u 407 1024 377 33.681 -3.230 5.386
+ntp1.aa.net.uk 195.66.241.2 2 u 297 1024 377 23.248 -7.219 7.755
dildano.hawaga. 188.39.213.7 2 u 5h 1024 0 15.896 1.865 0.000
pygar.hawaga.or 188.39.213.7 2 u 6h 1024 0 23.405 -0.833 0.000
config:
a network based timeserver:
server 90.155.53.94
this MSF server:
server 127.127.28.2
fudge 127.127.28.2 refid MSF time1 0.030
127.127.28.2 is a fake IP address that
means use reference clock driver 28.2
which means use a shared memory buffer.
different values there mean to use different
drivers in NTP to get time from a reference
clock, often tied to specific clock hardware.
time1 is a manually configured time
offset - see later section.
refid is the name we will publish this time
source under: see ntpq output. By convention,
MSF is used for this particular radio time
signal.
How to build the C code
How to make it start at boot
(ntpd already does...)
C code and shell wrapper:
how to read a GPIO pin in C - edge based (I think)
- how to configure it from bash - see 'start.sh'
shift buffer implementation
parity checking
how to write to a shared memory buffer for NTP
anything else?
Example output:
In the first case, when it wasn't connected:
msf shift.c
main: getting NTP shm
Key:
. = edge detected on input pin
T = timeout without edge on input
> = Starting decode
X0 = Decode failed: insufficient zeroes in scan zone
X1 = Decode failed: insufficient ones in scan zone
* = Decode inhibition ended
main: entering main loop
..TTTTTTTTTT
But, on the right pi:
[TODO: a video of this happening, screenshot-as-gif? so that it
can be viewed offline, appear on slides?]
....................................................................................................>
checkdecode: matched num ones threshold, numOnesInFirst = 250
checkdecode: numZeroesInSecond = 247
checkdecode: Matched num zeroes threshold
decode: Decoding
decodeBCD: Decoding
decodeBCD: Decoded time is '17/07/11 23:20 BST
tellNTP: Telling ntpd
tellNTP: ntpmem is 0x76f78000
tellNTP: ntpmem->mode = 0
tellNTP: ntp struct is free, so we can populate it.
tellNTP: MSF time = 1499811600 seconds
tellNTP: system edge time = 1499811600.033369 seconds
tellNTP: system report time = 1499811600.034633 seconds
tellNTP: result delivered to ntpd
about 33ms off...
* dodgy bits of hardware This was my first raspberry pi hardware project, and my first electronics dabbling in around 15 years. The connectors and project housing are terrible: dodgy solder. Probably a headphone jack would be a better connector? Location of device is really awkward - I've only got one corner up on a curtain rail in my flat that I can get a signal and still be in wire-length of the pi. At the pi end it's jumpers jammed into breadboard, because I also use that pi for trying out new stuff.
also mention? wired up a GPS I had sitting around to ntpd to see how easy that was. http://benctechnicalblog.blogspot.com/2017/07/wintec-grays-2-gps-device-feeding-to-ntp.html that has a crazy big offset! ntpd can have multiple stratum 0 clocks: