FreqMeasure frequencies off by 2X

Status
Not open for further replies.

elkayem

Active member
I am running the FreqMeasureMulti example "Serial_Output" straight out of the box on a Teensy LC, and getting frequency measurements that are exactly half of what they should be (as measured on my scope). Now I know how to multiply by 2 as much as the next guy, but I thought this might point to a more fundamental problem.

The Arduino IDE is configured as Board: "Teensy LC" and CPU Speed: "48 MHz".
 
Is the scope measuring single transitions or cycles?

Can you write a simple sketch to test and show? With an output toggled every 100 ms and that pin connected to the FreqMeas pin what does it read versus the scope?

With Pin 13 LED to the Freq pin - Add code like below to your FreqMeasure sketch and you should see 5 Hz { change:: CYCLE_DELAY from 100 to 10 and it should give 50 Hz }

Code:
#define qBlink() {GPIOC_PTOR=32;} // toggle the pin 13 LED set to output

elapsedMillis foo;
void setup() {
  Serial.begin(9600);
  while (!Serial && millis() < 4000 );
  pinMode(LED_BUILTIN, OUTPUT);
  qBlink();
// ...
  foo = 0;
}

#define CYCLE_DELAY 100 // added for single # change
void loop() {
  if ( foo > CYCLE_DELAY ) {
    foo -= CYCLE_DELAY;
    qBlink();
  }
// ...
}
 
Last edited:
Sorry, I don't think I answered your first question either. Scope is measuring rising edge, so whole cycles. When I connect one of the FreqMeasure pins to 13, I measure 2.5 Hz, but visually the LED is clearly blinking at 5 Hz.
 
That's odd without a connection problem the Teensy should get it right. If you can post the complete sketch ( with added FreqMeasure code ) then Paul or others could reproduce it for attention - But probably not until next year :)

Happy New Year!
 
It is possible that there is a glitch in the FreqMeasureMulti library when using a Teensy LC, I hadn’t one at the hand to test when contributing the last updates. In fact, the timers in the LC are slightly different and they are also clocked in a different way. In order to fix it, I’d need to know some details: basically, this library doesn’t measure the frequency, but the pulse width time, which can then be converted in a frequency value in a second step. Thus, please let me know what the raw measured pulse tick value is, so that I can see if the pulse ticks are wrongly interpreted, or if the PW to frequency conversion is wrong. In ever case, everything is locked to a fixed bus or pll clock, so if the result is off by a factor, it will always be off by the same factor. As a workaround, a simple multiplication will help to get reliable results.
 
Running the examples FreqMeasureMulti Serial_Output, i added tone(13,5); to setup() and jumpered 13 to 6, and on LC it prints
2.50, (no pulses), (no pulses)
2.50, (no pulses), (no pulses)
and on T3.2@96mhz
5.00, (no pulses), (no pulses)
5.00, (no pulses), (no pulses)

i need to look at the library code, the LC TPM is clocked differently than T3 FTM counter.

EDIT: LC TPM ticks at PLL/2 T3.* FTM ticks at F_BUS. so LC TPM is ticking @48mhz. it looks like library has some conditional code for KINETISL/F_PLL ????
 
Last edited:
FIXED
as discussed in https://forum.pjrc.com/threads/48189-Complementary-PWM-with-the-Teensy-LC
setting TPMx_CnSC needs to be disabled, wait, and then set, so in the lib's FreqMeasureMulti::isr for the KINETISL do

csc[0] = 0; // disable
asm volatile ("nop"); // wait

csc[0] = (next_is_falling ? FTM_CSC_FALLING : FTM_CSC_RAISING) | FTM_CSC_CHF;


i had used delayMicroseconds(1), but nop seems to work ....

EDIT: i wonder if similar adjustment is needed in capture_read() of FreqMeasure lib
https://github.com/PaulStoffregen/FreqMeasure/blob/master/util/FreqMeasureCapture.h
EDIT: NOT, capture_read() is OK. setting CHF bit does not require disable/delay
 
Last edited:
@elkayem, did you try the fix in post #10, adding two lines to library FreqMeasureMulti/FreqMeasureMulti.cpp (line 212 or there abouts).
example works for me on LC with that fix.
 
@elkayem, did you try the fix in post #10, adding two lines to library FreqMeasureMulti/FreqMeasureMulti.cpp (line 212 or there abouts).
example works for me on LC with that fix.

Just tried it. Brilliant! Yes, it works. I was never concerned about my code outputting the right result. I had a 2x in front of the frequency to correct this issue. But I knew this was a more fundamental issue, and you solved it.

I notice you opened an Issue on GitHub to fix this once and for all, great!

I confess, I don't really understand the fix you just posted. I suppose this means I need to start studying the Kinetis KL26 user manual...

Thanks again for looking into this. I'm glad this community exists!
 
I committed the fix on github. Thanks!

https://github.com/PaulStoffregen/FreqMeasureMulti/commit/d42db7465a6af8293b2b75a3029fff860e6a30af

I've been doing more testing here. This is a copy of the example, which reads all 6 pins.

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

// Measure 3 frequencies at the same time! :-)
FreqMeasureMulti freq1;
FreqMeasureMulti freq2;
FreqMeasureMulti freq3;
FreqMeasureMulti freq4;
FreqMeasureMulti freq5;
FreqMeasureMulti freq6;

void setup() {
  Serial.begin(57600);
  while (!Serial) ; // wait for Arduino Serial Monitor
  delay(10);
  Serial.println("FreqMeasureMulti Begin");
  delay(10);
  freq1.begin(6);
  freq2.begin(9);
  freq3.begin(10);
  freq4.begin(20);
  freq5.begin(22);
  freq6.begin(23);
}

float sum1=0, sum2=0, sum3=0, sum4=0, sum5=0, sum6=0;
int count1=0, count2=0, count3=0, count4=0, count5=0, count6=0;
elapsedMillis timeout;

void loop() {
  if (freq1.available()) {
    sum1 = sum1 + freq1.read();
    count1 = count1 + 1;
  }
  if (freq2.available()) {
    sum2 = sum2 + freq2.read();
    count2 = count2 + 1;
  }
  if (freq3.available()) {
    sum3 = sum3 + freq3.read();
    count3 = count3 + 1;
  }
  if (freq4.available()) {
    sum4 = sum4 + freq4.read();
    count4 = count4 + 1;
  }
  if (freq5.available()) {
    sum5 = sum5 + freq5.read();
    count5 = count5 + 1;
  }
  if (freq6.available()) {
    sum6 = sum6 + freq6.read();
    count6 = count6 + 1;
  }
  // print results every half second
  if (timeout > 500) {
    if (count1 > 0) {
      Serial.print(freq1.countToFrequency(sum1 / count1));
    } else {
      Serial.print("(no pulses)");
    }
    Serial.print(",  ");
    if (count2 > 0) {
      Serial.print(freq2.countToFrequency(sum2 / count2));
    } else {
      Serial.print("(no pulses)");
    }
    Serial.print(",  ");
    if (count3 > 0) {
      Serial.print(freq3.countToFrequency(sum3 / count3));
    } else {
      Serial.print("(no pulses)");
    }
    Serial.print(",  ");
    if (count4 > 0) {
      Serial.print(freq4.countToFrequency(sum4 / count4));
    } else {
      Serial.print("(no pulses)");
    }
    Serial.print(",  ");
    if (count5 > 0) {
      Serial.print(freq5.countToFrequency(sum5 / count5));
    } else {
      Serial.print("(no pulses)");
    }
    Serial.print(",  ");
    if (count6 > 0) {
      Serial.print(freq6.countToFrequency(sum6 / count6));
    } else {
      Serial.print("(no pulses)");
    }
    Serial.println();
    sum1 = 0;
    sum2 = 0;
    sum3 = 0;
    sum4 = 0;
    sum5 = 0;
    sum6 = 0;
    count1 = 0;
    count2 = 0;
    count3 = 0;
    count4 = 0;
    count5 = 0;
    count6 = 0;
    timeout = 0;
  }
}
 
Status
Not open for further replies.
Back
Top