0

I am working on a project that will require timer interrupts.

Using STM32cubeIDE, I generated code that should work with timer-interrupts. Here is a truncation of what my main.cpp looks like: (htim1 is a global handle)

  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM1_Init();

  HAL_TIM_Base_Start_IT(&htim1);
  while(1);

Here is what MX_TIM1_INIT() looks like:

static void MX_TIM1_Init(void)
{

  /* USER CODE BEGIN TIM1_Init 0 */

  /* USER CODE END TIM1_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

  /* USER CODE BEGIN TIM1_Init 1 */

  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 84-1;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 0xFFFF-1;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */

  /* USER CODE END TIM1_Init 2 */
  HAL_TIM_MspPostInit(&htim1);

}

Here is what my interrupt handler looks like:

void TIM1_UP_TIM10_IRQHandler(void)
{
  /* USER CODE BEGIN TIM1_UP_TIM10_IRQn 0 */

  /* USER CODE END TIM1_UP_TIM10_IRQn 0 */
//    HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12); //O-SCOPE DEBUG on PA6
//  if (timer1 == nullptr) return;
    //timer1->TimerISR();
  HAL_TIM_IRQHandler(&htim1);
  /* USER CODE BEGIN TIM1_UP_TIM10_IRQn 1 */

  /* USER CODE END TIM1_UP_TIM10_IRQn 1 */
}

And here is my callback function:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
     HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12); //O-SCOPE DEBUG on PA6
}

No matter what I do I can't get the debugger to even enter the handler.... Could anyone enlighten me as to what I am doing wrong? Thanks!

  • Try to enable update interrupt through NVIC Settings tab of timer configuration window. – recep Mar 23 '21 at 09:44

1 Answers1

2

I would never use HAL library to set up the timers. It makes no sense for me. In the example below I will omit clock (in my case 168MHz) & GPIO settings. As you did not state what model of STM32F4 you use, this code was tested using STM32F446RET uC. Other STM32F4 have identical timers.

  1. Setting the timer:
  __HAL_RCC_TIM1_CLK_ENABLE();

  TIM1 -> PSC = (20000 - 1);
  TIM1 -> ARR = (4200 - 1);

  //168e6 / (20000 * 4200) = 2 - two interrupts per second

  TIM1 -> EGR |= TIM_EGR_UG;  // reinitialize the counter and reload registers
  TIM1 -> DIER |= TIM_DIER_UIE;

  NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);

  TIM1 -> CR1 = TIM_CR1_CEN;
  1. The interrupt handler. If you program in C++ handlers have to be declared as extern "C" !!!
//if you compile as C++ you need to declare handlers as "normal" C functions
//#ifdef`s are not needed if this code will never be compiled as C progream
#ifdef __cplusplus
extern "C" {
#endif

void TIM1_UP_TIM10_IRQHandler(void)
{
    if(TIM1 -> SR & TIM_SR_UIF)
    {
        TIM1 -> SR = ~(TIM_SR_UIF); // clear UIF flag
        GPIOA -> ODR ^= 1 << 5;   // toggle PA5
    }
}

#ifdef __cplusplus
}
#endif

And my LED connected to PA5 changes the state every 500ms.

Job done - isn't it easier than HAL?

0___________
  • 34,740
  • 4
  • 19
  • 48
  • I will implement this tomorrow and let you know how it goes. Thank you so much! – Jonathan Just Mar 23 '21 at 00:54
  • This worked! Why is it that I have to make my functions compile as C? I didn't have to do that for my UART. Thanks! – Jonathan Just Mar 23 '21 at 15:40
  • @JonathanJust because C++ changes the name and it does not match the irq handler name in the startup file. It is called "mangling". To disable it you need to tell compiler that it is the C function. It was done by someone else in your UART. It will not work without `extern "C"` – 0___________ Mar 23 '21 at 16:52