cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103 TIM2 counting properly but won't interrupt

RPasc.2
Associate III

For a simple LED Blink program using interrupts, TIM2 is counting correctly, but its IRQs are not happening. As expected, there are about 1440 TIM2 "count-outs" per 1.0 seconds.

Over the past few years several CubeMX timer IRQ bugs have surfaced, but I'd expect they would have been fixed by now. Are there any left to be resolved ?

Most probably I have missed some MX configuration, but I have no idea where that would be. Any ideas and pertinent experience will be appreciated.

Here are the two MX TIM2 configuration screen shots:

(I hope you see the full-size images and not the tumbnails I see.) This message editor's file-attachment button is grayed-out!)

0693W000006HKb5QAG.png 

0693W000006HKbKQAW.pngHere's the entire program code:

/*  2020-12-30 10:50:07 PM
    main.c    C:\Users\HTPC\STM32CubeIDE\workspace_1.5.0\BluePill_Timer_NonBlocking\Core\Src
    "STM32 Timers and Timer Interrupts"
    https://www.digikey.be/en/maker/projects/getting-started-with-stm32-timers-and-timer-interrupts/d08e6493cefa486fb1e79c43c0b08cc6
    Example 3: Interrupt-driven LED timer to blink the BluePill User LED.
*/
...
/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;
UART_HandleTypeDef huart2;
 
/* CubeMX-generated System Function Prototypes
   System Function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_TIM2_Init(void);
 
int main(void)
{
    /* USER CODE BEGIN 1 */
    // {null}
 
    /* MCU Configuration--------------------------------------------------------
       Reset of all peripherals, init the Flash ixface and the System clock rate. */
    HAL_Init();
 
    /* Configure the system clock */
    SystemClock_Config();
 
    /* USER CODE BEGIN SysInit */
    // {null}
 
    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    // Configure LED GPIO pin Output Level = Off/'1'; LED is a current source.
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);  // Init: LED=Off
    //
    MX_USART2_UART_Init();
    MX_TIM2_Init();
 
    // For serial TX. RX unused but configured for use.
    char uart_buf[50];
    int uart_buf_len;
    uint16_t timer_start_cnt, timer_delta_cnt;
 
    // "Start-of-Program" header for terminal display..
    uart_buf_len = sprintf(uart_buf, "\n\rProgram Start:\n\r");
    HAL_UART_Transmit(&huart2, (uint8_t *)uart_buf, uart_buf_len, 100);
 
    /* USER CODE BEGIN 2
       Start the timer. */
    HAL_TIM_Base_Start_IT(&htim2);
 
    while (1)   // MAIN LOOP
    {
        /* USER CODE BEGIN 3 */
        timer_start_cnt = __HAL_TIM_GET_COUNTER(&htim2);
        HAL_Delay(1000);
 
        // Get end count and calc the elapsed.
        timer_delta_cnt = __HAL_TIM_GET_COUNTER(&htim2) - timer_start_cnt;
 
        // Send the elapsed count for the display.
        uart_buf_len = sprintf(uart_buf, "%u ticks\n\r", timer_delta_cnt);
        HAL_UART_Transmit(&huart2, (uint8_t *)uart_buf, uart_buf_len, 100);
    }
}  // end Main
 
/* System Clock Configuration */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
    /* Initializes the RCC Oscillators according to the s
       pecified parameters in the RCC_OscInitTypeDef structure.
    */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }
 
    /* Initializes the CPU, AHB and APB buses clocks. */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    {
        Error_Handler();
    }
}
 
/* TIM2 Init Function */
static void MX_TIM2_Init(void)
{
    /* USER CODE BEGIN TIM2_Init 0 */
    TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    TIM_MasterConfigTypeDef sMasterConfig = {0};
 
    /* USER CODE BEGIN TIM2_Init 1
    BluePill APB2 input system clock to timer = 72 MHz
    Let TIM2_Prescaler = 50,000 --> F_TIMER2 = 1,440 Hz (F_LED = 0.5 Hz)
 
    Use a static variable to count timer overflow events.
    Set the counter period to 770 for a 0.500 sec interrupt rate to toggle the LED.
    */
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 50000;   // F_TIM2CLK --> 1440 Hz toggle rate
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 32768;      // 50% of 2**16
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
    {
        Error_Handler();
    }
    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
    {
        Error_Handler();
    }
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
    {
        Error_Handler();
    }
 
    /* USER CODE BEGIN TIM2_Init 2 */
    // {null}
}
...
 
/* USER CODE BEGIN 4 */
// Callback: timer has counted out.
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    static int timer_ITR_ctr = 0;
 
    // Check if timer MX_TIM2 triggered this IRQ handler callback.
    if (htim == &htim2)
    {
        timer_ITR_ctr = timer_ITR_ctr + 1;  // Intentional simple increment.
        if (timer_ITR_ctr == 720)           // 0.5 secs elapsed: Toggle the LED output pin state.
        {
            HAL_GPIO_TogglePin(GPIOA, LED_Pin) ;
            //HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);   // Turn LED On.
 
            // 0.500 seconds has passed.
            timer_ITR_ctr = 0;  //Prepare to count another 720 count-outs.
        }
    }
}
...

16 REPLIES 16
RPasc.2
Associate III

These checkboxes were checked when the project was first created.

I regenerated the project: Nowhere is a call made to HAL_TIM_PeriodElapsedCallback.

The call to HAL_TIM_PeriodElapsedCallback is done within HAL_TIM_IRQHandler. It wouldn't and shouldn't be in your project code, it's part of the drivers.
See for yourself:
https://github.com/STMicroelectronics/STM32CubeF1/blob/003dfc9e6c2e424c19a25df3934afaf7fce660d6/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c#L3859
If you feel a post has answered your question, please click "Accept as Solution".
RPasc.2
Associate III

Then, shouldn't the call be made and be able to be found in the drivers' code ?

Isn't the drivers' code within the MXCube-generated project code ?

Yes. It's in the same file as HAL_TIM_Start and all the other HAL_TIM_* calls. I linked to the exact line it's called.
If you feel a post has answered your question, please click "Accept as Solution".
RPasc.2
Associate III

In file stm32f1xx_it.c there is only a call to HAL_TIM_IRQHandler(&htim2); and none to HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim).

TDK
Guru

Yep, that's how it works. As stated above:

"The call to HAL_TIM_PeriodElapsedCallback is done within HAL_TIM_IRQHandler."

Good luck.

If you feel a post has answered your question, please click "Accept as Solution".
RPasc.2
Associate III

There is neither a function called "HAL_TIM_Start()" nor a call to it.

It's also puzzling thet there is no function defined in the project directory tree named "HAL_TIM_IRQHandler()", yet function the "TIM2_IRQHandler()" makes a call to it. How can that be ? Shouldn't the linker complain loudly about this ?