cancel
Showing results for 
Search instead for 
Did you mean: 

Timer to measure PWM signal and redirect to another GPIO

scook116
Associate II
Posted on October 08, 2015 at 21:45

I want to create a PWM pass-through program that will read a PWM duty cycle from an RC receiver on a pin (Pulse-width: 1ms-2ms @ 50Hz) and then output that duty cycle on another GPIO Pin at 50Hz. 

(eventually, the program will alter the pulse-width values if a condition occurs but for now I'm attempting the pass-through.)

I've heard that you can redirect a timers capture channel to output to another peripheral. Would this be suitable?

I have also heard of doing a DMA Peripheral-to-Peripheral transfer, is that a possible solution?

I'll be running this off of the STM32F407VGTx Board.

I'm an engineer who was taught MC's using 8051's and PLC's, and of course Arduino boards. I have a solid understanding of the STM32's general operation as a MC. What I lack is the intuition of when and where to use the STM32's peripheral features (like Timer CC channels and such) in order to take full advantage over the level of control this chip offers.

#stm32f
2 REPLIES 2
Posted on October 08, 2015 at 22:52

I'm not sure I bring intuition as much as I bring the willingness to read the manual and experiment. Might look like magic, but it's not.

So yeah, figure DMA2 based transfers, as it's more flexible wrt bus/memory.

Pick a TIM on APB2, program that PWM Input mode, counter in maximal mode.

You can config either CH1 or CH2 to be the duty/period respectively, as the counter resets. Get the DMA associated with the TIMx_CHx you're using. This will be the trigger. Have the DMA source be the TIMx_CCx, and the destination the TIMz_CCz of a TIM you have in PWM Output mode, period of time base set to be 50 Hz, and in the same time scale as the measuring timer. ie perhaps have both a 1 MHz, giving 1us granularity. The width of the transfer is important, but all APB2 TIM's are 16-bit

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
scook116
Associate II
Posted on October 16, 2015 at 01:05

Thanks again, Clive. I appreciate your time and your wisdom on my issues.

This slice of Timer Config code is from a basic PWM input program I found.

TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; // PB4 TIM3_CH1
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(TIM3, &TIM_ICInitStructure);

The last statement, ''TIM_PWMIConfig'', seems to be a pretty efficient method of capturing an input PWM signal with 1 pin. I'm sure you know all about this already, but this PWMI function changes the timers polarity to a Falling edge, after the timer has detected a Rising Edge. This is the Interrupt that's called to store the 'CCRx' values.

void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
Reading[0] = TIM_GetCapture1(TIM3); // Period (us) ~20000
Reading[1] = TIM_GetCapture2(TIM3); // Duty/Width (us) ~1500 or whatever (600-2400 us)
}
}

Since 'TIM_PWMIConfig' is being used, what is in Reading[0] and Reading[1]? Does Reading[1] contain a computed Duty Cycle and [0] a computed Period? Or are they still just the captured Timer Values (as normal)? I ask because I'm printing both Reading[0] and [1] into my monitor and not getting the correct values. There IS a Duty Cycle and there is a period being measured, but they are scaled up, larger in value than the input signal. Naturally I fiddled with the Timer prescaler but to no avail. Then I hooked the Timer directly to the APB1 bus, timer with no prescale, and APB1 bus set to 1MHZ. I'm missing something..