cancel
Showing results for 
Search instead for 
Did you mean: 

TIM4 in OC Toggle mode does not always work with TIM_OC_Start_IT() and TIM_OC_Stop_IT()

Kmax18
Senior II

Hello, this is my equipment: 
1) MCU STM32G0B1RETx (LQFP64 packaging) on a custom board.
2) STM32CubeIDE Version: 1.17.0.
3) STM32CubeMX Version 6.13.0.

For visual indicators (LEDs flashing) we use the TIM4 CH1 in OC Toggle mode (no output). The timer configuration was created with the MX software.
TIM4 CH1 generates a periodic signal with a frequency of 2 Hz, which requires a CCR1 value of 5000:

CCR1 value = f_TIM4_CNT_CLK / (2 * f_TIM4_CH1) = 10000 Hz/(2 * 1 Hz) = 5000

The relevant source code is listed below. It is loosely based on the ST HAL example 'TIM_OCToggle': This solution works only partially.
* The function TIM4_sequence_start() initiates the timer OC toggle sequence, while
* the function HAL_TIM_OC_DelayElapsedCallback() counts the interrupts and stops the OC toggle sequence after the specified number of interrupts, that is, 2 x LED flashes.

Problem description:

The timer OC toggle sequence does not start every time the function TIM4_sequence_start() is called.
Example: in the following scenario the interrupts only work the first time and the third time, nothing happens the second time. There is sufficient time between the sequences (6 seconds), therefore timing is probably not an issue.
This behavior is consistent:

  • TIM4_sequence_start().    >>> initiates 3 LED flashes (6 interrupts) using TIM_OC_Start_IT().
  • HAL_TIM_OC_DelayElapsedCallback() stops the sequence with TIM_OC_Stop_IT().  >>> works as expected
  • Wait 6 seconds
  • TIM4_sequence_start()    >>> initiates 3 LED flashes (6 interrupts) using TIM_OC_Start_IT().
  • HAL_TIM_OC_DelayElapsedCallback()    >>> Does not work, no interrupts
  • Wait 6 seconds
  • TIM4_sequence_start()    >>> initiates 3 LED flashes (6 interrupts) using TIM_OC_Start_IT().
  • HAL_TIM_OC_DelayElapsedCallback()    >>> works as expected

Question 1:

Are the HAL functions TIM_OC_Start_IT() and TIM_OC_Stop_IT() sufficient?
Is it necessary to clear any timer register bits, or re-enable the interrupt after calling TIM_OC_Stop_IT?

Question 2:

Could the issue be caused by NVIC priorities?
Both TIM3 (10 ms time base) and TIM4 (OC toggle mode) have a higher NVIC priority than Systick, which is used for periodic, unrelated checks. See the below screenshot.

Kmax18_0-1741578692921.png

Please advise. Thank you!

 

 

 

HAL_StatusTypeDef TIM4_sequence_start(int16_t sysError)
{
    /* Verify that all TIM1 channels are ready (not busy) */
    if ( ( TIM_CHANNEL_STATE_GET(&htim4, TIM_CHANNEL_1) ||
           TIM_CHANNEL_STATE_GET(&htim4, TIM_CHANNEL_2) ||
           TIM_CHANNEL_STATE_GET(&htim4, TIM_CHANNEL_3) ||
           TIM_CHANNEL_STATE_GET(&htim4, TIM_CHANNEL_4) ) != HAL_TIM_CHANNEL_STATE_READY)
    {
        Error_Handler();
    }

  // Reset the TIM4 interrupt counter
  TIM4IrqCount = 0;

  /* Start the timer channel in Output Compare mode */
  halError = HAL_TIM_OC_Start_IT(&htim4, TIM_CHANNEL_1);
  if(halError != HAL_OK)
  {
      Error_Handler();
  }

  return HAL_OK;
}  // TIM4_sequence_start



void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
    uint16_t autoreload_value;
    uint32_t uhCapture = 0;

    /* Get configured autoreload value */
    autoreload_value = __HAL_TIM_GET_AUTORELOAD(htim);

    if (htim == &htim4)
    {
        if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)     /* TIM1_CH1 toggle */
        {
            /* Number of expected OC interrupts = 2 * Beeps/LED flashes */
            TIM4IrqCount++;
            if (TIM4IrqCount >= 2 * asidError.numErrorBeeps)
            {
                TIM4IrqCount = 0;   // Reset for next error indicator
                halError = HAL_TIM_OC_Stop_IT(htim, TIM_CHANNEL_1);
                if(halError != HAL_OK)
                {
                    /* Stop Error */
                    Error_Handler();
                }
            }
            else
            {
                /* [kmathia] TIM1 time stamp: start time */
                uhCapture = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);

                /* Set the Capture Compare Register value */
                /* If elapsed time CCR1_VALUE has not reached autoreload ('reset'),
                 * otherwise keep the CCR value within the autoreload time */
                if (uhCapture + TIM4_CCR1_VALUE < autoreload_value)
                {
                    __HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, (uhCapture + TIM4_CCR1_VALUE));
                }
                else
                {
                    __HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, (uhCapture + TIM4_CCR1_VALUE) - autoreload_value);
                }
            }
        }
        }

        switch (sysError)
        {
            case ERR_LEFTMOTOR:  // nVR2 error, left motor hardware
                HAL_GPIO_TogglePin(LED_BAT1_R_GPIO_Port, LED_BAT1_R_Pin);
                HAL_GPIO_TogglePin(LED_BAT2_Y_GPIO_Port, LED_BAT2_Y_Pin);
                HAL_GPIO_TogglePin(LED_BAT3_Y_GPIO_Port, LED_BAT3_Y_Pin);
                HAL_GPIO_TogglePin(HORN_GPIO_Port, HORN_Pin);
                break;
            default:
                Error_Handler();
                break;
        }
    }
}

 

 

 

 

 

 

 

 

 

 

0 REPLIES 0