cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 timer misses count in Input Capture mode

Mechatronz
Associate II
Posted on June 29, 2018 at 10:16

Hi everyone. I am using STM32F303RE and STM32L011 nucleo boards as a part of my experiment. I used STM32F303RE to generate PWM signal (in Interrupt mode) for 1MHz.

Clock Source - PLLCLK (8Mhz * 9 = 72 MHz).

Timer Period = 71

PWM pulse = 35 (for 50% duty cycle)

I used picoscope to measure the frequency. You can see the image below.

0690X0000060LXDQA2.png

Now, i set up the STM32L011 in input capture mode (interrupt mode) to capture this 1 MHz signal. It has 32MHz clock source. The input signal is divided by 8 ( sConfigIC.ICPrescaler = TIM_ICPSC_DIV8;)

In Interrupt mode, i used CCR register to get the captures done. I read it through UART in serial plot.

0690X0000060LXEQA2.png

As you can see, the timer misses a count. I don't know the problem behind this but this always happens. The timer always misses a count. I tested with different signals but got the same result. Even tried PWM with STM32L011 and captured in another controller, but the result is the same.

Here is the capture_flag_function that i use to get the values

void capture_flag_function (void)

{

switch(capture_flag)

{

case 1:

compare_value = htim2.Instance->CCR1;

break;

case 2:

capture_new = htim2.Instance->CCR1;

CAPTURE_sm = BUFF_FULL;

break;

default:

break;

}

}

by comparing compare_value and capture_new, i obtain the count value.

if(capture_new > compare_value)

count_new = capture_new - compare_value;

if(capture_new < compare_value)

count_new = 65536 - compare_value + capture_new;

Does anyone have an idea of the problem I am facing? Or can you give me suggestions if I am doing something wrong. Thank you.

#count #stm32f303 #stm32-timer-counter #timer-interrupts #frequency-detection #stm32l0-timer #stm32f303-timer

Note: this post was migrated and contained many threaded conversations, some content may be missing.
24 REPLIES 24
henry.dick
Senior II
Posted on June 29, 2018 at 13:16

'

Does anyone have an idea of the problem I am facing?'

touch to tell, as some of the numbers don't make sense to me, with the few lines of code shown.

a high probability event here is that your fast capturing event was blocked by your slow uart transmission event. If I were you, I would significantly slow down the input signal to make sure that your code has no logic flaws and go from there.

btw, that if statement to calculate count values is totally unnecessary.

Posted on June 29, 2018 at 13:34

The numbers make sense if you see to the frequency that I have mentioned. I will state it more clearly for you.

     freq = 256000 /capture; //freq in kHz. 8*32000kHz. As i have divided the input signal by 8.

now, for example, freq = 256000/255 (as mentioned in figure) = 1004 kHz (approx.)

My project involves measuring the high frequency input signal ( upto 2 MHz). This is not from a PWM source but a different hardware setup. I already slowed it down using the division option from the timer, which i have mentioned already.

      

And for that if statement, it is absolutely necessary as I am not resetting the timer every time I encounter a rising/falling edge. It is necessary to take care of the overflow.

So, neglecting all the sarcasm, I wanted to know the problem faced because of the accuracy of the internal clocks. This occured when I tried to measure higher frequency. See the image below.

0690X0000060LS5QAM.png

Now, the picoscope measurement of the same frequency.

0690X0000060LYBQA2.png

As you can see, the counts are pretty much good but not accurate enough. There is always count miss of 1-2, whether it is a lower frequency or higher.

With regard to the UART, I tried in debug mode without any UART transmission. Guess what? The same thing happens.

0690X0000060LYGQA2.png0690X0000060LYLQA2.png

I hope you got my point now.

Posted on June 29, 2018 at 14:52

When N = 72

Period = N - 1  (71)

Pulse = N / 2   (36) 50% duty

The delta math is completely unnecessary when using uint16_t unsigned math

uint16_t a, b, delta;

delta = b - a; // Works of ALL values for a MAXIMAL TIMER, ie 0-65535

Pretty sure your math doesn't work for a counter that rolls 0-71, assuming your other chip is in maximal mode

Not sure how it sets the flag changing state

Not clear from description what TIM2 settings are.

A more complete presentation of code would be better than selective cut-n-paste, and prose describing what it is supposed to do.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
T J
Lead
Posted on June 30, 2018 at 03:09

I would make the timer run as fast as possible,

not this:

The input signal is divided by 8 (  sConfigIC.ICPrescaler = TIM_ICPSC_DIV8;)

Posted on June 30, 2018 at 10:20

I think we are deviating from the topic. My question is with regard to the clock accuracy and why it usually misses a count and doesn't accumulate. Its not about the efficiency of my code (atleast for now).

Answering your question, I already mentioned that I am using two microcontrollers. One to produce PWM signal (which is perfect enough as you can see in picoscope measurement) and another to measure it. So, I am not in any way resetting my second microcontroller. The period stays at max i.e., 65535 (65535+1 for calculations). So, overflow tends to happen.I hope I am not stating anything wrong. Also, please refer to my previous reply. I have used another source (this time its not PWM). So, it involves only one microcontroller.

Here is my TIM2 code to make it more clear for you..

/* TIM2 init function (STM32L011 32MHz max frequency) */

static void MX_TIM2_Init(void)

{

  TIM_ClockConfigTypeDef sClockSourceConfig;

  TIM_MasterConfigTypeDef sMasterConfig;

  TIM_IC_InitTypeDef sConfigIC;

  htim2.Instance = TIM2;

  htim2.Init.Prescaler = 0;

  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;

  htim2.Init.Period = 65535;

  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

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

  {

    _Error_Handler(__FILE__, __LINE__);

  }

  if (HAL_TIM_IC_Init(&htim2) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

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

  {

    _Error_Handler(__FILE__, __LINE__);

  }

  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;

  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;

  sConfigIC.ICPrescaler = TIM_ICPSC_DIV8;

  sConfigIC.ICFilter = 0;

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

  {

    _Error_Handler(__FILE__, __LINE__);

  }

}

For PWM generation, I used the following settings (STM32F303 - 72MHz max frequency)

/* TIM2 init function */

static void MX_TIM2_Init(void)

{

  TIM_ClockConfigTypeDef sClockSourceConfig;

  TIM_MasterConfigTypeDef sMasterConfig;

  TIM_OC_InitTypeDef sConfigOC;

  htim2.Instance = TIM2;

  htim2.Init.Prescaler = 0;

  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;

  htim2.Init.Period = 71;

  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;

  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

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

  {

    _Error_Handler(__FILE__, __LINE__);

  }

  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

  if (HAL_TIM_IC_Init(&htim2) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

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

  {

    _Error_Handler(__FILE__, __LINE__);

  }

  sConfigOC.OCMode = TIM_OCMODE_PWM1;

  sConfigOC.Pulse = 35;

  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;

  sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;

  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

 

  HAL_TIM_MspPostInit(&htim2);

}

Now, getting to the point, the problem exists irrespective of DMA / IT mode for input capture. Its just about one count getting missed somewhere. I tried it with/without UART (refer to my previous reply).

My question is with regard to the clock accuracy and nothing else. Please don't get me wrong and help me stay in that topic. Thank you.

Posted on June 30, 2018 at 10:23

Thank you for your reply. If you have sometime, please go through the specs of STM32L011 and STM32 F303RE. You will get to know their maximum frequency is 32 and 72 MHz respectively (without use of any external clock). The timers can support till that extent. Now, the setting you specified is for the incoming signal. Input capture is done for every 8 pulses of input. So, I am slowing down the input and not the clock. Hope you get that right. Also, I tried reducing it to DIV4, DIV2 and then DIV1, but it got worse. For higher frequency range, the timer suffered in getting the counts right and the noise level was high.

So, answering your question, the clocks are running at high speed (as much as possible). Also, please refer to my previous replies for more information. Thank you.

T J
Lead
Posted on June 30, 2018 at 14:38

Lets go back to the beginning,

I don't have an STM32L processor here..

Now, i set up the STM32L011 in input capture mode (interrupt mode) to capture this 1 MHz signal. It has 32MHz clock source.  The input signal is divided by 8 (  sConfigIC.ICPrescaler = TIM_ICPSC_DIV8;)

you have a STM32L011 running at 32MHz

you want to capture a signal at 1MHz  (roughly 32 clock cycles per rising edge...  maybe 45ish)

you count 8 pulses of an input event then interrupt ? on a capture counter/timer in counter mode ? yes ?

is that in counter mode or timer mode ?  which timer is that ?

where do you set the count to 8 ?

in that interrupt you read a different free running timer ?

is that this one ? htim2.Instance->CCR1;

Show me the code here:

In Interrupt mode, i used CCR register to get the captures done. I read it through UART in serial plot.  huh ?

what is this picture serialPlot ?,

from a uart pin ?  what is the bottom axis time trace  in mSeconds ? what is the left axis ?
T J
Lead
Posted on June 30, 2018 at 15:01

I cannot be sure about your code without rewriting it completely.

I use the cube so that everything is done correctly.

are you using one timer or two ?

I don't think you understand Input Capture and prescalers..

please check your reference manual.

16.3.5 Input capture mode

In Input capture mode, the Capture/Compare Registers (TIMx_CCRx) are used to latch the

value of the counter after a transition detected by the corresponding ICx signal.

This does not count 8 rising edges and grab a different timer value...

T J
Lead
Posted on June 30, 2018 at 15:16

Your text above looks good,

but where is the div 8 ?  you are counting slower , div 1 is the fastest counting.

you are getting an interrupt every 1uSec ?  = 1MHz  <- this is your issue

is that correct ?