首页 > 解决方案 > LED 闪烁“太快”@ NUCLEO-H755ZI-Q

问题描述

你好!

根据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();
}

标签: stm32nucleostm32h7

解决方案


推荐阅读