Getting Started with STM32F103: Timer Interrupt

In the previous guide (here), we took a look how to configure TIM2 of STM32F103 to generate precise delay from 1 milliseconds up to 65 seconds.

In this guide, we shall use timer interrupt to generate interrupt each second and toggle the LED within the interrupt.

In this guide, we shall cover the following:

  • What is an interrupt.
  • Connection.
  • Configure TIM2 to generate Interrupt.
  • Code.
  • Demo.

1. What is an interrupt:

Interrupt is a process to notify the cpu that there is a request and it should be handled as soon as possible See figure below.

The CPU will find the current instruction in the main loop (which is empty in our case) and jump to ISR function to toggle PA5 and jump back to main loop.

For more information, please refer to this guide (here)

2. Connection:

The connection of LED to PA5 as following:

You will need the following:

  • STM32F103C8 aka BluePil
  • 220Ohm Resistor.
  • Any color LED.
  • Hookup wires.
  • Breadboard.

3. Configure TIM2 to generate Interrupt:

First thing is to set PA5 as output:

	RCC->APB2ENR|=RCC_APB2ENR_IOPAEN;

	/*Configure PA5 as output*/
	GPIOA->CRL|=GPIO_CRL_MODE5;
	GPIOA->CRL&=~(GPIO_CRL_CNF5);

Then configure the timer.

First enable clock access to TIM2 (For details, check the previous guide from here):

	/*Enable clock access to timer2*/
	RCC->APB1ENR|=RCC_APB1ENR_TIM2EN;

Since the MCU is running at 8MHz and we need 1 second interrupt, we shall set the prescaler to 8000-1 to get 1KHz rate which is 1 millisecond:

TIM2->PSC=8000-1; /*8000000/8000 =1000 i.e. 1ms*/

Then set the maximum value to reach using ARR register. Since we need 1 second, we need to ARR to 1000-1 as following:

TIM2->ARR=1000-1; /*count up to 1000 which is 1 second*/

To enable timer interrupt, we need to set UIE(Update interrupt enable) bit in TIMx DMA/Interrupt enable register (TIMx_DIER):

TIM2->DIER|=TIM_DIER_UIE;

Then enable timer2 interrupt in NVIC:

NVIC_EnableIRQ(TIM2_IRQn);

Finally enable the timer:

TIM2->CR1|=TIM_CR1_CEN;

Within the interrupt handler:

void TIM2_IRQHandler(void)
{
	if(TIM2->SR & TIM_SR_UIF)
	{
		GPIOA->ODR ^=GPIO_ODR_ODR5;

		TIM2->SR &=~TIM_SR_UIF;
	}
}

Check the interrupt source if it is from update:

if(TIM2->SR & TIM_SR_UIF)

IF it is, toggle PA5 and clear the flag:

		GPIOA->ODR ^=GPIO_ODR_ODR5;

		TIM2->SR &=~TIM_SR_UIF;

4. Code:

Hence, the entire code as following:

#include "stm32f1xx.h"

int main(void)
{
	RCC->APB2ENR|=RCC_APB2ENR_IOPAEN;

	/*Configure PA5 as output*/
	GPIOA->CRL|=GPIO_CRL_MODE5;
	GPIOA->CRL&=~(GPIO_CRL_CNF5);

	/*Enable clock access to timer2*/
	RCC->APB1ENR|=RCC_APB1ENR_TIM2EN;

	/*Configure timer2*/
	TIM2->PSC=8000-1; /*8000000/8000 =1000 i.e. 1ms*/
	TIM2->ARR=1000-1; /*count up to 1000 which is 1 second*/
	TIM2->DIER|=TIM_DIER_UIE;
	NVIC_EnableIRQ(TIM2_IRQn);
	TIM2->CR1|=TIM_CR1_CEN;

	while(1)
	{


	}
}

void TIM2_IRQHandler(void)
{
	if(TIM2->SR & TIM_SR_UIF)
	{
		GPIOA->ODR ^=GPIO_ODR_ODR5;

		TIM2->SR &=~TIM_SR_UIF;
	}
}

5. Demo:

When you compile the code and connect the LED as shown in the connection you should get 1 second toggle rate.

Happy coding 🙂

Add Comment

Your email address will not be published. Required fields are marked *