cancel
Showing results for 
Search instead for 
Did you mean: 

Inaccurate frequency meter

MHuer.1
Associate II

Hi all,

I am trying to implement a frequency counter using an STM32F446 and STM32CubeIDE. I am following the reciprocal measurement approach of one STM32 tutorial available in internet (see screenshot). Basically, i am using the input capture mode to save the CNT value of the first rising edge. I would like to measure in the range of 50-100Khz but my results are not accurate enough.

I am generating the PWM signal to be measured also with the same STM board using the PWM output of timer 3. The generated signal seems to be good enough, I have checked it with an Nscope USB oscilloscope. It only has a few noisy edges that might have been caused by the cables that I am using (single stand wires). Could this be the main problem?

This is the code that i am using:

//write the input capture callback. Called whenever an interrupt from any timer is generated

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)

{

if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_2)

{

//read capture value

val2=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2);//first time stamp, rising edge

if(val2!= 0)

{

//calculate frequency & duty cycle

timer2clk=HAL_RCC_GetPCLK1Freq()*2/ (htim->Init.Prescaler + 1);// timer_clock is modified by the prescaler of the timer

freq=(timer2clk)/val2;

}

else

{

freq=0;

}

}

}

int main(void)

{

 /* USER CODE BEGIN 1 */

 /* USER CODE END 1 */

 /* MCU Configuration--------------------------------------------------------*/

 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

 HAL_Init();

 /* USER CODE BEGIN Init */

 /* USER CODE END Init */

 /* Configure the system clock */

 SystemClock_Config();

 /* USER CODE BEGIN SysInit */

 /* USER CODE END SysInit */

 /* Initialize all configured peripherals */

 MX_GPIO_Init();

 MX_TIM2_Init();

 MX_TIM3_Init();

 /* USER CODE BEGIN 2 */

 //init timer for PWM generation and frequency calculation

 HAL_TIM_Base_Start(&htim3);

 HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);

 //freqdesired=timerclock/(prescalar+1*period+1)

 timer3clk= HAL_RCC_GetPCLK1Freq()*2;

 period=htim3.Instance->ARR+1;

 calculated_psc = ((timer3clk)/(set_freq*period))-1;

 htim3.Instance->PSC=calculated_psc;

 //init timer for PWM measure

 HAL_TIM_Base_Start(&htim2);

 HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);

 /* USER CODE END 2 */

 /* Infinite loop */

 /* USER CODE BEGIN WHILE */

 while (1)

 {

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

 }

 /* USER CODE END 3 */

}

How could i improved the results??

4 REPLIES 4

Base the measurement on time elapsed between two edge captures.

JW

TDK
Guru

> my results are not accurate enough.

Perhaps you should explain this better.

Frequency counters take measurements by capturing a LOT of edges, whereas you are capturing two and making your measurement based off of those. This is going to be more noisy than the previous approach. You're also going to be subject to the jitter of the HSI and PLL if you use them as a clock source. Only so good you can do under that scenario.

A better approach would be to use a timer in IC DMA mode, then periodically see how many edges were captured and the duration between them to calculate the frequency.

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

for the moment I would need an accuracy of 1Hz or 0.1 Hz. I will try with the HSE.

Concerning the timer in IC DMA mode, i am just starting with MCU, is there a good tutorial which explain how to use DMA with timers?

Thanks for your answer!

MHuer.1
Associate II

I tried bypassing the HSE from the SST debugger (8 Mhz). My problem relies in the value of the val2 variable (number of timer counts from one rising edge to the next one). It is not a fixed value and fluctuates between 2-3 values, therefore the frequency value fluctuates as well. Would the IC DMA mode help?