Input capture in STM32

Today I have finally decided to write on this topic. Timers are and always have been one of the most challenging topic in any microcontroller. So today We are going to use one of the functionality of STM32 Timers i.e Input Capture.

As the name implies, Input capture is used to capture the input signal given to the microcontroller and measures its frequency and pulse width. In this tutorial, I will only cover the frequency part and the pulse width will be covered in next one where we will use PWM Input to do that.



HOW TO


Input capture works in the following way:-
(1) Whenever a rising edge is detected, a callback function is called.
(2) Here we are going to capture the TIMESTAMP and store it in some variable
(3) On detecting the second rising edge, another TIMESTAMP will be captured and stored
(4) Now the frequency can be calculated by first finding the difference between these 2 captured values and than dividing the timer clock by this difference.

Yeah I know it's not that hard to understand it. But while implementing, we need to take care of few things and we will see them along this explanation. So let me start with the CubeMx first



As you can see in the clock configuration that all Timer clocks are at 45 MHz. Anyway I am going to select TIM3 which is connected to the APB1 Clock in F446RE and which is running at 45MHz.

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




You can see above that the only thing I changed from default setup is that I enabled the Channel 1 Input Capture mode and the ARR is set to 0xffff. This is the max value to which the time is going to count.

The minimum frequency that the Timer can read is equal to (TIMx CLOCK/ARR). In our case it will be (45MHz/65536) = 687 Hz. You can check this in the video below that if the frequency input is less than this, the controller will just show some garbage value.


We can decrease the TIMx clock to reduce the minimum frequency but this will also reduce the maximum frequency that can be measured. So you have to be very reasonable about the range here.


Some Insight into the CODE


void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
 if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
 {
  if (Is_First_Captured==0)
  {
   IC_Value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
   Is_First_Captured =1;
  }

  else if (Is_First_Captured)
  {
   IC_Value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
   Difference = IC_Value2-IC_Value1;
   Frequency = HAL_RCC_GetPCLK1Freq()/Difference;
   Is_First_Captured = 0;
  }
 }
}

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 in the second rising edge, the Is_First_Captured is 1 now so IC_Val2 will be recorded and you can see the rest.

Frequency is equal to the (TIMx clock / Difference). In my case TIM3 CLOCK is same as PCLK1 but it might not be same in your case so make sure you do the correction here.

In the main function, we have to start the TIMER in the Input capture interrupt mode by using

HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);


CODE

uint32_t IC_Value1 = 0;
uint32_t IC_Value2 = 0;
uint32_t Difference = 0;
uint32_t Frequency = 0;
uint8_t Is_First_Captured = 0;  // 0- not captured, 1- captured


void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
 if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)  // if interrput source is channel 1
 {
  if (Is_First_Captured==0)  // is the first value captured ? 
  {
   IC_Value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);  // capture the first value
   Is_First_Captured =1;  // set the first value captured as true
  }

  else if (Is_First_Captured)  // if the first is captured
  {
   IC_Value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);  // capture second value

   if (IC_Value2 > IC_Value1)  
   {
    Difference = IC_Value2-IC_Value1;   // calculate the difference
   }

   else if (IC_Value2 < IC_Value1)
   {
    Difference = ((0xffff-IC_Value1)+IC_Value2) +1;
   }

   else
   {
    Error_Handler();
   }

   Frequency = HAL_RCC_GetPCLK1Freq()/Difference;  // calculate frequency
   Is_First_Captured = 0;  // reset the first captured
  }
 }
}

int main(void)
{

  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_TIM3_Init();


  HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);


  while (1)
  {

  }

}


RESULT





Input capture in STM32 Input capture in STM32 Reviewed by Controllerstech on October 30, 2019 Rating: 5

1 comment:

  1. If I change the prescaler of TIM3, can I measure lower frequcy PWM

    ReplyDelete

Powered by Blogger.