don't understand interrupt timing

flok

Well-known member
Hello,

I've connected a PPS (pulse per second, by using a GPS) source to a Teensy 4.1.
Then I measure the number of cycles (via ARM_DWT_CYCCNT) between each interrupt. I do that both in the interrupt handler and in "loop()".
The one in the loop-function produces an histogram that I expected:

1787548033690.png


one bump. Note that the x-axis is in nanoseconds with an offset (see the +9.9999e8). Y-axis is how often a measurement was seen. 50 bins.
If I do the same with the data from the interrupt-routine, I get:

1787548301272.png


My question now is, why are there 2 bumps?

The interrupt handler is:

volatile uint32_t d = 0; volatile uint64_t ts = 0; uint32_t delta_nanos_32(uint32_t *const last) { asm("dsb"); uint32_t c = ARM_DWT_CYCCNT; uint32_t m = c; c -= *last; *last = m; return c * 1000000000ULL / F_CPU; } void int_func() { static uint32_t last = 0; d = delta_nanos_32(&last); ts = micros_64(); }

The loop() function also uses delta_nanos_32 by the way.


[...]

Oh hang on, maybe it (the two bumps) is caused by the Ethernet interrupt. My goal was producing a simple time server so I enabled Ethernet. I'm now testing (will take a few hours) what the graph looks like with Ethernet disabled (I expected that the GPIO interrupt would have a higher prio than the Ethernet handling).
 
Last edited:
The trouble with either of these methods is that many Teensy libraries disable interrupts completely for an unknown length of time. Usually pretty short, but it wrecks all attempts to measure a signal’s period by hooking it to a GPIO interrupt, let alone in loop().

If your GPIO interrupt is lower priority, or blocked by disabled interrupts, then you’ll occasionally get one “long” period followed immediately by a “short” one, leading to a double peak … actually, thinking about it, it ought to be a triple peak … short, correct and long … hmmm. Everything will then be smeared further by different durations of blocking time.

You’d be much better off using one of the purpose-built libraries, like FreqMeasure, which use Teensy hardware capabilities to capture a precise cycle count regardless of interrupt priorities or masking. The downside is you often need to use specific pins.
 
Having a higher priority ISR would be an issue.

Not sure why the "dsb" - especially before reading the CYCNT? That may add some variation. Reading CYCCNT is an efficient 3 cycle read, any code before that adds room for interrupt, or delay.

Code:
uint32_t delta_nanos_32(uint32_t *const last, uint32_t c) {
  asm("dsb");
  uint32_t m = c;
  c -= *last;
  *last = m;
 
  return c * 1000000000ULL / F_CPU;
}

void int_func() {
  static uint32_t last = 0;
  d = delta_nanos_32(&last, ARM_DWT_CYCCNT);
  ts = micros_64();
}
 
Without Ethernet, without asm("dsb") it looks like:

1787590065574.png


Slightly different.
 

Attachments

  • 1787577746077.png
    1787577746077.png
    25.7 KB · Views: 35
Last edited:
Still pretty dreadful compared to the likely accuracy of your 1PPS signal (though you haven’t provided a link to a datasheet, so I’m slightly guessing here…). The spread is over 300 CPU cycles, or 0.5μs, whereas I believe a decent 1PPS signal can be well under 0.1μs.

Then again, that might be good enough for your use case.
 
Still pretty dreadful compared to the likely accuracy of your 1PPS signal (though you haven’t provided a link to a datasheet, so I’m slightly guessing here…). The spread is over 300 CPU cycles, or 0.5μs, whereas I believe a decent 1PPS signal can be well under 0.1μs.

Then again, that might be good enough for your use case.
It is from a really cheap gps (a few euro, not more) so 0,5 us might not bad.
I also have an ublox timing gps, as soon as I dare it (the ublox was really expensive and I'm afraid I destroy it), I'll connect it instead and retest.
For that I created this https://nurdspace.nl/PPS_splitter (the nurdspace-link won't work outside Europe, so here is the pdf: pps-splitter.pdf) a while ago. It seems to work (tested with scoop and function generator) but yeah :)
[...]
oh the LED dims if I connect the splitter-board. maybe not try that for longer than a second :oops:
 
Last edited:
It‘d probably be worth testing the cheap unit using the FreqMeasure library; that should resolve to about 6.7ns, since it uses a 150MHz clock. And of course will be unaffected by interrupt latency.

Have you tried a 74LVC04 on your splitter, rather than 74HC04? I believe it would have a better propagation delay at 3.3V.
 
Back
Top