cancel
Showing results for 
Search instead for 
Did you mean: 

Input capture not consistent

Richard Cooke
Associate II
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
17 REPLIES 17
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

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

Posted on April 09, 2018 at 23:22

Richard,

How do you read out the measured values?

Jan

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 Venmo
Up vote any posts that you find helpful, it shows what's working..
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 Venmo
Up vote any posts that you find helpful, it shows what's working..
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 II
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

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