cancel
Showing results for 
Search instead for 
Did you mean: 

Frequency Measurement with NUCLEO-U575ZI-Q

mebrahim
Associate II

I'm trying to use the frequency measurement with NUCLEO-U575ZI-Q. As per suggested, the max allowed frequency of SYSCLK is 160 MHz which I use. I'm configuring TIM2 Channel 1 in direct input capture mode. I use 0 as the prescaler and the max value for the counter (but I reset the timer every time I calculate the frequency). I detect the rising edge and I don't use any Input Filter (which could be a 4 bit value). 
The strange part is when I try to measure frequencies below 500 KHz, the result is super stable and reliable. I used both a lab function generator and the STM PWM generator via TIM 1 as the input test signal.
However, when I try signals above 800 KHz for testing I read values which are sometimes 800KHz and sometimes 400KHz! 
Even stranger, when the input signal is above 1 MHz, I either measure 800KHz or 533.3333KHz!. 
I use the IC interrupt to implement my calculations as following. It might me useful to switch to DMA but again, I cannot justify how it is possible not to be able to measure 1 MHz with a 160MHz internal clock!
I have included my interrupt implementation in the following:

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 = (htim1.Init.Period - IC_Val1) + IC_Val2;

}

 

float refClock = TIMCLK;

 

if (Difference != 0){

frequency = refClock/(Difference*(htim2.Init.Prescaler+1));

}

__HAL_TIM_SET_COUNTER(htim, 0); // reset the counter

Is_First_Captured = 0; // set it back to false

}

}

 

}

 

For the reference, I'm also providing my TIM2 setting in the following:

static void MX_TIM2_Init(void)

{

 

/* USER CODE BEGIN TIM2_Init 0 */

 

/* USER CODE END TIM2_Init 0 */

 

TIM_ClockConfigTypeDef sClockSourceConfig = {0};

TIM_MasterConfigTypeDef sMasterConfig = {0};

TIM_IC_InitTypeDef sConfigIC = {0};

 

/* USER CODE BEGIN TIM2_Init 1 */

 

/* USER CODE END TIM2_Init 1 */

htim2.Instance = TIM2;

htim2.Init.Prescaler = 0;

htim2.Init.CounterMode = TIM_COUNTERMODE_UP;

htim2.Init.Period = 4.294967295E9;

htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

if (HAL_TIM_Base_Init(&htim2) != HAL_OK)

{

Error_Handler();

}

sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)

{

Error_Handler();

}

if (HAL_TIM_IC_Init(&htim2) != HAL_OK)

{

Error_Handler();

}

sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)

{

Error_Handler();

}

sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;

sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;

sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;

sConfigIC.ICFilter = 0;

if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)

{

Error_Handler();

}

/* USER CODE BEGIN TIM2_Init 2 */

 

/* USER CODE END TIM2_Init 2 */

 

}

 

Finally, my variable definition:
#define TIMCLK 160000000

2 REPLIES 2

It's not that it can't measure, it's that the interrupt load is too high / saturating.

Make the interrupt/callback more efficient. Still likely to impair the processor doing anything else useful.

Perhaps don't interrupt, but read when needed.

Consider the PWM Input Capture that measures Period and Duty in a pair of CH1/CH2 CCRx registers you can read at your convenience in a main loop without interrupts.

Look also at the Input Prescaler, a way of measure 2, 4 or 8 cycles at a time, for less loading, better precision.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Thanks for the response. The first point is, the interrupt load to me is already very low. I have 2 if clauses, one subtraction and just one division. The second point is the interrupt happens only at the detection of a rising edge. How to have the correct counter values without the rising edge interrupt?
To me the only solution would be the use of GPDMA.
On the other hand I don't get the connection of Prescaler and multi cycle calculations. The Prescaler only divides the internal clock frequency (which is not what I want). And in fact, the issue is that the interrupt is losing the rising edges so it doesn't matter how many cycles I'm using.