TIM2 溢出不会触发 TIM2_IRQHandler @ STM32G031J6

Posted

技术标签:

【中文标题】TIM2 溢出不会触发 TIM2_IRQHandler @ STM32G031J6【英文标题】:TIM2 overflow does not trigger TIM2_IRQHandler @ STM32G031J6 【发布时间】:2021-12-02 00:07:14 【问题描述】:

通过以下代码,我想让 STM32G031J6M6 的引脚 5 (PA11) 以 50 kHz 闪烁。为此,我将 TIM2 配置为每 10 us 溢出一次。这是调用一个切换 PA11 电平的 ISR(“TIM2_IRGHandler”)。 现在一切正常:切换正常工作,TIM2 计数为 10,重置并再次开始计数。 现在的问题是,当 TIM2 溢出时,我的 ISR 没有被调用。相反,程序只是“崩溃”。我猜它会在 TIM2 溢出时进入一些“默认处理程序”。

(代码编译为 C 代码,不是 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();

【问题讨论】:

我不记得这个硬件但是你应该从后台程序中反复调用TIM2-&gt;SR &amp;= ~TIM_SR_UIF;吗?这不是你的中断正在寻找的标志吗? 是的,该标志必须由软件清除。它不会自动/由硬件清除。 ...但这不是您的 ISR 所基于的标志,因此只能从 ISR 中清除它吗? @Lundin run_app 不会在循环中调用。 在 IRQ 处理程序中执行 WFE 似乎是一个挂起的秘诀,如果你删除它怎么办? 【参考方案1】:

好的,这个(德国)论坛(-> link to thread) 的人让我走上了正确的道路,最后回答了这个问题:我们可以通过将 TIM2_IRQn 的优先级明确设置为“0”来解决问题。然而,与其治疗症状,不如解决原因,在这种情况下,实际上只能是 SysTick。 但是,我无法再用原始代码重现问题了……如果有人知道这个奇怪现象的答案,当然欢迎。

但现在基本上问题已经解决了。以下代码可以正常工作:

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

【讨论】:

以上是关于TIM2 溢出不会触发 TIM2_IRQHandler @ STM32G031J6的主要内容,如果未能解决你的问题,请参考以下文章

在没有隐藏溢出的情况下,transitionend 事件在 FireFox 中没有持续触发

移动 Safari - 输入插入符号不会随着溢出滚动一起滚动:触摸

STM32定时器溢出模式计时设置

导致除法溢出错误 (x86)

detours hooked CreateFile 函数触发堆栈溢出

ADC配置成定时器触发的启发