Getting Started with STM32H5 ARM Cortex M33: Timer Interrupt

In this guide, we shall use timer to generate interrupt for precise time control for our application.

In this guide, we shall cover the following:

  • What in timer interrupt.
  • STM32CubeMX setup.
  • Firmware development.
  • Results.

1. What is Timer Interrupt:

timer interrupt in a microcontroller is a mechanism where the microcontroller generates an interrupt signal based on events associated with a timer peripheral. These events can include reaching a specific count, an overflow, or a match between the timer count and a predefined value. The timer interrupt allows the microcontroller to execute a specific task (Interrupt Service Routine, ISR) in response to the timer event without continuously polling the timer status.

How Timer Interrupt Works

1. Timer Peripheral:

• A timer is a hardware module in the microcontroller that increments or decrements a counter at a fixed rate, derived from the system clock or a prescaled clock.

2. Event Generation:

• As the timer runs, it can trigger events such as:

• Overflow (counter rolls back to zero).

• Match with a specific compare value.

• A trigger input or external signal.

3. Interrupt Request (IRQ):

• When the specified event occurs, the timer generates an interrupt request (IRQ) to the CPU.

4. Interrupt Service Routine (ISR):

• The microcontroller pauses its main program to execute a small function (ISR) associated with the timer interrupt.

5. Return to Main Program:

• After the ISR finishes, the CPU resumes executing the main program from where it left off.

Why Use Timer Interrupts?

1. Precise Timing:

• Timer interrupts provide highly accurate timing, independent of the program’s execution state.

2. Non-blocking Delays:

• Unlike software delays, a timer interrupt allows the microcontroller to perform other tasks while waiting for the timer event.

3. Periodic Tasks:

• Execute tasks at regular intervals (e.g., sampling a sensor every 1 ms).

4. Event Timing:

• Measure durations or count specific events (e.g., pulses in an encoder).

Key Components of Timer Interrupts

1. Timer Counter:

• The main register that counts up or down based on the timer’s clock.

2. Prescaler:

• Divides the clock frequency to adjust the timer’s counting speed.

3. Compare Registers:

• Define specific count values that trigger interrupts.

4. Interrupt Flags:

• Indicate the occurrence of a timer event and need to be cleared in the ISR.

5. NVIC (Nested Vectored Interrupt Controller):

• Manages the priority and execution of interrupts.

Applications of Timer Interrupts

1. Real-Time Clock:

• Generate accurate time intervals (e.g., 1-second ticks).

2. PWM Generation:

• Create precise Pulse Width Modulation signals for motor control or LED dimming.

3. Frequency Measurement:

• Measure signal frequency by counting pulses within a fixed time.

4. Sensor Sampling:

• Read data from sensors at regular intervals.

5. Debouncing:

• Avoid false triggers in button presses by implementing debouncing logic.

6. Communication Protocols:

• Time-critical operations like UART bit sampling or SPI communication.

2. STM32CubeMX Configuration:

Create new project with name of Timer_Interrupt. For how to create new project for STM32H5, please refer to this guide here.

After the project creation, enable TIM2 and TIM3 as following:

Enabling TIM2:

From timers, select TIM2 and set the clock source to be internal.

In similar manner, enable the clock to TIM3.

Next from clock configuration, we need to find the frequencies of the timers:

By default, STM32H563Zi is running at 32MHz. Hence, the timers are 32MHz in speed.

Hence, we can configure TIM2 as following:

Set the prescaler to 32000-1 which will reduce the timer frequency to 1KHz (32MHz/32KHz = 1KHz).

Set the ARR to 1000-1, this will let the timer to count to 1000 which will give 1 second (1KHz/1KHz= 1Hz = 1 second).

From the NVIC, enable timer2 global interrupt as following:

For TIM3, the configuration as following:

Set the prescaler to 32000-1.

Set the period to be 2000-1 which will provide interrupt each 2 seconds.

Also, enable the interrupt for TIM3 as following:

Also, enable UART, for how to enable UART, please refer to this guide here.

Save the project this will generate the project.

3. Firmware Development:

Once the project has been generated, in main.c file, in user begin PV (Private variable), declare the following two volatile variables as following:

volatile uint8_t tim2_done=0, tim3_done=0;

These two variables are the flag to tell the firmware that the interrupt is generated.

Also, declare a buffer to hold data to be transmitted over UART as following:

uint8_t uart_data[100]={0};

Next, in user code begin 2of the main function, start both timer in the interrupt mode as following:

  HAL_TIM_Base_Start_IT(&htim2);
  HAL_TIM_Base_Start_IT(&htim3);

The function HAL_TIM_Base_Start_IT will start the timer in counting mode and generate interrupt periodically.

In user code begin 3 of while 1 loop:

Check if the interrupt is generate, if yes, reset the variable and print the interrupt source as following:

uint16_t len;
	  if(tim2_done==1)
	  {
		  tim2_done=0;
		  len=sprintf(uart_data,"Timer 2 interrupt triggered\r\n");
		  HAL_UART_Transmit(&huart3, uart_data, len, 100);
	  }

	  if(tim3_done==1)
	  {
		  tim3_done=0;
		  len=sprintf(uart_data,"Timer 3 interrupt triggered\r\n");
		  HAL_UART_Transmit(&huart3, uart_data, len, 100);
	  }

The len variable shall store the length of the string to be sent. Usually, sprintf returns number of the characters.

Next, open stm32h5xx_hal_tim.c source file as following and locate the following function:

The function:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

Shall be called each time the timer has overflowed (reaches to the maximum value and get back to zero).

Since this function is declared as weak, the user can override this function is his firmware.

In user code begin 4 of the main.c file, declare the function as following:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance ==TIM2)
	{
		tim2_done=1;
	}

	if(htim->Instance ==TIM3)
	{
		tim3_done=1;
	}

}

Within the function, check which timer is the source of the interrupt and set the flag.

Thats all for the guide.

Save the project, build it and run it on your STM32H563Zi board.

4. Results:

Open your favourite terminal application, set the baudrate to be 115200 and you should see the following:

Notice that timer 2 interrupt triggered is twice compared to timer 3 which is what we set in the CubeMX.

Happy coding 😉

Add Comment

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