A simple MSF based NTP server for AVR
I used the EP2S and matching antennae, manufactured by HKW. The mega8535 microcontroller is in a STK200 development board. The board interfaces to the rest of the world with RS232 and SLIP. The board originally came with a 2313, but this proved to have insufficient SRAM and flash to develop more than the basic IP functionality (128 bytes SRAM and 2K of flash). The aerial connects to the aerial inputs on the EP2S, the GND and VCC go straight from the Port D connector on the development board to the EP2S (and the PON connection on the receiver is also connected to ground). The signal comes in on the third wire to bit 2 of port D, which activates the external interrupt. And that's all the hardware needed, apart from some cables (thanks to Jenny for soldering up a neat little cable for me). My impression is that the wires from the receiver to the the microprocessor board (in my case three six foot strands of solid core bell wire) act as rather good aerials, picking up all kinds of noise. Something shielded might be better though I haven't tried this yet.
The receiver seems to need a good ground to work properly, if you don't have one via the serial link to the PC (for example, because it's a laptop with an isolated power supply) it's a good idea to add an earth wire to a handy nearby radiator or whatever. Possibly a loop of wire near the antenna connected to receiver ground will do, but I haven't tried this.
The main components are:
A simple IP stack, implementing ICMP echo request/reply and UDP. It
does what I need for NTP and very little more. A single transmit and
receive buffer is used and transmitted packets are always the same
size as those they are a response to. The code, however, allows the
simultaneous receipt of a packet with the transmission of another, so
we can eg. reply to pings almost as fast as the serial connection will
allow. (It helps that the serial line is only running at 38400 baud
(the best I can get with a 4Mhz clock on the AVR, higher baud rates
aren't accurate enough for reliable transmission), so the time taken
to respond to a ping is small compared to transmission time). The
We use the 16-bit timer as the main system clock and the external interrupt (generated at the beginning of each second) to adjust the clock as best we can to the MSF signal in a PLL. This is done by keeping a running average of the length of each second in clock cycles and the average offset of the second interrupt from the clock wraparound time. Each second the clock is adjusted a little to compensate for the current offset and so, over time, the offset is reduced. It's a bit more complex than that of course, if you adjust the clock too much, then it jumps around all over the place and never settles down, if you don't adjust it enough it settles down, but not to the right place. If all is well then we converge on a state with a small average offset and therefore small steps, so low jitter.
The actual MSF data is read by way of the 8-bit timer, set up to generate 40 sampling interrupts a second. Each bit (considering the MSF transmission as a 10-baud signal) is then sampled 3 times and a majority taken (every fourth sample occurs roughly when the signal is changing and so we ignore it). The sampling timing isn't critical, but we restart the timer appropriately at each second interrupt. The MSF data is carried on bit 1 and bit 2 of the second, and gets read into two 8 byte buffers in the course of a minute. I don't bother checking the parity (my excuse is that the BST bit isn't parity checked at all and parity is a pretty weak check anyway). Instead we check that at least 2 minutes data are exactly 60 seconds apart and then treat any deviations with suspicion. The error rate with a well positioned aerial (and being only about 100 miles from Rugby) is pretty low it has to be said.
The MSF signal itself is connected to pin 2 of Port D. Towards the end of each second we enable the external interrupt, which then triggers when the second marker high to low transition occurs. The actually time of the interrupt is quite variable, up to 20 ms variation either side of the average. This is presumably due to the receiver as the MSF signal itself is precise to < 1ms (according to the NPL, who ought to know), and the EP2S datasheet also mentions such variation (I guess it's intended for eg. conventional radio clocks etc. rather than high-precision timekeeping).
Since I didn't want to write a TCP stack for the AVR, but I did want
some sort of handy web access, I wrote a little proxy server
Getting and building the code
The code is in a gzipped tar file: Download
$ tar xvzf avr-ntp.tgz $ cd avr-ntp $ make
The target type is specified in Makefile.avr and is currently atmega8535.
Files are built in the obj-unix and obj-avr subdirectories.
Download to your AVR using your favourite programmer.
To set up the slip connection:
$ make slip
does the necessary calls to slattach and ifconfig. There is nothing to set up proxy ARP (yet). Alter the device and IP addresses in the Makefile as required.
If you do try this stuff, please mail me with any problems, comments etc.
The AVR libc project.