cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103ZE TIM1 InputCapture

richard2399
Associate II
Posted on February 19, 2014 at 17:16

HI,

I'm trying to configure TIMER1 CHANNEL2 for InputCapture to measure a pulse from some external hardware. My init code looks like this:

  ////////////////////////////////////////////////

  // Enable Timer1 clock and release reset

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);

  RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1,DISABLE);

  TIM_InternalClockConfig(TIM1);

  RCC_GetClocksFreq(&RCC_Clocks);

  Int32U Tim1Clock = RCC_Clocks.PCLK2_Frequency ;

  if(RCC_Clocks.HCLK_Frequency != RCC_Clocks.PCLK2_Frequency)

  {

    Tim1Clock = 2*RCC_Clocks.PCLK2_Frequency ;

  }

  // Time base configuration

  TIM_TimeBaseStructure.TIM_Prescaler = 1;

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseStructure.TIM_Period = 65535;          

  TIM_TimeBaseStructure.TIM_ClockDivision = 0;

  TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);

  // Channel 2 Configuration in InputCapture

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;

  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;

  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

  TIM_ICInitStructure.TIM_ICFilter = 0x0;

  TIM_ICInit(TIM1, &TIM_ICInitStructure);

 

  /* Enable the TIM1 global Interrupt */

  NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQChannel;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

At the moment I just want to catch the rising edge to calculate frequency but in the next revision I want to time between a rising and the next falling edge.

My interrupt handler is not getting called. I have a logic analyser on the pins and can see the signals so I know the hardware is working OK.

I think I have missed something silly and hope someone can kindly point me in the right direction.

Many thanks,

Richard.
12 REPLIES 12
Posted on February 19, 2014 at 17:22

Do the NVIC initialization first

  /* TIM1 counter enable */

  TIM_Cmd(TIM1, ENABLE);

  /* TIM1 Main Output(Input) Enable */

  TIM_CtrlPWMOutputs(TIM1, ENABLE);

  /* Enable TIM1 channel 2 interrupt source */

  TIM_ITConfig(TIM1, TIM_IT_CC2, ENABLE);

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
richard2399
Associate II
Posted on February 20, 2014 at 12:29

Many thanks for the excellent advice - got that all sorted now.

One further question, though...

Looking in stm32f10x_tim.h, it seems that the ICFilter can be set to either TIM_ICPolarity_Rising or TIM_ICPolarity_Falling and as Rising is 0x00 it makes it difficult to OR the two values to generate an interrupt on either edge.

I want to be able to time between one rising edge and the next falling edge on the same pin. What is the preferred method of doing this?

Do I need to change the filter in my ISR to the next expected edge or is there a more subtle way of triggering on either edge that I haven't spotted?

Thanks again,

Richard.

Posted on February 20, 2014 at 13:15

Then you have a couple of options.

There's TIM_ICPolarity_BothEdge, you could use a second channel (CH1) and TIM_ICSelection_IndirectTI (1<->2, 3<->4) on the opposite edge.

You could use PWMInput mode, which allows you to measure an entire period, and provides duty information. This resets the timer's counter each time, so not quite the same as input capture timestamping over a longer timebase.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
richard2399
Associate II
Posted on February 20, 2014 at 15:01

Just grep'ed through my header and source files and I can't find TIM_ICPolarity_BothEdge. I don't see how that could work as the polarity field is just a single bit in the register.

I don't think the PWMCapture would work as I only want to catch a single pulse every now and then.

The two channels idea might work. Is there an example anywhere? I tried this but don't get an interrupt generated:

  /* Enable the TIM1 CCR Interrupt */

  NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQChannel;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

  // Channel 2 Configuration in InputCapture

  // Capture Rising edge on channel 1

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;

  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;

  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

  TIM_ICInitStructure.TIM_ICFilter = 0x0;

  TIM_ICInit(TIM1, &TIM_ICInitStructure);

  // Capture Falling edge on channel 2 edge

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;

  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;

  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;

  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

  TIM_ICInitStructure.TIM_ICFilter = 0x0;

  TIM_ICInit(TIM1, &TIM_ICInitStructure);

 

 

  //////////////////////////////////////

  //Enable timer and interrupts

 

  //Timer1 counter enable

  TIM_Cmd(TIM1, ENABLE);

  //Enable TIM1 Channel2 interrupt source

  TIM_ITConfig(TIM1, TIM_IT_CC2,ENABLE);

  //Enable TIM1 Channel1 interrupt sources

  TIM_ITConfig(TIM1, TIM_IT_CC1,ENABLE); Thanks again,

Richard.

Posted on February 20, 2014 at 15:34

> I don't see how that [input capture on both polarity] could work as the polarity field is just a single bit in the register.

This is true for 'F1xx. In the newer models, there is an upgraded timer module, which features the both edge capture, being set by the TIMxCCER.CCnNP/CCnP couple of bits.

But even in 'F1xx, you can set CC1 to capture one edge from the CH1 pin, and CC2 to capture the other edge from the CH1 pin - by setting TIMx_CCMR1.CC2S[1:0] to 0b10.

I don't speak the ''library'' goobledygook.

JW

Posted on February 20, 2014 at 15:50

I don't know what version of the library you're looking at, but

\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\inc\stm32f10x_tim.h

/**
******************************************************************************
* @file stm32f10x_tim.h
* @author MCD Application Team
* @version V3.5.0
* @date 11-March-2011
* @brief This file contains all the functions prototypes for the TIM firmware
* library.
******************************************************************************
/** @defgroup TIM_Input_Capture_Polarity
* @{
*/
..
#define TIM_ICPolarity_Rising ((uint16_t)0x0000)
#define TIM_ICPolarity_Falling ((uint16_t)0x0002)
#define TIM_ICPolarity_BothEdge ((uint16_t)0x000A)
#define IS_TIM_IC_POLARITY(POLARITY) (((POLARITY) == TIM_ICPolarity_Rising) || \
((POLARITY) == TIM_ICPolarity_Falling))
#define IS_TIM_IC_POLARITY_LITE(POLARITY) (((POLARITY) == TIM_ICPolarity_Rising) || \
((POLARITY) == TIM_ICPolarity_Falling)|| \
((POLARITY) == TIM_ICPolarity_BothEdge))

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on February 20, 2014 at 15:54

I tried this but don't get an interrupt generated:

If your signal is still entering via CH2, then CH2 is DIRECT, and CH1 is INDIRECT
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on February 20, 2014 at 16:56

Yes, but then in stm32f10x_tim.c, when it comes to using the polarity field:

if((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM2) || (TIMx == TIM3) ||

     (TIMx == TIM4) ||(TIMx == TIM5))

  {

    assert_param(IS_TIM_IC_POLARITY(TIM_ICInitStruct->TIM_ICPolarity));

  }

  else

  {

    assert_param(IS_TIM_IC_POLARITY_LITE(TIM_ICInitStruct->TIM_ICPolarity));

  }

i.e. the both polarity is available only for timers >=TIM9.

Indeed, a look into RM0008 confirms that.

Strange. Must have some historical reason, too.

JW
richard2399
Associate II
Posted on February 20, 2014 at 17:16

Excellent! After a bit of time trawling through the libraries I managed to translate your code into something that would compile. I now have my rising edge interrupt firing every 20ms (as planned) and a subsequent falling edge interrupt between 300us and 650us later.

Thanks everyone for all your help.

Richard.