FlexTimer - Modify FTM1_MOD on the fly

Status
Not open for further replies.

nitrojam

Member
Hi,

I have a working Flextimer (FTM1) program based on some code found on the forum and I wanted to know if it was possible to reset / modify the FTM1_MOD in the main loop :

Code:
/*https://forum.pjrc.com/threads/30822-Teensy-3-1-and-Flextimer(s)-Counting-external-pulses-accurately
 * Connect pin 10 (CMP1_OUT) to pin 23 (FTM1_QD_PHA)
 * Connect 10 MHz sinewave input (200 mV peak) to Teensy pin 3 (A9)
 * Connect 1 pps trigger to pin 16 (A2)
 */

const int base_frequency = 10000000;
volatile uint32_t CountValue, CountValueOld;
volatile uint32_t FTM1CountOVFlow; // don't need to initialize since rollover is handled
volatile bool CaptureFlag = false;
bool CountingOK = false;

void setup() {
  pinMode(4, INPUT_PULLUP);  // Needed for Quad decoder  
  Serial.begin(0); 
  while (!Serial);
  Serial.println(__FILE__ " " __DATE__ " " __TIME__);
  //ComparatorSetup();
  FTM1Setup();
  Serial.printf("%9s %11s\n", "Frequency", "CountValue");
}

void loop() {
  unsigned long  ppsWatchdog = millis() + 1100;
  while (!CaptureFlag && millis() < ppsWatchdog); // loop and wait up to 1.1 s
  if (CaptureFlag) {
    CaptureFlag = false;  // clear flag from channel
    if (CountingOK) Serial.printf("%9lu %11ld\n", CountValue-CountValueOld,CountValue-CountValueOld-base_frequency);
    CountValueOld = CountValue;
    CountingOK = true; // postpones displaying until 2 CaptureFlags in a row
  } else { 
    Serial.println("1 pps missing.");
    CountingOK = false;
  }
}

// Setup FlexTimer1
void FTM1Setup() { 
  // input capture 1 pps on Teensy pin 16 (A2), 10 MHz clock from Teensy pin 3
  // FTM1 Channel 0
  FTM1_MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
  FTM1_FILTER = 0x00; // no filtering
  FTM1_SC = 0; 
  FTM1_CNTIN = 0; // Count initial value
  FTM1_CNT = 0x0000; // Reset the count to CNTIN
  FTM1_MOD = 0xFFFF; // max modulus = 65535 (0xFFFF)
  FTM1_C0SC =   FTM_CSC_ELSA; // Rising edge no interrupts
  //configure Teensy input capture channels
  PORTA_PCR12 |= PORT_PCR_MUX(7); //MUX = alternative function 7 on Chip Pin 28 (FTM1_QD_PHA) = Teensy Pin 3 -- Signal to count
  PORTA_PCR13 |= PORT_PCR_MUX(7); //MUX = alternative function 7 on Chip Pin 29 (FTM1_QD_PHB) = Teensy Pin 4 -- Tie high
  PORTB_PCR0  |= PORT_PCR_MUX(3); //MUX = alternative function 3 on Chip Pin 35 (FTM1_CH0) = Teensy Pin 16 (A2)
 
  SIM_SOPT4 |= SIM_SOPT4_FTM1CH0SRC(0); // 00 source is FTM1_CH0 signal (1 pps)

  //set flextimer quad decode mode and enable overflow interrupt
  FTM1_QDCTRL = FTM_QDCTRL_QUADMODE | FTM_QDCTRL_QUADIR | FTM_QDCTRL_QUADEN; // comes in on pin 3
  FTM1_SC = FTM_SC_TOIE | FTM_SC_CLKS(0); // actually not important in QUAD mode ?
  
  NVIC_ENABLE_IRQ(IRQ_FTM1);
  // NVIC_SET_PRIORITY(IRQ_FTM1, 48);
  Serial.println("FlexTimer FTM1 Setup Complete");
}

extern "C" void FASTRUN ftm1_isr(void) { // Process CHF first, unless counter is close to overflow
 if (FTM1_SC & FTM_SC_TOF) { // read the timer overflow flag (TOF in FTM1_SC) rate = 10 MHz/65536 ~ 152 Hz, 6.6 ms
    FTM1_SC &= ~FTM_SC_TOF;   // clear interrupt from timer overflow
    FTM1CountOVFlow++;       
  } // TOF

  // now poll CH0 and see if it had any activity
  if (FTM1_C0SC & FTM_CSC_CHF) { // rate = 1 pps
    FTM1_C0SC &= ~FTM_CSC_CHF;  // clear flag from channel
    CaptureFlag = true;
    if (FTM1_C0V < FTM1_CNT) {CountValue = (FTM1CountOVFlow << 16) + FTM1_C0V; return;} // very rare - just happened since interrupt
    else {CountValue = (FTM1CountOVFlow << 16) + FTM1_C0V  - (1 << 16); return;} // from 10 us into previous cycle
  }  
  delayMicroseconds(10); // to split the interval -- should be longer than max. interrupt latency
  if (FTM1_C0SC & FTM_CSC_CHF) { // try again, now 10 us into new cycle; good if no other interrupts are > 10 us
    FTM1_C0SC &= ~FTM_CSC_CHF;  // clear flag from channel
    CaptureFlag = true;
    CountValue = (FTM1CountOVFlow << 16) + FTM1_C0V; // happened between just after start and 100 us into cycle
  } 
} // ISR

Basically, I am comparing a 10Mhz signal with a 1pps from GPS.
The goal is to, once the 10mhz is setlled and corrected thanks to the GPS 1pps, only count the 10mhz, to derive a second : I therefore need to go from FTM1_MOD=0xFFFF to FTM1_MOD=0x270F (=9999) in order to precisely calculate a second.

Of course, if you have a better idea, just let me know !
Thanks for your help !
 
I seem to remember this does work, but it was some time ago that I tried it. I think I disabled the clock selection first before changing MOD, and re-enabled it after. There is a note in para 36.3.5 advises you to write to CNT (which resets the count to its initial value) before changing MOD.

Not keen on your "delay" inside an ISR. Time wasting.

How are you controlling/changing the 10 MHz source? Is this using the DAC on a 10MHz oscillator analogue input (Voltage Controlled Oscillator)?
 
Status
Not open for further replies.
Back
Top