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

Thread: Low level usage of timers

  1. #1
    Junior Member
    Join Date
    Sep 2019
    Posts
    15

    Low level usage of timers

    I have read the specifications on timers (KL26 Sub-Family Reference Manual) and partially got it to work but I still have a problem with the prescaling.

    I would like to start a timer at a high resolution, e.g. 1Mhz/1us, and run this timer for a given time. Then I don't want an interrupt to be executed but instead check the Overflow flag.

    Here is the code:


    Code:
    void setup() {
      // Initialize pins
      pinMode(14, OUTPUT);
    
      // Setup timer
      MCG_C1 &= ~0b010; // Disable IRCLK
      MCG_SC &= ~0b01110; // Divider = 1 => 4MHz
      MCG_C2 |= 0b001;  // IRCS. fast internal reference clock enabled
      
      // Clock source
      SIM_SOPT2 |= 0b00000011000000000000000000000000;  // MCGIRCLK
    
      // Prescaler: 4 -> 4MHz/4 = 1MHz => 1us
      TPM0_SC = 0;
      TPM0_SC |= 0b00000010;  // Prescaler /4 = 1Mhz
      TPM0_SC |= 0b00001000;  // Enable timer
     
      MCG_C1 |= 0b010;  // IRCLKEN = enabled
    
      // When this is reached the overflow flag is set.
      TPM0_MOD = 1000; // 1000us = 1ms
    
      // Loop: toggle a pin each time the timer elapses (overflows)
      bool out = false;
      while(true) {
        TPM0_CNT = 0;  // Start value for timer
        TPM0_SC |= FTM_SC_TOF;  // Clear overflow
        
        out = !out;
        digitalWrite(14, out);
        MAIN_LED(out);
        
        TPM0_CNT = 0;  // Start value for timer
        TPM0_SC |= FTM_SC_TOF;  // Clear pending bits
        
        // Wait on timer overflow
        while(!(TPM0_SC & FTM_SC_TOF));
      } 
    }

    The code above seems to work fine. With an oscilloscope I can see that pin 14 toggles. But unfortunately it shows 500us for the timer instead of 1000us what I had expected.

    But even more strange: It doesn't even matter what prescaler I use. I can change the line to
    Code:
     TPM0_SC |= 0b00000111;  // Prescaler /128
    The output is still the same, i.e. the oscilloscoe still shows 500us.

    What am I missing? Why is the prescaler not having any effect?

  2. #2
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,237
    You need to spin-wait to clear TPM0_SC and move enable MCG_C1 to after the other MCG stuff. You should then be able to change the prescale.
    Code:
    void setup() {
      // Initialize pins
      pinMode(14, OUTPUT);
    
      // Setup timer
      MCG_C1 &= ~0b010; // Disable IRCLK
      MCG_SC &= ~0b01110; // Divider = 1 => 4MHz
      MCG_C2 |= 0b001;  // IRCS. fast internal reference clock enabled
      MCG_C1 |= 0b010;  // IRCLKEN = enabled
      
      // Clock source
      SIM_SOPT2 |= 0b00000011000000000000000000000000;  // MCGIRCLK
    
      // Prescaler: 4 -> 4MHz/4 = 1MHz => 1us
      TPM0_SC = 0;
      while ( 0 != (TPM0_SC & 8)) TPM0_SC = 0;  // spin wait 
      TPM0_SC |= 0b00000010;  // Prescaler /4 = 1Mhz
      TPM0_SC |= 0b00001000;  // Enable timer
    
      // When this is reached the overflow flag is set.
      TPM0_MOD = 1000 - 1; // 1000us = 1ms
    
      // Loop: toggle a pin each time the timer elapses (overflows)
      bool out = false;
      while(true) {
        TPM0_CNT = 0;  // Start value for timer
        TPM0_SC |= FTM_SC_TOF;  // Clear overflow
        
        out = !out;
        digitalWrite(14, out);
    //    MAIN_LED(out);
        
        TPM0_CNT = 0;  // Start value for timer
        TPM0_SC |= FTM_SC_TOF;  // Clear pending bits
        
        // Wait on timer overflow
        while(!(TPM0_SC & FTM_SC_TOF));
      } 
    }
    
    void loop() {}
    For the CMOD field in the TPMx_SC, the ref manual mysteriously states "when disabling the counter, this field remain set until
    acknolwedged in the TPM clock domain
    ."

    You could get the equivalent wave form on a PWM pin with 2 lines of code in setup(), e.g. for pin 23
    analogWriteFrequency(23,500);
    analogWrite(23, 128);
    or use the IntervalTimer to toggle pin 14 every 1000 us
    Last edited by manitou; 09-18-2019 at 05:06 PM.

  3. #3
    Junior Member
    Join Date
    Sep 2019
    Posts
    15
    Hello manitou,

    thanks very much, that was the problem.
    The prescaler is working now.

    BTW:
    I'm not using it to generate wave forms, so the PWM won't help me.
    Instead I use it to check that certain code paths are not taken longer than a certain time frame.
    I.e. if I execute some code and afterwards see that the overflow flag is set I know that the algorithm has taken too long.
    The oscilloscope was used just to verify that it's working (or not).

Posting Permissions

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