Configuring Timer Interrupts on STM32 Microcontrollers

The timer's period is determined by the values in the Auto-Reload Register (ARR) and the Prescaler (PSC). The formula for calculating the interrupt period is as follows:

Timer Period = (ARR + 1) * (PSC + 1) / Timer Clock Frequency

The ARR value sets the maximum count before the counter resets, generating an overflow event and potentially an interrupt. For example, if the timer counts from 0 to 9999 (ARR=9999), it completes 10,000 counts per period.

The PSC divides the input clock to slow down the counting rate. A PSC value of 7199 divides the clock by 7200. For a standard 72 MHz timer clock, this results in a 10 kHz counting frequency (72,000,000 / 7200).

Combining these parameters allows precise timing. For instance, with a 72 MHz clock, PSC=7199, and ARR=9999, the interrupt period is (10,000 * 7,200) / 72,000,000 = 1.0 second.

Below is the header file periph_timer.h:

#ifndef PERIPH_TIMER_H
#define PERIPH_TIMER_H

#include "stm32f10x.h"

void timer_setup(void);

#endif /* PERIPH_TIMER_H */

The implemantation in periph_timer.c configures the timer:

#include "periph_timer.h"
#include <stdint.h>

/**
 * Configures Timer 2 for periodic interrupt generation.
 */
void timer_setup(void) {
    // Enable clock for Timer 2 (APB1 bus)
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    // Select internal clock source
    TIM_InternalClockConfig(TIM2);

    // Configure time base unit
    TIM_TimeBaseInitTypeDef timebase_cfg;
    timebase_cfg.TIM_Prescaler = 7200 - 1;        // Scale clock to 10 kHz
    timebase_cfg.TIM_CounterMode = TIM_CounterMode_Up;
    timebase_cfg.TIM_Period = 10000 - 1;          // Count to 10000
    timebase_cfg.TIM_ClockDivision = TIM_CKD_DIV1;
    timebase_cfg.TIM_RepetitionCounter = 0;       // Not used for basic timers
    TIM_TimeBaseInit(TIM2, &timebase_cfg);

    // Clear pending update flag
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);

    // Enable update interrupt
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

    // Configure NVIC for Timer 2 interrupt
    NVIC_InitTypeDef nvic_cfg;
    nvic_cfg.NVIC_IRQChannel = TIM2_IRQn;
    nvic_cfg.NVIC_IRQChannelPreemptionPriority = 1;
    nvic_cfg.NVIC_IRQChannelSubPriority = 0;
    nvic_cfg.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvic_cfg);

    // Start the timer
    TIM_Cmd(TIM2, ENABLE);
}

A example main application demonstrates usage:

#include "stm32f10x.h"
#include "display.h"
#include "periph_timer.h"

volatile uint32_t event_counter = 0;

int main(void) {
    display_init();
    timer_setup();

    display_print_string(1, 1, "Count:");

    while (1) {
        display_print_number(1, 7, event_counter, 5);
    }
}

// Interrupt Service Routine for Timer 2
void TIM2_IRQHandler(void) {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
        event_counter++;
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}

Tags: STM32 Timer Interrupt Embedded Systems c programming

Posted on Fri, 17 Jul 2026 17:27:09 +0000 by MrJW