AnsweredAssumed Answered

PWM: Help on PWM setup to prevent off duty cycle

Question asked by Kim Tommy on Oct 28, 2015
Latest reply on Oct 30, 2015 by Kim Tommy
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.

QuickPrint1.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;
  }
}

Outcomes