STM32F4: Interrupt Timer

Rather than using a busy-wait approach to timing, as shown in a previous post here, it is much more efficient to make this interrupt driven. Adding an interrupt involves configuring the NVIC (Nested Vectored Interrupt Controller). In addition, the flags used are different – the IT flags are used instead. This is different to a lot of other micros, where the same flag is used to trigger and clear an interrupt.

The interrupt handler is straightforward – it checks for the interrupt source (TIM_IT_Update) and if that is SET, then it toggles the LED. Unlike other micros, the flag is not automatically cleared, so must be cleared manually (at least, this is my current view of things).

void TIM2_IRQHandler(void)
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
GPIO_ToggleBits(GPIOD, GPIO_Pin_13);

The main loop is even simpler than before, it just configures the timer and ports and then spins around in an infinite loop. Configuring the timer is similar to before, but has a couple of extra steps to setup the interrupts and tie the timer to an interrupt:

void INTTIM_Config(void)
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the TIM2 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 1000 - 1; // 1 MHz down to 1 KHz (1 ms)
TIM_TimeBaseStructure.TIM_Prescaler = 84 - 1; // 24 MHz Clock down to 1 MHz (adjust per your clock)
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* TIM IT enable */
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
/* TIM2 enable counter */

Download the complete listing here.

13 thoughts on “STM32F4: Interrupt Timer

  1. I was basically wanting to know if you ever considered modifying the page layout of your website? It is very well written; I really like what youve got to state. But maybe you can create a little more in the way of written content so people can connect with it better. Youve got an awful lot of wording for only having one or two photographs. Maybe you can space it out better?

    1. Thanks for the feedback. I was putting up small atomic articles, each concentrating on a module/approach, and was intending for the interrupt timer to be read in conjunction with the busy-wait timer. I will put up some cross links.

  2. hi every body , i have a question about the timer:
    if my timer had an interrupt degree higher than than the interruption coming from the USB (messages come from the USB and every message had a special traitement) what can i do to fix it ?

  3. What’s concretely the difference between using a classical timer interrupt like in this article and using the SysTick interrupt ? Thanks :)

    1. Hi there,
      The SysTick timer is a 24 bit downcounting timer specified by ARM. The idea is that with a common timer structure, it will be easy to port RTOSes between different vendors (e.g. STM and AVR). The other timers have different widths (16 bit/32 bit), are generally more complex (downcounting, upcounting) and are often linked to peripherals (PWM, Capture/Compare).

  4. Hi..I was just wondering if you can intialise timer periods during run time? I am facing some problem in this regard. This was useful. But if you could throw some light on the problem I am facing that would be great!

    1. Yes, you can dynamically change timer periods during run time – it is very simple and it is how you implement frequency modulation on DDS. All you need to do is to change timer parameters somewhere else in your code, e.g. on a button press or from another timer.
      There are two ways I can think of doing this.
      The first is just to reinitialize the timer, in very much the same way in the INTTIM_Config(). In fact, you could even pass the period to this function as an argument.
      The other way is to dig a little deeper into the CMSIS documents and you will find the function:
      void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint32_t Autoreload)
      The “Autoreload” is the same as the period, i.e. the value to which the counter counts until it goes to zero (reload).

  5. Thanks Andrew! :) I tried the second approach and it worked fine! The first approach you mentioned is where I was getting stuck! It probably takes too many clock cycles to get the period updated or something. I had directly tried to work with TIMx->ARR = ” Variable” . I hadn’t converted it to a 32 bit no. and it was declared 16-bit. The auto reload function doesn’t need an explicit conversion I guess! :)

    Thank you very much again !

    1. Yes of course it is :-) Having a non-volatile interrupt controller would not be of much use to anyone would it? Thanks for spotting that, I have edited the post.

Leave a Reply