简体   繁体   中英

TIM2 overflow does not trigger TIM2_IRQHandler @ STM32G031J6

With the following code I want to make pin 5 (PA11) of an STM32G031J6M6 blink at 50 kHz. To do this, I configured TIM2 to overflow every 10 us. This is to call an ISR ("TIM2_IRGHandler") that toggles the level of PA11. Now everything actually works fine: the toggle works and TIM2 counts to 10, resets and starts counting again. The problem now is, that my ISR is not called when TIM2 overflows. Instead, the program simply "crashes" . I guess it enters some "default handler" on TIM2 overflow.

(The code is compiled as C code and not C++.)

#include <stdlib.h>

#include <stm32g031xx.h>

/*!
 * \brief Configures pin 5 ("PA11") as digital output.
 */
void config_output(void) {
  RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
  GPIOA->MODER &= ~(0x3u << (11 * 2));
  GPIOA->MODER |= (0x1u << (11 * 2));
  GPIOA->OTYPER &= ~(0x1u << (11 * 1));
}

/*!
 * \brief Configures TIM2 overflow with 10 us period (-> 100 kHz).
 */
void config_blink_timer(void) {
  //Enable the TIM2 clock.
  RCC->APBENR1 |= RCC_APBENR1_TIM2EN;

  //Make sure the timer's "counter" is off.
  TIM2->CR1 &= ~TIM_CR1_CEN;

  //Reset the peripheral.
  RCC->APBRSTR1 |= (RCC_APBRSTR1_TIM2RST);
  RCC->APBRSTR1 &= ~(RCC_APBRSTR1_TIM2RST);

  //Set the timer prescaler/autoreload timing registers.
  TIM2->PSC = 16 - 1; //-> 16 MHz / 16 = 1 MHz
  TIM2->ARR = 10 - 1; //-> 1/1 MHz * 10 = 10 us (100 kHz)

  //Send an update event to reset the timer and apply settings.
  TIM2->EGR |= TIM_EGR_UG;

  //Enable TIM2 interrupts.
  NVIC_EnableIRQ(TIM2_IRQn);
}

/*!
 * \brief Enables the "Cycle Timer", which will now fire interrupts that trigger
 * execution of the "App Loop" (--> \c TIM2_IRQHandler()).
 */
void run_app(void) {
  //Clear TIM2_IRQn update interrupt,
  TIM2->SR &= ~TIM_SR_UIF;

  //Enable the hardware interrupt.
  TIM2->DIER |= TIM_DIER_UIE;

  //Enable the timer.
  TIM2->CR1 |= TIM_CR1_CEN;
}

/*!
 * \brief Initializes any peripheral being used.
 */
void init(void) {
  //Disable interrupts.
  __disable_irq();

  config_output();
  config_blink_timer();

  //Enable interrupts.
  __enable_irq();
}

/*!
 * \brief Initializes the system and runs the application.
 */
int main(void) {
  init();

  run_app();

  while(1)
    __WFI();

  return EXIT_SUCCESS;
}

/*!
 * \brief This IRQ handler will be triggered every 10 us by the "Blink Timer".
 * This "time base" is used to blink a LED with a defined pattern (50 kHz,
 * 50% DS).
 */
void TIM2_IRQHandler(void) {
  //Toggle PA11 (pin 5).
  GPIOA->ODR ^= (0x1u << 11);

  //Clear TIM2 update interrupt flag.
  TIM2->SR &= ~TIM_SR_UIF;

  //Power-down until next "tick"/interrupt.
  __WFE();
}

Okay, the guys in this (German) forum (-> link to thread) put me on the right track and finally answered the question: We can fix the Problem by explicitly setting priority for TIM2_IRQn to "0". Instead of treating symptoms, however, it would be better to tackle the cause, which in this case can actually only be SysTick. However, I can no longer reproduce the problem with the original code ... If someone knows the answer to this strange phenomenon, he is of course welcome.

But basically the problem is solved for me now. The following code works fine:

#include <stdlib.h>

#include <stm32g031xx.h>

/*!
 * \brief Configures pin 5 ("PA11") as digital output.
 */
void config_output(void) {
  RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
  GPIOA->MODER &= ~(0x3u << (11 * 2));
  GPIOA->MODER |= (0x1u << (11 * 2));
  GPIOA->OTYPER &= ~(0x1u << (11 * 1));
}

/*!
 * \brief Configures TIM2 overflow with 10 us period (-> 100 kHz).
 */
void config_blink_timer(void) {
  //Enable the TIM2 clock.
  RCC->APBENR1 |= RCC_APBENR1_TIM2EN;

  //Make sure the timer's "counter" is off.
  TIM2->CR1 &= ~TIM_CR1_CEN;

  //Reset the peripheral.
  RCC->APBRSTR1 |= (RCC_APBRSTR1_TIM2RST);
  RCC->APBRSTR1 &= ~(RCC_APBRSTR1_TIM2RST);

  //Set the timer prescaler/autoreload timing registers.
  TIM2->PSC = 16 - 1; //-> 16 MHz / 16 = 1 MHz
  TIM2->ARR = 10 - 1; //-> 1/1 MHz * 10 = 10 us (100 kHz)

  //Send an update event to reset the timer and apply settings.
  TIM2->EGR |= TIM_EGR_UG;

  //Enable TIM2 interrupts and set priority.
  NVIC_EnableIRQ(TIM2_IRQn);
  NVIC_SetPriority(TIM2_IRQn, 0);
}

/*!
 * \brief Enables the "Cycle Timer", which will now fire interrupts that trigger
 * execution of the "App Loop" (--> \c TIM2_IRQHandler()).
 */
void start_app(void) {
  //Clear TIM2_IRQn update interrupt,
  TIM2->SR &= ~TIM_SR_UIF;

  //Enable the hardware interrupt.
  TIM2->DIER |= TIM_DIER_UIE;

  //Enable the timer.
  TIM2->CR1 |= TIM_CR1_CEN;
}

/*!
 * \brief Initializes any peripheral being used.
 */
void init(void) {
  //Disable interrupts.
  __disable_irq();

  config_output();
  config_blink_timer();

  //Enable interrupts.
  __enable_irq();
}

/*!
 * \brief Initializes the system and runs the application.
 */
int main(void) {
  init();

  start_app();

  while(1)
    __WFI();

  return EXIT_SUCCESS;
}

/*!
 * \brief This IRQ handler will be triggered every 10 us by the "Blink Timer".
 * This "time base" is used to blink a LED with a defined pattern (50 kHz,
 * 50% DS).
 */
void TIM2_IRQHandler(void) {
  //Clear TIM2 update interrupt flag.
  TIM2->SR &= ~TIM_SR_UIF;

  //Toggle PA11 (pin 5).
  GPIOA->ODR ^= (0x1u << 11);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM