TelephoneBill
Well-known member
Here is some top level comment on an interesting experiment I have been working on... to create a precision Frequency Standard using Teensy3.1, derived from a radio time signal. If there is wider interest, then I can add more detail (program code etc) to this post.
Other posts have described/measured the accuracy of the Teensy3.1 clock rate (https://forum.pjrc.com/threads/28098-Crystal-pull-range-on-3-1?goto=newpost). It was noted that a register called OSC0_CR gives digital control of the internal chip capacitors that "fine tune" the 16 MHz crystal module to bring it very close to an exact value. For example, binary "0010" was measured (by JBeale) as giving -3ppm below 16.000000 MHz and "1100" as +10ppm above. It was also suggested that "dithering" between these two values could be used as a method to "home in" on an exact average value for the Teensy clock rate. It was this suggestion that has prompted my current experiment.
It should be appreciated that there is no temperature control of the crystal module, and that internal heating or heat from surround components will inevitably cause the crystal to drift away from an exact value - even if a measurement could be found for the required amount of dither at a specific moment. But if this dither could be adjusted in real time to compensate for the drift, then it might be possible to create a precision Frequency Standard that would track any changes to give a reference signal accurate in the short term to better than 1 Hz - and longer term to even better than that.
A key factor in convincing myself that this could be done was in realising that the frequency of the USA and UK radio time signals (WWVB and MSF respectively) transmitted on 60 KHz was an exact sub multiple of 120 MHz. And that Teensy's default clock rate of 96 MHz could be increased reliably to 120 MHz and above (many have shown up to 144 MHz "overclocking"). The overclocked internal clock rate is generated by the chip itself using a phase locked loop from the base 16 MHz. A six times PLL gives the default 96 MHz. You enable these higher overclock values by "uncommenting" statements in the "boards.txt" file (part of the Teensyduino/Arduino environment). 120 MHz is one of the available values.
By overclocking to 120 MHz, this then provides an internal Peripheral Clock Rate of 60 MHz (cpu rate divided by two). And you can divide this Peripheral Rate by 1000 inside a Flex Timer (e.g. FTM1) to generate a very clean and precise 60 KHz square wave. This in turn can be compared against the carrier wave from the transmitted radio time signal, such as to synchronise these two together in a phase locked loop (PLL). The control for this PLL would be to programmatically adjust the dither rate of OSC0_CR to maintain the phase lock.
Once you have synchronised the Teensy clock rate to the radio time signal, then that Peripheral Clock Rate is a precision 60 MHz. So you can then use a second FTM Flex Timer to create a whole variety of precise frequencies. For example, divide by 6 gives a precision 10 MHz, or divide by 60 gives a precise 1 MHz.
My experiment has demonstrated that this actually works. I used a simple 3 inch ferrite loopstick to pick up the UK MSF radio transmission on 60 KHz. This was first amplified by a simple JFET using a 1K load resistor, and then amplified again by two stages of a TL082 (dual op amp chip). I then filtered this by a mini 60 KHz crystal in the input stage of a INA126 instrumentation op amp. That crystal had to be carefully selected from a bunch of ten bought off eBay in order to find one that was a very close match in frequency to 60.000 KHz.
The bandwidth of that last instrumentation op amp stage was very narrow (less than 3 Hz) in order to do two jobs: (i) To remove extraneous signal noise cause by local switched mode power supplies (computers, LED lights etc), and (ii) To overcome the interruptions in the UK MSF signal - the 1 Second data is encoded as on/off carrier modulation (up to 50/50 mark/space on the minute). The output from the INA126 is a beautiful 60 KHz sine wave of about 1 volt amplitude peak to peak. It does have some amplitude variations (due to the interrupted carrier), but the narrow bandwidth of the mini 60 KHz crystal "rings on" for a number of milliSeconds after carrier switch off, such as to decay exponentially, but never reaches zero amplitude. In the USA, the WWVB signal is not interrupted, so should be an even better sine wave.
The 60 KHz output signal from the radio receiver was then fed to the Teensy3.1 breadboard via a simple twisted pair length of wire, about 3 feet long (chopped from one of the twisted pairs inside a standard ethernet distribution cable). You need to provide some isolation distance between the radio receiver and Teensy, or else the 60 KHz sq wave electric radiation from Teensy will be picked up directly and swamp the radio. I ought to use some degree of electrostatic shielding around the ferrite loop, but found it worked fine without it in practice.
On board the Teensy breadboard, the radio signal was first fed to a "digital inverter" input (one sixth part of 74HCT14B chip), biased into a "linear analogue amp" by a 100K resistor from output back to input. This "squared up" the signal from sine wave to a fast edged square wave, which was then fed as a digital input into Teensy Pin 17 (CH1 for FTM1).
FlexTimer FTM1 was the Teensy 60 KHz sq wave timer, used in "output Toggle mode". A "modulus value" of 499 then provided a counter (0 to 499 = divide 60 MHz by 500) for each "half-cycle", giving a divide by 1000 factor overall for a complete cycle. The rising edge of the Radio 60 KHz signal (FTM1 Channel1) would then trap the instantaneous value of the counter at some point midway between 0 and 499. By reading this CH1 count value in the Teensy main program loop, I could then decide to adjust the "dither rate" of OSC0_CR such as to always push this CH1 value back towards the midpoint of 250. If the count was above 250, then slow down the 16 MHz clock, and if below it then speed it up. In this way, a control loop was organised to adjust the dither rate accordingly and consequently nudge the 60 MHz peripheral clock rate to "lock" the cycles of the FTM1 counter to that of the incoming radio 60 KHz sq wave on pin 17.
The method of controlling the dither rate was another simple piece of code in the Teensy program. I created a program global variable (FreqCounter) to act as a "half cycle counter" for the cycling of the output from FTM1. This would increment inside an "Interrupt Service Routine", called whenever the FTM1 toggled on "overflow" of the modulus. On reaching a value of 1000, this would be reset automatically (in code) to zero - and start incrementing again. For a number of cycles while this count was less than, say, 500, then the value of the OSC0_CR register would be set to "0010" (-3ppm). Once the global counter "FreqCounter" had exceeded that value, then the OSC0_CR register would be set to "1100" (+10 ppm). In this way, part of the time for 1000 toggles of FMT1, the OSC0_CR would have one value - and the rest of the time for 1000 cycles it would have another value. Thus the overall frequency of the 16 MHz external crystal module could be adjusted up and down, and consequently, the Peripheral Clock Rate derived from it would vary in sympathy. All that was needed was to change the static value (in my code its called "FreqAdjust") and this would "fine tune" the dither rate.
Now here is an interesting point. If the Peripheral Clock Rate at 60 MHz is locked as a multiple of the precise radio 60 KHz frequency, then the cpu clock rate of 120 MHz will also be locked to it. This means that Teensy is now locked in time to UTC (Universal Co-ordinated Time) as defined by NIST to an accuracy of 1 part in 10e12 (or 2 parts in 10e12 by NPL in the UK).
Proof that this all works as described is shown in the picture attached below...
Light Blue Trace 2 is the Radio 60 KHz sine wave going into the twisted pair length of wire. The slight sine wave distortion is caused by the slew rate of INA126 (amplitude is above 1 volt peak to peak). Yellow Trace 1 is the Teensy generated 60 KHz sq wave output from FlexTimer FMT1. Purple Trace 3 is the radio signal square wave conversion from the 74HCT14B going in on Teensy pin 17. The Darker Blue Trace 4 is an independant 10 KHz signal derived from a GPS module in satellite lock.
This picture shows that all the traces for Teensy are now locked in time to UTC. With the Peripheral Clock Rate now accurately controlled, other output standard frequencies can be created. For example, FlexTimer FTM0 could be configured for 10 MHz whilst FTM2 was configured for 1 MHz. And any internal Teensy global variable that counted 120,000 FTM1 "overflows" (inside the ISR for example) would be an extremly accurate 1 Second timer. And 86,400 counts of such a variable would denote a very accurate 1 Day !!!
Other posts have described/measured the accuracy of the Teensy3.1 clock rate (https://forum.pjrc.com/threads/28098-Crystal-pull-range-on-3-1?goto=newpost). It was noted that a register called OSC0_CR gives digital control of the internal chip capacitors that "fine tune" the 16 MHz crystal module to bring it very close to an exact value. For example, binary "0010" was measured (by JBeale) as giving -3ppm below 16.000000 MHz and "1100" as +10ppm above. It was also suggested that "dithering" between these two values could be used as a method to "home in" on an exact average value for the Teensy clock rate. It was this suggestion that has prompted my current experiment.
It should be appreciated that there is no temperature control of the crystal module, and that internal heating or heat from surround components will inevitably cause the crystal to drift away from an exact value - even if a measurement could be found for the required amount of dither at a specific moment. But if this dither could be adjusted in real time to compensate for the drift, then it might be possible to create a precision Frequency Standard that would track any changes to give a reference signal accurate in the short term to better than 1 Hz - and longer term to even better than that.
A key factor in convincing myself that this could be done was in realising that the frequency of the USA and UK radio time signals (WWVB and MSF respectively) transmitted on 60 KHz was an exact sub multiple of 120 MHz. And that Teensy's default clock rate of 96 MHz could be increased reliably to 120 MHz and above (many have shown up to 144 MHz "overclocking"). The overclocked internal clock rate is generated by the chip itself using a phase locked loop from the base 16 MHz. A six times PLL gives the default 96 MHz. You enable these higher overclock values by "uncommenting" statements in the "boards.txt" file (part of the Teensyduino/Arduino environment). 120 MHz is one of the available values.
By overclocking to 120 MHz, this then provides an internal Peripheral Clock Rate of 60 MHz (cpu rate divided by two). And you can divide this Peripheral Rate by 1000 inside a Flex Timer (e.g. FTM1) to generate a very clean and precise 60 KHz square wave. This in turn can be compared against the carrier wave from the transmitted radio time signal, such as to synchronise these two together in a phase locked loop (PLL). The control for this PLL would be to programmatically adjust the dither rate of OSC0_CR to maintain the phase lock.
Once you have synchronised the Teensy clock rate to the radio time signal, then that Peripheral Clock Rate is a precision 60 MHz. So you can then use a second FTM Flex Timer to create a whole variety of precise frequencies. For example, divide by 6 gives a precision 10 MHz, or divide by 60 gives a precise 1 MHz.
My experiment has demonstrated that this actually works. I used a simple 3 inch ferrite loopstick to pick up the UK MSF radio transmission on 60 KHz. This was first amplified by a simple JFET using a 1K load resistor, and then amplified again by two stages of a TL082 (dual op amp chip). I then filtered this by a mini 60 KHz crystal in the input stage of a INA126 instrumentation op amp. That crystal had to be carefully selected from a bunch of ten bought off eBay in order to find one that was a very close match in frequency to 60.000 KHz.
The bandwidth of that last instrumentation op amp stage was very narrow (less than 3 Hz) in order to do two jobs: (i) To remove extraneous signal noise cause by local switched mode power supplies (computers, LED lights etc), and (ii) To overcome the interruptions in the UK MSF signal - the 1 Second data is encoded as on/off carrier modulation (up to 50/50 mark/space on the minute). The output from the INA126 is a beautiful 60 KHz sine wave of about 1 volt amplitude peak to peak. It does have some amplitude variations (due to the interrupted carrier), but the narrow bandwidth of the mini 60 KHz crystal "rings on" for a number of milliSeconds after carrier switch off, such as to decay exponentially, but never reaches zero amplitude. In the USA, the WWVB signal is not interrupted, so should be an even better sine wave.
The 60 KHz output signal from the radio receiver was then fed to the Teensy3.1 breadboard via a simple twisted pair length of wire, about 3 feet long (chopped from one of the twisted pairs inside a standard ethernet distribution cable). You need to provide some isolation distance between the radio receiver and Teensy, or else the 60 KHz sq wave electric radiation from Teensy will be picked up directly and swamp the radio. I ought to use some degree of electrostatic shielding around the ferrite loop, but found it worked fine without it in practice.
On board the Teensy breadboard, the radio signal was first fed to a "digital inverter" input (one sixth part of 74HCT14B chip), biased into a "linear analogue amp" by a 100K resistor from output back to input. This "squared up" the signal from sine wave to a fast edged square wave, which was then fed as a digital input into Teensy Pin 17 (CH1 for FTM1).
FlexTimer FTM1 was the Teensy 60 KHz sq wave timer, used in "output Toggle mode". A "modulus value" of 499 then provided a counter (0 to 499 = divide 60 MHz by 500) for each "half-cycle", giving a divide by 1000 factor overall for a complete cycle. The rising edge of the Radio 60 KHz signal (FTM1 Channel1) would then trap the instantaneous value of the counter at some point midway between 0 and 499. By reading this CH1 count value in the Teensy main program loop, I could then decide to adjust the "dither rate" of OSC0_CR such as to always push this CH1 value back towards the midpoint of 250. If the count was above 250, then slow down the 16 MHz clock, and if below it then speed it up. In this way, a control loop was organised to adjust the dither rate accordingly and consequently nudge the 60 MHz peripheral clock rate to "lock" the cycles of the FTM1 counter to that of the incoming radio 60 KHz sq wave on pin 17.
The method of controlling the dither rate was another simple piece of code in the Teensy program. I created a program global variable (FreqCounter) to act as a "half cycle counter" for the cycling of the output from FTM1. This would increment inside an "Interrupt Service Routine", called whenever the FTM1 toggled on "overflow" of the modulus. On reaching a value of 1000, this would be reset automatically (in code) to zero - and start incrementing again. For a number of cycles while this count was less than, say, 500, then the value of the OSC0_CR register would be set to "0010" (-3ppm). Once the global counter "FreqCounter" had exceeded that value, then the OSC0_CR register would be set to "1100" (+10 ppm). In this way, part of the time for 1000 toggles of FMT1, the OSC0_CR would have one value - and the rest of the time for 1000 cycles it would have another value. Thus the overall frequency of the 16 MHz external crystal module could be adjusted up and down, and consequently, the Peripheral Clock Rate derived from it would vary in sympathy. All that was needed was to change the static value (in my code its called "FreqAdjust") and this would "fine tune" the dither rate.
Now here is an interesting point. If the Peripheral Clock Rate at 60 MHz is locked as a multiple of the precise radio 60 KHz frequency, then the cpu clock rate of 120 MHz will also be locked to it. This means that Teensy is now locked in time to UTC (Universal Co-ordinated Time) as defined by NIST to an accuracy of 1 part in 10e12 (or 2 parts in 10e12 by NPL in the UK).
Proof that this all works as described is shown in the picture attached below...
Light Blue Trace 2 is the Radio 60 KHz sine wave going into the twisted pair length of wire. The slight sine wave distortion is caused by the slew rate of INA126 (amplitude is above 1 volt peak to peak). Yellow Trace 1 is the Teensy generated 60 KHz sq wave output from FlexTimer FMT1. Purple Trace 3 is the radio signal square wave conversion from the 74HCT14B going in on Teensy pin 17. The Darker Blue Trace 4 is an independant 10 KHz signal derived from a GPS module in satellite lock.
This picture shows that all the traces for Teensy are now locked in time to UTC. With the Peripheral Clock Rate now accurately controlled, other output standard frequencies can be created. For example, FlexTimer FTM0 could be configured for 10 MHz whilst FTM2 was configured for 1 MHz. And any internal Teensy global variable that counted 120,000 FTM1 "overflows" (inside the ISR for example) would be an extremly accurate 1 Second timer. And 86,400 counts of such a variable would denote a very accurate 1 Day !!!
Last edited: