cancel
Showing results for 
Search instead for 
Did you mean: 

Interrupt on CEN bit setting in TIM7

foruvarov
Associate II
Posted on March 06, 2013 at 13:06

Hello everybody!

I'm using timer TIM7 on STM32F407 to generate an interrupt on overflow. It works fine except one thing. When I enable the counter at first time it rises an interrupt immediately, right after setting the CEN bit in TIM7_CR1 register. Following iterations are ok.

Does anybody know what's the problem?

Initialization code

void TIM7_Init(void)

{

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);

  

  TIM7->CR1 |= TIM_CR1_OPM | TIM_CR1_URS; //One-pulse mode and Update generation only on Counter Overflow

  TIM7->DIER |= TIM_DIER_UIE;   // Interrupt generation on Counter Overflow

  TIM7->PSC = 1600;      //With HSI frequency 16MHz gives a 100us period

  

  NVIC_InitStruct.NVIC_IRQChannel = TIM7_IRQn;

  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;

  NVIC_Init(&NVIC_InitStruct);

}

PushButton Handler

void EXTI0_IRQHandler(void)

{

  for (volatile uint32_t cnt=200000; cnt!=0; cnt--);  //wait until bounce stops

  EXTI_ClearITPendingBit(EXTI_Line0); //reset pending state

  GPIO_ToggleBits(GPIOD, GPIO_Pin_12); //LED

  TIM7->ARR = 10000; //delay 1s

  TIM7->CR1 |= TIM_CR1_CEN; //start counting

}

Overflow handler

void TIM7_IRQHandler(void)

{

  TIM7->SR &= 0xFFFFFFFE; //reset UIF flag

  GPIO_ToggleBits(GPIOD, GPIO_Pin_15); //LED

}

#stm32f4-timer-tim7-interrupt
4 REPLIES 4
Posted on March 06, 2013 at 15:00

Do you reset the chip using the hardware reset/poweron, or are you resetting it from some form of a debugger?

I'd reset the timer explicitly in RCC after enabling its clock, to be sure.

>   TIM7->SR &= 0xFFFFFFFE; //reset UIF flag

Don't &=, do =, as all bits in TIMx_SR are of rc_w0 type, so you could inadvertently clear a bit which has been set meantime. It won't matter in the code as you presented it, but it's a good practice for future when you will manipulate multiple flags.

Also, it might be perhaps a better style to stick to either using the ''peripheral library'', or directly the registers, not mixing them.

JW

foruvarov
Associate II
Posted on March 07, 2013 at 05:10

Thanks for reply!

I'm reseting the chip both ways: with debugger and with hardware using NRST pin. The result is same. Also I tried to reset UIF flag in SR register and NVIC pending bit right after setting the CEN bit in CR1 register. Unfortunately, it has no any effect.

Posted on March 15, 2013 at 15:46

Turns out, your problem has its explanation in the following sentence from the manual (RM0090 rev.4, p.526):

''The new prescaler ratio is taken into account at the next update event.''

So, after the first button press, the timer does count up to 10000, but at the maximum rate given by default prescaler value = 0 (which appears to be immediately for the human observer). Only then the new prescaler is taken into account.

Hower, if you'd read out the PSC register after write, you'd see the new value. There is apparently another, user-invisible register for the real prescaling. All this ''shadowing'', although I see its purpose, is quite confusing; pity that all those ''shadow'' registers are not visible for the users for debugging purposes.

The code below should do what you intend. Note, that if _SR register clear follows immediately after setting the UG bit in _EGR register, the update event is not cleared from _SR register - apparently, there is some internal timing of events involved but I am not going to investigate it further.

JW

---

void EXTI0_IRQHandler(void)

{

  for (volatile uint32_t cnt=200000; cnt!=0; cnt--);  //wait until bounce stops

  EXTI_ClearITPendingBit(EXTI_Line0);    //reset pending state

  GPIO_ToggleBits(GPIOD, GPIO_Pin_12); //LED

  TIM7->ARR = 10000;    //delay 1s

  TIM7->CR1 |= TIM_CR1_CEN; //start counting

}

void TIM7_IRQHandler(void)

{

//  TIM7->SR &= 0xFFFFFFFE;    //reset UIF flag

  if (TIM7->SR & 1) {

    GPIO_ToggleBits(GPIOD, GPIO_Pin_15);    //LED

  } else {

    GPIO_ToggleBits(GPIOD, GPIO_Pin_14);    //LED

  }

  TIM7->SR = 0xFFFE;    //reset UIF flag

}

static void TIM7_Init(void)

{

  NVIC_InitTypeDef NVIC_InitStruct;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);

  TIM7->PSC = 1600;        //With HSI frequency 16MHz gives a 100us period

  TIM7->EGR = TIM_EGR_UG;  // generate update to force the prescaler to be accepted

  TIM7->CR1 |= TIM_CR1_OPM | TIM_CR1_URS; //One-pulse mode and Update generation only on Counter Overflow

  TIM7->SR = 0;            // clear all status (namely the update flag)

  TIM7->DIER |= TIM_DIER_UIE;   // Interrupt generation on Counter Overflow

  NVIC_InitStruct.NVIC_IRQChannel = TIM7_IRQn;

  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;

  NVIC_Init(&NVIC_InitStruct);

}

Posted on March 15, 2013 at 15:58

Just one more minor thing:

TIM7->PSC = 1600;        //With HSI frequency 16MHz gives a 100us period

It should be 1599. Not that it matters when used with HSI which is much more imprecise than that (and also jitters like hell 🙂 ), just I like things to be done precisely.

JW