AnsweredAssumed Answered

PMW Timer Configuration Help Needed

Question asked by roofie01 on Jan 31, 2015
Latest reply on Feb 1, 2015 by t.a

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.

Attachments

Outcomes