Input Capture in STM32

This is yet another tutorial in the Timer Series in STM32, and today we will see how to use Input Capture in STM32.
We will use the input capture to measure the Frequency and width of the input signal.

Let’s see the Cube MX setup first.

CubeMX Setup

CLOCK CFG
  • Here I am going to use two timers, i.e Timer 1 for the PWM output and Timer 2 for the Input Capture
  • Timer 1 is connected to the APB2 clock, which is running at 180 MHz
  • Timer 2 is connected to the APB1 clock, which is running at 90 MHz

This part is very important. The minimum frequency, which the device can read will depend on it. Below is the configuration for the TIMER 2

TIM2 CFG
  • I have enabled the Input capture Direct Mode for channel 1
  • The Prescalar is set o 90, which would divide the APB2 clock by 90, making the Timer 2 clock = 1 MHz
  • I am leaving the ARR to 0xffffffff (Max for 32 bit Timer)
  • The minimum frequency that the Timer can read is equal to (TIMx CLOCK/ARR). In our case it will be (1MHz/0xffffffff) Hz.

The TIMER1 is configures to give a PWM output signal. If you want to know more about PWM output, check out the tutorial PWM (Pulse Width Modulation) in STM32 – Controllerstech.com



Measuring Frequency

In order to measure the Frequency of the input signal, we need to measure the time between the 2 rising edges, or between 2 falling edges.

Below is the figure explaining the same

  • When the first Rising edge occurs, the counter value is recorded.
  • Another counter value is recorded after the second rising edge occurs.
  • Now the difference between these 2 counter values is calculated.
  • The Difference in the counter values will give us the frequency.
  • This entire process is shown below
#define TIMCLOCK   90000000
#define PRESCALAR  90

uint32_t IC_Val1 = 0;
uint32_t IC_Val2 = 0;
uint32_t Difference = 0;
int Is_First_Captured = 0;

/* Measure Frequency */
float frequency = 0;

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
	{
		if (Is_First_Captured==0) // if the first rising edge is not captured
		{
			IC_Val1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); // read the first value
			Is_First_Captured = 1;  // set the first captured as true
		}

		else   // If the first rising edge is captured, now we will capture the second edge
		{
			IC_Val2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);  // read second value

			if (IC_Val2 > IC_Val1)
			{
				Difference = IC_Val2-IC_Val1;
			}

			else if (IC_Val1 > IC_Val2)
			{
				Difference = (0xffffffff - IC_Val1) + IC_Val2;
			}

			float refClock = TIMCLOCK/(PRESCALAR);

			frequency = refClock/Difference;

			__HAL_TIM_SET_COUNTER(htim, 0);  // reset the counter
			Is_First_Captured = 0; // set it back to false
		}
	}
}
  • The above callback function is called whenever the rising edge is detected.
  • When called first time, Is_First_Captured was 0 so the hence the IC_Val1 will be recorded.
  • When called after the second rising edge, the Is_First_Captured is 1 now so IC_Val2 will be recorded.
  • We will then calculate the Difference between the 2 values.
  • Reference clock is calculated based on the setup we have done for our timer.
  • Frequency is equal to the (Reference clock / Difference).

In the main function, we have to start the TIMER in the Input capture interrupt mode.
I am also starting the Timer 1 in the PWM mode, so to provide the signal for the Timer2.

  TIM1->CCR1 = 50;
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);

  HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
Frequency measured using input capture



Measuring Pulse Width

In order to measure the Pulse width, we want the interrupt to trigger on both the edges of the incoming signal.
To do so, we need to modify the CubeMX as shown below.

As you can see in the figure above, I have switched the Polarity to both the edges.
This will make the interrupt to trigger on both the edges of the incoming signal


  • When the first rising edge occurs, The counter value is stored in the ICVal 1
  • The next interrupt will occur at the falling edge, and the counter value is stored in the IC val 2
  • The Pulse width can be calculated using this counter value.
  • The process for the same is shown below
/* Measure Width */
uint32_t usWidth = 0;

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)  // if the interrupt source is channel1
	{
		if (Is_First_Captured==0) // if the first value is not captured
		{
			IC_Val1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); // read the first value
			Is_First_Captured = 1;  // set the first captured as true
		}

		else   // if the first is already captured
		{
			IC_Val2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);  // read second value

			if (IC_Val2 > IC_Val1)
			{
				Difference = IC_Val2-IC_Val1;
			}

			else if (IC_Val1 > IC_Val2)
			{
				Difference = (0xffffffff - IC_Val1) + IC_Val2;
			}

			float refClock = TIMCLOCK/(PRESCALAR);
			float mFactor = 1000000/refClock;

			usWidth = Difference*mFactor;

			__HAL_TIM_SET_COUNTER(htim, 0);  // reset the counter
			Is_First_Captured = 0; // set it back to false
		}
	}
}
  • The above callback function is called when either the Rising or Falling edge is detected.
  • When called for the rising edge, Is_First_Captured was 0 so the hence the IC_Val1 will be recorded.
  • When called for the falling edge, the Is_First_Captured is 1 now so IC_Val2 will be recorded.
  • We will then calculate the Difference between the 2 values.
  • This difference is the time for which the Pulse is high, and this time will depend on the timer configuration.
  • To measure this time in microseconds, we have to use the reference clock.
  • Reference clock is calculated based on the setup we have done for our timer.
  • And finally, the usWidth will be calculated.

Check out the VIDEO Below



DOWNLOAD

You can buy me a coffee Sensor by clicking DONATE OR Just click DOWNLOAD to download the code

controllerstech
Subscribe
Notify of
guest
17 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Menu