Skip to main content
Richard Cooke
Associate III
April 9, 2018
Question

Input capture not consistent

  • April 9, 2018
  • 8 replies
  • 3697 views
Posted on April 09, 2018 at 19:55

Hi Folks,

I'm struggling with getting a stable value for the input capture using the example from the latest STM32Cube_FW_L0_V1.10 download.  I'm using the STM32L031K6-Nucleo board and the Atollic TrueStudio 9.0. 

My input signal is a stable 100Hz signal,  2ms high and 8ms low.  Looking at the signal with my scope the signal is well behaved and stable.  The input is connected to PA1 which is TIM2 channel 2.

Here is my TIM2 setup:

/*♯♯-1- Configure the TIM peripheral ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

  /* Set TIMx instance */

  TimHandle.Instance = TIM2;

 

  /* Initialize TIMx peripheral as follow:

       + Period = 0xFFFF

       + Prescaler = 0

       + ClockDivision = 0

       + Counter direction = Up

  */

  TimHandle.Init.Period        = 0xFFFF;

  TimHandle.Init.Prescaler     = 3;

  TimHandle.Init.ClockDivision = 0;

  TimHandle.Init.CounterMode   = TIM_COUNTERMODE_UP;  

  if(HAL_TIM_IC_Init(&TimHandle) != HAL_OK)

  {

    /* Initialization Error */

    ErrorHandler();

  }

 

  /*♯♯-2- Configure the Input Capture channel ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

  /* Configure the Input Capture of channel 2 */

  sICConfig.ICPolarity  = TIM_ICPOLARITY_RISING;

  sICConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;

  sICConfig.ICPrescaler = TIM_ICPSC_DIV1;

  sICConfig.ICFilter    = 0;   

  if(HAL_TIM_IC_ConfigChannel(&TimHandle, &sICConfig, TIM_CHANNEL_2) != HAL_OK)

  {

    /* Configuration Error */

    ErrorHandler();

  }

 

  /*♯♯-3- Start the Input Capture in interrupt mode ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

  if(HAL_TIM_IC_Start_IT(&TimHandle, TIM_CHANNEL_2) != HAL_OK)

  {

    /* Starting Error */

    ErrorHandler();

  }

My callback():

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)

{

  if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)

  {

    if(uhCaptureIndex == 0)

    {

      /* Get the 1st Input Capture value */

      uwIC2Value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);

      uhCaptureIndex = 1;

    }

    else if(uhCaptureIndex == 1)

    {

      /* Get the 2nd Input Capture value */

      uwIC2Value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);

      

      /* Capture computation */

      if (uwIC2Value2 > uwIC2Value1)

      {

        uwDiffCapture = (uwIC2Value2 - uwIC2Value1);

      }

      else if (uwIC2Value2 < uwIC2Value1)

      {

        uwDiffCapture = ((0xFFFF - uwIC2Value1) + uwIC2Value2) + 1;

      }

      else

      {

        uwDiffCapture = 0;

      }

      /* uwFrequency computation

      TIM2 counter clock = RCC_Clocks.HCLK_Frequency */      

      uwFrequency = HAL_RCC_GetHCLKFreq()/ (uwDiffCapture + 1);

      uhCaptureIndex = 0;

    }

  }

HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);   // to make sure the intr is being called

}

The uwlC2Value1, uwlC2Value2, uwDiffCapture and uwFrequency are all not stable.  They seem to be all over the place.  For example, the uwFrequency values: 1899, 1281, 6241, 1441, 932, 645, 4136, 58254, 8738, 696.

Any ideas what I might be doing wrong?

Thanks in advance,

Richard Cooke

#input-capture
This topic has been closed for replies.

8 replies

Tesla DeLorean
Guru
April 9, 2018
Posted on April 09, 2018 at 20:44

The math is unnecessarily complicated, a simple delta with uint16_t variables should suffice.

The TIM clock is also being divided by 4, so clearly not HCLK

You'd want a prescaler so 10ms wouldn't exceed 65535 ticks, but not clear what speed system is clocking at. At 32 MHz I'd think you'd need to divide down by at least 5.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
April 9, 2018
Posted on April 09, 2018 at 20:52

Is your system clock below some 2.6MHz? If not, your timer overflows several times between the captures.

TIM2 is a 32-bit timer, btw.

JW

Tesla DeLorean
Guru
April 9, 2018
Posted on April 09, 2018 at 22:39

>>TIM2 is a 32-bit timer, btw.

Not on the L031

>>Is your system clock below some 2.6MHz?

1 / ((1 / 100) / 65536) = 6553600, so below 6.5 MHz for a timebase should be able to measure 10 ms intervals

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
April 9, 2018
Posted on April 09, 2018 at 23:16

>>TIM2 is a 32-bit timer, btw.

> Not on the L031

What'a?

Indeed. Thanks. One learns something new every day

> 6.5 MHz

Not if one is tired and types in nonsense to the calculator... Sorry for the confusion

JW

Richard Cooke
Associate III
April 9, 2018
Posted on April 09, 2018 at 21:47

I'm still stumped.  I've changed the prescaler to 127 and it still gives the same unstable values. DiffCapture values: 71, 1, 4, 100, 69, 1, 57, 51, 1.

Any other things I could try?

Thanks,

Richard

Tesla DeLorean
Guru
April 9, 2018
Posted on April 09, 2018 at 22:55

 ,

 ,

uint16_t Prescaler = 8,

 ,

uint32_t uwFrequency = 0,

/* ♯ ♯ -1- Configure the TIM peripheral ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ */

 ,

 , /* Set TIMx instance */

 ,

 , TimHandle.Instance = TIM2,

 ,

 ,

 ,

 , /* Initialize TIMx peripheral as follow:

 ,

 , , , , , , + Period = 0xFFFF

 ,

 , , , , , , + Prescaler = 0

 ,

 , , , , , , + ClockDivision = 0

 ,

 , , , , , , + Counter direction = Up

 ,

 , */

 ,

 , TimHandle.Init.Period , , , , , , , = 0xFFFF,

 ,

 , TimHandle.Init.Prescaler , , , , = Prescaler - 1,

 ,

 , TimHandle.Init.ClockDivision = 0,

 ,

 , TimHandle.Init.CounterMode , , = TIM_COUNTERMODE_UP,  ,

 ,

 , if(HAL_TIM_IC_Init(&,TimHandle) != HAL_OK)

 ,

 , {

 ,

 , , , /* Initialization Error */

 ,

 , , , ErrorHandler(),

 ,

 , }

 ,

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)

 ,

{

 ,

 , static uint16_t uwIC2Value1, uwIC2Value2,

 ,

 , static int uhCaptureIndex = 0,

 ,

 , uint16_t uwDiffCapture,

 , if (htim->,Channel == HAL_TIM_ACTIVE_CHANNEL_2)

 ,

 , {

 ,

 , , , if (uhCaptureIndex == 0)

 ,

 , , , {

 ,

 , , , , , /* Get the 1st Input Capture value */

 ,

 , , , , , uwIC2Value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2),

 ,

 , , , , , uhCaptureIndex = 1,

 ,

 , , , }

 ,

 , , , else if (uhCaptureIndex == 1)

 ,

 , , , {

 ,

 , , , , , /* Get the 2nd Input Capture value */

 ,

 , , , , , uwIC2Value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2),

 ,

 , , , ,  ,

 ,

 , , , , , uwDiffCapture = (uwIC2Value2 - uwIC2Value1), // Delta

 , , , , , uwIC2Value1 = uwIC2Value2,

 , , , , , /* uwFrequency computation

 ,

 , , , , , TIM2 counter clock = RCC_Clocks.HCLK_Frequency */ , , , ,  ,

 , , , , , if (uwDiffCapture) // Perhaps ways to do with better precision

 ,

 , , , ,  , , ,  ,uwFrequency = (HAL_RCC_GetHCLKFreq() / (uint32_t)uwDiffCapture) / (uint32_t)Prescaler,

 ,

 , , , , , else

 ,

 , , , , , , , uwFrequency = 0,

 ,

 , , , }

 ,

 , }

 , HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin), , , // to make sure the intr is being called

 ,

}
Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
April 9, 2018
Posted on April 09, 2018 at 22:33

- check that the toggled pin toggles in the expected rhythm of input changes

- read out the relevant GPIO and timer registers' content and check/post

- tell us the set system frequency and the calculation for the expected differences values

JW

Richard Cooke
Associate III
April 9, 2018
Posted on April 09, 2018 at 23:10

Hi Jan,

I'm toggling the green LED on the board every time the interrupt is called and according to my scope it's perfectly in sync with the incoming 100Hz signal.  No jitter at all.

I've changed the clock to 2MHz (I think):

 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;

  RCC_OscInitStruct.HSIState = RCC_HSI_ON;

  RCC_OscInitStruct.HSICalibrationValue = 16;

  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;

  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_4;

  RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;

  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

  {

//    _Error_Handler(__FILE__, __LINE__);

    /* Initialization Error */

      while(1);

  }

    /**Initializes the CPU, AHB and APB busses clocks

    */

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK

                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;

  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV4;

  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

The system clock is 32Mhz and with the AHBCLK divider it should be 8Mhz.  I tried using a prescaler of 3 which should give me a 2Mhz clock (0.5us/count).  If the ON pulse width is approximately 2ms and the period is 10ms that should be at most 20000 counts.

Thanks, again,

Richard

waclawek.jan
Super User
April 9, 2018
Posted on April 09, 2018 at 23:22

Richard,

How do you read out the measured values?

Jan

henry.dick
Associate II
April 9, 2018
Posted on April 09, 2018 at 23:13

You count 4 x 65k cycles over 10ms, or max of frequency of 26Mhz. If you are running your mcu faster than that, your code will fail.

You can increase the prevalent to see if the error goes away.

Richard Cooke
Associate III
April 9, 2018
Posted on April 09, 2018 at 23:34

I'm using the HAL and STM32CubeMX to setup my chip.  I've changed the APBxCLKs to be only 1Mhz and I still get the unstable count values.  This should allow me to measure a 100Hz signal shouldn't it? It should be only 1000 counts.

I've tried prescaler values of 3, 15, 63, and 127 all with the same crazy results.  Is there anything esle I can try.  This is driving me crazy.  It should be simple but I guess my computer didn't get that memo.

Tesla DeLorean
Guru
April 10, 2018
Posted on April 10, 2018 at 00:06

>>It should be only 1000 counts.

I'd hope it would be 10000 ticks (1,000,000 / 100)

10ms 10000us

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Richard Cooke
Associate III
April 9, 2018
Posted on April 10, 2018 at 00:17

You're correct Clive.  Don't know what I was thinking.  But with a prescaler of 3 it should be 10000/4 = 2500 counts right?

Tesla DeLorean
Guru
April 10, 2018
Posted on April 10, 2018 at 03:39

Yes

Not done this with the L0/HAL combination, but with several STM32/SPL, both as Input Capture, and PWM Input mode.

I pasted the form of code that should work earlier. Looking at the repo example they are using uint32_t for the uwIC2ValueX variables. I'd use uint16_t to contain the wrapping.

Might try tomorrow on a L4 system to hand, there I have measured a GPS 1PPS in 30.72 MHz clock ticks, but there TIM2/TIM5 are 32-bit.

Make sure you have a good common ground between the L0 and your 100 Hz source, my test methodology here is to to generate an example clock with another TIM on-board and loop back the pins externally.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
T J
Senior III
April 10, 2018
Posted on April 10, 2018 at 06:14

Clive, ' my test methodology here is to to generate an example clock with another TIM on-board and loop back the pins externally.'

close but not the same Jitter, since the IO clocks are synchronised within your processor.

Richard,

Clives result would be cleaner than the real result, since in reality the Incoming signal is not aligned in any way with the processor clock.

 in other words, Clive's result would be the very best you could expect, although Richards final Jitter would add a random time within 1 IOclock period

Richard Cooke
Associate III
April 11, 2018
Posted on April 11, 2018 at 16:47

Hi Folks,

I'm a bit embarrassed by this whole issue as I figured it out and it was my fault.   I was using the Truestudio debugger to look at the TIM2 counter values.  I finally decided to store the counts in an array and pause the program to look at the values.  They were all vary close with just a jitter of 0.21uS.  

I'm still not 100% sure I understand why the debugger values are all screwed up since I was pausing the execution after the 2nd count was saved but that is a minor issue now that I can go forward.

I do have one other issue.  Anyone have an idea on how I can make sure that I always read the positive pulse width?  Looks like my code will sometimes read the pulse width but if I re-start the program there's a chance that I get the pulse width of the gap between pulses. So, should I be using the PWM input mode?

Thanks again,

Richard

waclawek.jan
Super User
April 11, 2018
Posted on April 11, 2018 at 18:08

I'm a bit embarrassed by this whole issue

No need to be. Lesson learned, and thank you for coming back with the solution, it helps others.

I'm still not 100% sure I understand why the debugger values are all screwed up

Part of the lesson is, that debuggers *are* intrusive, and sometimes in surprising ways. The more automation and 'magic' they provide, the heavier may be the impact on the mcu's working. They can stop the core, the timers (see DBGMCU registers) and reading the registers may influence the peripherals and/or the whole bus matrix, etc.

Looks like my code will sometimes read the pulse width but if I re-start the program there's a chance that I get the pulse width of the gap between pulses

Define pulses and gap. Make drawings.  Start a new thread if it's a new problem.

JW