Generating/Approximating a PPS signal from Teensy 4.1

Agreed and fixed. Anyway, disabled interrupts are not that unusual. This is what a search for __disable_irq() on the Teensy4 core returns.

@luni, you're right. I have some applications where I try to avoid code that disables interrupts, maybe more out of habit than being sure it matters. That is harder to do on T4 than T3. In many cases I think HiResClock will simplify things.
 
In case you like to fiddle with the more modern aspects of C++, you might like my HiResClock library (https://github.com/luni64/HiResClock). It implements a std::chrono compliant c++ clock (see e.g. here https://en.cppreference.com/w/cpp/chrono) which uses F_CPU (600MHz) as time base. Thus it has a resolution of 1.666ns and measures time in nanoseconds since 1970-01-01. By default it syncs to the RTC at start. Here an example how you generate a RTC synced ns timestamp with this clock:

Code:
#include "HiResClock.h"

using namespace std::chrono;

void setup()
{
    HiResClock::begin(); // start the clock and sync to rtc (works with and without battery)
}

void loop()
{
    // long form:
    auto now       = HiResClock::now();               // get current timepoint
    auto dur       = now.time_since_epoch();          // calculate the chrono::duration since 1970-01-01 (in some system units, here 1/600Mhz)
    auto dur_in_ns = duration_cast<nanoseconds>(dur); // cast to a chrono::duration in units of nanoseconds (or milliseconds, or hours...)
    uint64_t ns    = dur_in_ns.count();               // read out the actual nanoseconds from the duration

    // short form:
    // uint64_t ns = duration_cast<nanoseconds>(HiResClock::now().time_since_epoch()).count();

    Serial.print(ns / 1E9, 9);      // print the timestamp in the desired form (e.g. 1687969637.753705324)

    //--- quick check ---
    Serial.print(" - ");
    time_t s = (time_t)(ns / 1E9); // transform to time_t...
    Serial.print(ctime(&s));       // and pretty print corresponding time

    delay(250);                    // repeat every 250ms
}

Prints:
Code:
1687981600.000000000 - Wed Jun 28 19:46:40 2023
1687981600.250008344 - Wed Jun 28 19:46:40 2023
1687981600.500017404 - Wed Jun 28 19:46:40 2023
1687981600.750026226 - Wed Jun 28 19:46:40 2023
1687981601.000035285 - Wed Jun 28 19:46:41 2023
1687981601.250044345 - Wed Jun 28 19:46:41 2023
1687981601.500053167 - Wed Jun 28 19:46:41 2023
1687981601.750062227 - Wed Jun 28 19:46:41 2023
1687981602.000071287 - Wed Jun 28 19:46:42 2023
1687981602.250080585 - Wed Jun 28 19:46:42 2023
1687981602.500089406 - Wed Jun 28 19:46:42 2023
1687981602.750098228 - Wed Jun 28 19:46:42 2023
1687981603.000107288 - Wed Jun 28 19:46:43 2023
1687981603.250116348 - Wed Jun 28 19:46:43 2023
1687981603.500125408 - Wed Jun 28 19:46:43 2023
1687981603.750134229 - Wed Jun 28 19:46:43 2023

The integer part of the calculated values corresponds to a normal time_t value. Resolution is 1.66ns. There are a few more examples how to use it in the lib repository and here https://github.com/TeensyUser/doc/wiki/Durations-Timepoints-and-Clocks and here: https://github.com/TeensyUser/doc/wiki/Implementing-a-high-resolution-Teensy-clock

Thank you Luni for pointing this out. The current implementation of my PPS generation now uses your TeensyTimerTool library (following similarly to this example: https://github.com/luni64/TeensyTimerTool/blob/master/examples/01_Basic/RTC_Timer/RTC_Timer.ino) as I found the clock drift to be comparable to the one generated by `void setupRTCInterrupt() {...}` as described in your first post. If you are interested in how I address clock drift, my implementation is here: https://github.com/BEAMRobotics/ig_...f76936303b29cfadfa88f614f1/main/main.ino#L160


Thank you to everyone else for their insights, any comments/critiques on my current implementation are welcome:
 
Thank you to everyone for your insights, our current implementation follows that shown here: https://github.com/BEAMRobotics/ig_handle/blob/update_for_release/main/main.ino#L1. We have used Luni's TeensyTimerTool library to access the RTC and generate a PPS. We account for drift by zeroing a microsecond counter each time the interrupt is called. This microsecond counter provides an estimate of the microseconds elapsed since the ISR is called. Any comments or criticism on our current implementation is welcome.
 
Last edited:
Link got '...' shorted from this?: github.com/BEAMRobotics/ig_handle/blob/main/main/main.ino
That code has this "// microsSincePPS = 0;" and not seeing where microsSincePPS is referenced for estimation?

This comment seems odd as digitalWriteFast() is very few optimized instructions and is typical for use in an _ISR() - at least on Teensy:
Code:
  /*  It's not really recommended to write to pins from an interrupt as it can
   * take a relatively long time to execute.
 
@luni , I noticed an issue in your HiResClock library. In file T4xSource.h, function getTicks() returns tickType, which is uint64_t for T4. However, curVal, which is the variable meant to hold the 64-bit return return value, is defined as uint32_t. curVal needs to be uint64_t (or tickType?) to get the whole 64 bits.
 
@luni , I noticed an issue in your HiResClock library. In file T4xSource.h, function getTicks() returns tickType, which is uint64_t for T4. However, curVal, which is the variable meant to hold the 64-bit return return value, is defined as uint32_t. curVal needs to be uint64_t (or tickType?) to get the whole 64 bits.
Thanks, fixed it in v0.1.3
 
Back
Top