cancel
Showing results for 
Search instead for 
Did you mean: 

PMW Timer Configuration Help Needed

Rogers.Gary
Senior II
Posted on January 31, 2015 at 16:24

I am having trouble to get a couple of pins to toggle in PWM mode. It works, but there's a problem with the pin staying high. Here's what I am trying to do, it's quite simple, so I don't see why it is so much problem.

The timebase calculation is good, and I can generate frequencies +/- 100mHz. Note that both output pins *must* start at 0 (low), and return to 0 (low).

The 2 outputs must be PWM, call them Output1 and Output2. That wiould be Channel1 and Channel2. They will be exactly the same frequency, and exactly the same pulse width. The only difference is this: The start edge of Output 2 must be delayed from Output1 by an interval of timerPeriod / 2. Because of this, I understand that I cannot do this on the same timer

 

Here is basic code, 2 functions. The first one is the GPIO setup, the other is PWM configuration. The maximum frequency into the function is about 100Hz, the duty cycle is between 0.1 and 0.5.

void GPIO_Configuration(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

/* GPIOD Configuration: Use TIM4 to to PD12 (also LED on board) */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_Init(GPIOD, &GPIO_InitStructure);

/* GPIOC Configuration: TIM3 CH1 (PC6) */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

GPIO_Init(GPIOC, &GPIO_InitStructure);

/* Connect TIM3 pins to AF2 */

GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM3);

/* Connect TIM4 pins to AF2 */

GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);

}

void PWM_TIMER_Configuration(float32_t frequency, float32_t dutyCycle)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_OCInitTypeDef TIM_OCInitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

uint16_t Prescaler, Period;

// 20 KHz timebase, assumes APB1 H/4 TIMCLK4 H/2

Prescaler = ((SystemCoreClock / 2) / 20000);

Period = (uint16_t)( TIMER_BASE / frequency );

/* Time base configuration */

TIM_TimeBaseStructure.TIM_Period = Period - 1;

TIM_TimeBaseStructure.TIM_Prescaler = Prescaler - 1;

TIM_TimeBaseStructure.TIM_ClockDivision = 0;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

//set timer 3 & 4 to same frequency

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

//assign variable

uint32_t timerPeriod = TIM_TimeBaseStructure.TIM_Period;

/* Output Compare PWM1 Mode configuration: Channel 1 */

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

//create pulse width ''onTIme'' for both channels

uint16_t onTime = (uint16_t) (timerPeriod * txData[frqValue].dutyCycle);

TIM_OCInitStructure.TIM_Pulse = onTime;

TIM_OC1Init(TIM3, &TIM_OCInitStructure);

TIM_OC1Init(TIM4, &TIM_OCInitStructure);

TIM_Cmd(TIM3, ENABLE);

//set timer 4 immediately to timerPeriod / 2 = 180 degrees shift

TIM4->CNT = TIM3->CNT + (timerPeriod /2 );

TIM_Cmd(TIM4, ENABLE);

//Set up TIM3 interrrupt

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

}

See the attached image showing what the output looks like. The yellow trace is TIM3, the green is TIM4. Notice how TIM4 wants to stay high, this is exactly what must not occur.  Ideally the TIM3 should look just like TIM4, with a clean transition LOW to high at start and the same at the end. TIM4 is delayed by the correct amount, but the starting relationship isn't quite right, the trace looks goofy, and I'm not sure if it's because TIM3 starts at HIGH.

I want to monitor after timer 3 & 4 start the interrupt routine, let it run a specific amount of cycles, then stop it by doing this:

TIM_Cmd(TIM4, DISABLE);

TIM_Cmd(TIM4, DISABLE);

or this:

TIM3->CNT=0; TIM4->CNT=0; TIM3->CCR1=0;TIM4->CCR1=0;

I have tried the above, forcing the pin low, configured as a pull-up, pull-down and pull to nothing. So what am I doing wrong? I've even tried every direct register setting instead of the TIM_Cmd function, made no difference.

Any help would be really appreciated. Really stuck here and I must get this working.

Thank you.
2 REPLIES 2
Posted on January 31, 2015 at 21:13

TIM3->CCR1=Period;

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 February 01, 2015 at 14:19

Mhmm... TIM4, green trace, shouldn't stay high? But green waveform looks okay for me. TIM3 or yellow trace behaves like you have connected the pin to a capacitor. You are aplying the same values to both of timers. So, I believe the bug isn't in the code. Maybe try to change the pin. I had a similar problem, the pin was high, but it should have been low, because on the discovery board was pull-up resistor.  Take a shot.