cancel
Showing results for 
Search instead for 
Did you mean: 

frequency measurement behavior

Gaston
Senior

Hi,

I'm measuring a 40-60Hz frequency range from an input capture timer (STM32L475RCTX TIM4). The result is an expected calculation from 4000 to 6000 (40.00Hz-60.00Hz) using this initialization code:

static void MX_TIM4_Init(void)
{
 
  /* USER CODE BEGIN TIM4_Init 0 */
 
  /* USER CODE END TIM4_Init 0 */
 
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_IC_InitTypeDef sConfigIC = {0};
 
  /* USER CODE BEGIN TIM4_Init 1 */
 
  /* USER CODE END TIM4_Init 1 */
  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 50-1;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 65535;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_IC_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_BOTHEDGE;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM4_Init 2 */
 
  /* USER CODE END TIM4_Init 2 */
 
}

The frequency computation is performed in HAL_TIM_IC_CaptureCallback routine and here's the result form an input frequency of 50.00Hz:

0693W00000D0bUoQAJ.png 

The result is 5037 that means 50.37Hz and the 0.37Hz does not a problem so far. The problem is when I pause the execution, restart and resume it. Then the result sometimes falls in 5037 (the same result than before) but sometimes is 4965 as shown:

0693W00000D0bWpQAJ.pngThe result changes when I do a pause, restart (reset) and resume the execution from the IDE. How can I manage to always get the same frequency result after successive restart cycles?

regards,

gaston

1 ACCEPTED SOLUTION

Accepted Solutions
You need to use the same edge for the frequency calculation unless you have a guaranteed 50% duty cycle. Probably you don't have this and the difference is just due to capturing rising then falling vs. capturing falling then rising. Every reset would randomly choose between the two.
If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

4 REPLIES 4
TDK
Guru

I'm guessing ignoring the first edge might be helpful here. Try to do the calculation based on the second and third edges rather than the first and second.

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

Hi TDK,

In order to do as you've suggested I've changed the callback routine this way:

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim){
 
	if(htim->Instance == TIM4){
 
		if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2){
 
			//HAL_GPIO_TogglePin(ACPW_GPIO_Port, ACPW_Pin);
			acqStruct.zcdFlg = true;						// zero cross detector
 
			if(acqStruct.uhCaptureIndex == 0){
 
				// Get the 1st Input Capture value
				acqStruct.uwIC2Value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
				acqStruct.uhCaptureIndex = 1;
			}
			else{
				if(acqStruct.uhCaptureIndex == 1){
 
 
					// Get the 2nd Input Capture value
					acqStruct.uwIC2Value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
					acqStruct.uhCaptureIndex = 2;
				}
				else{
					// ***********Get the 2nd Input Capture value
					// Get the 3rd Input Capture value
					acqStruct.uwIC2Value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
 
					// Capture computation
					if (acqStruct.uwIC2Value2 > acqStruct.uwIC2Value1){
						acqStruct.uwDiffCapture = (acqStruct.uwIC2Value2 - acqStruct.uwIC2Value1);
					}
					else{
						if (acqStruct.uwIC2Value2 < acqStruct.uwIC2Value1){
							// 0xFFFF is max TIM4_CCRx value
							acqStruct.uwDiffCapture = ((0xFFFF - acqStruct.uwIC2Value1) + acqStruct.uwIC2Value2) + 1;
						}
						else{
							// If capture values are equal, we have reached the limit of frequency measures
							//Error_Handler();
						}
					}
 
					// Frequency computation: for this example TIMx (TIM4) is clocked by
					//   APB2Clk
					acqStruct.Frequency = (HAL_RCC_GetPCLK2Freq() / acqStruct.uwDiffCapture);
					//acqStruct.uhCaptureIndex = 0;
					acqStruct.uhCaptureIndex = 1;
 
					// Moving Average
					acqStruct.avgFrequency = acqMovingAverage(&acqStruct.averageBuffer[ACQ_FRQ_IX][0], ACQ_N_AVERAGE, acqStruct.Frequency, ACQ_FRQ_IX) + 1;
				}
			}
		}
	}
}

But the result still changes after successive restart cycles. I wonder if there some method to determine the edge type (rising/fallling) in the callback routine. By the way, this problem appears when configuring Both Edges in Polarity Selection. If I select Rise Edge everything goes okay and the frequency result is stable for successive restart cycles.

gaston

You need to use the same edge for the frequency calculation unless you have a guaranteed 50% duty cycle. Probably you don't have this and the difference is just due to capturing rising then falling vs. capturing falling then rising. Every reset would randomly choose between the two.
If you feel a post has answered your question, please click "Accept as Solution".

Great! It solves my problem. Thank you for your help TDK.

I share the code using Input Capture with Both Edges implementation for the Frequency measurement.

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim){
 
	if(htim->Instance == TIM4){
 
		if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2){
 
			//HAL_GPIO_TogglePin(ACPW_GPIO_Port, ACPW_Pin);
			acqStruct.zcdFlg = true;						// zero cross detector
 
			if(acqStruct.uhCaptureIndex == 0){
 
				// Get the 1st Input Capture value
				acqStruct.uwIC2Value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
				acqStruct.uhCaptureIndex = 1;
			}
			else{
				if(acqStruct.uhCaptureIndex == 1){
					
					// Skip 2nd Input Capture value 
					acqStruct.uhCaptureIndex = 2;
				}
				else{
 
					// Get the 3rd Input Capture value
					acqStruct.uwIC2Value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
 
					// Capture computation
					if (acqStruct.uwIC2Value2 > acqStruct.uwIC2Value1){
						acqStruct.uwDiffCapture = (acqStruct.uwIC2Value2 - acqStruct.uwIC2Value1);
					}
					else{
						if (acqStruct.uwIC2Value2 < acqStruct.uwIC2Value1){
							// 0xFFFF is max TIM4_CCRx value
							acqStruct.uwDiffCapture = ((0xFFFF - acqStruct.uwIC2Value1) + acqStruct.uwIC2Value2) + 1;
						}
						else{
							// If capture values are equal, we have reached the limit of frequency measures
							//Error_Handler();
						}
					}
 
					// Frequency computation: for this example TIMx (TIM4) is clocked by
					//   APB2Clk
					acqStruct.Frequency = (HAL_RCC_GetPCLK2Freq() / acqStruct.uwDiffCapture);
					acqStruct.uhCaptureIndex = 0;
 
					// Moving Average
					acqStruct.avgFrequency = acqMovingAverage(&acqStruct.averageBuffer[ACQ_FRQ_IX][0], ACQ_N_AVERAGE, acqStruct.Frequency, ACQ_FRQ_IX) + 1;
				}
			}
		}
	}
}

regards,

gaston