2013-02-12 07:17 AM
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 #pwm2013-02-12 08:09 AM
Hi,
I have also the same problem if you find a solution please contact me.thanks a lot.2013-02-14 12:16 PM
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.
2013-06-24 04:33 AM
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.2013-06-24 05:58 AM
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]
2014-06-21 08:18 AM
2015-12-09 02:22 AM
Hi
Is that possible with this method to compute Duty cycle?How should this be done ?2015-12-09 04:40 AM
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.2016-01-13 06:25 AM
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.
2016-01-13 09:44 AM
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.