This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

PWM Synchronization

Other Parts Discussed in Thread: MOTORWARE, CONTROLSUITE

I'm using a LaunchXL F28069 to run an H-Bridge, and I want to offset the PWM signals from each other, but I'm not having any luck.  I've set the two poles equal to 50% duty cycle so I can check the phasing, but no matter what I do they're perfectly synchronized.  Ideally, I'd like to run them as center-aligned, but offset the PWM signal for phase B by a particular angle (120°, or 90°, or whatever, measured with reference to the PWM wave on phase A).  As far as I can tell, this is handled by TBPHS and TBCTL.

I'm using InstaSpin Lab 11, and have adjusted the code in hal.c, but am not seeing any results.  Am I missing something stupid?  I've read the EPWM section of the TMS320x2806x Technical Manual, but I don't see anything else I should be doing.  At the end is my copy of HAL_setupPwms from hal.c.  I can't seem to get the upload function to upload a text file; it just dumps a huge icon inline with this text.

I added PWM_enableCounterLoad(obj->pwmHandle[cnt]); in the TBCTL section to enable phase loading during synchronization, and immediately after that I set the TBPHS register.

Thanks in advance for any help.

Matt


void HAL_setupPwms(HAL_Handle handle,
                   const float_t systemFreq_MHz,
                   const float_t pwmPeriod_usec,
                   const uint_least16_t numPwmTicksPerIsrTick)
{
  HAL_Obj   *obj = (HAL_Obj *)handle;
  uint16_t   halfPeriod_cycles = (uint16_t)(systemFreq_MHz*pwmPeriod_usec) >> 1;
  uint_least8_t    cnt;


  // turns off the outputs of the EPWM peripherals which will put the power switches
  // into a high impedance state.
  PWM_setOneShotTrip(obj->pwmHandle[PWM_Number_1]);
  PWM_setOneShotTrip(obj->pwmHandle[PWM_Number_2]);
  PWM_setOneShotTrip(obj->pwmHandle[PWM_Number_3]);

  for(cnt=0;cnt<3;cnt++)
    {
      // setup the Time-Base Control Register (TBCTL)
      PWM_setCounterMode(obj->pwmHandle[cnt],PWM_CounterMode_UpDown);
      PWM_disableCounterLoad(obj->pwmHandle[cnt]);
      PWM_setPeriodLoad(obj->pwmHandle[cnt],PWM_PeriodLoad_Immediate);
      PWM_setSyncMode(obj->pwmHandle[cnt],PWM_SyncMode_EPWMxSYNC);
      PWM_setHighSpeedClkDiv(obj->pwmHandle[cnt],PWM_HspClkDiv_by_1);
      PWM_setClkDiv(obj->pwmHandle[cnt],PWM_ClkDiv_by_1);
      PWM_setPhaseDir(obj->pwmHandle[cnt],PWM_PhaseDir_CountUp);
      PWM_setRunMode(obj->pwmHandle[cnt],PWM_RunMode_FreeRun);
      PWM_enableCounterLoad(obj->pwmHandle[cnt]);

      // setup the Timer-Based Phase Register (TBPHS)
      if (cnt == 0)
      {
       PWM_setPhase(obj->pwmHandle[cnt],0);
      }
      else if (cnt == 1)
      {
       PWM_setPhase(obj->pwmHandle[cnt],1500);
      }

      // setup the Time-Base Counter Register (TBCTR)
      PWM_setCount(obj->pwmHandle[cnt],0);

      // setup the Time-Base Period Register (TBPRD)
      // set to zero initially
      PWM_setPeriod(obj->pwmHandle[cnt],0);

      // setup the Counter-Compare Control Register (CMPCTL)
      PWM_setLoadMode_CmpA(obj->pwmHandle[cnt],PWM_LoadMode_Zero);
      PWM_setLoadMode_CmpB(obj->pwmHandle[cnt],PWM_LoadMode_Zero);
      PWM_setShadowMode_CmpA(obj->pwmHandle[cnt],PWM_ShadowMode_Shadow);
      PWM_setShadowMode_CmpB(obj->pwmHandle[cnt],PWM_ShadowMode_Immediate);

      // setup the Action-Qualifier Output A Register (AQCTLA)
      PWM_setActionQual_CntUp_CmpA_PwmA(obj->pwmHandle[cnt],PWM_ActionQual_Set);
      PWM_setActionQual_CntDown_CmpA_PwmA(obj->pwmHandle[cnt],PWM_ActionQual_Clear);

      // setup the Dead-Band Generator Control Register (DBCTL)
      PWM_setDeadBandOutputMode(obj->pwmHandle[cnt],PWM_DeadBandOutputMode_EPWMxA_Rising_EPWMxB_Falling);
      PWM_setDeadBandPolarity(obj->pwmHandle[cnt],PWM_DeadBandPolarity_EPWMxB_Inverted);

      // setup the Dead-Band Rising Edge Delay Register (DBRED)
      PWM_setDeadBandRisingEdgeDelay(obj->pwmHandle[cnt],HAL_PWM_DBRED_CNT);

      // setup the Dead-Band Falling Edge Delay Register (DBFED)
      PWM_setDeadBandFallingEdgeDelay(obj->pwmHandle[cnt],HAL_PWM_DBFED_CNT);
      // setup the PWM-Chopper Control Register (PCCTL)
      PWM_disableChopping(obj->pwmHandle[cnt]);

      // setup the Trip Zone Select Register (TZSEL)
      PWM_disableTripZones(obj->pwmHandle[cnt]);
    }


  // setup the Event Trigger Selection Register (ETSEL)
  PWM_disableInt(obj->pwmHandle[PWM_Number_1]);
  PWM_setSocAPulseSrc(obj->pwmHandle[PWM_Number_1],PWM_SocPulseSrc_CounterEqualZero);
  PWM_enableSocAPulse(obj->pwmHandle[PWM_Number_1]);
 

  // setup the Event Trigger Prescale Register (ETPS)
  if(numPwmTicksPerIsrTick == 3)
    {
      PWM_setIntPeriod(obj->pwmHandle[PWM_Number_1],PWM_IntPeriod_ThirdEvent);
      PWM_setSocAPeriod(obj->pwmHandle[PWM_Number_1],PWM_SocPeriod_ThirdEvent);
    }
  else if(numPwmTicksPerIsrTick == 2)
    {
      PWM_setIntPeriod(obj->pwmHandle[PWM_Number_1],PWM_IntPeriod_SecondEvent);
      PWM_setSocAPeriod(obj->pwmHandle[PWM_Number_1],PWM_SocPeriod_SecondEvent);
    }
  else
    {
      PWM_setIntPeriod(obj->pwmHandle[PWM_Number_1],PWM_IntPeriod_FirstEvent);
      PWM_setSocAPeriod(obj->pwmHandle[PWM_Number_1],PWM_SocPeriod_FirstEvent);
    }


  // setup the Event Trigger Clear Register (ETCLR)
  PWM_clearIntFlag(obj->pwmHandle[PWM_Number_1]);
  PWM_clearSocAFlag(obj->pwmHandle[PWM_Number_1]);

  // first step to synchronize the pwms
  CLK_disableTbClockSync(obj->clkHandle);

  // since the PWM is configured as an up/down counter, the period register is set to one-half
  // of the desired PWM period
  PWM_setPeriod(obj->pwmHandle[PWM_Number_1],halfPeriod_cycles);
  PWM_setPeriod(obj->pwmHandle[PWM_Number_2],halfPeriod_cycles);
  PWM_setPeriod(obj->pwmHandle[PWM_Number_3],halfPeriod_cycles);

  // last step to synchronize the pwms
  CLK_enableTbClockSync(obj->clkHandle);

  return;
}  // end of HAL_setupPwms() function

  • driving an H bridge you aren't using InstaSPIN-FOC, is there a reason you are trying to use a MotorWare lab?

    thinking if you just want to use an F2806x Launchpad you should start with some of the controlSUITE generic examples.

    You will also get more help over on the C2000 main e2e forum. I can move this thread over if you like.
  • Chris,

    We actually ARE using the estimator. We're just using it on a single-phase system. It's actually working great, except for some distortion we're getting when the two poles are switching at exactly the same time.

    I wasn't sure if I should post this in the C2000 forum because it's InstaSpin code, but it's OK if you think the response will be better there.

    Matt
  • interesting.

    I've sent to Richard to see if he can assist
  • Matt,

    The initialization code in your post looks like it's set up to generate three PWM pairs with fixed zero phase.  To change this so you have one master and one phase time-base you'll need to focus on re-configuring the TBCTL registers in the adjacent time-bases you want to synchronize.  At the moment all three TBCTL registers are configured similarly in the same init loop, but you'll need to configure the master and slave modules differently.

    To illustrate this, let's assume these are PWM1 (master) and PWM2 (slave) for the moment.  The attached diagram shows what we want to do.

    In PWM1 you'll need disable counter load, and to set the SYNCOSEL field to generate a SYNC signal on zero counter match:

    PWM_disableCounterLoad(obj->pwmHandle[0]);

    PWM_setSyncMode(obj->pwmHandle[0], 1);

    In PWM2, enable the PHSEN field to allow the counter to reload on a SYNC input, and (if you want to synchronize further modules in the chain) pass through the SYNC signal:

    PWM_enableCounterLoad(obj->pwmHandle[1]);

    PWM_setSyncMode(obj->pwmHandle[1], 0);

    I think this code I about right but I haven't tested it.  After you build and compile it, I recommend viewing the TBCTL registers in a CCS registers watch window to confirm they have been configured correctly.  Once this is done, as long as both PWMs have the same period, you should be able to control the relative phase offset on PWM2 by the function:

    PWM_setPhase(obj->pwmHandle[1], phase);

    I hope this helps.

    Regards,

    Richard

    PWM phase control.pdf

  • Richard,

    That did exactly what we needed. Thanks for the help.

    Matt