Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 2 of 2

Thread: FlexTimer - Modify FTM1_MOD on the fly

  1. #1
    Junior Member
    Join Date
    Jun 2019
    Posts
    1

    FlexTimer - Modify FTM1_MOD on the fly

    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 !

  2. #2
    Senior Member
    Join Date
    Mar 2015
    Location
    UK
    Posts
    219
    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)?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •