Skip to main content
Associate
September 11, 2023
Solved

Timer compare function interrupt not triggered sometimes

  • September 11, 2023
  • 7 replies
  • 5532 views

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 
This topic has been closed for replies.
Best answer by waclawek.jan
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

7 replies

Issamos
Super User
September 11, 2023

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

Joey_DuhAuthor
Associate
September 11, 2023

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

Issamos
Super User
September 11, 2023

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

Best regards.

II

waclawek.jan
Super User
September 11, 2023

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 II
September 11, 2023

> 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_DuhAuthor
Associate
September 12, 2023

@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.

waclawek.jan
Super User
September 12, 2023

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

JW

 

Joey_DuhAuthor
Associate
September 12, 2023

@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;
 }
}

 

waclawek.jan
waclawek.janBest answer
Super User
September 12, 2023
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

Joey_DuhAuthor
Associate
September 13, 2023

@waclawek.jan It really helps me a lot. I thought what I set is only 1 bit not a whole bits of register. But I trace the assembly code and it really did the LDR->BIC->STR and it cause the other interrupt flags clear either.

image.png

Many thanks.

Piranha
Principal III
September 14, 2023

The reasons why for register accesses the bit-fields are harmful and useless:

  1. If one omits the volatile qualifier, the code is just broken.
  2. With the volatile qualifier every bit or bit-field access leads to a separate set of RMW instructions, which leads to a generally inefficient and for some uses (interrupt clearing) again broken code.