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