Low level usage of timers

Status
Not open for further replies.

Maziac

Member
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?
 
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
  [B][COLOR="#FF0000"]MCG_C1 |= 0b010;  // IRCLKEN = enabled[/COLOR][/B]
  
  // Clock source
  SIM_SOPT2 |= 0b00000011000000000000000000000000;  // MCGIRCLK

  // Prescaler: 4 -> 4MHz/4 = 1MHz => 1us
  TPM0_SC = 0;
  [B][COLOR="#FF0000"]while ( 0 != (TPM0_SC & 8)) TPM0_SC = 0;  // spin wait [/COLOR][/B]
  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:
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).
 
Status
Not open for further replies.
Back
Top