Teensy 3.6 crystal accuracy and how to improve it

Status
Not open for further replies.

Polymorph

Active member
I'm not new to electronics, but I am fairly new to Arduino and very new to Teensy.

For my first real project, I'm working on this in stages. The plan is start with a frequency counter with a GPS module as a reference/calibration standard, then that controls a DDS like the AD8951. The Teensy will check the output of the DDS and correct it as needed.

I see the Teensy 3.0/1/2 uses a 16MHz crystal. I think I could replace that with a TCXO with +-2.5ppm temp and +-1.5ppm initial accuracy.

But what does the Teensy 3.6 have on it? I see the clock is no longer a multiple of 16.

I may also borrow an idea from another thread here, and stick a Dallas 18B20 on board, but I'm worried about the complexity of changing the crystal register.

Please forgive my ignorance.

I've got a Teensy 3.0 on a little display. I reprogrammed a NEO-6 to output 10MHz. It is currently locked to satellites. The readout on the Teensy 3.0 toggles between 9,999,990 and 9,999,991 Hz. When I change the measurement time to 10S, the display is pretty solidly on 9,999,990 Hz. -1ppm, well within specs for the on-board crystal, but a TCXO would be much closer.

Back to 1 second period: I warmed the crystal on the Teensy 3.0 for about 30 seconds with my fingertip, and the frequency is now toggles between 9,999,992 and ,999,993 Hz, going down as it cools back to room temperature. After being on for an hour, it is now wandering around 4 or 5 for the last digit.

Set to 10 second capture time, the last digits are 5.2 for several minutes, then slowly drifting upwards. It is now on 6.x for the last digit and still drifting upwards.

Clearly this drifts enough with temperature that simply correcting it one time won't get me much. A TCXO on board would be much better.

So what crystal is the Teensy 3.6 using?

Code:
/* Adapted from
 * Arduino Macro Frequency Counter
 * 
 *        Teensy 3.0 or higher
 * NOTES: Signal must be logic level
 *        Input pin is 13
 *        Teensy 3.x good to about 65MHz
 *        SCL to A5
 *        SDA to A4
 *        No limitations on analogWrite()
 *        For FreqMeasure, use with PPS from GPS module to calibrate
 *        Input pin is 3
 *        Pin 4 unusable with analogWrite()
 */

#include <Wire.h>                                     //I2C library for the OLED
#include <Adafruit_SSD1306.h>                         //OLED driver
#include <FreqCount.h>                                //FreqCount library for you know...counting frequencies
                                                      //find it here: https://github.com/PaulStoffregen/FreqCount
#define OLED_RESET 4                                  //it's a thing
Adafruit_SSD1306 display(OLED_RESET);                 //create instance of the SSD1306 called display

void setup()   {                

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);          //begin the OLED @ hex addy )x3C
  display.display();                                  //show the buffer
  delay(2000);                                        //bask in the glory of LadyAda
  display.clearDisplay();                             //enough basking
  FreqCount.begin(10000);                              //start counting 1,2,3,4...
//  tone(14, 20000);                                    //something to count

}

void loop() {

  if (FreqCount.available()) {                        //if the code if working
    double count = FreqCount.read();                   //create float var called count and populate it with current frequency count
    float period = (1000000000000/count);                   //create float var called period and populate it with the inverse of the frequency
  display.clearDisplay();                             //always clear the display first
  display.setTextSize(1);                             //smallest text size
  display.setTextColor(WHITE);                        //my only choice, really
  display.setCursor(0,0);                             //cursor to upper left
  display.println("Arduino Freq. Counter");           //print heading to buffer
  display.println("------- ----- -------");           //print some pretty line to buffer
  display.print("F: ");                          //print the name of the function to buffer
  display.print(count/10);                               //print the actual counted frequency to buffer
  display.println("Hz");                              //print units to buffer & drop down 1 line
  display.print("P: ");                          //print the name of the fuction to buffer
  display.print(period);                         //print the period of signal in picoseconds to buffer
  display.print("pS");                                //print the units to buffer
  display.display();                                  //SHOW ME THE BUFFER!!!!
  }
}
 
I believe the crystal we use on Teensy 3.x has a 30 ppm spec. Most of them perform surprisingly well, but that's not a guaranteed spec. It's an ordinary quartz crystal, certainly not comparable to a TCXO.

Removing the crystal without damage to the board would take a pretty amazing feat of desoldering skill. The BGA chip is rather sensitive to non-uniform heating. If you heat the edge of the chip enough (but not the whole chip uniformly), the non-uniform thermal expansion will sheer the BGA solder connections.

But if you do miraculously remove the crystal without destroying the board, NXP's datasheets say it is ok to apply a 16 MHz square wave.

Or if you make your own board using the MKL02 chip, driving the XTAL input pin with a square wave is supposed to be legal. Refer to the MK66 reference manual (page 187 - BGA balls M12 & M11, and page 194 - table 11-7) to figure out which of the 2 XTAL pins is input vs output.
 
I've not removed a surface mount component this challenging before. I do have a preheater (that hot fan the board sits on) and a rework hot air gun. Maybe a tiny nozzle and the preheater...

Thank you for the information.
 
TelephoneBill, yes, that is a good post. I am very interested in the information there on changing the registers on the chip to adjust the oscillator.

Although if I can remove the crystal without destroying the Teensy, that will be much simpler. Looking closely at a Teensy 3.6, that is going to be challenging.
 
If you are trying to match the frequency (or subharmonic) of a NEO6 with a DDS type oscillator, you might do this without changing the crystal.

The crystal can be considered as a "relative" measure of time (rather than absolute). The FTM timers can "freeze" a count into a register by a transition of an external pin (and hold it until you read). This is what FTM1_C1V is doing in my ISR code. So using two such pins and registers, you could trap two values - one of the NEO6 reference, and one of the DDS. If the crystal frequency drifts, it will do this for both readings, so the difference should cancel any temperature effect.

A key point to be clear about is that when using a precise reference like a NEO6, its the accuracy (in time) of the edge transition that matters, rather than its absolute frequency. That's why 1PPS is often used. So timing from one edge to another at 1 KHz is no worse or better than timing at 10 MHz. It means you can drop the NEO6 down to a slow rate of edge transitions, if that suits your purpose.

Keep the crystal out of any air drafts too. Popping a little cotton wool blanket over it will slow down any temperature variations. And setting the bus frequency higher will help to get a more precise value of count.
 
Just to satisfy my scientific curiosity:
The -1ppm which you measure in the original post will lead to an error of less then 1 second over 10 days. What kind of application would consider this as not being sufficiently accurate?
 
TelephoneBill That is true, however, this would require that I always have a GPS lock.

Theremingenieur On some level, I'm chasing accuracy for its own sake. However, that -1ppm is only a measure I took at one particular temperature at one particular moment. It continued to drift as the room warmed up and the circuit warmed up. Worst case for the crystal would be if both initial accuracy and stability were off by the same direction, so about 40ppm off. At 144MHz, that is nearly 6kHz error. At 450MHz, 18kHz.

I think I'm going to build the audio stuff into a separate project due to the differing requirements. A TCXO by itself is overkill, really, no need for GPS.

The RF will require much tighter accuracy.
 
An idea occurred to me today. I thought I'd check and see how accurate the clock in a GPS module is when it is not locked to satellites. I noticed that the NEO-7N and NEO-M8N and NEO-M8Q GPS receivers have a TCXO in them rather than a garden variety crystal.

https://www.u-blox.com/en/product/neo-7-series

https://www.u-blox.com/en/product/neo-m8-series

Unfortunately, I wasn't aware of this before so the GPS modules I have are all standard crystal. There are some NEO-M8N modules on Amazon, but they either take 5 weeks to get here, or they are for specific quadcopters and may not be reprogrammable. So I'm waiting to hear back.

So I think I'll see if it is possible to set them for an output frequency of 16MHz, then just feed that via buffer to the clock input of the Teensy. That way, when GPS is not available, it is still on a stable TCXO, and it will be even more accurate when GPS is available. No fiddling with registers to correct for clock errors. If they top out at 10MHz, then I may try setting them to 8MHz and doubling.

I'm having a hard time finding specifications for either type of oscillator in the NEO GPS modules. The TCXO should be a lot more accurate than just a crystal alone.

I could feed the same 16MHz to the AD9833 module. It doesn't have to be on a 25MHz clock.

For the RF version with the AD9851, which requires a 125MHz clock signal, I will have to see if it is possible to use the hardware timers in the Teensy 3.6, running at 240MHz, to generate a 125MHz clock. Perhaps it will be difficult getting a 50% duty cycle at that frequency. If so, I could use 120MHz. I'm more likely to be able to get 1/2 the clock at 50% duty cycle.
 
OK, so the maximum frequency out of these GPS modules is 10MHz. The internal clock, I'm led to believe, is 48MHz, so an even division of that should be cleaner.

There is a PLL clock multiplier, 50% duty cycle output, with 2x, 2.5x, 3x, 3.333x, 4x, and 5x. I learned that from a series of posts on the EEVBlog forum.
https://www.onsemi.com/PowerSolutions/product.do?id=NB3N502

https://www.eevblog.com/forum/proje...ignal-amplify-module-for-arduino-rasppery-pi/

Seems pretty simple to use. Program the GPS for 8MHz output, and multiply by 2 to get 16MHz. For the AF freq counter/sig gen, that can clock both the Teensy and the AD9833.

For the RF version, 8MHz x2 = 16MHz, and 8MHz x3 x5 = 120MHz to replace the 125MHz clock on the AD9851.

I have a DIY Mall branded USB GPS module labeled G28UF8FUSB, which came up in a lot of Chinese language searches. They seem to indicate that this does have a TCXO on board. There are pads on the board labeled for a separate connector including PPS. This will do for now and is simpler to reprogram with the built-in USB.
 
In my continual search for unnecessary accuracy and a tidal wave of information from members here, the EEVBlog forums, and a variety of places around the web, I think I have two paths:

Use a NEO-M8N or 7N as the clock source as they use a TCXO, so accuracy without satellite lock is still in the single-digit ppm range. Program it to output 8MHz and use a frequency doubler. That would serve as an unreasonably accurate clock for the AF analyzer (tops out at 1 or 2MHz). The NEO-6 versions with TCXO seem to be unobtanium or cost so much that it is cheaper to just get an M8N or 7N.

Use any of the GPS modules and use the 1PPS output. Program it to change to 50% duty cycle when locked and 10% when not locked, use that as a lock indication. Use a VCTCXO 16MHz as the clock source for the Teensy. Measure the 1PPS output and average it over a very long time to average out the subtraction or addition of a clock cycle that the GPS periodically performs to keep the PPS signal sync'd. Adjust the voltage to the VCTCXO using one of the 12 bit DACs. Have a Dallas 18B20 temp sensor on the oscillator, log the temperature vs correction voltage and average over long periods. Use that table when GPS satellite lock is lost. This would be for the RF analyzer, preferably able to go up to 70cm/450MHz amateur radio band.

I mean, why have 8 digits if the last 3 are garbage?

The U-Blox documentation on their GPS chips indicate "RMS 30ns, 99% 60ns", which I think may refer to long term and short term accuracy for the 1PPS signal. Which would mean 30ppb and 60ppb.
 
Removing the crystal oscillator from a Teensy 3.0 board was surprisingly easy.

I wasn't trying to save the XO, so I just put a big screwdriver tip in my soldering iron, turned it up to 800F/425C, and applied it to the top of the can.

Solder melted, I wiped it quickly off the edge of the board. It would have been more difficult if it had any other components between the XO and the edge of the board.

Now to figure out which pads go to what, and hork a VCTCXO in there.

Teensy3.0MinusXO.jpg
Sorry for the blurry cell phone image. My phone won't focus very close.
 
Last edited:
Looks like all should be that simple, the crystal should be removable using the same method as it is right next to the edge on all. Keeping in mind the 4.0 uses a 24MHz crystal.
 
Replacing Teensy 3.6 xtal with a TCXO.

I'm not new to electronics, but I am fairly new to Arduino and very new to Teensy.

For my first real project, I'm working on this in stages. The plan is start with a frequency counter with a GPS module as a reference/calibration standard, then that controls a DDS like the AD8951. The Teensy will check the output of the DDS and correct it as needed.

I see the Teensy 3.0/1/2 uses a 16MHz crystal. I think I could replace that with a TCXO with +-2.5ppm temp and +-1.5ppm initial accuracy.

But what does the Teensy 3.6 have on it? I see the clock is no longer a multiple of 16.

I may also borrow an idea from another thread here, and stick a Dallas 18B20 on board, but I'm worried about the complexity of changing the crystal register.

Please forgive my ignorance.

I've got a Teensy 3.0 on a little display. I reprogrammed a NEO-6 to output 10MHz. It is currently locked to satellites. The readout on the Teensy 3.0 toggles between 9,999,990 and 9,999,991 Hz. When I change the measurement time to 10S, the display is pretty solidly on 9,999,990 Hz. -1ppm, well within specs for the on-board crystal, but a TCXO would be much closer.

Back to 1 second period: I warmed the crystal on the Teensy 3.0 for about 30 seconds with my fingertip, and the frequency is now toggles between 9,999,992 and ,999,993 Hz, going down as it cools back to room temperature. After being on for an hour, it is now wandering around 4 or 5 for the last digit.

Set to 10 second capture time, the last digits are 5.2 for several minutes, then slowly drifting upwards. It is now on 6.x for the last digit and still drifting upwards.

Clearly this drifts enough with temperature that simply correcting it one time won't get me much. A TCXO on board would be much better.

So what crystal is the Teensy 3.6 using?

Code:
/* Adapted from
 * Arduino Macro Frequency Counter
 * 
 *        Teensy 3.0 or higher
 * NOTES: Signal must be logic level
 *        Input pin is 13
 *        Teensy 3.x good to about 65MHz
 *        SCL to A5
 *        SDA to A4
 *        No limitations on analogWrite()
 *        For FreqMeasure, use with PPS from GPS module to calibrate
 *        Input pin is 3
 *        Pin 4 unusable with analogWrite()
 */

#include <Wire.h>                                     //I2C library for the OLED
#include <Adafruit_SSD1306.h>                         //OLED driver
#include <FreqCount.h>                                //FreqCount library for you know...counting frequencies
                                                      //find it here: https://github.com/PaulStoffregen/FreqCount
#define OLED_RESET 4                                  //it's a thing
Adafruit_SSD1306 display(OLED_RESET);                 //create instance of the SSD1306 called display

void setup()   {                

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);          //begin the OLED @ hex addy )x3C
  display.display();                                  //show the buffer
  delay(2000);                                        //bask in the glory of LadyAda
  display.clearDisplay();                             //enough basking
  FreqCount.begin(10000);                              //start counting 1,2,3,4...
//  tone(14, 20000);                                    //something to count

}

void loop() {

  if (FreqCount.available()) {                        //if the code if working
    double count = FreqCount.read();                   //create float var called count and populate it with current frequency count
    float period = (1000000000000/count);                   //create float var called period and populate it with the inverse of the frequency
  display.clearDisplay();                             //always clear the display first
  display.setTextSize(1);                             //smallest text size
  display.setTextColor(WHITE);                        //my only choice, really
  display.setCursor(0,0);                             //cursor to upper left
  display.println("Arduino Freq. Counter");           //print heading to buffer
  display.println("------- ----- -------");           //print some pretty line to buffer
  display.print("F: ");                          //print the name of the function to buffer
  display.print(count/10);                               //print the actual counted frequency to buffer
  display.println("Hz");                              //print units to buffer & drop down 1 line
  display.print("P: ");                          //print the name of the fuction to buffer
  display.print(period);                         //print the period of signal in picoseconds to buffer
  display.print("pS");                                //print the units to buffer
  display.display();                                  //SHOW ME THE BUFFER!!!!
  }
}

Were you successful with the TCXO replacement? I have ordered a high precision TCXO (0.1 ppm), but due to the coronavirus it will not be here for more than a month.
My need is for extremely high timing precision, i.e., event timing with long term accuracy to less than a microsecond (currently the variations are about 40 us over a 500 second period).
 
Status
Not open for further replies.
Back
Top