cancel
Showing results for 
Search instead for 
Did you mean: 

Using ch2 and ch4 as input capture

kahseng05
Associate II
Posted on March 18, 2015 at 13:44

Hello,

I'd like to use channel 2 and channel 4 of TIM2 as input capture. Channel 2 work fine, but channel seems returning the timer counter. Here's the code:

GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM16, ENABLE);
/*Trigger pin configuration*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_1);
TIM_TimeBaseStructure.TIM_Prescaler = 71;
TIM_TimeBaseStructure.TIM_Period = 60000;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM16, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OC1Init(TIM16, &TIM_OCInitStructure);
TIM_CtrlPWMOutputs(TIM16, ENABLE);
TIM_Cmd(TIM16, ENABLE);
TIM_SetCompare1(TIM16, 10);
/*Echo Pin configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_2);
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_PWMIConfig(TIM2, &TIM_ICInitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11,GPIO_AF_1);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
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_PWMIConfig(TIM2, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);
TIM_Cmd(TIM2, ENABLE);

#clive1
26 REPLIES 26
kahseng05
Associate II
Posted on March 22, 2015 at 15:06

Hi Clive, I am able to determine the pulse and period using the coding below.

May I ask how can I calculate distance with the pulse obtained and why do I have to read the pin state?

void TIM2_IRQHandler(){
B = TIM_GetCapture2(TIM2);
delta = B - A;
A = B;
sprintf(str,''%d

 '' ,delta);
printUART2(str);
TIM2 ->SR = 0;
}

Posted on March 22, 2015 at 15:54

Ok,

If you are timestamping the Rising Edge, then you're going to be able to measure the period, not the period+duty.

If you are timestamping BothEdges, then you're going to need to make THREE measurements (A, B ,C). One pair of measurements in a 50 Hz (20 ms) servo example is going (C-A) is going to be ~20 ms and the other (B-A) is going to be 1~2 ms. You can read the pin state to confirm the phase of the signal.

You could do TWO measurements and read the pin state to understand where high pulse (1-2 ms, mark) ended, or you can do a test that it's between 1-2, or less than 3 ms, because presumably the space is going to be 17 ms or more.

Think about the points you're measuring, and the nature of the signals you're looking at.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
kahseng05
Associate II
Posted on March 22, 2015 at 17:50

Hi, by repeating the method above, I'm able to use ultrasonic sensor 1 by 1, but when 2 ultrasonic sensors are used simultaneously, only 1 giving values. I would like to ask is there any thing I can do to solve it?

Posted on March 22, 2015 at 17:58

You're interrupt handler is going to have to do a better job of selectively handling and clearing the interrupts on specific CCx sources, and how to hold state for each of the 2-4 channels you want to measure.

Probably also want to remove the uart/printf stuff from there too, as it's going to bog everything down. Compute results in the interrupt, print them in a foreground task/loop.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
kahseng05
Associate II
Posted on March 22, 2015 at 19:08

Sorry to ask that, how to know that the channel flag is clear. I just know how to clear the timer flag. Besides, I have no idea on what u mean by how to hold state for each of the channel.

Posted on March 23, 2015 at 02:37

Hold the state information (the stuff you need to remember from call to call) in an arrayed structure, and not dozens of individually defined/named global variables.

void TIM2_IRQHandler()
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) == SET)
{
/* Clear TIM2 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
// .. TIM_GetCapture1(TIM2);
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET)
{
/* Clear TIM2 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
// .. TIM_GetCapture2(TIM2);
}
// ..
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
kahseng05
Associate II
Posted on March 26, 2015 at 18:00

Hi, I encountered a problem that a very large and incorrect value pop out in the middle of the data I obtained even after applying your suggestion. How can I solve this problem? Thanks in advance. 

Posted on March 26, 2015 at 18:39

Sanity check that the measurements for the two consecutive rising edges are ~20ms apart?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
kahseng05
Associate II
Posted on March 26, 2015 at 19:50

I tried to read the pin state using GPIOx->IDR, in order to know whether the consecutive rising edges is 20 ms, but it showed the values of 65535, 65487 and 65519. Is this results that I should obtain? If no, may you show me the proper method to check whether the rising edge is 20 ms apart?

Posted on March 26, 2015 at 20:03

You're time stamping the edges in the timer, review the measurements, they are in ticks of the counter timebase.

Measurements, A, B, C

C-A should be approximately 20000 cycles at 1 MHz (1us), right? B-A some thing in the ~1000-2000 range. If the measurements look wrong, don't use them.

For a 16-bit count, use 16-bit unsigned int's to do the math, it will wrap automatically in the desired fashion.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..