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;
}
 
I have had two teensy's in the drawer for a long time.

And now was the time to build Dan's Teensy 4.1 NTP server.
I have previously made Dan's "Archmax" STM32F4xx server.

For the Teensy-4.1 I'm using a LEA-M8T w. batt (diy) backup for the config ram.

And a 26dB "Ice-Cone" timing antenna, connected to a 4-1 active splitter (20dB gain)
Behind one of the active splitter ports are , another "passive" 8-1 splitter :
Mini-Circuits power splitter ZB8PD-2-S+ - With DC-Blockers on all inputs.
That "buys me anther 8 ports" :cool:

All my LEA-M8T's are connected to the MiniCircuit splitter, they're sensitive enough to be unaffected by the insersion loss.
My TBOLT is directly on the active splitter "quite deaf" , compared to the uBlox'es.


I have attached a screenshot of the Teensy WebServer.

teensy-1-webpage.png


And these are the web values at bottom.
The "DOP" values look strange , but else ...

Code:
PPS To GPS: 108 ms

millis() at PPS: 7171.825

millis() at GPS Timestamp: 7171933

millis() now: 7172.409

NTP time: 3977734437

IEEE 1588 counter at PPS: 3124372634

Offset between NTP/GPS times: -0.000000001 s

Estimate of NTP clock freq: 0.000004342 s/s

ChiSq fit of freq measure: 0.460

PID output: 4342 ns/s (ppb)

GPS lock Status: 3D

GPS Strong signals (> 25db): 9, Weak Signals (10db-24db): 5, No Signal (0db-9db): 3

GPS pdop=100, hdop=100, vdop=100

My local servers right now are :
DDrown - STM32F407 "Archmax" lookalike.
jclark - Raspi CM4 NTP/PTP server.
DDrown - Teensy-4.1 NTP server.

All uses LEA-M8T receivers.

My linux server(s) are jumping a bit around between the 3 local ntp servers i have , and some "damm good" swedish ntp servers.

But strangely enough they still seems prefer (most often connect to) the servers this way :
Archmax
Teensy-4.1
Raspi CM4.

I would have expected the Teensy to be the most used now.

Code:
# ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*archmax-01.luna .PPS.            1 u   77  256  377    0.377   -0.007   0.036
-n1.taur.dk      .PHC0.           1 u   35  512  377   17.233   +0.420   0.225
-sv-rpi4-01.luna .PHC0.           1 u    4  512  377    0.353   -0.010   0.022
+teensy-1.luna-l .PPS.            1 u   17  512  377    0.109   -0.042   0.053
+time.dfm.dk     .DFM.            1 u   10  512  377    2.480   -0.009   0.051
-mmo2.ntp.netnod .PPS.            1 u    1  512  377    2.032   -0.005   0.083
-sth1.ntp.netnod .PPS.            1 u   11  512  377   10.457   +0.189   0.237
-sth2.ntp.netnod .PPS.            1 u   21  512  377   10.255   +0.126   0.266
#gbg1.ntp.netnod .PPS.            1 u    8  512  377   16.869   +5.266   0.129
#gbg2.ntp.netnod .PPS.            1 u   15  512  377   16.704   +5.413   0.275
-mmo1.ntp.netnod .PPS.            1 u  257  256  377    2.292   -0.145   0.158
#gohere.hojmark. 194.58.202.20    2 u  139  256  377    5.745   -1.567   0.030
-91.229.203.9    10.12.0.11       2 u   37  512  157    3.902   -0.169   0.463
#time.cloudflare 10.229.8.4       3 u   29  512  377   11.478   -0.902   0.096

Thanx again Dan :)
This was the easiest DIY NTP server i have ever made.

Ps:
If you ever get the time .... I still have a few CH32V307's in the drawer

Or is the capture hw "too sick" ?
You mentioned being able to correct in sw.
 

Attachments

  • teensy-1-webpage.png
    teensy-1-webpage.png
    116.9 KB · Views: 19
  • teensy-1-webpage-2.png
    teensy-1-webpage-2.png
    127.7 KB · Views: 22
Last edited:
Back
Top