你好!
根据STM32H755ZI的手册RM0399 §9.5.6(第 377 页),复位后默认时钟应为 64 MHz(HSI)。由于相同的代码在其他设备上运行良好,例如 NUCLEO-F303K8,我预计(红色)LED 以 1 Hz 的频率闪烁。但是,事实并非如此。我还尝试使用预分频器值TIM2->PSC
(似乎 ISR 是由其他东西触发的,但是如果我只是禁用TIM2
.
/*!*****************************************************************************
* \file main.cpp
* \brief
* This program implements a very basic application that makes a LED blink with
* 1 Hz.
*/
#include <stdlib.h>
#include <stm32h755xx.h>
#define SYSTEM_CLOCK 64000000
/*!
* \brief Configures pin PB14 ("LD3/Red LED") as digital output.
*/
static void Config_Red_Led(void) {
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOBEN;
GPIOB->MODER &= ~(0x3u << (2 * 14));
GPIOB->MODER |= (0x1u << (2 * 14));
GPIOB->OTYPER &= ~(0x1u << 14);
GPIOB->ODR = ~(0x1u << 14);
}
/*!
* \brief Configures TIM2 overflow with 10 us period.
*/
static void Config_10us_Blink_Timer(void) {
//Enable the TIM2 clock.
RCC->APB1LENR |= RCC_APB1LENR_TIM2EN;
//Enable TIM2 interrupts.
NVIC_EnableIRQ(TIM2_IRQn);
//Make sure the timer's "counter" is off.
TIM2->CR1 &= ~TIM_CR1_CEN;
//Reset the peripheral.
RCC->APB1LRSTR |= (RCC_APB1LRSTR_TIM2RST);
RCC->APB1LRSTR &= ~(RCC_APB1LRSTR_TIM2RST);
//Set the timer prescaler/autoreload timing registers.
TIM2->PSC = SYSTEM_CLOCK / 1000000;
TIM2->ARR = 10 - 1;
//Send an update event to reset the timer and apply settings.
TIM2->EGR |= TIM_EGR_UG;
}
/*!
* \brief Enables the "Blink Timer", which will now fire interrupts that trigger
* execution of the "App Loop" (--> \c TIM2_IRQHandler()).
*/
static 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.
*/
static void Init(void) {
//Disable CPU to respond to any configurable interrupt.
__disable_irq();
Config_Red_Led();
Config_10us_Blink_Timer();
//Enable CPU to respond to any configurable interrupt.
__enable_irq();
}
/*!
* \brief Initializes the system and runs the application.
*/
int main(void) {
Init();
Run_App();
while(true);
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.
*/
extern "C" void TIM2_IRQHandler(void) {
//Blink the LED with a PWM signal of 1 Hz period and 50% DS.
{
static auto s = 0;
if(++s >= 50000) {
//Toggle PB14, which is the LED ("LD3/Red LED").
GPIOB->ODR ^= (1 << 14);
s = 0;
}
}
//Clear TIM2 update interrupt flag.
TIM2->SR &= ~TIM_SR_UIF;
//Power-down until next "tick"/interrupt.
//__WFE();
}
如果我改用 TIM6,频率约为 2 Hz,现在修改预分频器值确实很重要。即,如果我假设 128 MHz 而不是 64 MHz,我会得到 1 Hz LED Blinker:
/*!*****************************************************************************
* \file main.cpp
* \brief
* This program implements a very basic application that makes a LED blink with
* 1 Hz.
*/
#include <stdlib.h>
#include <stm32h755xx.h>
/*!
* \brief Configures pin PB14 ("LD3/Red LED") as digital output.
*/
static void Config_Red_Led(void) {
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOBEN;
GPIOB->MODER &= ~(0x3u << (2 * 14));
GPIOB->MODER |= (0x1u << (2 * 14));
GPIOB->OTYPER &= ~(0x1u << 14);
GPIOB->ODR = ~(0x1u << 14);
}
/*!
* \brief Configures TIM6 overflow with 10 us period.
*/
static void Config_10us_Blink_Timer(void) {
//Enable the TIM6 clock.
RCC->APB1LENR |= RCC_APB1LENR_TIM6EN;
//Enable TIM6 interrupts.
NVIC_EnableIRQ(TIM6_DAC_IRQn);
//Make sure the timer's "counter" is off.
TIM6->CR1 &= ~TIM_CR1_CEN;
//Reset the peripheral.
RCC->APB1LRSTR |= (RCC_APB1LRSTR_TIM6RST);
RCC->APB1LRSTR &= ~(RCC_APB1LRSTR_TIM6RST);
//Set the timer prescaler/autoreload timing registers.
TIM6->PSC = 128000000 / 1000000;
TIM6->ARR = 10 - 1;
//Send an update event to reset the timer and apply settings.
TIM6->EGR |= TIM_EGR_UG;
}
/*!
* \brief Enables the "Blink Timer", which will now fire interrupts that trigger
* execution of the "App Loop" (--> \c TIM6_DAC_IRQHandler()).
*/
static void Run_App(void) {
//Clear TIM6_IRQn update interrupt,
TIM6->SR &= ~TIM_SR_UIF;
//Enable the hardware interrupt.
TIM6->DIER |= TIM_DIER_UIE;
//Enable the timer.
TIM6->CR1 |= TIM_CR1_CEN;
}
/*!
* \brief Initializes any peripheral being used.
*/
static void Init(void) {
//Disable CPU to respond to any configurable interrupt.
__disable_irq();
Config_Red_Led();
Config_10us_Blink_Timer();
//Enable CPU to respond to any configurable interrupt.
__enable_irq();
}
/*!
* \brief Initializes the system and runs the application.
*/
int main(void) {
Init();
Run_App();
while(true);
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.
*/
extern "C" void TIM6_DAC_IRQHandler(void) {
//Blink the LED with a PWM signal of 1 Hz period and 50% DS.
{
static auto s = 0;
if(++s >= 50000) {
//Toggle PB14, which is the LED ("LD3/Red LED").
GPIOB->ODR ^= (1 << 14);
s = 0;
}
}
//Clear TIM6 update interrupt flag.
TIM6->SR &= ~TIM_SR_UIF;
//Power-down until next "tick"/interrupt.
//__WFE();
}