cancel
Showing results for 
Search instead for 
Did you mean: 

Timer compare function interrupt not triggered sometimes

Joey_Duh
Associate II

Hi everyone, I meet a problem and I'm not sure it's MCU issue or I program not proper.

I meet this issue both on the STM8 and STM32 MCUs.

I enable TIM_2 Ch1 as input to capture the signal and TIM_2 Ch2 as output to do the compare function.

 

void init_TIM_2
{
  RCC.APB1ENR.bit.TIM2EN = 1;
  ..
  TIM2.CCMR1.bit.Inmode.IC1S = 1;
  TIM2.CCMR1.bit.Inmode.IC1PSC = 0;
  TIM2.CCER.bit.CC1P = 0;
  TIM2.CCER.bit.CC1E = 1;
  ..
  TIM2.CCMR1.bit.Outmode.OC2S = 0;
  TIM2.CCER.bit.CC2E = 1;
  TIM2.DIER.bit.CC2IE = 1;
  ..
}

 

 Also I enable the global interrupt with the NVIC module. So the interrupt is working.

And what I do in the interrupt just set a new compare value and toggle an GPIO pin.

 

void TIM2_ISR(void)
{
  if (TIM2.SR.bit.CC2IF)
  {
    int p = TIM2_CCR;
    int new_val = 0;
    ..
    // Calculate a new compare value
    // Toggle the GPIO pin
    ..
    TIM2.CCR = p + new_val;

    TIM2.SR.bit.CC2IF = 0;
  }
}

 

I found it will miss the compare value sometime.

I trace the CCR value and timer counter value of TIM2, the CCR value should be greater than the counter value in normal case. But I found it's not triggered the ISR and the counter just exceed the CCR value sometimes.

If I program not proper, please have some advise for me. Thank you!

The actual data trace list as below:

TIM2 CCR valueTIM2 counter valueNotes
2173556321729923 
2173556321735024 
2173556321740124The counter val > CCR and no interrupt event
2173556321745225 
1 ACCEPTED SOLUTION

Accepted Solutions
TIM2.SR.bit.CC1IF = 0;

This is exactly what I was talking about above:

> Doesn't this lead to RMW? That might clear inadvertently other flags in the TIMx_SR register, too.

Read the linked article. Don't use bitfields to clear status register, that results in RMW even if it looks elegant; write directly to TIMx_SR. I don't know how did you define TIM2, but using the "normal" CMSIS-mandated device header, you would be adviced not to write

TIM2->SR &= ~TIM_SR_CC1IF;

but rather

TIM2->SR = ~TIM_SR_CC1IF;

JW

View solution in original post

11 REPLIES 11
Issamos
Lead II

Hello @Joey_Duh 

I suggest you to double check and debug your code step by step to localise the problem. Also, I suggest you to verify the interrupt priority of timer2, if it's very low it may have some problems from Time to time as you mentioned.

Best regards.

II

Hi Issamos,

Thanks for your reply.

I checked my interrupt config and the priority I set whatever it's high or low the symptom is the same.

What I do to debug this issue is to record the timer compare value(CCR) and timer counter value(CNT) as I mentioned. The GPIO should not keep low or keep high because I make GPIO toggle when interrupt triggered.

I think the compare ISR must be triggered if the compare value is set greater than the current CNT.

But it seems not, so I still confused.

Many thanks.

Joey

Try to debug using break points everywhere it seems to be source of issue.

Best regards.

II

What programming language is this?

 

TIM2.SR.bit.CC2IF = 0;

 

Doesn't this lead to RMW? That might clear inadvertently other flags in the TIMx_SR register, too.

Post the entire ISR content. I am not interested in how do you calculate the new CCRx value, but whether there are or are not other TIM registers' changes.

> trace the CCR value and timer counter value of TIM2

How?

Does the GPIO pin toggle properly, or what exactly are you observing on it?

JW

LCE
Principal

> What programming language is this?

TIM2.SR.bit.CC2IF = 0;

Jan has a point here.

Have you built your own struct called "TIM2"?
If yes, then this might be okay, but irritating for everybody else, because in the STM32 header files "TIM2" is a pointer, with the registers in a timer typedef struct, so that you can access the registers like:

TIM2->CR = ...;

Joey_Duh
Associate II

@Issamos The timer compare ISR triggered is worked, but not worked everytime.  That's why I record the timer register value in background but not using break point. Also the break point would pause the program and the ISR cannot stop in my design even 1 times.

@waclawek.jan @LCE I have my own TIM2 struct and the CC2IF is one bit of the Timer status register which means the content of the counter TIM2_CNT has matched the content of the TIM2_CCR2
register.
 

And actually what I post is the entire ISR content. GPIO toggle properly if the ISR actually triggered. And runs a few minutes or seconds it just a line because the ISR not triggered. I record the timer register value in the background because I need to make sure if the counter is lower than the CCR value.

How and where do you handle the capture in channel 1?

JW

 

@waclawek.jan I handle the capture in the background.

void get_capture_val(void)
{
  if (TIM2.SR.bit.CC1IF == 1)
  {
    // ..
    // Handle the capture value
    // ..
    TIM2.SR.bit.CC1IF = 0;
  }
}

 

TIM2.SR.bit.CC1IF = 0;

This is exactly what I was talking about above:

> Doesn't this lead to RMW? That might clear inadvertently other flags in the TIMx_SR register, too.

Read the linked article. Don't use bitfields to clear status register, that results in RMW even if it looks elegant; write directly to TIMx_SR. I don't know how did you define TIM2, but using the "normal" CMSIS-mandated device header, you would be adviced not to write

TIM2->SR &= ~TIM_SR_CC1IF;

but rather

TIM2->SR = ~TIM_SR_CC1IF;

JW