I have already covered how to measure the frequency using input capture in STM32 in my previous tutorial. But this is not only what this feature can do so Today in this tutorial we will see how to measure the pulse width using single channel input capture.
I am using STM32F103C8 and this method should work in every other STM32 devices too.
HOW DOES IT WORK
I will try to explain in the best possible way I can. Let’s first see the CubeMx setup and I’ll explain along as we move on
As shown above the APB1 clock is at 72 MHz and I will use TIM2 for the input capture.
The picture above shows that the prescalar is set to (72-1). The reason behind this is I want to measure the pulse width in microseconds so I further divided the TIM2 clock to 1 MHz i.e. (72MHz)/72 = 1 MHz. This will give me a period of 1 us. So the Timer counter will increment every 1 us. If you want the pulse time to be in millisecond, than lower your TIMx clock to let’s say 60 MHz and set the prescalar to 60000. This is because the timer is 16 bit Timer and the maximum value it can have is 65536.
Next, NOTE THAT the ARR value is set to MAX i.e 0xffff. If you remember in my previous tutorial I told you that the minimum frequency that the device can measure, depends on ARR. So here this minimum frequency will be (1 MHz)/65536 = 15.2Hz.
If you want to measure even lower frequency let’s say for example 2 Hz, Than you need to use prescalar as 720. This will reduce the TIMx clock to (72MHz/720=100,000) and Now with the ARR of 65536, you can get the min frequecy of (100000/65536) = 1.52 Hz. This will affect the Timer counter as the Timer clock will now be 100,000 Hz that means the period will be 10 us.
Also make sure the polarity selection is for RISING edge and interrupt is turned on.
Now what happens is that the counter starts counting from 0, it increments every 1 us (in my case) and counts upto the value set in ARR. Whenever a rising edge is detected, interrupt gets triggered and the first timestamp is captured. Similarly on falling edge another timestamp is captured. Now because the counter is counting every us, the difference in these to values will also be in us. Which basically gives us the time for which the pulse was high in us.
But hey How will the falling edge be captured, We only enabled the rising edge ? Well inside the HAL_TIM.h, There is a function called __HAL_TIM_SET_CAPTUREPOLARITY and we can use it to change the polarity during the runtime. So basically whenever the rising edge is captured, we are going to change the polarity to falling edge and vice versa.
Some Insight into the CODE
Captures the first Timestamp on the rising edge and stores it in the IC_Val1 variable. Once the value is successfully stored, the Polarity is now switched to the falling edge
Second value is captured and stored in a variable called IC_Val2. After that the counter resets to 0 and the polarity switches back to the rising edge.
Difference = IC_Val2-IC_Val1;
The difference between the two captured values gives the pulse width of the signal.
YOU CAN DOWNLOAD FULL CODE AT THE END OF THIS POST