简体   繁体   English

TIM2溢出不触发TIM2_IRQHandler@STM32G031J6

[英]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.使用以下代码,我想让 STM32G031J6M6 的引脚 5 (PA11) 以 50 kHz 的频率闪烁。 To do this, I configured TIM2 to overflow every 10 us.为此,我将 TIM2 配置为每 10 us 溢出一次。 This is to call an ISR ("TIM2_IRGHandler") that toggles the level of PA11.这是为了调用一个 ISR(“TIM2_IRGHandler”)来切换 PA11 的电平。 Now everything actually works fine: the toggle works and TIM2 counts to 10, resets and starts counting again.现在一切正常:切换正常,TIM2 计数到 10,重置并再次开始计数。 The problem now is, that my ISR is not called when TIM2 overflows.现在的问题是,当 TIM2 溢出时,我的 ISR 没有被调用。 Instead, the program simply "crashes" .相反,程序只是“崩溃”了 I guess it enters some "default handler" on TIM2 overflow.我猜它会在 TIM2 溢出时进入一些“默认处理程序”。

(The code is compiled as C code and not C++.) (代码被编译为 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();
}

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".好的,这个(德语)论坛(-> 线程链接)中的人让我走上了正确的轨道,并最终回答了这个问题:我们可以通过将 TIM2_IRQn 的优先级明确设置为“0”来解决问题。 Instead of treating symptoms, however, it would be better to tackle the cause, which in this case can actually only be SysTick.然而,与其治疗症状,不如解决原因,在这种情况下,它实际上只能是 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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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