0
\$\begingroup\$

I am experiencing a really odd behavior of the STM32s timer interrupt. I have two timers. tim3 runs at a fixed 40 Hz and calls a registered function if updated. tim2 is started after tim3 caused an interrupt and should run for one cycle with a duration of 184 us. It is stopped afterwards. A GPIO pin is used to show the result on an oscilloscope. The following code is working as expected.

void BaseClockCb (TIM_HandleTypeDef *htim) {
    HAL_GPIO_WritePin(Test_GPIO_Port, Test_Pin, GPIO_PIN_SET);
    HAL_TIM_Base_Start_IT(&htim2);
}

void BreakCb (TIM_HandleTypeDef *htim) {
    HAL_TIM_Base_Stop_IT(&htim2);
    __HAL_TIM_SET_COUNTER(&htim2, 0);
    HAL_GPIO_WritePin(Test_GPIO_Port, Test_Pin, GPIO_PIN_RESET);
}

void SystemClock_Config(void);

int main (void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_RegisterCallback(&htim3, HAL_TIM_PERIOD_ELAPSED_CB_ID, &BaseClockCb);
  HAL_TIM_RegisterCallback(&htim2, HAL_TIM_PERIOD_ELAPSED_CB_ID, &BreakCb);

  HAL_TIM_Base_Start_IT(&htim3);
  /* USER CODE END 2 */



  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
}

This produces a 184 us peak every 25 ms on the GPIO pin. However, the code breaks if tim2 is started in the main loop via a flag.

uint8_t flag = 0;

void BaseClockCb (TIM_HandleTypeDef *htim) {
    flag = 1;
}

void BreakCb (TIM_HandleTypeDef *htim) {
    HAL_TIM_Base_Stop_IT(&htim2);
    __HAL_TIM_SET_COUNTER(&htim2, 0);
    HAL_GPIO_WritePin(Test_GPIO_Port, Test_Pin, GPIO_PIN_RESET);
}

void SystemClock_Config(void);

int main (void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_RegisterCallback(&htim3, HAL_TIM_PERIOD_ELAPSED_CB_ID, &BaseClockCb);
  HAL_TIM_RegisterCallback(&htim2, HAL_TIM_PERIOD_ELAPSED_CB_ID, &BreakCb);

  HAL_TIM_Base_Start_IT(&htim3);
  /* USER CODE END 2 */



  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      if(flag) {
          flag = 0;
          HAL_GPIO_WritePin(Test_GPIO_Port, Test_Pin, GPIO_PIN_SET);
          HAL_TIM_Base_Start_IT(&htim2);
      }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

This code results in a couple of us long peak. The BreakCb function is called way before it is supposed to be. This always happens if the tim2 is started from the main loop, even if you do something like this and remove tim3.

 while (1)
    {
        HAL_GPIO_WritePin(Test_GPIO_Port, Test_Pin, GPIO_PIN_SET);
        HAL_TIM_Base_Start_IT(&htim2);
        HAL_Delay(25);
    }

Has anybody experienced this behavior before and knows why it happens? Thank you

\$\endgroup\$
  • \$\begingroup\$ It should be "volatile uint8_t flag = 0;", if "flag" can get accessed both from an interrupt and main program flow. \$\endgroup\$ – jms Feb 28 at 13:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.