FreqMeasure.read on Teensy 3.1 @ 96MHz

Status
Not open for further replies.

MGeo

New member
Hello,

I've been experimenting with (and possibly abusing?) the FreqMeasure library on a Teensy 3.1. I'm using it to read an encoded pulse stream that encodes binary data as a series of 16us and 24us pulses (idle = high, 16us with 8 us low pulse followed by 8us high = bit “0”, and 24us with 16us low followed by 8us high = bit "1"). I'm compiling my code in the IDE with clock speed set to 96 MHz.

The documentation at https://www.pjrc.com/teensy/td_libs_FreqMeasure.html states the following for FreqMeasure.read:
FreqMeasure.read();
Read a measurement. An unsigned long (32 bits) containing the number of CPU clock cycles that elapsed during one cycle of the waveform. Each measurement begins immediately after the prior one without any delay, so several measurements may be averaged together for better resolution.


From this I expect FreqMeasure.read() to give me (more or less) a series of 16*96=1536 and 24*96=2304 values indicating the pulse with. Instead it gives me a series of ~768 and ~1152 pulse widths. So almost exactly half of what I expected based on the function description. The great news is that it works quite reliably. But I would like to better understand why I get the values that I am seeing.

1.) I assume FreqMeasure.read() gives the elapsed time from rising to rising or falling to falling clock edges. Is this a correct assumption and is this an adjustable setting?
2.) Is the actual .read clock frequency indeed 1/2 of the CPU clock speed?
3.) Is there a more appropriate library to do what I am attempting to do here?

I've started going over the library code at the detail level but I have a ways to go understanding the FTM registers. Any help or pointers would be greatly appreciated.

I am using the following code (a lightly modified version of the Serial_Output example).

Code:
/* FreqMeasure - Example with serial output
 * http://www.pjrc.com/teensy/td_libs_FreqMeasure.html
 *
 * This example code is in the public domain.
 */
#include <FreqMeasure.h>

void setup() {
  Serial.begin(115200);
  FreqMeasure.begin();
}

double f=0;
int count=0;

void loop() {
  if (FreqMeasure.available()) {
    // average several reading together
    f = FreqMeasure.read();
    count = count + 1;
    if (count > 30) {
      //float frequency = FreqMeasure.countToFrequency(sum / count);
      Serial.println(f);
      f = 0;
      count = 0;
    }
  }
}

And I get this as typical serial stream output:
Code:
768
765
768
768
1155
765
768
768
768
1152
771
768
768
1149
1149
768
1155
771
768
1152
1152
771
768
768
768
292225
768
765
768
1152
774
765
1146
771
768
1155
762

Thanks!
George

Pulse stream on Chn0 (ignore the rest) as measured on my Saleae Logic analyzer:
screenshot.jpg
 
Last edited:
I think, and it looks like so from a quick peek at the code, that FreqMeasure on Teensy 3.1 uses flex timer 1 and is clocked at the
periperal bus frquency 48MHz, not the core CPU frequency of 96MHz.
 
From this I expect FreqMeasure.read() to give me (more or less) a series of 16*96=1536 and 24*96=2304 values indicating the pulse with. Instead it gives me a series of ~768 and ~1152 pulse widths. So almost exactly half of what I expected based on the function description. The great news is that it works quite reliably. But I would like to better understand why I get the values that I am seeing.

On Teensy 3.1, the timers (and almost all on-chip peripherals) run from from F_BUS, not F_CPU.

F_BUS is created using an integer division of F_CPU, and the chip has a maximum spec of 50 MHz for F_BUS. When Teensy runs at 96 MHz, F_BUS is 48 MHz.

If you run Teensy 3.1 at 72 MHz, F_BUS will be 36 MHz. However, at F_CPU = 48 MHz, divide-by-1 will be used, so F_BUS will be 48 MHz.

If you uncomment the faster overclocking options in boards.txt, 120 MHz mode will use divide-by-2, which is the highest resolution you can get for this measurement (and many people have reported 120 MHz mode very stable). However, 144 MHz mode will use divide-by-3 for F_CPU, so you're back to 48 MHz.

This applies to Teensy 3.1, and also Teensy 3.0. I should mention for completeness, and anyone who later finds this info by searching, that Teensy-LC works differently!

On Teensy-LC, these timers run by the F_PLL clock divided by 2. F_PLL is always 96 MHz on Teensy-LC, because that's the only option which makes the USB port work. So the timer always runs at 48 MHz, even when F_CPU is only 24 MHz.

In the future, slower modes might be enabled on Teensy-LC, where F_PLL isn't used at all (and USB doesn't work). In those modes, there are a few different options for how the timer clock can be configured. Today, I just don't know how we'll end up configuring the timer when/if such modes are implemented. But something to keep in mind is Teensy-LC's timers to support async operation, where the timer can run from a much faster or much slower clock than the CPU, which isn't necessary phase synchronized.

The situation on Teensy 3.1 is much simpler. The timers always run from F_BUS, which is always an integer divide from F_CPU.
 
Status
Not open for further replies.
Back
Top