cancel
Showing results for 
Search instead for 
Did you mean: 

PWM: Help on PWM setup to prevent off duty cycle

kimtommy
Associate II
Posted on October 28, 2015 at 15:57

Hi all

We need some help on a PWM setup. I�ll first present the use case then the issue we�re having and code. I�m pretty sure this is a PWM/timer understanding/register setup issue, but I just can figure out what is wrong. Please note that we are not using most of the STM libraries as our current project does not allow it. The question/issue can probably be answered without the code though.

Use:

PWM at approx 200kHz with even (50%) duty cycle. Both P and N channel used. PWM is turned on and off after a certain amout of pulses, e.g 10 off, 10 on. Timer 1 is used for PWM and Timer17 for turning on and off the PWM, interrupt based.

Issue:

First and last PWM pulse do either have too long or too short duty cycle. Seems that 0,9 microseconds after turning on the PWM from the interrupt the pin gets set. What we would want is it to wait until next pulse/timer1 hits. See image below.

Yellow

: Low indicates PWM on

Blue

: PWM signal, shows short first PWM pulse, long last pulse

Violet

: PWM n signal.

0690X00000605JgQAI.png

Question:

Is it possible to do what we want to do here; Turn on and off the PWM but resetting the output/counter so that we only get 50% duty cycle pulses?

-------------------------

Code:

I�ve done a real effort at cherry picking and replacing dynamic code for the example this time. Giving it all would just be too much for anyone to bother looking into.

Microprocessor STM32F106

////////////////////

// INITIALIZATION //

////////////////////

{

  // TIM1 used for PWM

  RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;

  RCC->APB2RSTR |= RCC_APB2RSTR_TIM1RST;

  RCC->APB2RSTR &= ~RCC_APB2RSTR_TIM1RST;

  TIM1->ARR = 1;

  TIM1->PSC = (24000000 / (200000 * 2)) - 1; // Original code: (PowerPwmClockFrequency / (Frequency * 2)) - 1

  TIM1->CCMR1 |= (TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2PE);

  TIM1->CR1 = TIM_CR1_ARPE | TIM_CR1_CEN;

  TIM1->EGR = TIM_EGR_UG;

  TIM1->BDTR = TIM_BDTR_MOE;

  // TIM17 used for turning on and off PWM

  RCC->APB2ENR |= RCC_APB2ENR_TIM17EN;

  RCC->APB2RSTR |= RCC_APB2RSTR_TIM17RST;

  RCC->APB2RSTR &= ~RCC_APB2RSTR_TIM17RST;

  

  TIM17->ARR = TIM1->ARR;

  TIM17->PSC = TIM1->PSC;

  

  NVIC_SetPriority(TIM1_TRG_COM_TIM17_IRQn, 0); // Highest interrupt level

  NVIC_DisableIRQ(TIM1_TRG_COM_TIM17_IRQn);

  

  TIM17->CR1 = TIM_CR1_ARPE | TIM_CR1_CEN;  // Enable timer

  TIM17->DIER = TIM_DIER_UIE;               // Enable timer interrupt

  TIM17->EGR = TIM_EGR_UG;                  // Set interval time

/*

..

..

*/  

  TIM17->ARR = SafeModeOffCycleTime;  // e.g. 20 for 10 pulses

  TIM1->CCR2 = 1;

  TIM1->CCER = (TIM1->CCER & ~((TIM_CCER_CC1NP | TIM_CCER_CC1NE | TIM_CCER_CC1P | TIM_CCER_CC1E) << 2)) | ((TIM_CCER_CC1NE | TIM_CCER_CC1E) << 2);

  NVIC_EnableIRQ(TIM1_TRG_COM_TIM17_IRQn);

}

//////////////////////////////////////////////

// INTERRUPT HANDLER TO TURN PWM ON AND OFF //

//////////////////////////////////////////////

void TIM1_TRG_COM_TIM17_IRQHandler(void)

{

  TIM17->SR = 0x0000;                             // Clear interrupt flag

  if (PwmSleepModeActive == FALSE)

  {

    TIM17->ARR = SafeModeOffCycleTime; // SafeModeOffCycleTime e.g. 20 for 10 pulses

    PwmSleepModeActive = TRUE;

    TIM1->CCR2 = 1;

  }

  else

  {

    TIM17->ARR = SafeModeOnCycleTime; // SafeModeOnCycleTime e.g. 20 for 10 pulses

    PwmSleepModeActive = FALSE;

    TIM1->CCR2 = 0;

  }

}

#stm32f1 #pwm
2 REPLIES 2
Posted on October 28, 2015 at 18:53

Perhaps you want to write TIM17->CNT = 0 in the interrupt to ensure the starting phase setting. Or wait for it to hit a specific phase angle when turning off.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
kimtommy
Associate II
Posted on October 30, 2015 at 15:25

Thanks clive1

I expect you mean TIM1->CNT = 0; or perhaps both of them. This had a minor effectonly improving the first pulse somewhat. 

We have preload bits set to enable shadow registers so I don't quite understand why this is happening. Still to me it seems to be a setting missing that should prevent PWM to start up/stop before the next change for the PWM. As it is now as soon as CCRx=1 is set the P and N pins are set and this leads to the problem seen.

Any further suggestions would be very appreciated.

Waiting for a specific phase angle without help from the PWM/Timer subsystem itself seems like a big challenge.

EDIT: I've identified what is wrong. Please wait till I get back with more information on the bug. I still have no solution so there will be a followup question on how to do what was originally attempted here.

Best Regards

Kim