cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103RB timers input capture Both Edges

smuryginim
Associate II
Posted on November 29, 2012 at 21:47

Hi all!!!

I want to measure a signal with help of timer. I tried to use TIM_ICPolarity_BothEdge but then i uderstand that it doesn't work correctly. So i measured my signal with help of two chanel of one timer. But it was interesting for me how i can to use Both Edge? I found in Aplication note some information about timers: ''For the STM32F10x family, polarity selection for both edges can be achieved by using TI1F_ED, but only for TI1 input.'' Is this mean that i may use only 1 channel for capturing signal on both Edges? So i do follow steps to init my timer.

/*********Timer4 Inizialization*************/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 65535; //20 mS
TIM_TimeBaseStructure.TIM_Prescaler = 7; //1 uS 1 MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM_ICConfig.TIM_Channel = TIM_Channel_1;
TIM_ICConfig.TIM_ICPolarity = TIM_ICPolarity_BothEdge;
TIM_ICConfig.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICConfig.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICConfig.TIM_ICFilter = 0;
TIM_ICInit(TIM4, &TIM_ICConfig);
TIM_SelectInputTrigger(TIM4, TIM_TS_TI1F_ED); /// SET /*********Timer4 Inizialization*************/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 65535; //20 mS
TIM_TimeBaseStructure.TIM_Prescaler = 7; //1 uS 1 MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM_ICConfig.TIM_Channel = TIM_Channel_1;
TIM_ICConfig.TIM_ICPolarity = TIM_ICPolarity_BothEdge;
TIM_ICConfig.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICConfig.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICConfig.TIM_ICFilter = 0;
TIM_ICInit(TIM4, &TIM_ICConfig);
TIM_SelectInputTrigger(TIM4, TIM_TS_TI1F_ED);
 TIM_ITConfig(TIM4, TIM_IT_CC1 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);
TIM_ClearITPendingBit(TIM4, TIM_IT_CC1 | TIM_IT_CC3 | TIM_IT_CC4);
/* Enable timer */
TIM_Cmd(TIM4, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
NVIC_Init(&NVIC_InitStructure);

and it is counting on one edge. What i did wrong? With best regards Ivan.
7 REPLIES 7
Posted on November 29, 2012 at 22:29

So, are you trying to count edges on CH1, or the period/duty of the signal?

If you want to count edges, then yes you can only use CH1, but you're not doing an Input Compare, but rather slaving off an External Clock. The Timer only has a SINGULAR counting element, and it is the CNT register, the CCR's are latches which sample CNT I'd suspect as a blind stab this might be workable

// The ONLY counting element is the timer count itself, clock it 
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
#if 1 
TIM_SelectInputTrigger(TIM4, TIM_TS_TI1F_ED);
TIM4->SMCR |= TIM_SlaveMode_External;
#else
TIM_TIxExternalClockConfig(TIM4, TIM_TIxExternalCLK1Source_TI1ED, TIM_ICPolarity_BothEdge, 0);
#endif
TIM_Cmd(TIM4, ENABLE);

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
smuryginim
Associate II
Posted on November 30, 2012 at 06:40

Clive1, Thank your for reply!

I want to measure the duration of input signal. So when i do so:

void TIM4_IRQHandler(void) {
if (TIM_GetITStatus(TIM4, TIM_IT_CC1) == SET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC1);
if(CapturerNumber == 0)
{
/* Get the Input Capture value */
IC1ReadValue1 = TIM4->CCR1; 
CapturerNumber = 1;
}
else if(CapturerNumber == 1)
{
/* Get the Input Capture value */
IC1ReadValue2 = TIM4->CCR1;
/* Capture computation */
if (IC1ReadValue2 > IC1ReadValue1)
Capturer = (IC1ReadValue2 - IC1ReadValue1); 
else Capturer = ((0xFFFF - IC1ReadValue1) + IC1ReadValue2); 
/* Duration of impuls */ 
TIM4Time_ms = ((float)Capturer/1000);
CapturerNumber = 0;
}
}

I have the period of the signal, because this interrupt only capture one edge. Can i capture signal on both edges? With best regards, Ivan
Posted on November 30, 2012 at 11:30

One immediate problem is you are measuring every other delta, ie if it where seeing both edges you'd only ever measure the MARK time.

if(CapturerNumber == 0)
{
/* Get the Input Capture value */
IC1ReadValue1 = TIM4->CCR1;
CapturerNumber = 1;
}
else if(CapturerNumber == 1)
{
/* Get the Input Capture value */
IC1ReadValue2 = TIM4->CCR1;
/* Capture computation */
if (IC1ReadValue2 > IC1ReadValue1)
Capturer = (IC1ReadValue2 - IC1ReadValue1);
else Capturer = ((0xFFFF - IC1ReadValue1) + IC1ReadValue2); // THIS IS ALSO WRONG
/* Duration of impuls */
TIM4Time_ms = ((float)Capturer/1000);
CapturerNumber = 1; // Measure NEXT delta, not reset

IC1ReadValue1 = IC1ReadValue2;
}

I'd avoid doing floating point math here as it limits the frequency measurable.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
smuryginim
Associate II
Posted on December 06, 2012 at 13:56

Thank you, clive for your reply! Finally i init timers)

khettat
Associate
Posted on September 29, 2014 at 12:45

Hi,

I am using TIM2 channel as an IC on an STM32F103, i would like ro detect the both edges coming on ch3, but i read in this forum that is not operational for this uC. So i wrote a first solution which consist to use ch3 for rising edges and ch4 for falling edges and it was working very successful. Actually i have some hardware constraints and i have to free PB11 connexted to ch4. So, i have to ch3 for the both edges. I tried to toggle the capture edge inside the interruption routine, but it doesn't work correctly, have any idea about this ???

void
TIM2_IRQHandler(
void
)
{
if
(TIM_GetITStatus(CALM_TIMER, CALM_BEMF_IT_CHANNEL) != RESET)
{
/* Reset interrupt flags */
TIM_ClearITPendingBit(CALM_TIMER, CALM_BEMF_IT_CHANNEL);
if
(TIM_ICInitStructure.TIM_ICPolarity == TIM_ICPolarity_Falling)
{
//TIM_ITConfig(CALM_TIMER, CALM_BEMF_IT_CHANNEL, DISABLE);
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInit(CALM_TIMER, &TIM_ICInitStructure);
//CALM_TIMER->CCER = 0x00000100;
//TIM_ITConfig(CALM_TIMER, CALM_BEMF_IT_CHANNEL, ENABLE);
if
((Calm_Index < CALM_Num_Of_Cycles) 
&& (Calm_State == CALIBRATION_ENABLED))
{
if
(Calm_Index >= 0) 
{ 
Calm_Table[Calm_Index].BRT = Calm_GetTimCapture(CALM_TIMER);
Calm_Index++;
} 
else
{
Calm_Index++; 
} 
}
}
else
if
(TIM_ICInitStructure.TIM_ICPolarity == TIM_ICPolarity_Rising)
{
//TIM_ITConfig(CALM_TIMER, CALM_BEMF_IT_CHANNEL, DISABLE);
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInit(CALM_TIMER, &TIM_ICInitStructure);
//CALM_TIMER->CCER = 0x00000200;
//TIM_ITConfig(CALM_TIMER, CALM_BEMF_IT_CHANNEL, ENABLE);
if
((Calm_Index <= CALM_Num_Of_Cycles) 
&& (Calm_State == CALIBRATION_ENABLED))
{
if
((Calm_Index >= 0)
&&(Calm_SyncFlag == FALSE))
{
Calm_Table[Calm_Index].BFT = Calm_GetTimCapture(CALM_TIMER);
Calm_SyncFlag = TRUE;
} 
}
}
}

Just for precision, CALM is the name of a module that i am developing actually. Best regards Karpovski
Posted on September 29, 2014 at 13:42

You still can have both CH3 and CH4 using a single input from the TIMx_CH3 pin - see CC3S and CC4S fields of  TIMx_CCMR2.

JW

khettat
Associate
Posted on September 29, 2014 at 14:48

Yes its a very good idea waclawek, it worked very much using only one pin mapped on CH3.

In TIM2 initialization routine, i just initialized CH3 selection like this:

TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

And CH4 IC channel like this:

TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;

Thank's