2020-03-18 08:53 PM
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);
}
2020-03-18 09:17 PM
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...
2020-03-19 06:54 AM
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.
2020-03-19 11:24 AM
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:
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:
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.
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.
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
2020-03-19 12:39 PM
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.
2020-03-19 01:17 PM
If your ultimate goal is to measure the frequency of an input PWM signal, consider configuring a timer in PWM input mode.
2020-03-19 04:40 PM
2020-03-19 04:42 PM