2021-01-02 03:46 PM
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!)
Here'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.
}
}
}
...
2021-01-10 09:59 AM
These checkboxes were checked when the project was first created.
I regenerated the project: Nowhere is a call made to HAL_TIM_PeriodElapsedCallback.
2021-01-10 10:08 AM
2021-01-10 10:12 AM
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 ?
2021-01-10 10:16 AM
2021-01-10 10:20 AM
In file stm32f1xx_it.c there is only a call to HAL_TIM_IRQHandler(&htim2); and none to HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim).
2021-01-10 10:27 AM
Yep, that's how it works. As stated above:
"The call to HAL_TIM_PeriodElapsedCallback is done within HAL_TIM_IRQHandler."
Good luck.
2021-01-10 07:58 PM
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 ?