Teensy4.1 Time between rising edges using Cycle Counter

riseley

Member
I am trying to determine the time difference (Sub microseconds) between the rising edges of 2 pulse trains at 1000Hz using the code attached. Using an oscilloscope, the time difference is approx 50.1 microsec. However it seems that I am missing a few calculations and am seeing high values on occasion based on the output below. Can someone explain this behaviour and recommend a method to avoid this error?
Thank you.

12:34:23.167 -> 50156
12:34:23.167 -> 50148
12:34:23.167 -> 50158
12:34:23.167 -> 50011
12:34:23.167 -> 50176
12:34:23.167 -> 50025
12:34:23.167 -> 50171
12:34:23.167 -> 550643
12:34:23.167 -> 550450
12:34:23.167 -> 50153
12:34:23.167 -> 50268
12:34:23.167 -> 50153
12:34:23.199 -> 50166
12:34:23.199 -> 50160
12:34:23.199 -> 50141
12:34:23.199 -> 50128
12:34:23.199 -> 50013
12:34:23.199 -> 550258
 

Attachments

  • Teensy4_1DualEdgeTimer_copy_20231016123227.ino
    769 bytes · Views: 23
  • Osc image.jpg
    Osc image.jpg
    65.4 KB · Views: 25
That is a small small code piece and easily inserted inline with the post using toolbar "#" CODE marking:
Code:
//volatile unsigned long time1;
//volatile unsigned long time2;

unsigned long time1;
unsigned long time2;
unsigned long tdiff;


volatile boolean valid1 = false;
volatile boolean valid2 = false;

void int1() {
  if (!valid1) {
    time1 = ARM_DWT_CYCCNT;
    valid1 = true;
  }
}

void int2() {
  if (valid1 && !valid2) {
    time2 = ARM_DWT_CYCCNT;
    valid2 = true;
  }
}

void setup() {
  attachInterrupt(9, int1, RISING);
  attachInterrupt(10, int2, RISING);
  ARM_DEMCR |= ARM_DEMCR_TRCENA;
  ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
}

void loop() {
  if (valid2) {
    //  if ((tdiff) < 700000) {
    tdiff = ((time2 - time1) * 1E9f / F_CPU);
    Serial.println(tdiff);
    //     }
    noInterrupts();
    valid1 = valid2 = false;
    interrupts();
  }
}

One issue may be the Serial.print of diff before setting the flags to false? The int1 and int2 may get out of sync? like:
Code:
void loop() {
  if (valid2) {
    //  if ((tdiff) < 700000) {
    tdiff = ((time2 - time1) * 1E9f / F_CPU);
    //     }
    noInterrupts();
    valid1 = valid2 = false;
    interrupts();
[B]    Serial.println(tdiff);
[/B]  }
}

Note:On T_4.1 the CYCCNT is already running.

There might be a better way to just have int2() to the diff math when it is ready to prevent some loop() interference ...
 
You could make the flow a bit more rigid, for example start by enabling only int1 which would disable itself and enable int2 (and log the time). Then have int2 disable itself and re-enable int1 (and calculate the time diff). That way it's not possible for them to get out of sync.
Ideally though you could use one of the timer modules that have triggers for capturing events like this (like a quad timer).
 
You could make the flow a bit more rigid, for example start by enabling only int1 which would disable itself and enable int2 (and log the time). Then have int2 disable itself and re-enable int1 (and calculate the time diff). That way it's not possible for them to get out of sync.
Ideally though you could use one of the timer modules that have triggers for capturing events like this (like a quad timer).

That's a good direction - and if it is okay to miss some samples (as is likely that case now), and the events are far enough apart:

Enable int > capture time: enable int2 when triggered: disable int1
int2> capture time: disable int2: flag DIFF ready
loop> if DIFF ready: print Diff value:: clear DIFF Flag : enable int1

That would miss some cycles
also, it might hit the timing wrong and miss the twin events in sync if they are too close.

If a series of events without miss is desired then Serial.print()'s would have to wait until the series data is collected to an array. It could be done continuously with a ring buffer type storage array, or big enough ping pong buffer pair, that can fill during the print period.
 
Consider using the FreqMeasure library. It does this type of measurement completely in hardware and uses interrupts only to grab the measured data after the hardware has made the elapsed time measurement. That means the measurement can tolerate interrupt latency from other libraries. By measuring directly with pin interrupts, you will have some sensitivity to interrupt latency if using USB or even just the normal timing functions like millis() which always run with an interrupt.
 
for fun here is a ping pong buffer that seems to work having a second Teensy toggling the pins 9 and 19 at different rates with an interval timer

Interesting if this works at speed?

The hard part seems to have been the pin toggle part ... smaller us's is more

Original code was missing pinMode() on the INPUT's - but worked to cath interrupts ???
Two buffers of '#define ppSize 128' hold samples until 7/8'ths full then it swaps and prints the used buffer - here in series of size 113.
> at the speed I'm using the buffer swaps seem to catch all data even with USB Serial.print()'s
Not sure of tdiff calc that was there - this just prints the cycle count difference.
There is a delayMicroseconds(4); to make sure the SerMon can keep up with prints - but not needed here it seems with reduced toggle rate.

Code:
unsigned long tdiff;
[B]#define ppSize 128[/B]
struct ppBuf {
  uint32_t index;
  uint32_t val1[ppSize];
  uint32_t val2[ppSize];
};

ppBuf *pIntppBuf;
ppBuf ppBuffA;
ppBuf ppBuffB;

void int1() {
  pIntppBuf->val1[pIntppBuf->index] = ARM_DWT_CYCCNT;
}

void int2() {
  if (pIntppBuf->val1[pIntppBuf->index] < 2 * F_CPU)
  {
    pIntppBuf->val2[pIntppBuf->index] = ARM_DWT_CYCCNT;
    pIntppBuf->index += 1;
  }
}

bool buffAB = false;
ppBuf *pWorkppBuf;
void setup() {
  Serial.begin(9600);
  pinMode(9, INPUT);
  pinMode(10, INPUT);
  while (!Serial && (millis() <= 6000))
    ;
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);

  for (int ii = 0; ii < ppSize; ii++) {
    ppBuffA.val1[ii] = 2 * F_CPU;
    ppBuffB.val1[ii] = 2 * F_CPU;
  }
  ppBuffA.index = 0;
  ppBuffB.index = 0;
  if (buffAB) {
    pIntppBuf = &ppBuffB;
    pWorkppBuf = &ppBuffA;
  } else {
    pIntppBuf = &ppBuffA;
    pWorkppBuf = &ppBuffB;
  }
  buffAB = !buffAB;
  attachInterrupt(9, int1, RISING);
  attachInterrupt(10, int2, RISING);
}

void loop() {
  if (pIntppBuf->index > (ppSize-ppSize/8)) {
    noInterrupts();
    if (buffAB) {
      pIntppBuf = &ppBuffB;
      pWorkppBuf = &ppBuffA;
    } else {
      pIntppBuf = &ppBuffA;
      pWorkppBuf = &ppBuffB;
    }
    buffAB = !buffAB;
    interrupts();
    uint32_t ii = 0;
    while (pWorkppBuf->index > ii) {
      //tdiff = ((pWorkppBuf->val2[ii] - pWorkppBuf->val1[ii]) * 1E9f / F_CPU);
      [B]tdiff = ((pWorkppBuf->val2[ii] - pWorkppBuf->val1[ii]));[/B]
      Serial.println(tdiff);
      [B]delayMicroseconds(4);[/B]
      pWorkppBuf->val1[ii] = 2 * F_CPU;
      ii++;
    }
    Serial.print("\t>>>> series size=");
    Serial.println(pWorkppBuf->index);
    pWorkppBuf->index = 0;
  }
}

Buffers are large with 4 copies of 128 uint32_t's - but plenty of room for more if that helps:
Code:
Memory Usage on Teensy 4.1:
  FLASH: code:11484, data:4040, headers:9048   free for files:8101892
   [B]RAM1: variables:6880[/B], code:8816, padding:23952   free for local variables:484640
   RAM2: variables:12416  free for malloc/new:511872

Here's the signal trigger code that was good enough to see rate changes - though slower than 1KHz:
Code:
#include "IntervalTimer.h"
IntervalTimer cycleMaker;
#define divFactor 10
#define usToggle 100/divFactor
int mm = 1, nn = 0;
void one_s_task() {
  mm++;
  nn++;
  if (0 == (mm % divFactor)) {
    digitalToggleFast(9);
    digitalToggleFast(13);
  }
  if (0 == (nn % divFactor)) {
    digitalToggleFast(10);
  }
  if (nn > usToggle * divFactor) {
    nn = (nn % divFactor);
    mm = 1+ (mm % divFactor);
  }
}

elapsedMillis myTime;
void setup() {
  Serial.begin(9600);
  while (!Serial && (millis() <= 6000))
    ;
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  pinMode(13, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  myTime = 0;
  cycleMaker.begin(one_s_task, usToggle);
}

void loop() {
  if (myTime > 16 * 1000) {
    cycleMaker.end();
    Serial.print("\nanykey to continue ...");
    while (0 > Serial.read())
      ;
    while (0 < Serial.read())
      ;
    myTime = 0;
    cycleMaker.begin(one_s_task, usToggle);
    Serial.print("... continuing ...\n");
  }
}
 
Consider using the FreqMeasure library. It does this type of measurement completely in hardware and uses interrupts only to grab the measured data after the hardware has made the elapsed time measurement. That means the measurement can tolerate interrupt latency from other libraries. By measuring directly with pin interrupts, you will have some sensitivity to interrupt latency if using USB or even just the normal timing functions like millis() which always run with an interrupt.

Yes, please use FreqMeasure or FreqMeasureMulti. It really doesn't make sense to try to get sub-microsecond accuracy any other way.
 
p#1 goal determine:
the time difference (Sub microseconds) between the rising edges of 2 pulse trains at 1000Hz

i.e. the time diff between Rising of two pins as posted #9 and #10.

Image shows they are both at the same freq - just shifted by some amount to be measured.

Would be interesting to see how "FreqMeasure or FreqMeasureMulti" could be applied to solve that?
 
I have amended the code per below and the results seem though better are still seeing the ocassional incorrect values. I will try some of the other suggestions and report back.
17:45:23.275 -> 53915
17:45:23.275 -> 53911
17:45:23.275 -> 53921
17:45:23.275 -> 53908
17:45:23.275 -> 53911
17:45:23.275 -> 53908
17:45:23.275 -> 53906
17:45:23.275 -> 53915
17:45:23.275 -> 53911
17:45:23.275 -> 53908
17:45:23.275 -> 554215
17:45:23.275 -> 53896

Code:
unsigned long time1;
unsigned long time2;
unsigned long tdiff;


volatile boolean valid1 = false;
volatile boolean valid2 = false;

void int1() {
  if (!valid1) {
    time1 = ARM_DWT_CYCCNT;
    valid1 = true;
  }
}

void int2() {
  if (valid1 && !valid2) {
    time2 = ARM_DWT_CYCCNT;
    valid2 = true;
  }
}

void setup() {
  attachInterrupt(9, int1, RISING);
  attachInterrupt(10, int2, RISING);
}

void loop() {
  if (valid2) {
    tdiff = ((time2 - time1) * 1E9f / F_CPU);
    noInterrupts();
    valid1 = valid2 = false;
    interrupts();
    Serial.println(tdiff);
  }
}
 
@riseley - would be interesting to see if the first code in p#6 above gives desired results

It does work but there is some latency in the output. I am now thinking about just averaging 100 samples and sending an output to Serial. Alternatively try suggestions in p#3 & 4 by missing a few samples.
 
Consider using the FreqMeasure library. It does this type of measurement completely in hardware and uses interrupts only to grab the measured data after the hardware has made the elapsed time measurement. That means the measurement can tolerate interrupt latency from other libraries. By measuring directly with pin interrupts, you will have some sensitivity to interrupt latency if using USB or even just the normal timing functions like millis() which always run with an interrupt.

Can you provide a suggestion as to how this can be done? Both pulse trains are at the same frequency with a phase lag between the two.
 
Great that it works!

It does work but there is some latency in the output. I am now thinking about just averaging 100 samples and sending an output to Serial. Alternatively try suggestions in p#3 & 4 by missing a few samples.

Yes latency is expected in order to prevent the USB I/O from issues. I could only test against my simulator that doesn't hit 1000Hz. Easy to adjust edit the indicated "#define ppSize 128" to a smaller number. That is the number of samples batched before display.

Try #define ppSize 32 and it will print after each 28 samples instead of after 113.

At some point going lower might cause USB Serial.print()'s to interfere with the interrupts as it has higher priority - in that case setting the pin interrupt priority higher might help with that given how short the _ISR() code is and only 2,000 per second.
 
Can you provide a suggestion as to how this can be done? Both pulse trains are at the same frequency with a phase lag between the two.

That was my question in p#8 as well ...

An AVG of 100 samples that will not change much faster than the p#6 code that prints 113 samples. If each sample is not printed but an average it could be done more often - like every 10 or 16.

This code there:
Code:
void loop() {
  [B][U]if (pIntppBuf->index > (ppSize-ppSize/8)) {[/U][/B]
    noInterrupts();
    if (buffAB) {
      pIntppBuf = &ppBuffB;
      pWorkppBuf = &ppBuffA;
    } else {
      pIntppBuf = &ppBuffA;
      pWorkppBuf = &ppBuffB;
    }
    buffAB = !buffAB;
    interrupts();
    uint32_t ii = 0;
[B]    while (pWorkppBuf->index > ii) {
      //tdiff = ((pWorkppBuf->val2[ii] - pWorkppBuf->val1[ii]) * 1E9f / F_CPU);
      tdiff = ((pWorkppBuf->val2[ii] - pWorkppBuf->val1[ii]));
      [B][U]Serial.println(tdiff);[/U][/B]
      [COLOR="#FF0000"]delayMicroseconds(4);[/COLOR]
      pWorkppBuf->val1[ii] = 2 * F_CPU;
      ii++;
    }
[/B]    Serial.print("\t>>>> series size=");
    Serial.println(pWorkppBuf->index);
    pWorkppBuf->index = 0;
  }
}

Could do an average based on a value set in the IF() for how many collected points to average with setting this value in the IF() : ...( > ppSize-ppSize/8))
Then the WHILE() section iterates the samples collected and instead of printing each value an average [and MIN and MAX?] could be calculated and then printed much faster without interfering with sample collection.
Comment or remove this as it will waste time if USB can keep up: delayMicroseconds(4);

p#3 idea wasn't bad but not ideal (given the low 2KHz interrupts the Teensy can handle) as p#6 solution it seems as it works without risking loss of samples. p#4 also suggested the PingPong buffers and that is what is done with p#6.

<edit> Note: the buffer size can be larger that the value test in the IF() - and if the system can keep up with avg calc and print then the entry to the IF() will always be at the chosen pIntppBuf->index value
 
It does work but there is some latency in the output. I am now thinking about just averaging 100 samples and sending an output to Serial. Alternatively try suggestions in p#3 & 4 by missing a few samples.

Edit to this loop() code does average of numToAvg of the observed difference in cycles between Pin #9 and #10:
Note: tdiff now unused and results likely only valid if the two source freq's are about 200 nanoseconds out of sync with use of two pin interrupts.
Note: YMMV?: It calculates and prints each 10 samples - but USB showing bulk output then long delay when it should continue? - perhaps that is my simulator code? Added delay(4) us and Serial.flush() and no change.
Code:
[B]#define numToAvg 10[/B]
void loop() {
  if (pIntppBuf->index >= numToAvg-1) {
    noInterrupts();
    if (buffAB) {  // Change INT data pointer
      pIntppBuf = &ppBuffB;
    } else {
      pIntppBuf = &ppBuffA;
    }
    interrupts();
    if (buffAB) {  // Change WORK data pointer
      pWorkppBuf = &ppBuffA;
    } else {
      pWorkppBuf = &ppBuffB;
    }
    buffAB = !buffAB;  // update indicator of data buffer in use
    uint32_t ii = 0;
    uint64_t avgSum = 0; // 64 bit to avoid overflow
    while (pWorkppBuf->index > ii) {
      if (numToAvg > ii)
        avgSum += ((pWorkppBuf->val2[ii] - pWorkppBuf->val1[ii]));
      pWorkppBuf->val1[ii] = 2 * F_CPU;
      ii++;
    }
    Serial.print(avgSum / numToAvg);
    Serial.print("\t>>>> AVG size=");
    Serial.println(pWorkppBuf->index+1);
    delayMicroseconds(4);
    Serial.flush();
    pWorkppBuf->index = 0;
  }
}
 
Can you provide a suggestion as to how this can be done? Both pulse trains are at the same frequency with a phase lag between the two.

Try this code. Your pulses must be on pins 10 and 12.
It uses the hardware timers in the imxrt1060 chip. Details: see NXP i.MX RT1060 Processor Reference Manual.

It should be possible to wire the timer capture inputs via crossbar to other pins.


Code:
#include <imxrt.h>
#include <util/atomic.h>

#define buf_size  256
volatile int buffer[buf_size];

volatile int head = 0;
volatile int tail = 0;

volatile uint16_t Captured10, Captured12;
volatile uint16_t FromCaptured10toCaptured12;
volatile uint16_t FromCaptured12toCaptured10;

volatile double low_pass_filtered_FromCaptured10toCaptured12 = 0.0;
volatile double low_pass_filtered_FromCaptured12toCaptured10 = 0.0;
volatile double low_pass_filtered_Period10 = 0.0;
volatile double low_pass_filtered_Period12 = 0.0;

volatile float f = 0.001;  // low pass filter constant
volatile uint16_t Period10, prev_Captured10;
volatile uint16_t Period12, prev_Captured12;

#define prescale  4

void setup() 
{
     Serial.begin(115200);
    int retry = 0;    // Serial is the USB port, but if no PC connected/active, then proceed anyway
    while ((!Serial) && (retry++ < 100))
        delay(10);
    if (CrashReport)
      Serial.print(CrashReport);
    Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);

    Serial.printf ("Sensing edges on pin 10 and pin 12, reporting the time in us from edge on 10 to edge on 12.\n");
    double fmin = 150E6 / (prescale * 65536);

    Serial.printf ("f_min = %1.3f kHz\n", fmin/1E3);
    for (int i=0; i<buf_size; i++)
      buffer[i] = 0;

    IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 0x11;   // wire pin10 = B0-00 to QTIMER1_TIMER0
    IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_01 = 0x11;   // wire pin12 = B0-01 to QTIMER1_TIMER1

    IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_00 = IOMUXC_PAD_HYS | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); // 22k pullup
    IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_01 = IOMUXC_PAD_HYS | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); // 22k pullup

    TMR1_CTRL0   = 0x0000;
    TMR1_LOAD0   = 0x0000;
    TMR1_SCTRL0  = TMR_SCTRL_IEFIE | TMR_SCTRL_CAPTURE_MODE(1);   // Input Edge Flag Interrupt Enable
    TMR1_CNTR0 = 0;

    TMR1_CTRL1   = 0x0000;
    TMR1_LOAD1   = 0x0000;
    TMR1_SCTRL1  = TMR_SCTRL_IEFIE | TMR_SCTRL_CAPTURE_MODE(1);    // Input Edge Flag Interrupt Enable
    TMR1_CNTR1 = 0;
    TMR1_CTRL1 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(0b1010) | TMR_CTRL_SCS(1);    // prescaler=4
    TMR1_CTRL0 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(0b1010) | TMR_CTRL_SCS(0);    // prescaler=4


    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) 
    {
      TMR1_CNTR1 = 0;
      TMR1_CNTR0 = 0;   // keep same counter values as Counter 0 (as much as possible... they will be one instruction cyc;le apart...)
    }

    attachInterruptVector(IRQ_QTIMER1, t1_isr); 
    NVIC_ENABLE_IRQ(IRQ_QTIMER1);
    NVIC_SET_PRIORITY(IRQ_QTIMER1, 16);
}


void t1_isr()
{
    if (TMR1_SCTRL0 & TMR_SCTRL_IEF)
    {
      Captured10 = TMR1_CAPT0;
      TMR1_SCTRL0 &= ~TMR_SCTRL_IEF;
      FromCaptured12toCaptured10 = Captured10 - Captured12;

      low_pass_filtered_FromCaptured12toCaptured10 = f * FromCaptured12toCaptured10 + (1-f) * low_pass_filtered_FromCaptured12toCaptured10;


      Period10 = Captured10 - prev_Captured10;
      low_pass_filtered_Period10 = f * Period10 + (1-f) * low_pass_filtered_Period10;

      prev_Captured10 = Captured10;

      buffer[head] = 0x10000 | Captured10;
      head++;
      if (head > buf_size)
        head = 0;
    }
    if (TMR1_SCTRL1 & TMR_SCTRL_IEF)
    {
      Captured12 = TMR1_CAPT1;
      TMR1_SCTRL1 &= ~TMR_SCTRL_IEF;
      FromCaptured10toCaptured12 = Captured12 - Captured10;

      low_pass_filtered_FromCaptured10toCaptured12 = f * FromCaptured10toCaptured12 + (1-f) * low_pass_filtered_FromCaptured10toCaptured12;

      Period12 = Captured12 - prev_Captured12;
      low_pass_filtered_Period12 = f * Period12 + (1-f) * low_pass_filtered_Period12;
      prev_Captured12 = Captured12;
      buffer[head] = 0x20000 | Captured12;
      head++;
      if (head > buf_size)
        head = 0;
    }
}

double CYCCNT_to_us (uint32_t cycles)
{
    return (double)cycles / (600 / (4*prescale));
}

double dCYCCNT_to_us (double cycles)
{
    return cycles / (600 / (4*prescale));
}

uint32_t us_to_CYCCNT (double us)
{
    us *= 600.0 / (4*prescale);
    return (uint32_t)us;
}

volatile uint16_t prev_uint16_counts = 0;

void loop()
{
/*    int buffer_element = buffer[tail];

    if (buffer_element & 0x30000)
    {
      uint16_t uint16_counts = buffer_element & 0xffff;
      uint16_t uint16_dt = uint16_counts - prev_uint16_counts;
      double dt = CYCCNT_to_us(uint16_dt);

      if (buffer_element & 0x10000)
      {
        Serial.printf ("%d %d %d pin 10 edge t=%1.3f us\n", (buffer_element>>16) & 0x3, tail, uint16_counts, dt);
      }
      else
      {
        Serial.printf ("%d %d %d pin 12 edge t=%1.3f us\n", (buffer_element>>16) & 0x3, tail, uint16_counts, dt);
      }
      prev_uint16_counts = uint16_counts;

      buffer[tail] = 0;

      tail++;
      if (tail > buf_size)
        tail = 0;

    }
*/

/*    else
    {
      Serial.printf ("pin10=%d, ", (TMR1_SCTRL0 >> 8) & 1);
      Serial.printf ("pin12=%d\n", (TMR1_SCTRL1 >> 8) & 1);

    }
*/
      Serial.printf ("pin10=%d pin12=%d Period10=%1.3f us Period12=%1.3f us, edge10->edge12 in %1.3f us, edge12->edge10 in %1.3f us\n", 
                        (TMR1_SCTRL0 >> 8) & 1, (TMR1_SCTRL1 >> 8) & 1, 
                        dCYCCNT_to_us(low_pass_filtered_Period10),dCYCCNT_to_us(low_pass_filtered_Period12),
                        dCYCCNT_to_us(low_pass_filtered_FromCaptured10toCaptured12),dCYCCNT_to_us(low_pass_filtered_FromCaptured12toCaptured10)) ;
      delay (300);
}
 
Hardware timers in capture modes. Even better code. Now with 32 bit timers, 6.7 ns resolution, input pulse frequencies from many MHz down to 0.07 Hz. Using pin 10 (or 7 via XBAR) for input A, using pin 12 (or 8 via XBAR) for input B.

Code:
#include <imxrt.h>
#include <TimeLib.h>

#define buf_size  256
volatile uint32_t buffer_captured[buf_size];
volatile int buffer_which[buf_size];

volatile int head = 0;
volatile int tail = 0;

volatile uint32_t CapturedPinA, CapturedPinB;
volatile int32_t FromCapturedPinAtoCapturedPinB;
volatile int32_t FromCapturedPinBtoCapturedPinA;

volatile double low_pass_filtered_FromCapturedPinAtoCapturedPinB = 0.0;
volatile double low_pass_filtered_FromCapturedPinBtoCapturedPinA = 0.0;
volatile double low_pass_filtered_PeriodPinA = 0.0;
volatile double low_pass_filtered_PeriodPinB = 0.0;

volatile float f = 0.1;  // low pass filter constant
volatile uint32_t PeriodPinA, prev_CapturedPinA;
volatile uint32_t PeriodPinB, prev_CapturedPinB;

IntervalTimer myTimer_1ms;
const int ledPin = 13;
volatile bool ledState = 0;

int L2prescale = 0;
int prescale  = 1 << L2prescale;

int A_input_pin_is_10 = 1;  // if 0 then we'll use pin 7 instead
int B_input_pin_is_12 = 1;  // if 0 then we'll use pin 8 instead

void xbar_connect1(unsigned int input, unsigned int output)
{
  if (input >= 88) return;
  if (output >= 132) return;

  volatile uint16_t *xbar = &XBARA1_SEL0 + (output / 2);

  uint16_t val = *xbar;
  if (!(output & 1))
    val = (val & 0xFF00) | input;
  else 
     val = (val & 0x00FF) | (input << 8);
  *xbar = val;
}

void setup() 
{
    Serial.begin(115200);
    int retry = 0;    // Serial is the USB port, but if no PC connected/active, then proceed anyway
    while ((!Serial) && (retry++ < 100))
        delay(10);
    if (CrashReport)
      Serial.print(CrashReport);
    Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);

    Serial.printf ("Sensing edges on PinA and pin PinB, reporting the time in us from edge on PinA to edge on PinB.\n");
    double fmin = 150E6 / (prescale * 65536.0 * 65535.0);

    Serial.printf ("f_min = %1.5f Hz\n", fmin/1E6);
    for (int i=0; i<buf_size; i++)
    {
        buffer_captured[i] = 0;
        buffer_which[i] = 0;
    }

    if (A_input_pin_is_10)
    {
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 0x11;   // wire pin 10, aka GPIO_B0-00, aka CORE_PIN10 to QTIMER1_TIMER0
      IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_00 = IOMUXC_PAD_HYS | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); // 22k pullup
    }
    else
    {
      volatile uint32_t *pad = &CORE_PIN7_PADCONFIG;
      volatile uint32_t *mux = &CORE_PIN7_CONFIG;   // pin 7, aka GPIO_B1_01
      uint32_t XBARA1_IN_INOUTn = XBARA1_IN_IOMUX_XBAR_INOUT15;
      uint32_t mux_value = 0x11;
      volatile uint32_t *select_input = &IOMUXC_XBAR1_IN15_SELECT_INPUT;
      uint32_t select_input_value = 1;
 
      *mux = mux_value;   
      *select_input = select_input_value; 
      CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
      xbar_connect1 (XBARA1_IN_INOUTn, XBARA1_OUT_QTIMER1_TIMER0);
      IOMUXC_GPR_GPR6 |=  IOMUXC_GPR_GPR6_QTIMER1_TRM0_INPUT_SEL;

      *pad = IOMUXC_PAD_HYS | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); // 22k pullup
    }

    if (B_input_pin_is_12)
    {
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_01 = 0x11;   // wire pin 12,  aka GPIO_B0-01, aka CORE_PIN12 to QTIMER1_TIMER1
      IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_01 = IOMUXC_PAD_HYS | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); // 22k pullup
    }
    else
    {
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 0x11;   // wire pin 8, aka GPIO_B1-00 to XBAR1_INOUT14
      IOMUXC_XBAR1_IN14_SELECT_INPUT = 1; // B1-00
      CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
      xbar_connect1 (XBARA1_IN_IOMUX_XBAR_INOUT14, XBARA1_OUT_QTIMER1_TIMER1);
      IOMUXC_GPR_GPR6 |=  IOMUXC_GPR_GPR6_QTIMER1_TRM1_INPUT_SEL;

      IOMUXC_SW_PAD_CTL_PAD_GPIO_B1_00 = IOMUXC_PAD_HYS | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); // 22k pullup
   }


    int pcs = 0x8 + L2prescale;

    TMR1_CTRL0   = 0x0000;
    TMR1_CSCTRL0 = 0;
    TMR1_LOAD0   = 0x0;
    TMR1_SCTRL0  = TMR_SCTRL_IEFIE | TMR_SCTRL_CAPTURE_MODE(1);   
    TMR1_CTRL0 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(pcs) | TMR_CTRL_SCS(0);    
    TMR1_CTRL2   = 0x0000;
    TMR1_CSCTRL2 = 0;
    TMR1_LOAD2   = 0x0;
    TMR1_SCTRL2  = TMR_SCTRL_CAPTURE_MODE(1);   
    TMR1_CTRL2 = TMR_CTRL_CM(7) | TMR_CTRL_PCS(4+0) | TMR_CTRL_SCS(0);    

    TMR1_CTRL1   = 0x0000;
    TMR1_CSCTRL1 = 0;
    TMR1_LOAD1   = 0x0000;
    TMR1_SCTRL1  = TMR_SCTRL_IEFIE | TMR_SCTRL_CAPTURE_MODE(1);    
    TMR1_CTRL1 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(pcs) | TMR_CTRL_SCS(1);    
    TMR1_CTRL3   = 0x0000;
    TMR1_CSCTRL3 = 0;
    TMR1_LOAD3   = 0x0000;
    TMR1_SCTRL3  = TMR_SCTRL_CAPTURE_MODE(1);   
    TMR1_CTRL3 = TMR_CTRL_CM(7) | TMR_CTRL_PCS(4+1) | TMR_CTRL_SCS(1);    

    TMR1_ENBL &= ~0b1111;
    TMR1_CNTR0 = 0;
    TMR1_CNTR1 = 0;   
    TMR1_CNTR2 = 0;
    TMR1_CNTR3 = 0;   
    TMR1_ENBL |= 0b1111;

    attachInterruptVector(IRQ_QTIMER1, t1_isr); 
    NVIC_ENABLE_IRQ(IRQ_QTIMER1);
    NVIC_SET_PRIORITY(IRQ_QTIMER1, 16);
 
    pinMode(ledPin, OUTPUT);

    myTimer_1ms.begin(timerAction_1ms_prio_2, 1000);  // timerAction to run every 0.001 seconds
    myTimer_1ms.priority (3*16); //  lower number = higher priority

}

void timerAction_1ms_prio_2 ()
{
    digitalWrite(ledPin, ledState);
    ledState = !ledState;
}

void t1_isr()
{
    bool had_a_PinA = 0;
    bool had_a_PinB = 0;

    if (TMR1_SCTRL0 & TMR_SCTRL_IEF)
    {
      CapturedPinA = TMR1_CAPT0 + (((uint32_t)TMR1_CAPT2) << 16);
      TMR1_SCTRL0 &= ~TMR_SCTRL_IEF;
      TMR1_SCTRL2 &= ~TMR_SCTRL_IEF;
      had_a_PinA = 1;
    }
    if (TMR1_SCTRL1 & TMR_SCTRL_IEF)
    {
      CapturedPinB = TMR1_CAPT1 + (((uint32_t)TMR1_CAPT3) << 16);
      TMR1_SCTRL1 &= ~TMR_SCTRL_IEF;
      TMR1_SCTRL3 &= ~TMR_SCTRL_IEF;
      had_a_PinB = 1;
    }
    
    if (had_a_PinA)
    {
      FromCapturedPinBtoCapturedPinA = CapturedPinA - CapturedPinB;

      low_pass_filtered_FromCapturedPinBtoCapturedPinA = f * FromCapturedPinBtoCapturedPinA + (1-f) * low_pass_filtered_FromCapturedPinBtoCapturedPinA;


      PeriodPinA = CapturedPinA - prev_CapturedPinA;
      low_pass_filtered_PeriodPinA = f * PeriodPinA + (1-f) * low_pass_filtered_PeriodPinA;

      prev_CapturedPinA = CapturedPinA;

      buffer_captured[head] = CapturedPinA;
      buffer_which[head] = 1;
      head++;
      if (head > buf_size)
        head = 0;
    }

    if (had_a_PinB)
    {
      FromCapturedPinAtoCapturedPinB = CapturedPinB - CapturedPinA;

      low_pass_filtered_FromCapturedPinAtoCapturedPinB = f * FromCapturedPinAtoCapturedPinB + (1-f) * low_pass_filtered_FromCapturedPinAtoCapturedPinB;

      PeriodPinB = CapturedPinB - prev_CapturedPinB;
      low_pass_filtered_PeriodPinB = f * PeriodPinB + (1-f) * low_pass_filtered_PeriodPinB;
      prev_CapturedPinB = CapturedPinB;
      buffer_captured[head] = CapturedPinB;
      buffer_which[head] = 2;
      head++;
      if (head > buf_size)
        head = 0;
    }
}

double CYCCNT_to_us (int32_t cycles)
{
    return (double)cycles / (600.0 / (4*prescale));
}

double dCYCCNT_to_us (double cycles)
{
    return cycles / (600.0 / (4*prescale));
}

uint32_t us_to_CYCCNT (double us)
{
    us *= 600.0 / (4*prescale);
    return (uint32_t)us;
}

volatile uint32_t prev_uint32_counts = 0;

void loop()
{
  volatile int display_mode = 0;

  if (display_mode == 1)
  {
    int buffer_which_element = buffer_which[tail];
    if (buffer_which_element & 0x3)
    {
      uint32_t buffer_element = buffer_captured[tail];
      uint32_t uint32_counts = buffer_element;
      int32_t int32_dt = uint32_counts - prev_uint32_counts;
      double dt;
      dt = CYCCNT_to_us(int32_dt);

      if (buffer_which_element & 1)
      {
        Serial.printf ("%d %3d %08x %d pin PinA edge t=%1.3f us\n", buffer_which_element, tail, buffer_element, int32_dt, dt);
      }
      else
      {
        Serial.printf ("%d %3d %08x %d PinB edge t=%1.3f us\n", buffer_which_element, tail, buffer_element, int32_dt, dt);
      }
      prev_uint32_counts = uint32_counts;

      buffer_which[tail] = 0;

      tail++;
      if (tail > buf_size)
        tail = 0;

    }
  }
  else
  {
      Serial.printf ("PinA=%d PinB=%d PeriodPinA=%1.3f us PeriodPinB=%1.3f us, edgePinA->edgePinB in %1.3f us, edgePinB->edgePinA in %1.3f us\n", 
                        (TMR1_SCTRL0 >> 8) & 1, (TMR1_SCTRL1 >> 8) & 1, 
                        dCYCCNT_to_us(low_pass_filtered_PeriodPinA),dCYCCNT_to_us(low_pass_filtered_PeriodPinB),
                        dCYCCNT_to_us(low_pass_filtered_FromCapturedPinAtoCapturedPinB),dCYCCNT_to_us(low_pass_filtered_FromCapturedPinBtoCapturedPinA)) ;
       delay (300);
  }
}
 
Hardware timers in capture modes. Even better code. Now with 32 bit timers, 6.7 ns resolution, input pulse frequencies from many MHz down to 0.07 Hz. Using pin 10 (or 7 via XBAR) for input A, using pin 12 (or 8 via XBAR) for input B.

Code:
#include <imxrt.h>
#include <TimeLib.h>

#define buf_size  256
volatile uint32_t buffer_captured[buf_size];
volatile int buffer_which[buf_size];

volatile int head = 0;
volatile int tail = 0;

volatile uint32_t CapturedPinA, CapturedPinB;
volatile int32_t FromCapturedPinAtoCapturedPinB;
volatile int32_t FromCapturedPinBtoCapturedPinA;

volatile double low_pass_filtered_FromCapturedPinAtoCapturedPinB = 0.0;
volatile double low_pass_filtered_FromCapturedPinBtoCapturedPinA = 0.0;
volatile double low_pass_filtered_PeriodPinA = 0.0;
volatile double low_pass_filtered_PeriodPinB = 0.0;

volatile float f = 0.1;  // low pass filter constant
volatile uint32_t PeriodPinA, prev_CapturedPinA;
volatile uint32_t PeriodPinB, prev_CapturedPinB;

IntervalTimer myTimer_1ms;
const int ledPin = 13;
volatile bool ledState = 0;

int L2prescale = 0;
int prescale  = 1 << L2prescale;

int A_input_pin_is_10 = 1;  // if 0 then we'll use pin 7 instead
int B_input_pin_is_12 = 1;  // if 0 then we'll use pin 8 instead

void xbar_connect1(unsigned int input, unsigned int output)
{
  if (input >= 88) return;
  if (output >= 132) return;

  volatile uint16_t *xbar = &XBARA1_SEL0 + (output / 2);

  uint16_t val = *xbar;
  if (!(output & 1))
    val = (val & 0xFF00) | input;
  else 
     val = (val & 0x00FF) | (input << 8);
  *xbar = val;
}

void setup() 
{
    Serial.begin(115200);
    int retry = 0;    // Serial is the USB port, but if no PC connected/active, then proceed anyway
    while ((!Serial) && (retry++ < 100))
        delay(10);
    if (CrashReport)
      Serial.print(CrashReport);
    Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);

    Serial.printf ("Sensing edges on PinA and pin PinB, reporting the time in us from edge on PinA to edge on PinB.\n");
    double fmin = 150E6 / (prescale * 65536.0 * 65535.0);

    Serial.printf ("f_min = %1.5f Hz\n", fmin/1E6);
    for (int i=0; i<buf_size; i++)
    {
        buffer_captured[i] = 0;
        buffer_which[i] = 0;
    }

    if (A_input_pin_is_10)
    {
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 0x11;   // wire pin 10, aka GPIO_B0-00, aka CORE_PIN10 to QTIMER1_TIMER0
      IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_00 = IOMUXC_PAD_HYS | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); // 22k pullup
    }
    else
    {
      volatile uint32_t *pad = &CORE_PIN7_PADCONFIG;
      volatile uint32_t *mux = &CORE_PIN7_CONFIG;   // pin 7, aka GPIO_B1_01
      uint32_t XBARA1_IN_INOUTn = XBARA1_IN_IOMUX_XBAR_INOUT15;
      uint32_t mux_value = 0x11;
      volatile uint32_t *select_input = &IOMUXC_XBAR1_IN15_SELECT_INPUT;
      uint32_t select_input_value = 1;
 
      *mux = mux_value;   
      *select_input = select_input_value; 
      CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
      xbar_connect1 (XBARA1_IN_INOUTn, XBARA1_OUT_QTIMER1_TIMER0);
      IOMUXC_GPR_GPR6 |=  IOMUXC_GPR_GPR6_QTIMER1_TRM0_INPUT_SEL;

      *pad = IOMUXC_PAD_HYS | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); // 22k pullup
    }

    if (B_input_pin_is_12)
    {
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_01 = 0x11;   // wire pin 12,  aka GPIO_B0-01, aka CORE_PIN12 to QTIMER1_TIMER1
      IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_01 = IOMUXC_PAD_HYS | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); // 22k pullup
    }
    else
    {
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 0x11;   // wire pin 8, aka GPIO_B1-00 to XBAR1_INOUT14
      IOMUXC_XBAR1_IN14_SELECT_INPUT = 1; // B1-00
      CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
      xbar_connect1 (XBARA1_IN_IOMUX_XBAR_INOUT14, XBARA1_OUT_QTIMER1_TIMER1);
      IOMUXC_GPR_GPR6 |=  IOMUXC_GPR_GPR6_QTIMER1_TRM1_INPUT_SEL;

      IOMUXC_SW_PAD_CTL_PAD_GPIO_B1_00 = IOMUXC_PAD_HYS | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); // 22k pullup
   }


    int pcs = 0x8 + L2prescale;

    TMR1_CTRL0   = 0x0000;
    TMR1_CSCTRL0 = 0;
    TMR1_LOAD0   = 0x0;
    TMR1_SCTRL0  = TMR_SCTRL_IEFIE | TMR_SCTRL_CAPTURE_MODE(1);   
    TMR1_CTRL0 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(pcs) | TMR_CTRL_SCS(0);    
    TMR1_CTRL2   = 0x0000;
    TMR1_CSCTRL2 = 0;
    TMR1_LOAD2   = 0x0;
    TMR1_SCTRL2  = TMR_SCTRL_CAPTURE_MODE(1);   
    TMR1_CTRL2 = TMR_CTRL_CM(7) | TMR_CTRL_PCS(4+0) | TMR_CTRL_SCS(0);    

    TMR1_CTRL1   = 0x0000;
    TMR1_CSCTRL1 = 0;
    TMR1_LOAD1   = 0x0000;
    TMR1_SCTRL1  = TMR_SCTRL_IEFIE | TMR_SCTRL_CAPTURE_MODE(1);    
    TMR1_CTRL1 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(pcs) | TMR_CTRL_SCS(1);    
    TMR1_CTRL3   = 0x0000;
    TMR1_CSCTRL3 = 0;
    TMR1_LOAD3   = 0x0000;
    TMR1_SCTRL3  = TMR_SCTRL_CAPTURE_MODE(1);   
    TMR1_CTRL3 = TMR_CTRL_CM(7) | TMR_CTRL_PCS(4+1) | TMR_CTRL_SCS(1);    

    TMR1_ENBL &= ~0b1111;
    TMR1_CNTR0 = 0;
    TMR1_CNTR1 = 0;   
    TMR1_CNTR2 = 0;
    TMR1_CNTR3 = 0;   
    TMR1_ENBL |= 0b1111;

    attachInterruptVector(IRQ_QTIMER1, t1_isr); 
    NVIC_ENABLE_IRQ(IRQ_QTIMER1);
    NVIC_SET_PRIORITY(IRQ_QTIMER1, 16);
 
    pinMode(ledPin, OUTPUT);

    myTimer_1ms.begin(timerAction_1ms_prio_2, 1000);  // timerAction to run every 0.001 seconds
    myTimer_1ms.priority (3*16); //  lower number = higher priority

}

void timerAction_1ms_prio_2 ()
{
    digitalWrite(ledPin, ledState);
    ledState = !ledState;
}

void t1_isr()
{
    bool had_a_PinA = 0;
    bool had_a_PinB = 0;

    if (TMR1_SCTRL0 & TMR_SCTRL_IEF)
    {
      CapturedPinA = TMR1_CAPT0 + (((uint32_t)TMR1_CAPT2) << 16);
      TMR1_SCTRL0 &= ~TMR_SCTRL_IEF;
      TMR1_SCTRL2 &= ~TMR_SCTRL_IEF;
      had_a_PinA = 1;
    }
    if (TMR1_SCTRL1 & TMR_SCTRL_IEF)
    {
      CapturedPinB = TMR1_CAPT1 + (((uint32_t)TMR1_CAPT3) << 16);
      TMR1_SCTRL1 &= ~TMR_SCTRL_IEF;
      TMR1_SCTRL3 &= ~TMR_SCTRL_IEF;
      had_a_PinB = 1;
    }
    
    if (had_a_PinA)
    {
      FromCapturedPinBtoCapturedPinA = CapturedPinA - CapturedPinB;

      low_pass_filtered_FromCapturedPinBtoCapturedPinA = f * FromCapturedPinBtoCapturedPinA + (1-f) * low_pass_filtered_FromCapturedPinBtoCapturedPinA;


      PeriodPinA = CapturedPinA - prev_CapturedPinA;
      low_pass_filtered_PeriodPinA = f * PeriodPinA + (1-f) * low_pass_filtered_PeriodPinA;

      prev_CapturedPinA = CapturedPinA;

      buffer_captured[head] = CapturedPinA;
      buffer_which[head] = 1;
      head++;
      if (head > buf_size)
        head = 0;
    }

    if (had_a_PinB)
    {
      FromCapturedPinAtoCapturedPinB = CapturedPinB - CapturedPinA;

      low_pass_filtered_FromCapturedPinAtoCapturedPinB = f * FromCapturedPinAtoCapturedPinB + (1-f) * low_pass_filtered_FromCapturedPinAtoCapturedPinB;

      PeriodPinB = CapturedPinB - prev_CapturedPinB;
      low_pass_filtered_PeriodPinB = f * PeriodPinB + (1-f) * low_pass_filtered_PeriodPinB;
      prev_CapturedPinB = CapturedPinB;
      buffer_captured[head] = CapturedPinB;
      buffer_which[head] = 2;
      head++;
      if (head > buf_size)
        head = 0;
    }
}

double CYCCNT_to_us (int32_t cycles)
{
    return (double)cycles / (600.0 / (4*prescale));
}

double dCYCCNT_to_us (double cycles)
{
    return cycles / (600.0 / (4*prescale));
}

uint32_t us_to_CYCCNT (double us)
{
    us *= 600.0 / (4*prescale);
    return (uint32_t)us;
}

volatile uint32_t prev_uint32_counts = 0;

void loop()
{
  volatile int display_mode = 0;

  if (display_mode == 1)
  {
    int buffer_which_element = buffer_which[tail];
    if (buffer_which_element & 0x3)
    {
      uint32_t buffer_element = buffer_captured[tail];
      uint32_t uint32_counts = buffer_element;
      int32_t int32_dt = uint32_counts - prev_uint32_counts;
      double dt;
      dt = CYCCNT_to_us(int32_dt);

      if (buffer_which_element & 1)
      {
        Serial.printf ("%d %3d %08x %d pin PinA edge t=%1.3f us\n", buffer_which_element, tail, buffer_element, int32_dt, dt);
      }
      else
      {
        Serial.printf ("%d %3d %08x %d PinB edge t=%1.3f us\n", buffer_which_element, tail, buffer_element, int32_dt, dt);
      }
      prev_uint32_counts = uint32_counts;

      buffer_which[tail] = 0;

      tail++;
      if (tail > buf_size)
        tail = 0;

    }
  }
  else
  {
      Serial.printf ("PinA=%d PinB=%d PeriodPinA=%1.3f us PeriodPinB=%1.3f us, edgePinA->edgePinB in %1.3f us, edgePinB->edgePinA in %1.3f us\n", 
                        (TMR1_SCTRL0 >> 8) & 1, (TMR1_SCTRL1 >> 8) & 1, 
                        dCYCCNT_to_us(low_pass_filtered_PeriodPinA),dCYCCNT_to_us(low_pass_filtered_PeriodPinB),
                        dCYCCNT_to_us(low_pass_filtered_FromCapturedPinAtoCapturedPinB),dCYCCNT_to_us(low_pass_filtered_FromCapturedPinBtoCapturedPinA)) ;
       delay (300);
  }
}

The pulse train is quite stable but there appears to be a lot of fluctuations in readings. I am measuring a period of about 1001 us on Pin A and Pin B and edgePinA->edgePinB around 69.79 us with an oscilloscpe-See screenshot attached

10:46:30.594 -> PinA=1 PinB=1 PeriodPinA=959.789 us PeriodPinB=860.120 us, edgePinA->edgePinB in 136.595 us, edgePinB->edgePinA in 831.372 us
10:46:30.909 -> PinA=1 PinB=1 PeriodPinA=842.486 us PeriodPinB=990.729 us, edgePinA->edgePinB in 74.672 us, edgePinB->edgePinA in 852.206 us
10:46:31.179 -> PinA=1 PinB=0 PeriodPinA=900.215 us PeriodPinB=949.079 us, edgePinA->edgePinB in 94.427 us, edgePinB->edgePinA in 861.200 us
10:46:31.494 -> PinA=0 PinB=0 PeriodPinA=897.334 us PeriodPinB=949.554 us, edgePinA->edgePinB in 120.552 us, edgePinB->edgePinA in 881.348 us
10:46:31.794 -> PinA=0 PinB=0 PeriodPinA=992.260 us PeriodPinB=921.175 us, edgePinA->edgePinB in 107.647 us, edgePinB->edgePinA in 882.617 us
10:46:32.093 -> PinA=0 PinB=1 PeriodPinA=905.304 us PeriodPinB=869.002 us, edgePinA->edgePinB in 132.384 us, edgePinB->edgePinA in 795.635 us
10:46:32.393 -> PinA=1 PinB=1 PeriodPinA=993.481 us PeriodPinB=945.772 us, edgePinA->edgePinB in 95.978 us, edgePinB->edgePinA in 898.303 us
10:46:32.694 -> PinA=1 PinB=1 PeriodPinA=966.192 us PeriodPinB=944.498 us, edgePinA->edgePinB in 96.594 us, edgePinB->edgePinA in 884.823 us
10:46:33.009 -> PinA=0 PinB=0 PeriodPinA=902.933 us PeriodPinB=923.065 us, edgePinA->edgePinB in 106.763 us, edgePinB->edgePinA in 847.659 us
10:46:33.279 -> PinA=0 PinB=0 PeriodPinA=889.189 us PeriodPinB=915.680 us, edgePinA->edgePinB in 110.240 us, edgePinB->edgePinA in 835.892 us
10:46:33.608 -> PinA=0 PinB=0 PeriodPinA=871.553 us PeriodPinB=949.793 us, edgePinA->edgePinB in 94.095 us, edgePinB->edgePinA in 845.558 us
10:46:33.899 -> PinA=1 PinB=1 PeriodPinA=897.630 us PeriodPinB=961.287 us, edgePinA->edgePinB in 88.631 us, edgePinB->edgePinA in 863.356 us
 

Attachments

  • Untitled.jpg
    Untitled.jpg
    64.6 KB · Views: 25
The pulse train is quite stable but there appears to be a lot of fluctuations in readings. I am measuring a period of about 1001 us on Pin A and Pin B and edgePinA->edgePinB around 69.79 us with an oscilloscpe-See screenshot attached

10:46:30.594 -> PinA=1 PinB=1 PeriodPinA=959.789 us PeriodPinB=860.120 us, edgePinA->edgePinB in 136.595 us, edgePinB->edgePinA in 831.372 us
10:46:30.909 -> PinA=1 PinB=1 PeriodPinA=842.486 us PeriodPinB=990.729 us, edgePinA->edgePinB in 74.672 us, edgePinB->edgePinA in 852.206 us
10:46:31.179 -> PinA=1 PinB=0 PeriodPinA=900.215 us PeriodPinB=949.079 us, edgePinA->edgePinB in 94.427 us, edgePinB->edgePinA in 861.200 us
10:46:31.494 -> PinA=0 PinB=0 PeriodPinA=897.334 us PeriodPinB=949.554 us, edgePinA->edgePinB in 120.552 us, edgePinB->edgePinA in 881.348 us
10:46:31.794 -> PinA=0 PinB=0 PeriodPinA=992.260 us PeriodPinB=921.175 us, edgePinA->edgePinB in 107.647 us, edgePinB->edgePinA in 882.617 us
10:46:32.093 -> PinA=0 PinB=1 PeriodPinA=905.304 us PeriodPinB=869.002 us, edgePinA->edgePinB in 132.384 us, edgePinB->edgePinA in 795.635 us
10:46:32.393 -> PinA=1 PinB=1 PeriodPinA=993.481 us PeriodPinB=945.772 us, edgePinA->edgePinB in 95.978 us, edgePinB->edgePinA in 898.303 us
10:46:32.694 -> PinA=1 PinB=1 PeriodPinA=966.192 us PeriodPinB=944.498 us, edgePinA->edgePinB in 96.594 us, edgePinB->edgePinA in 884.823 us
10:46:33.009 -> PinA=0 PinB=0 PeriodPinA=902.933 us PeriodPinB=923.065 us, edgePinA->edgePinB in 106.763 us, edgePinB->edgePinA in 847.659 us
10:46:33.279 -> PinA=0 PinB=0 PeriodPinA=889.189 us PeriodPinB=915.680 us, edgePinA->edgePinB in 110.240 us, edgePinB->edgePinA in 835.892 us
10:46:33.608 -> PinA=0 PinB=0 PeriodPinA=871.553 us PeriodPinB=949.793 us, edgePinA->edgePinB in 94.095 us, edgePinB->edgePinA in 845.558 us
10:46:33.899 -> PinA=1 PinB=1 PeriodPinA=897.630 us PeriodPinB=961.287 us, edgePinA->edgePinB in 88.631 us, edgePinB->edgePinA in 863.356 us

Well, here in Holland, the same code on a T41 shows this:
PinA=0 PinB=1 PeriodPinA=2000.000 us PeriodPinB=1001.362 us, edgePinA->edgePinB in 1441.571 us, edgePinB->edgePinA in 45.741 us
PinA=0 PinB=1 PeriodPinA=2000.000 us PeriodPinB=1001.366 us, edgePinA->edgePinB in 903.056 us, edgePinB->edgePinA in 638.283 us
PinA=0 PinB=0 PeriodPinA=2000.000 us PeriodPinB=1001.360 us, edgePinA->edgePinB in 1258.351 us, edgePinB->edgePinA in 228.946 us
PinA=0 PinB=1 PeriodPinA=2000.000 us PeriodPinB=1001.360 us, edgePinA->edgePinB in 719.325 us, edgePinB->edgePinA in 821.579 us
PinA=0 PinB=0 PeriodPinA=2000.000 us PeriodPinB=1001.358 us, edgePinA->edgePinB in 1073.213 us, edgePinB->edgePinA in 414.070 us
PinA=0 PinB=1 PeriodPinA=2000.000 us PeriodPinB=1001.360 us, edgePinA->edgePinB in 750.261 us, edgePinB->edgePinA in 528.799 us
PinA=0 PinB=1 PeriodPinA=2000.000 us PeriodPinB=1001.361 us, edgePinA->edgePinB in 940.864 us, edgePinB->edgePinA in 600.401 us
PinA=0 PinB=0 PeriodPinA=2000.000 us PeriodPinB=1001.356 us, edgePinA->edgePinB in 1294.330 us, edgePinB->edgePinA in 192.924 us
PinA=0 PinB=1 PeriodPinA=2000.000 us PeriodPinB=1001.356 us, edgePinA->edgePinB in 753.985 us, edgePinB->edgePinA in 787.142 us
PinA=0 PinB=0 PeriodPinA=2000.000 us PeriodPinB=1001.355 us, edgePinA->edgePinB in 1106.703 us, edgePinB->edgePinA in 380.541 us
PinA=0 PinB=1 PeriodPinA=2000.000 us PeriodPinB=1001.355 us, edgePinA->edgePinB in 583.187 us, edgePinB->edgePinA in 840.037 us
PinA=0 PinB=1 PeriodPinA=2000.000 us PeriodPinB=1001.359 us, edgePinA->edgePinB in 973.028 us, edgePinB->edgePinA in 568.215 us
PinA=0 PinB=0 PeriodPinA=2000.000 us PeriodPinB=1001.358 us, edgePinA->edgePinB in 1326.297 us, edgePinB->edgePinA in 160.970 us
PinA=0 PinB=1 PeriodPinA=2000.000 us PeriodPinB=1001.360 us, edgePinA->edgePinB in 786.156 us, edgePinB->edgePinA in 755.052 us
PinA=0 PinB=0 PeriodPinA=2000.000 us PeriodPinB=1001.356 us, edgePinA->edgePinB in 1138.863 us, edgePinB->edgePinA in 348.378 us
PinA=0 PinB=0 PeriodPinA=2000.000 us PeriodPinB=1001.358 us, edgePinA->edgePinB in 599.446 us, edgePinB->edgePinA in 904.961 us
PinA=0 PinB=1 PeriodPinA=2000.000 us PeriodPinB=1001.357 us, edgePinA->edgePinB in 1004.913 us, edgePinB->edgePinA in 536.321 us
PinA=0 PinB=0 PeriodPinA=2000.000 us PeriodPinB=1001.353 us, edgePinA->edgePinB in 1357.195 us, edgePinB->edgePinA in 130.025 us

PinA is on pin 13 which has a 500 Hz square wave that is made by the same code, using Teensy Arduino timers with 1 ms, toggling 'LED', so blinking at 500 Hz (added that for testing). PinB is on a 1 kHz pulse generator, manually tuned to 1 kHz, so showing 1000 +/-2 us is good.
I'd argue it is dead stable, Maybe your pulses are not?
A good scope would allow "Envelope" and "Persistence to infinity". Does your scope then still suggest your signals are super stable? Or a ground wire is missing? Or the pulses go > 3.3V when high?
 
Back
Top