FreqMeasureMulti glitching with slow-ish rising inputs

andnate

Member
I have a 5V TTL signal coming in through a 10k/18k voltage divider with an 820pf cap to GND to convert it to a 3.3V signal being read by FreqMeasureMulti, but with the cap in place it occasionally glitches and reads 2x, 1.33x, or I *think* 4x the actual input frequency for a few counts before returning down. I'm filtering two samples using the example code from FreqMeasure. If I directly drive the pin at 3.3V with an Analog Discovery I get no glitches, or if the Teensy is on a breadboard with a voltage divider and no cap. If I remove the cap from the PCB my glitches go down significantly, but not entirely (One every minute or so vs several per second). The 10-90% rise time is less than 25us. Is there a way to implement glitch filtering for this, or am I doing something else wrong?
 
25 us is a long time for those inputs. I don't know how to specify the required rise time, but I'm pretty sure it's well under 1 us. We had a similar issue with FreqMeasureMulti and the ultimate fix was to add schmitt triggers. A work-around that we used was to define the pins as GPIO with interrupts on rising edges. The same pins configured that way do not require the very fast rise time, and we were able to get sufficient accuracy for our application by reading the ARM_DWT_CYCCNT cycle counter in the ISR and computing the periods ourselves. It's definitely not as convenient or accurate as FreqMeasureMulti, but it does work.

I hope that someone who knows the Teensy hardware well will comment on this thread and provide some insight.
 
Did you have any luck using the regular FreqMeasure library instead? It's nice to be able to select which pin to measure from but not a design necessity. I don't know the differences in the backend between the two and was wondering if there was some hardware thing that made a certain pin best.
 
Did you have any luck using the regular FreqMeasure library instead? It's nice to be able to select which pin to measure from but not a design necessity. I don't know the differences in the backend between the two and was wondering if there was some hardware thing that made a certain pin best.
FreqMeasure uses FlexPWM, the same as FreqMeasureMulti. FreqCount and FreqCountMany use QuadTimer and do pulse-counting, whereas FreqMeasure and FreqMeasureMulti use FlexPWM for input capture (and thereby period measurement). QuadTimer and GPT also have input capture capability, and it's possible they do not have the same rise time requirements as FlexPWM. There are only 2 pins that can be used for GPT input capture, and those are pins 15 and 40. If you have pin 15 available, you could try the sketch below to see if it works without glitching. One nice thing about GPT is that it has 32-bit counter. FlexPWM and QuadTimer are both 16-bit, and you have to do more in software to get 32.

Code:
// Paul's GPT pin capture of GPS PPT  altered by thd
//https://forum.pjrc.com/threads/54265-Teensy-4-testing-mbed-NXP-MXRT1050-EVKB-(600-Mhz-M7)?p=193217&viewfull=1#post193217
// CLKSRC 1 24mhz   4 32khz  (GPS PPS width too small for 32khz?)
// 1062 capture pin 15  Serial3 Rx    test with GPS pps or pwm on pin 14
// GPT2 capture 1 GPIO_AD_B1_03   Alt 8
//  for 32khz clock, GPS pps pulse width > 30 us
//#include "debug/printf.h"

void setup() {
  Serial.begin(9600);
  while (!Serial);
  delay(2000);
  Serial.println("ok");
  pinMode(13, OUTPUT);

  analogWriteFrequency(14, 100);  // test with PWM
  analogWrite(14, 128); // jumper pwm 14  to pin 15  Serial3 on T4B2 breakout

  // Connect GPS 1PPS signal to pin 15 (GPIO_AD_B1_03)
  IOMUXC_GPT2_IPP_IND_CAPIN1_SELECT_INPUT = 1;  // remap GPT2 capture 1
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 8; // GPT2 Capture1
  IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_03 = 0x13000; //Pulldown & Hyst

  CCM_CSCMR1 &= ~CCM_CSCMR1_PERCLK_CLK_SEL; // turn off 24mhz mode -> 150mhz
 
  CCM_CCGR0 |= CCM_CCGR0_GPT2_BUS(CCM_CCGR_ON) |
               CCM_CCGR0_GPT2_SERIAL(CCM_CCGR_ON);  // enable clock
 
  GPT2_CR = 0;
  GPT2_PR = 5; // 150/(5+1) = 25  // 0;
  GPT2_SR = 0x3F; // clear all prior status
  GPT2_IR = GPT_IR_IF1IE;
  GPT2_CR = GPT_CR_EN | GPT_CR_CLKSRC(1) |
            GPT_CR_FRR | GPT_CR_IM1(1);
  attachInterruptVector(IRQ_GPT2, capture);
  NVIC_ENABLE_IRQ(IRQ_GPT2);
}

volatile uint32_t capval;
volatile uint32_t delta;
volatile uint32_t count;

void capture() {
  static uint32_t prior = 0;
  capval = GPT2_ICR1;
  GPT2_SR = GPT_SR_IF1;
  delta = capval - prior;
  prior = capval;
  count++;
  asm("dsb");
}

void loop() {
  static uint32_t prev_count = 0;
  if (count != prev_count) {
    delayMicroseconds( 10 );
    Serial.printf("count=%10lu, capval=%10lu, delta=%10lu, CNT=%10lu\n", count, capval, delta, GPT2_CNT-capval );
    prev_count = count;
  }
}
 
25 us is a long time for those inputs. I don't know how to specify the required rise time, but I'm pretty sure it's well under 1 us. We had a similar issue with FreqMeasureMulti and the ultimate fix was to add schmitt triggers. A work-around that we used was to define the pins as GPIO with interrupts on rising edges. The same pins configured that way do not require the very fast rise time, and we were able to get sufficient accuracy for our application by reading the ARM_DWT_CYCCNT cycle counter in the ISR and computing the periods ourselves. It's definitely not as convenient or accurate as FreqMeasureMulti, but it does work.

I hope that someone who knows the Teensy hardware well will comment on this thread and provide some insight.
If you search the forums for "analog comparator" you'll find examples of the use of the hardware comparators to add hysteresis to an input signal. @FrankB contributed an example that uses two resistors to allow greater hysteresis than is available in the comparator hardware.
 
Back
Top