Teensy 4: Measuring multiple frequencies

Normally FreqMeasure isn't recommended for higher frequencies, mainly because the resolution diminishes as shorter periods are measured. But joepasquariello found some really impressive ways to work around the resolution limitations!

The other issue is the CPU overhead of interrupts. Since FreqMeasure needs an interrupt for each waveform cycle, the CPU usage scales up linearly as the frequency increases, and of course the CPU usage is multiplied by the number of waveforms you try to measure.

The measurement's sensitivity to interrupt latency caused by other libraries, USB communication, and general timer usage can also matter. In that regard, FreqMeasure is excellent.

FreqCount also has limitations, mainly that measuring small changes in frequency requires long gate intervals (or the sum of many shorter ones). But the interrupt overhead of FreqCount is fixed, one interrupt per gate interval, and with .FreqCountMany a single interrupt captures all 10. The effect of latency is that the interval may end slightly later, so you might get a gate interval which is 1000.01 us followed by 999.99 us on the next interval. You'll still get the correct total number of counts, but the frequency might appear to be slightly higher in the interval which was lengthened and slightly lower in the following interval.

FreqMeasure is very insensitive to interrupt latency, at least until it become so bad that it approaches 1 period of the measured waveform. As long as the interrupt response isn't so delayed that a measurement is missed, the actual measured value is based on hardware capture of the hardware timer, so you get a "perfect" result which isn't altered by the interrupt latency.

The number of timer bits, either native to the timer, or extended by software trickery with the timer overflow, plays a factor with both. On FreqMeasure, more bits means a longer period can be measured. On FreqCount, more bits allows a longer gate interval. But gate interval can be effectively lengthened by summing many smaller intervals, which is what the FreqCountMany code does.

Not sure if this really answered your question about the possible benefits of using the 32 bit GPT timers...
Hi Paul.
Thank you very much for such such an improvement in the many frequency reading with Teensy 4.0/4.1. I am working on a multy channel frequency reading device. The higher frequency reading is equally important as the number of channels for my device. I can decrease the number of channel to be able to read maximum frequency that Teensy 4.0 provide me. I am not so much expert on timer & clock issue. I tried to follow your response about 150 MHz question.
Do you mean that I can reach maximum frequency 150 MHz by decreasing the number of channels to 4 to reach 600 MHz.
Another question is maybe foolish but can I read 433 MHz with Teensy 4.0?
Or what is your suggestion about it?
Hi Paul.
Thanks for the great work! We use your boards in various applications. It would be really nice if you could show how to use all 16 counter inputs in this project, you said so in the comments "// TODO: can 6 more be used with XBAR1 and GPR6 ?"
Best regards, Akry.
This code is awesome. It has allowed me to diagnose and test a board design that has the highest reject rate from our customer and prove that the issue is NOT on our side. That said, I have encountered something that I'm wondering about though. I noticed that of the test frequencies on pins 0, 1, 2, 4 and 5 of 3 MHz, 15 MHz, 220 kHz, 10 MHz and 455 kHz only the MHz readings are spot on. 3, 15 and 10 MHz show 3000000, 15000000 and 10000000 exactly on the measurement channels and there is no "wandering" of the values. However, the 220 and 455 kHz signals are off by a small amount and tend to "wander" a bit. Would anyone know what could be causing this and is there a way to get the kHz readings as stable as the MHz readings? The customers board outputs frequencies between 100 kHz to 1 MHz so getting that range more accurate and stable would make our test set even better.

Thanks for any assistance anyone can provide.
When you call analogWriteFrequency(), you will only get the exact frequency requested if it divides evenly into the clock frequency of the timer that is generating the PWM signal. The pins used for PWM in Paul's sketch are 0,1,2,4,5, and those are all flexPWM, so the clock frequency is 150 MHz. The frequencies requested are listed below, along with the number of clocks per period for that frequency:

0    3 MHz     150/3 = 50
1   15 MHz     150/15 = 10
2  220 kHz     150/0.220 = 681.81
4   10 MHz     150/10 =15
5  455 kHz     150/0.455 = 329.67

Because 3, 15, 10 all divide evenly into 150, those PWM frequencies can be produced exactly. For the 220 kHz and 455 kHz, the divisor will be rounded, so the actual frequencies produced will be 150M/682 = 219941.35 and 150M/330 = 454545.45 Hz.

So, that's on the PWM (output) side. On the counting (input) side, each measurement is the number of rising edges seen in 200 ms. That's 1/5 second, so the frequency in Hz is the number of edges multiplied by 5. When I test the 455 kHz signal, I get mostly 454545, with some 454550. Is that what you mean by wander? What is happening is that the edge count can vary by 1, so the reported frequencies differ by 5. If you increase GATE_ACCUM from 100 to 500 and reduce MULT_FACTOR from 5 to 1, you will get a measurement every 1 second instead of every 200 ms, and the measurements will vary by only 1 Hz instead of 5. If measurement speed did not matter, you could measure over 100 seconds and get value with 0.01 Hz resolution, but that's a long time to wait.

If your lowest frequency is 100 kHz, then pulse counting with a gate period of 1 second seems reasonable.
Wow, thanks for the quick response and the detail. I was hoping that I could change the GATE_ACCUM and MULT_FACTOR to do what you indicated as we don't need the 200 mS update rate. I just haven't had the cycles to learn the controller. I appreciate that you already have that experience and are willing to share it with a newbie. Those changes are exactly what I need.

Thank you very much for your help.