TIM2溢出不触发TIM2_IRQHandler@STM32G031J6
TIM2 overflow does not trigger TIM2_IRQHandler @ STM32G031J6
使用以下代码,我想让 STM32G031J6M6 的引脚 5 (PA11) 以 50 kHz 的频率闪烁。为此,我将 TIM2 配置为每 10 微秒溢出一次。这是为了调用一个 ISR(“TIM2_IRGHandler”)来切换 PA11 的电平。
现在一切正常:切换正常,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();
}
好的,这个(德语)论坛 (-> 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);
}
使用以下代码,我想让 STM32G031J6M6 的引脚 5 (PA11) 以 50 kHz 的频率闪烁。为此,我将 TIM2 配置为每 10 微秒溢出一次。这是为了调用一个 ISR(“TIM2_IRGHandler”)来切换 PA11 的电平。 现在一切正常:切换正常,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();
}
好的,这个(德语)论坛 (-> 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);
}