cancel
Showing results for 
Search instead for 
Did you mean: 

Multiple PWM input capture on one timer

pliable3
Associate
Posted on February 12, 2013 at 16:17

Hello,

I am able to accurately capture one PWM input on each 16- and 32-bit timers on the STM32F4x and STM32F3x Discovery boards (using IC1 and IC2). But, I have not had any luck capturing two PWM singnals on a single timer. From the diagrams, it appears to be possible using IC3 and IC4.

Any ideas?

EDIT: Actually, I don't need the duty cycles - only the pulse widths. I would think that it would be possible to set up a timer to latch the pulse width counter only and sample 4 PWMs simultaneously, one on each channel. This would be ideal.

Thank you.

-Bob F.

#multiple-pwm-capture-two-signals #pwm
9 REPLIES 9
Cesar cfg
Associate II
Posted on February 12, 2013 at 17:09

Hi,

I have also the same problem if you find a solution please contact me.

thanks a lot.

pliable3
Associate
Posted on February 14, 2013 at 21:16

OP: Ok, I've got it (mostly) worked out thanks to a post here and a post elsewhere. The key is changing polarity of the signal in the IRQ handler. Here, I am assuming that the PWMs are phase aligned, so I only need to check for rising/falling edges of the Channel 1 signal. But this could easily be adapted to allow for PWMs that are not phase-aligned.

Here is my current code, reading 4 PWM signals with a single timer (the ccr[] array holds the current PWM pulse widths):

// Hold onto the Channel 1 init structure -- we will use it to reverse

// polarity on every edge interrupt.

static TIM_ICInitTypeDef TIM_CH1_ICInitStructure;

#define GPIO_AF_TIM2 GPIO_AF_2

void ConfigPwmIn() {

 GPIO_InitTypeDef GPIO_InitStructure;

 TIM_ICInitTypeDef TIM_ICInitStructure;

 NVIC_InitTypeDef NVIC_InitStructure;

 TIM_DeInit(TIM2 );

 /* TIM2 clock enable */

 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

 /* GPIOC clock enable */

 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE);

 /* TIM2 GPIO pin configuration : CH1=PD3, C2=PD4, CH3=PD7, CH4=PD6 */

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_7 | GPIO_Pin_6;

 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);

 /* Connect pins to TIM3 AF2 */

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource3, GPIO_AF_TIM2 );

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_TIM2 );

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource7, GPIO_AF_TIM2 );

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_TIM2 );

 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;

 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

 NVIC_Init(&NVIC_InitStructure);

 /* Enable capture*/

 TIM_CH1_ICInitStructure.TIM_Channel = TIM_Channel_1;

 TIM_CH1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;

 TIM_CH1_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

 TIM_CH1_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

 TIM_CH1_ICInitStructure.TIM_ICFilter = 0;

 TIM_ICInit(TIM2, &TIM_ICInitStructure);

 TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;

 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;

 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

 TIM_ICInitStructure.TIM_ICFilter = 0;

 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);

 /* Enable TIM2 */

 TIM_Cmd(TIM2, ENABLE);

 /* Enable CC1-4 interrupt */

 TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);

 /* Clear CC1 Flag*/

 TIM_ClearFlag(TIM2, TIM_FLAG_CC1 | TIM_FLAG_CC2 | TIM_FLAG_CC3 | TIM_FLAG_CC4 );

}

static volatile uint32_t ccr[4];

static volatile char pulseState = 0;

void TIM2_IRQHandler() {

 if (TIM2 ->SR & TIM_IT_CC1 ) {

  TIM2 ->SR &= (~TIM_IT_CC1 );

  if (pulseState == 0) {

   TIM_CH1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;

   // Any time we get a rising edge on CH1, we reset the counter. All channels are

   // phase aligned, so they all use this as a reference.

   TIM_SetCounter(TIM2, 0);

  } else {

   TIM_CH1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;

   // Pull the value on the falling edge.

   ccr[0] = TIM_GetCapture1(TIM2 );

  }

  pulseState = !pulseState;

  // Reverse polarity.

  TIM_ICInit(TIM2, &TIM_CH1_ICInitStructure);

 }

 if (TIM2 ->SR & TIM_IT_CC2 ) {

  TIM2 ->SR &= (~TIM_IT_CC2 );

  ccr[1] = TIM_GetCapture2(TIM2 );

 }

 if (TIM2 ->SR & TIM_IT_CC3 ) {

  TIM2 ->SR &= (~TIM_IT_CC3 );

  ccr[2] = TIM_GetCapture3(TIM2 );

 }

 if (TIM2 ->SR & TIM_IT_CC4 ) {

  TIM2 ->SR &= (~TIM_IT_CC4 );

  ccr[3] = TIM_GetCapture4(TIM2 );

 }

}

 -Bob F.

sajeed
Associate II
Posted on June 24, 2013 at 13:33

Hi Bob

I tried this but you loose accuracy when we reset the counter. When provided with 1K Hz frequency I am able to measure it as 1001 Hz. Any idea how we can do it without reseting the counter as you cannot measure 4 different frequencies which are not phase aligned by reseting the counter.

Posted on June 24, 2013 at 14:58

You don't have to reset the counter. You can make delta computation be between two subsequent measurements. ie CNT keeps ticking at the time base rate, CCR3[A] and CCR3[B] measurements are taken, and DeltaTicks = CCR3[B] - CCR3[A]

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
esovo1
Associate II
Posted on June 21, 2014 at 17:18

This post made my day 🙂 tnx

sorena
Associate II
Posted on December 09, 2015 at 11:22

Hi 

Is that possible with this method to compute Duty cycle?

How should this be done ?

Posted on December 09, 2015 at 13:40

Is that possible with this method to compute Duty cycle? How should this be done ?

Take the time stamps of the last three edges. From this you can compute the period and the mark/space. You can read the GPIO level if that helps, or for things like servos you can confirm the period is 50 Hz (20ms) and determine which is the shorter mark measurement.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Chilcott.Andrew
Associate
Posted on January 13, 2016 at 15:25

Has anyone actually managed to get it to work and can share some code?  I can measure frequency and duty cycle ok with channels 1 & 2 but get random values using channels 3 & 4.   I suspect its the timer being reset from the ch1&2 pair that is causing my problem.

Posted on January 13, 2016 at 18:44

Has anyone actually managed to get it to work and can share some code?  I can measure frequency and duty cycle ok with channels 1 & 2 but get random values using channels 3 & 4.   I suspect its the timer being reset from the ch1&2 pair that is causing my problem.

 

Yes, well that's what PWM Input mode is DOCUMENTED to do. The counter has a single counting element. And pairs CH1 and CH2 to make measurements. No amount of gyrations in software is going to change what the silicon does.

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