STM32 HAL Tutorial: Measuring Signal Frequency, Period, and Pulse Width
Abstract
Learn how to configure STM32 timers for input capture using HAL. Measure signal frequency, period, and pulse width with hands-on example.
1. Introduction
Timer Input Capture (IC) is used to:
- Measure external signal frequency
- Measure period or pulse width
- Trigger actions on rising/falling edges
Key concepts:
- Timer counts with a configured prescaler
- IC pin captures timer value when edge occurs
- Difference between captures allows time calculation
STM32 timers support multiple channels, each configurable as input capture.
2. Prerequisites
- STM32 board with TIMER
- STM32CubeIDE or VS Code installed
- Knowledge of HAL and TIMER
3. Timer Output Compare Overview
Parameter | Description |
Timer | Counts clock cycles at configured frequency |
Prescaler | Reduces timer clock to match expected signal |
Input channel | GPIO pin connected to signal |
Polarity | Rising, Falling, or Both edges |
Capture register | Stores timer value at input edge |
The hardware block diagram is usually shown like this, where the input signal goes into the TIMx_CH1:
In Input capture mode, the Capture/Compare Registers are used to latch the value of the Counter after a transition detected by the corresponding ICx signal. When a capture occurs, the corresponding flag is set and an interrupt or a DMA request can be sent if they are enabled.
The input capture module is used to capture the value of the counter after a transition is detected by the corresponding input channel. To get the external signal period, two consecutive captures are needed. The period is calculated by subtracting these two values:
- Period = Capture(1) /(TIMx_CLK *(PSC+1)*(ICxPSC)*polarity_index(2))
The capture difference between two consecutive captures CCRx_tn and CCRx_tn+1:
- If CCRx_tn < CCRx_tn+1: capture = CCRx_tn+1 – CCRx_tn
- If CCRx_tn > CCRx_tn+1: capture = (ARR_max – CCRx_tn) + CCRx_tn+1.
The polarity index is 1 if the rising or falling edge is used, and 2 if both edges are used.
4. CubeMX Configuration
1. Select Timer (e.g., TIM2)
2. Set Counter Mode = Up
3. Enable Input Capture Mode on channel 1
4. Set IC Polarity = Rising (or as needed)
5. Configure GPIO pin PA5 as alternate function for TIMx_CH1
6. Configure TIM3 as the PWM source
7. Configure the Clock tab
8. Generate HAL code
5. HAL Example: Timer Input Capture
/* USER CODE BEGIN PV */
uint32_t u32CaptureValue = 0;
uint32_t u32PreviousCaptureValue = 0;
uint32_t u32Frequency = 0;
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim2);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
uint32_t u32Delta = 0;
uint32_t u32ICValue1 = 0;
uint32_t u32ICValue2 = 0;
uint8_t u8FirstCapture = 0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
#ifdef SIMPLE_MEASUREMENT
u32CaptureValue = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
u32Frequency = HAL_RCC_GetPCLK1Freq()/ (u32CaptureValue - u32PreviousCaptureValue);
u32PreviousCaptureValue = u32CaptureValue;
#else
if(u8FirstCapture == 0)
{
u32ICValue1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
u8FirstCapture = 1;
}
else
{
u32ICValue2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
if(u32ICValue2 > u32ICValue1) //roll over did not happen
{
u32Delta = u32ICValue2 - u32ICValue1;
}
else
{
u32Delta = (0xFFFFFFFF - u32ICValue1) + u32ICValue2; //roll over happened
}
u32Frequency = HAL_RCC_GetPCLK1Freq()/ u32Delta;
htim->Instance->CNT = 0; //reset the counter
u8FirstCapture = 0;
}
#endif
}
// this code does not deal with overflow
}
/* USER CODE END 4 */
- HAL_TIM_IC_Start_IT() enables input capture interrupt
- HAL_TIM_IC_CaptureCallback() is triggered on edge capture
- Frequency or period can be calculated from timer counts
6. Hands-On Lab Example
- Connect a square wave signal to TIM2_CH1 pin
- Initialize timer in input capture mode
- Enable interrupts for input capture
- Observe captured values in u32ICValue1 and u32ICValue2
- Calculate signal frequency and period using formula
- Optional: Capture pulse width by measuring time between rising and falling edges
Tip: For precise measurement, choose prescaler to scale timer clock so that timer doesn’t overflow
7. Advantages
- Measures external signals accurately
- Works for frequency, period, and pulse width
- Can trigger events in firmware
- Can be combined with DMA for high-speed capture


