STM32 - Timers - Measuring Time

From Embedded Workshop
Jump to navigation Jump to search

Timers

Each of the STM32 parts has multiple timers, but some are better than others for measuring the duration of a function.

Profiling

I firmly believe until you actually measure the time a function takes, you are just guessing,
thinking "the function is working just fine"....
But, to measure the duration of many functions, you need a time base much finer than an OS Tick.
Micro-second resolution is often required.
Although I'd like a 32 bit timer, not all the STM32 parts have one.
I'm pretty sure all have at least a 16-bit timer.  Let's choose an unused timer, and get it
counting micro-second units of time.

Choose and Configure A Timer

Open STM32CubeIDE, <project>.ioc file to look at the timers and find one that's available
1) Click on "Pinout & Configuration" tab
2) Click on "Timers"
3) For STM32 devices without a 32-bit timer, like the STM32-F103RB, use TIM4
   (If your device has a 32-bit timer, like TIM5, use that)
4) Since we don't need an output pin for this timer, configure it as follows:
   Slave Mode: Disable
   Trigger Source: Disable
   □  Internal Clock - unchecked
   Channel1: PWM Generation No Output
5) In the Parameter Settings section, configure as follows:
   Prescaler (PSC -16 bits value): 72-1     This assumes the SYSCLK is 72MHz.  (Adjust accordingly)
   Counter Mode: Up
   Counter Period (AutoReload Register - 16 bits value): 65535
   Internal Clock Division (CKD): No Division
   auto-reload preload: Disable
   PWM Generation Channel 1
   Mode: PWM mode 1
   Pulse (16 bits value): 0
   Output compare preload Enable
   Fast Mode: Disable
   CH Polarity: High

The above selections will configure Timer4 to run as a 1us period timer

Start The Timer

In main.c, find the function, MX_TIM4_Init()
Insert HAL_TIM_Base_Start() function call between the comments as shown below:
 /* USER CODE BEGIN TIM4_Init 2 */
 // Start timer running
 HAL_TIM_Base_Start(&htim4);
 /* USER CODE END TIM4_Init 2 */

Use The Timer

Within the body of the code, where you wish to time something, like HAL_Delay(50), use something like the following:
volatile TIM_TypeDef *TIMx = TIM4; // Use data structure pointer to access TIM4 registers
uint32_t start_us = TIMx->CNT; // read us hardware timer
HAL_Delay(50); // delay 50us
uint32_t stop_us = TIMx->CNT; // read us hardware timer
// Report results
if(stop_us < start_us) stop_us += 1<<16; // roll-over, add 16-bit roll-over offset
printf("TIM4 time: %lu us\n",stop_us - start_us);