cancel
Showing results for 
Search instead for 
Did you mean: 

Input Capture callback function inaccurate and slow?

BKoll.1
Associate II

Hi everyone,

I'm using an STM32F0 Nucleo board.

I've been trying to implement an input capture function that tries to measure the frequency of an input PWM signal. I basically record a timer count when I get the first rising edge and the second rising edge and find the difference.

However, I'm getting super inaccurate readings. For example, when I set the PWM signal to 100Hz, my frequency says 200Hz. It continues to say 200Hz even if I set my PWM to 1000Hz.

Then, if I go to 10KHz for the PWM signal, I get no readings at all. Is there something wrong with my unit?

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef * htim){
//	 checking if active channel is correct
	if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){
//		 first need to check if first rise is captured
		if (firstRise == 0){
			// capture first value
			captures[0] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
			firstRise = 1;
		}
		// need the next rise
		else if (firstRise == 1){
			captures[1] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
			if (captures[1] > captures[0]){
			period = captures[1] - captures[0];
			}
			else{
				period = 0xffff - captures[0] + captures[1] + 1;
			}
			// so the frequency is going to be TIM clock / period
			// in this case the clock is the same as PCLK1 so...
			frequency = HAL_RCC_GetPCLK1Freq()/period;
 
			firstRise = 0; // reset the capture values
			numCaptures++;
		}
	}
 
	HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}

7 REPLIES 7
S.Ma
Principal

coding overshoot and longer than needed.

use a global uint16 previous, period;

each interrupt,

period = capure - previous;

previous = capture;

no need edge counter, no need 0xffff.

then later add code if capture period longer than timer...

besides this, there should be input prescaler to slow down interrupt rate.

timer should also have smarter hw featues to measure frequencies than using 8 bit mcu ways...

TDK
Guru

What does "I get no readings at all" mean? The function never fires?

What is HAL_RCC_GetPCLK1Freq()? Your minimum frequency you can capture will be this divided by 65536. If it's 16MHz, then your minimum capture is 244 Hz. Choose a prescaler that can get you the range of frequencies that you need.

Otherwise it seems fine.

If you feel a post has answered your question, please click "Accept as Solution".

Currently, my clock is set at 8MHz, and my prescalar is 65536. Thus my minimum is 122Hz.

What I mean by getting no readings is shown in the following images.

So I'm using a different timer on the board to output a PWM signal for my input capture pin to pick up. So if I set that timer to a prescalar value of 80-1, and an ARR value of 100-1, this should output a PWM signal with frequency 1000Hz, well above my minimum frequency. However, I pick up no values:

0693W000000UKVxQAO.png

It looks like it captured one rising edge, but nothing after that.

Similarly, if I adjust the PWM signal to a prescalar of 80-1, and an ARR value of 500-1, that will output a frequency of 200Hz, still above the min frequency. However, I still pick up no values:

0693W000000UKWqQAO.png

However, if I change the ARR value to be 600-1, while keeping the prescalar at 80-1, which is a PWM value of 166Hz then it actually does give me the correct frequency.

0693W000000UKZfQAO.png

And it turns out this works as intended only for a small range between ARR values of 501 to 800, but everything else below 501 doesn't capture.

So here's where I get confused...if I change the prescalar from 80 to 8, then I can actually capture a frequency of 1000Hz correctly, but I'm still limited to a range between ARR values of 501 and 8000 this time. I made a table comparing all these different values.

0693W000000UKqRQAW.png

Am I missing something here about how the STM32 is producing PWM signals? Does it have a limit on ARR values? My guess is that it actually does, and the limit is 500.

So if I turn up the clock speed, I bet this will work with higher PWM frequencies.

So then that begs another question, why is there this ARR limit?

Thanks,

Ben

TDK
Guru

The prescaler is 16 bits, so 65536 is not a valid value.

If it's 65535, then your timer tick rate is 8MHz / 65536 = 122Hz. So you can't capture anything faster than this. If you're trying to capture 1kHz signals, you'll want a much lower prescaler.

ARR has a 16-bit limit. It does not have a limit of 500.

I would suggest looking over the input capture section of the reference manual for a better understanding rather than changing ARR values and hoping for the best. Not the interaction between timer clock, prescaler, and auto-reload value.

Based on the code in your OP, you almost certainly want ARR = 65535.

If you feel a post has answered your question, please click "Accept as Solution".
KnarfB
Principal III

If your ultimate goal is to measure the frequency of an input PWM signal, consider configuring a timer in PWM input mode.

Since I figured my original issue out, this is my plan going forward
Oh my table is referring to the PWM generation mode of a different pin. I don't seem to be able to generate a PWM wave faster than 48KHz.
As for the input captue, I did as you described for my input capture pin...its prescalar is 65535.