cancel
Showing results for 
Search instead for 
Did you mean: 

PWM Input capture doesnt work on Ch3&4 pair

sajeed
Associate II
Posted on June 24, 2013 at 09:16

Hello

I am using STM32F05XXX uc and PWM input capture example provided with the standard peripheral library for measuring frequencies of 2 different pulses.Since the example had support only for the input capture using TIM2 channel 1 & 2 pair, I have modified the code to have the input capture done for Channel 3 & 4 pair. The measuring works perfectly for TIM2 Ch1 & 2 pair but gives random values for TIM2 channel 3 & 4 pair. Could you please let me know what might be going wrong or the reason for such a behavior.

Below is the code

/***************************************************************************/

void TIM2_IRQHandler(void)

{

  if (TIM2 ->SR & TIM_IT_CC2 )

  {

    /* Clear TIM2 Capture compare interrupt pending bit */

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);

    /* Get the Input Capture value */

    IC2Value = TIM_GetCapture2(TIM2);

    if (IC2Value != 0)

    {

      /* Duty cycle computation */

      DutyCycle = (TIM_GetCapture1(TIM2) * 100) / IC2Value;

      /* Frequency computation

         TIM2 counter clock = (RCC_Clocks.HCLK_Frequency)/2 */

      ReadFrequency = RCC_Clocks.HCLK_Frequency / IC2Value;

      //TIM2->CNT = 0;

    }

    else

    {

      DutyCycle = 0;

      ReadFrequency = 0;

    }

  }/*If it is ch4 interrupt*/

  if (TIM2 ->SR & TIM_IT_CC4 )

  {

    /* Clear TIM2 Capture compare interrupt pending bit */

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);

    /* Get the Input Capture value */

    IC4Value = TIM_GetCapture4(TIM2);

    if (IC4Value != 0)

    {

      /* Duty cycle computation */

      DutyCycle = (TIM_GetCapture3(TIM2) * 100) / IC4Value;

      /* Frequency computation

         TIM2 counter clock = (RCC_Clocks.HCLK_Frequency)/2 */

      ReadFrequency = RCC_Clocks.HCLK_Frequency / IC4Value;

      //TIM2->CNT = 0;

    }

    else

    {

      DutyCycle = 0;

      ReadFrequency = 0;

    }

  }/*If it is ch2 interrupt*/

}/*End of interrupt handler*/

/***************************************************************************/

Changes in the file stm32f0xx_tim.c

/***************************************************************************/

void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct)

{

  uint16_t icoppositepolarity = TIM_ICPolarity_Rising;

  uint16_t icoppositeselection = TIM_ICSelection_DirectTI;

  /* Check the parameters */

  assert_param(IS_TIM_LIST6_PERIPH(TIMx));

  /* Select the Opposite Input Polarity */

  if (TIM_ICInitStruct->TIM_ICPolarity == TIM_ICPolarity_Rising)

  {

    icoppositepolarity = TIM_ICPolarity_Falling;

  }

  else

  {

    icoppositepolarity = TIM_ICPolarity_Rising;

  }

  /* Select the Opposite Input */

  if (TIM_ICInitStruct->TIM_ICSelection == TIM_ICSelection_DirectTI)

  {

    icoppositeselection = TIM_ICSelection_IndirectTI;

  }

  else

  {

    icoppositeselection = TIM_ICSelection_DirectTI;

  }

  if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_1)

  {

    /* TI1 Configuration */

    TI1_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, TIM_ICInitStruct->TIM_ICSelection,

               TIM_ICInitStruct->TIM_ICFilter);

    /* Set the Input Capture Prescaler value */

    TIM_SetIC1Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);

    /* TI2 Configuration */

    TI2_Config(TIMx, icoppositepolarity, icoppositeselection, TIM_ICInitStruct->TIM_ICFilter);

    /* Set the Input Capture Prescaler value */

    TIM_SetIC2Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);

  }

  if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_2)  

  {

    /* TI2 Configuration */

    TI2_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, TIM_ICInitStruct->TIM_ICSelection,

               TIM_ICInitStruct->TIM_ICFilter);

    /* Set the Input Capture Prescaler value */

    TIM_SetIC2Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);

    /* TI1 Configuration */

    TI1_Config(TIMx, icoppositepolarity, icoppositeselection, TIM_ICInitStruct->TIM_ICFilter);

    /* Set the Input Capture Prescaler value */

    TIM_SetIC1Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);

  }

  if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_3)

  {

    /* TI1 Configuration */

    TI3_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, TIM_ICInitStruct->TIM_ICSelection,

               TIM_ICInitStruct->TIM_ICFilter);

    /* Set the Input Capture Prescaler value */

    TIM_SetIC3Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);

    /* TI2 Configuration */

    TI4_Config(TIMx, icoppositepolarity, icoppositeselection, TIM_ICInitStruct->TIM_ICFilter);

    /* Set the Input Capture Prescaler value */

    TIM_SetIC4Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);

  }

  if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_4)  

  {

    /* TI2 Configuration */

    TI4_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, TIM_ICInitStruct->TIM_ICSelection,

               TIM_ICInitStruct->TIM_ICFilter);

    /* Set the Input Capture Prescaler value */

    TIM_SetIC4Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);

    /* TI1 Configuration */

    TI3_Config(TIMx, icoppositepolarity, icoppositeselection, TIM_ICInitStruct->TIM_ICFilter);

    /* Set the Input Capture Prescaler value */

    TIM_SetIC3Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);

  }

}

/***************************************************************************/

#multiple-pwm-capture-two-signals #multiple-pwm-capture-two-signals #pwm-input-capture
9 REPLIES 9
Posted on June 24, 2013 at 15:01

Yes, PWM Input Capture resets the counter, as the CCR are simple latches and not counting elements. So you'd either need to use two timers, or use the regular Input Capture mode.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
sajeed
Associate II
Posted on June 25, 2013 at 14:43

Hi Clive

Thanks for you response . I used the regular input capture mode and I am able to capture the frequency and duty cycle of the input on Channel 1 but not able to do on TIM2_CH2. It gives random values. I feel in this mode the input capture should happen on both (or 4 channels) parallelly. I am right in understanding?.

Posted on June 25, 2013 at 17:16

Well you'd be measuring edge(s), CH1/2 wouldn't pair in a fashion to permit duty/frequency, you have to make such determinations by computing the delta between two subsequent measurements, for duty on apposing edges.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on June 25, 2013 at 20:13

// STM32 TIM2 4 Channel Input Capture STM32F0-Discovery - sourcer32@gmail.com
#include ''stm32f0xx.h''
#include ''stm32f0_discovery.h''
//**************************************************************************************
void TIM2_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
/* TIM2 Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* TIM2 Configuration */
TIM_DeInit(TIM2);
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 1000000) - 1; // 1 MHz, from 48 MHz
TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF; // Maximal, TIM2 is 32-bit counter
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // Rising/Falling/BothEdge
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
/* TIM1 enable counter */
TIM_Cmd(TIM2, ENABLE);
/* Enable the CCx Interrupt Request */
TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);
}
//**************************************************************************************
volatile uint32_t Freq[4];
void TIM2_IRQHandler(void)
{
uint32_t Current, Delta;
static uint32_t Last[4];
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
{
/* Clear TIM2_CH1 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
Current = TIM_GetCapture1(TIM2);
Delta = Current - Last[0];
Last[0] = Current;
if (Delta)
Freq[0] = 1000000 / Delta; // 1MHz clock
// ..
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)
{
/* Clear TIM2_CH2 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
Current = TIM_GetCapture2(TIM2);
Delta = Current - Last[1];
Last[1] = Current;
if (Delta)
Freq[1] = 1000000 / Delta; // 1MHz clock
// ..
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)
{
/* Clear TIM2_CH3 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
Current = TIM_GetCapture3(TIM2);
Delta = Current - Last[2];
Last[2] = Current;
if (Delta)
Freq[2] = 1000000 / Delta; // 1MHz clock
// ..
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET)
{
/* Clear TIM2_CH4 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);
Current = TIM_GetCapture4(TIM2);
Delta = Current - Last[3];
Last[3] = Current;
if (Delta)
Freq[3] = 1000000 / Delta; // 1MHz clock
// ..
}
}
//**************************************************************************************
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable and set TIM2 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//**************************************************************************************
void GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOA Periph clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* Configure TIM2 input */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
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_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Connect TIM pins to AF2 */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_2); // TIM2_CH1 PA5
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_2); // TIM2_CH2 PA1
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_2); // TIM2_CH3 PA2
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_2); // TIM2_CH4 PA3
}
//**************************************************************************************
int main(void)
{
NVIC_Config();
GPIO_Config();
TIM2_Config();
while(1); /* Infinite loop */
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
sajeed
Associate II
Posted on June 26, 2013 at 09:20

Hi Clive

Thanks for the detailed explanation. Actually I have already done the same along with it I'm toggling the ICpolarity at every interrupt and also calculating the duty cycle with the same channel not with the pair. I am able to get the frequency and duty cycle for ch1,3,4 but not on 2 so may be something wrong with the input pin or hardware. Thanks again for your support.

latka
Associate
Posted on March 07, 2015 at 14:13

Could you tell me, if i could set pwm via RC Reciver, using this code ? And How to calculate duty cycle ?

Posted on March 07, 2015 at 15:25

There's an pwm input capture method

https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=https%3a//my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/STM32%20Discovery%2c%20RC%20Receiver%2c%20PWM%20Input&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F&c...

, but you have to commit one timer per input.

To modify the method here, you'd need to capture both edges, and have two historical states (instead of one), and from those you can a) confirm the periodicity, b) determine the shorter of the two measurements and the duty of the servo pulse, ie the one that's 1-2ms, vs the two rising edge measurements which are ~20 ms (50Hz) apart.

The states you are recording are time stamps in units of the time base. If you have three measurements A, B, C.

Check that C-A is 20 ms, then B-A is the servo ON time.

The example as posted here just does frequency with measurements A, B, where B-A is the ticks over the period. And illustrates measurements of 4 channels/inputs, vs the single input of PWM Input mode, in the cited example.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
latka
Associate
Posted on March 07, 2015 at 15:53

if
(TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET)
{
/* Clear TIM2_CH4 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);
Current = TIM_GetCapture4(TIM2);
if
(Inputs[3].state == 0) {
Inputs[3].rise = Current;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
Inputs[3].state = 1;
} 
else
{
Inputs[3].fall = Current;
Inputs[3].capture = Inputs[3].fall - Inputs[3].rise;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
Inputs[3].state = 0;

Delta = Current - Last[3];
Last[3] = Current;
if
(Delta)
Freq[3] = 1000000 / Delta; 
// 1MHz clock
Duty[3]=Inputs[3].capture/Delta
}
// ...
}

Like that ? I don't need to check frequency and period of reciver because it's constans. Frequency is 50Hz and period is 20ms. I only need duty to set it on another PWM on TIM1. It's for quadcopter project. For PWM output i use TIM1
Posted on March 07, 2015 at 21:08

There's perhaps

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..