Teensy 4.1 NTP server

I am also getting a clock sync of 40.2 - 40.6ppm which seems to be way off what others are getting... The room is about 22C and the board is open-air. My GPS is a (presumably) knockoff M8N.

That ppm is a bit high (spec 30 ppm?). My dozen or so T4's are within 10 ppm, though the Teensy4-micromod is 40 ppm, but that's a different PCB layout and different crystal (Sparkfun). Is your T4.1 socketed? If you remove it from your PCB and put it in breadboard and hook it up to GPS and Ethernet, do you still get 40 ppm drift? Or do you have other T4.1s you can test?
 
That ppm is a bit high (spec 30 ppm?). My dozen or so T4's are within 10 ppm, though the Teensy4-micromod is 40 ppm, but that's a different PCB layout and different crystal (Sparkfun). Is your T4.1 socketed? If you remove it from your PCB and put it in breadboard and hook it up to GPS and Ethernet, do you still get 40 ppm drift? Or do you have other T4.1s you can test?

This T4.1 behaved the same when just hooked up with jumpers (eth port was on it's own little breakout)... I do have quite a few T4.1s and based on your comment I will swap a few in over the next few days and see how they behave. (Yes, the board I am using has a socket for the T4.1)


Cheers - N
 
I did sub in a second T4.1 (purchased at the same time as the first, from Sparkfun) and got results very closely aligned with the first example (40.2 - 40.6 ppm)

It doesn't really worry me as I am moving to a new approach to keep my timer in check using a DS3231 (paying attention to the type of it - and still disciplining to GPS every so often) but thought it was interesting.

Also relevant to this thread is that GPS master frame with the leap second offset. Takes up to 12.5 minutes after a fresh signal acquisition to get the leap second offset and the embedded value in your chip may differ from unit to unit depending on when they were made/flashed. Yes the battery backup does save it, but I do a lot of full resets on my units in testing and I only found out about the GPS master frame behaviour recently...

Cheers - N
 
Interesting... a 3rd T4.1 and this time I get the ticks evening out at about 999990 ticks, while the first two were both around 999960... This one was bought at a different time. I will try them all in the same board with exactly the same build and compare - but I suspect some of the T4.1s I have are significantly out of spec with the crystal.

(Is there a serial number in a Teensy I can extract?)

Cheers - N
 
In fact, checking under a microscope seems to show both the 24Mhz and 32.768kHz crystals are at least visually different on the two types of T4.1 I have that are giving in and (apparently) out of spec crystal performance.

differentTeensys_withmicro.jpg

The good (10ppm) Teensy is the one on the left with the "2400T" 24Mhz crystal... The one on the right (and another - not shown) Teensy both have the other crystals and stabilise at about 40ppm off...

Is this a known issue with some T4.1s? They were obtained from Sparkfun - any chance they are counterfeit? I haven't seen a counterfeit since the first 3.2 I bought

Cheers - N
 
That ppm is a bit high (spec 30 ppm?). My dozen or so T4's are within 10 ppm, though the Teensy4-micromod is 40 ppm, but that's a different PCB layout and different crystal (Sparkfun). Is your T4.1 socketed? If you remove it from your PCB and put it in breadboard and hook it up to GPS and Ethernet, do you still get 40 ppm drift? Or do you have other T4.1s you can test?

Just noticed that you also have a 40ppm T4.1 (although a micromod)... My most recent post in this thread shows that yes, I have different crystals on two fullsize T4.1s... It seems that some of the crystals are out of spec :-(

Cheers - N
 
(Is there a serial number in a Teensy I can extract?)

The Ethernet MAC address and USB id are unique. The MCU stencil has a "batch date", me thinks, (shown in your closeup photo), but your concern is with the crystal.
 
PRJC builds all the T_4.1's distributed by others like Sparkfun. The shown items are of different builds as one seems to be the early "A" 1062 and the one on the right s seems to indicate it is a newer/current "B" version of the NXP supplied 1062 MCU.

In these times with limited part availability, it is possible alternates are sourced to allow production. This is the first apparent notice of variation in the crystal showing this.

I can say the latest PJRC Supplied Beta T_4.1 with a "B" MCU shows a 2400T crystal in place. Other recent T_4.0 and 4.1 boards (Beta and other on desk) show the "A" MCU with the 2400T crystal.

Each Teensy does present a unique Serial number - there is code in CORES and the forum that can expose that to print, and it is presented over USB during Host connection and TyCommander displays that.
 
Thanks. It's not the end of the world as anything less than perfect needs to be compensated for in my application - I need ms synced separate units, but might be worth noting somewhere on the specs somewhere as it's about double the published tolerance in less accurate unit.

I have no reason to believe it is the MCU though so probably not worth bothering getting the serial unless someone would like a record of the units with the less accurate clock.

Cheers - Neil G
 
I'm running the T4.1 NTP server and it has been working well. I can load the server webpage and see the charts and the text stats at the bottom of the page OK. I'm wondering if there's an easy way to programmatically retrieve one of those stats, every so often. My first thought was to simply fetch the webpage as text and search for the line of interest, but I see it's not just plain text. The parameter I am interested in is the clock frequency estimate, as for example the web browser shows:
Code:
 Estimate of NTP clock freq: 0.00000851 s/s
However when I simply fetch the webpage as a text file (eg. wget 192.168.1.211) I see the actual number is hidden behind some sort of javascript:
Code:
<p>Estimate of NTP clock freq: <span id='pidD'></span> s/s</p>
Is there an easy way for a remote system using a Python script, for example, to retrieve this value via some URL query?

EDIT: I see using the browser developer tools that the number does appear in the HTML code, and refreshes periodically.
Code:
Estimate of NTP clock freq: <span id="pidD">0.000008502</span>  s/s
So there's some javascript magic that pushes out the updates. I wonder how to capture that update from eg. Python.
My knowledge of HTML is still pretty much Web 1.0.
 
Last edited:
jq is a very useful command line tool

Wondering what this useful JQ tool was, this came up:

stedolan.github.io/jq/

Windows and other OS versions at the ready. Shows here on WIN11 as:
Code:
jq - commandline JSON processor [version 1.6]

Usage:  jq [options] <jq filter> [file...]
        jq [options] --args <jq filter> [strings...]
        jq [options] --jsonargs <jq filter> [JSON_TEXTS...]

jq is a tool for processing JSON inputs, applying the given filter to
its JSON text inputs and producing the filter's results as JSON on
standard output.

The simplest filter is ., which copies jq's input to its output
unmodified (except for formatting, but note that IEEE754 is used
for number representation internally, with all that that implies).

For more advanced filters see the jq(1) manpage ("man jq")
and/or https://stedolan.github.io/jq

Example:

        $ echo '{"foo": 0}' | jq .
        {
                "foo": 0
        }

For a listing of options, use jq --help.
 
Wondering what this useful JQ tool was, this came up:

stedolan.github.io/jq/

Yup, that's jq.

On windows, you can use powershell like this:

Code:
PS C:\Users\abob\Downloads> (Invoke-RestMethod http://teensy-1.lan/state.json).pidD
0.000010007

Or if you want to still use jq:

Code:
PS C:\Users\abob\Downloads> (Invoke-WebRequest http://teensy-1.lan/state.json).Content | .\jq-win64.exe .pidD
1.0009e-05
 
Here is a plot of my Teensy's onboard crystal drift during 34 hours after a restart. (At least, I think this TeensyNTP-reported value is the onboard clock drift). Total change over that time was less than 0.4 PPM so that looks reasonably stable to me. The data plotted comes from running

Code:
curl -s [url]http://teensy-ntp1.lan/state.json[/url] | jq ".clockPpb"

once every minute. I have the T4.1 sitting in a 8" hollow concrete block which is inside a sealed styrofoam box, to reduce the rate of temperature change on the board. The PPS input comes from a GPSDO. The +5V power to the Teensy is just from a cheap wall-wart, so voltage stability is another variable.

ClockDrift.jpg
 
Last edited:
Here is a plot of my Teensy's onboard crystal drift during 34 hours after a restart. (At least, I think this TeensyNTP-reported value is the onboard clock drift). Total change over that time was less than 0.4 PPM so that looks reasonably stable to me. I have the T4.1 sitting in a 8" hollow concrete block which is inside a sealed styrofoam box, to reduce the rate of temperature change on the board. The PPS input comes from a GPSDO. The +5V power to the Teensy is just from a cheap wall-wart, so voltage stability is another variable.
View attachment 27296

That's a nice graph, low amounts of short term change as well.
 
I'm almost embarrassed to post this given I know there MUST be a better way to read the line of GPS response and parse it, but this does work... I wrote this because many Chinese GPS modules either don't save the default LS, or their batteries are dead and every time the unit restarts, you get the default leapsecond value for up to 12.5 minutes. I have modules giving 15D, 16D and 17D in my collection. (The current GPS Leapsecond offset is 18.)... (The D in those numbers is reported by the GPS module to indicate it's a Default value)

Anyway, this code sets a global variable "gpsleapsecond" and global boolean "gpsleapsecondvalid" and returns true if the leapsecond value from the GPS module (probably only UBlox modules running a non-ancient FW) is acquired from the satellites or False if it's the default value.

Code:
boolean leapsecond() {
  bool message_started = false;
  char GPS_info_char;
  char GPS_info_buffer[130];
  String line2parse = "";
  String leapsecondstring = "";
  unsigned int received_char = 0;

  gpsPort.println("$PUBX,04*37");
  delay(2);
  uint32_t startlstest = millis();
  while (millis() < (startlstest + 1900)) {
    while (gpsPort.available()) {
      GPS_info_char = gpsPort.read();
      if (GPS_info_char == '$') { // start of message
        message_started = true;
        received_char = 0;
      } else if (GPS_info_char == '*') { // end of message
        GPS_info_buffer[received_char] = '\0';
        line2parse = GPS_info_buffer;
        if (line2parse.startsWith("PUBX")) {
          //          DEBUG_CS.println(line2parse);
          for (int j = 0; j < 6; j++) {
            line2parse.remove(0, line2parse.indexOf(',') + 1);
          }
          leapsecondstring = line2parse.substring(0, line2parse.indexOf(','));
          if (leapsecondstring.indexOf('D') > 1) {
            gpsleapsecond = leapsecondstring.substring(0, 2).toInt();
            gpsleapsecondvalid = false;
            return false;
          } else {
            gpsleapsecond = leapsecondstring.toInt();
            gpsleapsecondvalid = true;
            return true;
          }
        }
        message_started = false; // ready for the new message
      } else if (message_started == true) { // the message is already started and I got a new character
        if (received_char <= 127) { // to avoid buffer overflow
          GPS_info_buffer[received_char] = GPS_info_char;
          received_char++;
        } else { // resets everything (overflow happened)
          GPS_info_buffer[received_char + 1] = '\0';
          message_started = false;
          received_char = 0;
        }
      }
    }
  }
  return 0;
}
 
Back
Top