Светодиод мигает слишком быстро @ NUCLEO-H755ZI-Q

Привет!

Согласно руководству STM32H755ZIRM0399, §9.5.6 (стр. 377), тактовая частота по умолчанию должна быть 64 МГц (HSI) после сброса. Поскольку тот же код отлично работал на других устройствах, таких как, например, NUCLEO-F303K8, я ожидал, что (красный) светодиод будет мигать с частотой 1 Гц. Но это не так. Я также пытался поиграть со значением прескалера ( TIM2->PSC), но это, похоже, не дает никакого эффекта... Кстати, светодиод действительно мигает, но с частотой ~7 Гц вместо ожидаемой 1 Гц. Кажется, что ISR запускается чем-то другим, но выполнение программы не доходит до 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 Гц, и теперь изменение значения прескалера имеет значение. Т.е. если я предполагаю 128 МГц вместо 64 МГц, я получаю 1 Гц 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();
}

0 ответов

Другие вопросы по тегам