STM32 External Interrupts and Timer Basics

Interrupt Fundamentals

An interrupt is a mechanism that temporarily suspends the main program execution when a specific interrupt condition is triggered. The CPU pauses the current task, executes an interrupt service routine (ISR), and then returns to continue the main program from where it left off.

Interrupt Priority

When multiple interrupt sources request service simultaneously, the NVIC (Nested Vector Interrupt Controller) evaluates their priority levels. Higher-priority interrupts are serviced first. If two interrupts have the same priority, the one with the lower vector number executes first.

Interrupt Nesting

A higher-priority interrupt can preempt a currently executing lower-priority interrupt handler. This nesting capability allows critical real-time events to be handled immediately without waiting for the completion of less urgent interrupt routines.

EXTI External Interrupts

The External Enterrupt (EXTI) controller monitors specified GPIO pins for electrical signal changes. When a configured pin experiences a transition (rising edge, falling edge, or both), the EXTI generates an interrupt request to the NVIC, which then interrupts the CPU to execute the corresponding ISR.

Supported Trigger Modes

  • Rising edge trigger
  • Falling edge trigger
  • Both edges trigger
  • Software trigger

Channel Configuration

The STM32F103 provides 16 external interrupt lines (EXTI0-EXTI15), plus additional lines for PVD output, RTC alarm, USB wakeup, and Ethernet wakeup. Each GPIO pin can be mapped to an EXTI line, but identical pin numbers across different ports cannot simultaneously trigger interrupts.

NVIC Priority Grouping

The NVIC uses a 4-bit priority field that can be divided into preemption priority (higher bits) and sub-priority (lower bits). A higher preemption priority allows an interrupt to nest over lower-priority handlers. When preemption priorities are equal, sub-priority determines the order. If both are equal, the vector number serves as the tiebreaker.

Configuration Example: External Interrupt on PB5

void Interrupt_Init(void)
{
    /* Enable peripheral clocks */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    /* Configure GPIO pin as input with internal pull-up */
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    /* Map external interrupt line to GPIO pin */
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource5);
    
    /* Configure EXTI line */
    EXTI_InitTypeDef EXTI_InitStruct;
    EXTI_InitStruct.EXTI_Line = EXTI_Line5;
    EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStruct.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStruct);
    
    /* Configure NVIC priority grouping */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    /* Configure NVIC for EXTI line */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
}

Interrupt Service Routine

void EXTI9_5_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line5) == SET) {
        /* Read input to confirm valid interrupt */
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5) == Bit_RESET) {
            event_counter++;
        }
        EXTI_ClearITPendingBit(EXTI_Line5);
    }
}

Timer Fundamentals

The general-purpose timer is a 16-bit incrementing counter driven by the internal APB bus clock (72 MHz for STM32F103). When the counter reaches the auto-reload register value, a timer update event is generated, which can trigger an interrupt. With a 72 MHz clock and maximum prescaler, the timer can achieve intervals up to approximately 59.65 seconds.

Timer Categories

Advanced Timer (TIM1): Full-featured timer with additional capabilities including repetition counter, dead-time generation, complementary outputs, and brake input.

General-Purpose Timers (TIM2, TIM3, TIM4): Support internal/external clock selection, input capture, output compare, encoder interface, and master/slave trigger modes.

Basic Timer (TIM6, TIM7): Simple timer with update interrupt and DAC trigger capabilities.

Timer Configuration Example: 1-second interrupt

void Timer_Init(void)
{
    /* Enable TIM2 clock */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    
    /* Select internal clock source */
    TIM_InternalClockConfig(TIM2);
    
    /* Configure timebase unit */
    TIM_TimeBaseInitTypeDef TIM_InitStruct;
    TIM_InitStruct.TIM_Prescaler = 7200 - 1;    /* 72MHz / 7200 = 10kHz */
    TIM_InitStruct.TIM_Period = 10000 - 1;   /* 10kHz / 10000 = 1Hz */
    TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_InitStruct.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &TIM_InitStruct);
    
    /* Clear update flag to prevent immediate interrupt */
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    
    /* Enable update interrupt */
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    
    /* Configure NVIC */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
    
    /* Enable timer */
    TIM_Cmd(TIM2, ENABLE);
}

Timer ISR

void TIM2_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) {
        second_counter++;
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}

PWM Output

Output Compare mode generates PWM (Pulse Width Modulation) signals by comparing the counter (CNT) value with the capture/compare register (CCR). When CNT matches CCR, the output pin can be set, reset, or toggled based on configuration.

PWM Parameters

  • Frequency: Determines how often the PWM signal completes one cycle
  • Duty Cycle: Ratio of pulse width to period, controlling average power
  • Resolution: Minimum step size for duty cycle adjustment

PWM Configuration Example

void PWM_Init(void)
{
    /* Enable GPIO and timer clocks */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    
    /* Configure PA6 as alternate function push-pull */
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    /* Configure timer timebase */
    TIM_TimeBaseInitTypeDef TIM_InitStruct;
    TIM_InitStruct.TIM_Prescaler = 720 - 1;     /* 72MHz / 720 = 100kHz */
    TIM_InitStruct.TIM_Period = 100 - 1;       /* 100kHz / 100 = 1kHz PWM frequency */
    TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInit(TIM3, &TIM_InitStruct);
    
    /* Configure output compare channel */
    TIM_OCInitTypeDef TIM_OCInitStruct;
    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStruct.TIM_Pulse = 50;           /* 50% duty cycle */
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC1Init(TIM3, &TIM_OCInitStruct);
    
    /* Enable timer */
    TIM_Cmd(TIM3, ENABLE);
}

GPIO Input Modes

Floating Input (GPIO_Mode_IN_FLOATING): High-impedance input with no internal pull-up or pull-down. Use when an external circuit actively drives the signal.

Pull-up Input (GPIO_Mode_IPU): Internal pull-up resistor connectsVDD through the pin. Use with active-low signals or switches connected to ground.

Pull-down Input (GPIO_Mode_IPD): Internal pull-down resistor connects VSS through the pin. Use with active-high signals or switches connected to VDD.

Tags: STM32 External Interrupt EXTI Timer PWM

Posted on Sat, 06 Jun 2026 16:23:59 +0000 by pvechi