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.

Cycle-by-Cycle PWM Trip with Comparator Outputs

I'm using an F28377D and I'm trying to get my PWM signals to trip as expected based on three analog comparator outputs.  The same analog input is compared to three different levels, each level being set by an internal DAC.  I want the two lower levels (CMPSS1 and CMPSS2) to cause cycle-by-cycle trips, and the higher level (CMPSS3) to cause a one-shot trip.  I have everything set up and working the way I want it to with one exception: the two cycle-by-cycle trips cause the PWMs to turn back on immediately when the analog compare signal goes low, rather than being synchronized with the next cycle.  From reading some posts on e2e I see that the TZA and TZB should be used if this behavior is desired, whereas I'm using the DCxEVT2.  However, whenever I set this up it always trips and the PWMs are always off. 

I'm sure what I want to do is possible and I just have something configured wrong.  Can anyone suggest what it might be?

Here is my code for setting up the three comparators:

void init_cmpss(void)

{
  pocTripLevel = calcPrimaryTripLevel(145.0);
  cbcTripLevel = calcPrimaryTripLevel(80.0);

  InitCmpss1();
  InitCmpss2();
  InitCmpss3();
}

 
static void InitCmpss1(void)
{
  EALLOW;


  // Set up CMPSS1 control registers.
  Cmpss1Regs.DACHVALS.bit.DACVAL = 0;
  Cmpss1Regs.COMPCTL.bit.COMPDACE = 1; // Enable CMPSS
  Cmpss1Regs.COMPCTL.bit.COMPHSOURCE = NEGIN_DAC; // NEG signal comes from DAC
  Cmpss1Regs.COMPDACCTL.bit.SELREF = REFERENCE_VDDA; // Use VDDA as the reference for DAC
  Cmpss1Regs.COMPDACCTL.bit.DACSOURCE = DACSOURCE_DACHVALS; // Select DACHVALA source as the DACHVALS shadow register


  // Set up hysteresis control register.
  Cmpss1Regs.COMPHYSCTL.bit.COMPHYS = COMPHYS_NONE;


  // Configure CTRIPOUT path. Asynch output feeds CTRIPH and CTRIPOUTH.
  Cmpss1Regs.COMPCTL.bit.CTRIPHSEL = CTRIP_ASYNCH;
  Cmpss1Regs.COMPCTL.bit.CTRIPOUTHSEL = CTRIP_ASYNCH;


  // Configure CTRIPOUTH output pin.
  OutputXbarRegs.OUTPUT4MUX0TO15CFG.bit.Mux0 = 0; // Configure XTRIPOUT4 to be CTRIPOUT1H
  OutputXbarRegs.OUTPUT4MUXENABLE.bit.Mux0 = 1; // Enable XTRIPOUT4 Mux for Output
  EPwmXbarRegs.TRIP4MUX0TO15CFG.bit.Mux0 = 0; // Configure TRIP4 for ePWM to be CTRIPOUT1H
  EPwmXbarRegs.TRIP4MUXENABLE.bit.Mux0 = 1; // Enable MUX

  EDIS;
}

 
static void InitCmpss2(void)
{
  EALLOW;


  // Set up CMPSS2 control registers.
  Cmpss2Regs.DACHVALS.bit.DACVAL = cbcTripLevel;
  Cmpss2Regs.COMPCTL.bit.COMPDACE = 1; // Enable CMPSS
  Cmpss2Regs.COMPCTL.bit.COMPHSOURCE = NEGIN_DAC; // NEG signal comes from DAC
  Cmpss2Regs.COMPDACCTL.bit.SELREF = REFERENCE_VDDA; // Use VDDA as the reference for DAC
  Cmpss2Regs.COMPDACCTL.bit.DACSOURCE = DACSOURCE_DACHVALS; // Select DACHVALA source as the DACHVALS shadow register


  // Set up hysteresis control register.
  Cmpss2Regs.COMPHYSCTL.bit.COMPHYS = COMPHYS_NONE;


  // Configure CTRIPOUT path. Asynch output feeds CTRIPH and CTRIPOUTH.
Cmpss2Regs.COMPCTL.bit.CTRIPHSEL = CTRIP_ASYNCH;
  Cmpss2Regs.COMPCTL.bit.CTRIPOUTHSEL = CTRIP_ASYNCH;


  // Configure CTRIPOUTH output pin.
OutputXbarRegs.OUTPUT7MUX0TO15CFG.bit.Mux2 = 0; // Configure XTRIPOUT7 to be CTRIPOUT2H
  OutputXbarRegs.OUTPUT7MUXENABLE.bit.Mux2 = 1; // Enable XTRIPOUT7 Mux for Output
  EPwmXbarRegs.TRIP7MUX0TO15CFG.bit.Mux2 = 0; // Configure TRIP7 for ePWM to be CTRIPOUT2H
  EPwmXbarRegs.TRIP7MUXENABLE.bit.Mux2 = 1; // Enable MUX

  EDIS;
}

 
static void InitCmpss3(void)
{
  EALLOW;


  // Set up CMPSS3 control registers.
  Cmpss3Regs.DACLVALS.bit.DACVAL = pocTripLevel;
  Cmpss3Regs.COMPCTL.bit.COMPDACE = 1; // Enable CMPSS
  Cmpss3Regs.COMPCTL.bit.COMPHSOURCE = NEGIN_DAC; // NEG signal comes from DAC
  Cmpss3Regs.COMPDACCTL.bit.SELREF = REFERENCE_VDDA; // Use VDDA as the reference for DAC
  Cmpss3Regs.COMPDACCTL.bit.DACSOURCE = DACSOURCE_DACHVALS; // Select DACHVALA source as the DACHVALS shadow register


  // Set up hysteresis control register.
Cmpss3Regs.COMPHYSCTL.bit.COMPHYS = COMPHYS_NONE;


  // Configure CTRIPOUT path. Asynch output feeds CTRIPL and CTRIPOUTL.
  Cmpss3Regs.COMPCTL.bit.CTRIPLSEL = CTRIP_ASYNCH;
Cmpss3Regs.COMPCTL.bit.CTRIPOUTLSEL = CTRIP_ASYNCH;


  // Configure CTRIPOUTL output pin.
  OutputXbarRegs.OUTPUT8MUX0TO15CFG.bit.Mux5 = 0; // Configure XTRIPOUT8 to be CTRIPOUT3L
  OutputXbarRegs.OUTPUT8MUXENABLE.bit.Mux5 = 1; // Enable XTRIPOUT8 Mux for Output
  EPwmXbarRegs.TRIP8MUX0TO15CFG.bit.Mux5 = 0; // Configure TRIP8 for ePWM to be CTRIPOUT3L
  EPwmXbarRegs.TRIP8MUXENABLE.bit.Mux5 = 1; // Enable MUX

  EDIS;
}

 

And here is my code for setting up the PWMs:

static void InitEPwm1(void)
{

  #define EPWM1_TIMER_TBPRD 5000 // 20 kHz count up/down in 200 MHz CPU clock ticks

  #define MAX_ON_TIME ((Uint16)(EPWM1_TIMER_TBPRD * (23.0/25.0)))

  EALLOW;


  // Setup TBCLK
  EPwm1Regs.ETSEL.bit.SOCAEN = 0; // Disable SOC on A group
  EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up/down
  EPwm1Regs.TBPRD = EPWM1_TIMER_TBPRD; // Set timer period - assuming clock of 200 MHz
  EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading
  EPwm1Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0
  EPwm1Regs.TBCTR = 0x0000; // Clear counter
  EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT
  EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
  EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // Sync downstream modules on counter = 0
  EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW;


  // Setup shadow register load on ZERO
  EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
  EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
  EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
  EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;


  // Set initial compare values
  EPwm1Regs.CMPA.half.CMPA = 0;
  EPwm1Regs.CMPB.half.CMPB = EPwm1Regs.TBPRD;


  // Set actions
  EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET; // Set PWM1A on Zero
  EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clear PWM1A on event A, up count
  EPwm1Regs.AQCTLB.bit.PRD = AQ_SET; // Set PWM1B on Zero
  EPwm1Regs.AQCTLB.bit.CBD = AQ_CLEAR; // Clear PWM1B on event B, up count


  // Configure cycle-by-cycle trip events for EPWM1. This consists of the inner loop error amplifier output

  // (TRIPINPUT4) and the cycle-by-cycle current limit comparator output (TRIPINPUT7).

  // From e2e... This is NOT explained clearly in the documentation:

  // SIDE NOTE: Something that had me confused for a while that might help someone else out: The

  // DCxEVTx in the TZCTL registers DO NOT LATCH WHEN THE COMPARE EVENT GOES AWAY! You have to

  // use the TZA and TZB settings to get behavior that latches the pwm signals (either OSHT or CBC).

  // EPwm1Regs.TZCTL.bit.TZA = TZ_FORCE_LO;
  // EPwm1Regs.TZCTL.bit.TZB = TZ_FORCE_LO;
  // EPwm1Regs.TZSEL.bit.DCAEVT2 = 1;
  // EPwm1Regs.TZSEL.bit.DCBEVT2 = 1;
  EPwm1Regs.TZDCSEL.bit.DCAEVT2 = TZ_DCAH_HI; // Event 2 (side A) occurs when the high comparator goes HIGH
  EPwm1Regs.TZDCSEL.bit.DCBEVT2 = TZ_DCBH_HI; // Event 2 (side B) occurs when the high comparator goes HIGH
  EPwm1Regs.DCTRIPSEL.bit.DCAHCOMPSEL = 0xF; // OR trip events specified by DCAHTRIPSEL
  EPwm1Regs.DCTRIPSEL.bit.DCBHCOMPSEL = 0xF; // OR trip events specified by DCBHTRIPSEL
  EPwm1Regs.DCAHTRIPSEL.bit.TRIPINPUT4 = 1; // Enable TRIPINPUT4, which is the error amplifier comparator output (for side A)
  EPwm1Regs.DCBHTRIPSEL.bit.TRIPINPUT4 = 1; // Enable TRIPINPUT4, which is the error amplifier comparator output (for side B)
  EPwm1Regs.DCAHTRIPSEL.bit.TRIPINPUT7 = 1; // Enable TRIPINPUT7, which is the cycle-by-cycle comparator output (for side A)
  EPwm1Regs.DCBHTRIPSEL.bit.TRIPINPUT7 = 1; // Enable TRIPINPUT7, which is the cycle-by-cycle comparator output (for side B)
  EPwm1Regs.TZCTLDCA.bit.DCAEVT2D = TZ_FORCE_LO; // Force EPWM1A low on event when counter is counting down
  EPwm1Regs.TZCTLDCA.bit.DCAEVT2U = TZ_FORCE_LO; // Force EPWM1A low on event when counter is counting up
  EPwm1Regs.TZCTLDCB.bit.DCBEVT2D = TZ_FORCE_LO; // Force EPWM1B low on event when counter is counting down
  EPwm1Regs.TZCTLDCB.bit.DCBEVT2U = TZ_FORCE_LO; // Force EPWM1B low on event when counter is counting up
  EPwm1Regs.DCACTL.bit.EVT2SRCSEL = DC_EVT2; // Configure path to be unfiltered
  EPwm1Regs.DCACTL.bit.EVT2FRCSYNCSEL = DC_EVT_ASYNC; // Configure path to be asynchronous
  EPwm1Regs.DCBCTL.bit.EVT2SRCSEL = DC_EVT2; // Configure path to be unfiltered
  EPwm1Regs.DCBCTL.bit.EVT2FRCSYNCSEL = DC_EVT_ASYNC; // Configure path to be asynchronous


  // Configure one-shot trip events for EPWM1. This consists only of the primary overcurrent comparator output (TRIPINPUT8).
  EPwm1Regs.TZDCSEL.bit.DCAEVT1 = TZ_DCAL_HI; // Event 1 (side A) occurs when the low comparator goes HIGH
  EPwm1Regs.TZDCSEL.bit.DCBEVT1 = TZ_DCBL_HI; // Event 1 (side B) occurs when the low comparator goes HIGH
  EPwm1Regs.DCTRIPSEL.bit.DCALCOMPSEL = 0xF; // OR trip events specified by DCALTRIPSEL
  EPwm1Regs.DCTRIPSEL.bit.DCBLCOMPSEL = 0xF; // OR trip events specified by DCBLTRIPSEL
  EPwm1Regs.DCALTRIPSEL.bit.TRIPINPUT8 = 1; // Enable TRIPINPUT8, which is the POC comparator output (for side A)
  EPwm1Regs.DCBLTRIPSEL.bit.TRIPINPUT8 = 1; // Enable TRIPINPUT8, which is the POC comparator output (for side B)
  EPwm1Regs.TZSEL.bit.DCAEVT1 = 1; // Configure DCA as one-shot
  EPwm1Regs.TZSEL.bit.DCBEVT1 = 1; // Configure DCB as one-shot
  EPwm1Regs.TZCTLDCA.bit.DCAEVT1D = TZ_FORCE_LO; // Force EPWM1A low on event when counter is counting down
  EPwm1Regs.TZCTLDCA.bit.DCAEVT1U = TZ_FORCE_LO; // Force EPWM1A low on event when counter is counting up
  EPwm1Regs.TZCTLDCB.bit.DCBEVT1D = TZ_FORCE_LO; // Force EPWM1B low on event when counter is counting down
  EPwm1Regs.TZCTLDCB.bit.DCBEVT1U = TZ_FORCE_LO; // Force EPWM1B low on event when counter is counting up
  EPwm1Regs.DCACTL.bit.EVT1SRCSEL = DC_EVT1; // Configure path to be unfiltered
  EPwm1Regs.DCACTL.bit.EVT1FRCSYNCSEL = DC_EVT_ASYNC; // Configure path to be asynchronous
  EPwm1Regs.DCBCTL.bit.EVT1SRCSEL = DC_EVT1; // Configure path to be unfiltered
  EPwm1Regs.DCBCTL.bit.EVT1FRCSYNCSEL = DC_EVT_ASYNC; // Configure path to be asynchronous

  EDIS;
}

 

  • Jon,

    I believe that you have the XBAR configurations and Digital Compare configurations correct.  I do want you to know that the explanations and documentation for all these parts are being worked on.

    I believe that your issue is purely in the Trip-Zone Submodule and how it connects to the digital compare module.

    I think the main gotchas I see are below:
    1) the TZCTL2.ETZE bit - if 0, the TZCTL register is used to configure the trip logic actions.  If 1, the TZCTLDCA, TZCTLDCB and TZCTL2 registers are used.
    2) the default action for most unused TZCTL* actions is to push the PWM to Hi-Z.  I would explicitly configure all trips that you are not using to do nothing.
    3) your CBC trip actions are not occurring because TZSEL.TDAEVT2 and DCBEVT2 are not set to 1.  This keeps it out of the CBC latch logic.
    4) CBC and OSHT trips come via the TZA and TZB path.  The DCxEVTy.force paths will force the PWM signal only when the Digital Compare logic is active (ie won't latch at all).

    I realize the above may not make sense alone.  I'm hoping that this + the attached pictures helps to clarify things.  In the picture, the highlighted are the paths/register bits that I believe to be active based on your code.

    Please let me know if this helps.


    Thank you,
    Brett

  • Brett,

    Thanks for the detailed response. I think I understand a bit better what's going on, but I'm still not getting the result I'm looking for.  One thing that would help is if I understood what's in the "Trip Logic" block of the figure. If I had to guess, I want to configure that to use the CBC Trip Event (or is it TZA/TZB?) from the latch in the middle of Figure 12-41.  I'm not sure how to do that.  Ignoring the one-shot trip for now, in the attached figure I've highlighted what I think I want the path to be for the DCxEVTy signals, and I've modified my code to what I think does that.  What I'm seeing is that in this case the CBC flag is always asserted and the PWMs never turn on.3173.201404010637.pdf

      EPwm1Regs.TZCLR.bit.CBCPULSE           = 0;   // CTR = zero clears trip latch
      EPwm1Regs.TZSEL.bit.DCAEVT2            = 1;
      EPwm1Regs.TZSEL.bit.DCBEVT2            = 1;
      EPwm1Regs.TZCTL2.bit.ETZE              = 1;               // Enable TZCTL2 register (override TZCTL register settings)
      EPwm1Regs.TZCTL2.bit.TZAU              = TZ_FORCE_LO;
      EPwm1Regs.TZCTL2.bit.TZAD              = TZ_FORCE_LO;
      EPwm1Regs.TZCTL2.bit.TZBU              = TZ_FORCE_LO;
      EPwm1Regs.TZCTL2.bit.TZBD              = TZ_FORCE_LO;
      EPwm1Regs.TZDCSEL.bit.DCAEVT2          = TZ_DCAH_HI;      // Event 2 (side A) occurs when the high comparator goes HIGH
      EPwm1Regs.TZDCSEL.bit.DCBEVT2          = TZ_DCBH_HI;      // Event 2 (side B) occurs when the high comparator goes HIGH
      EPwm1Regs.DCTRIPSEL.bit.DCAHCOMPSEL    = 0xF;             // OR trip events specified by DCAHTRIPSEL
      EPwm1Regs.DCTRIPSEL.bit.DCBHCOMPSEL    = 0xF;             // OR trip events specified by DCBHTRIPSEL
      EPwm1Regs.DCAHTRIPSEL.bit.TRIPINPUT4   = 1;               // Enable TRIPINPUT4, which is the error amplifier comparator output (for side A)
      EPwm1Regs.DCBHTRIPSEL.bit.TRIPINPUT4   = 1;               // Enable TRIPINPUT4, which is the error amplifier comparator output (for side B)
      EPwm1Regs.TZCTLDCA.bit.DCAEVT2D        = TZ_NO_CHANGE;
      EPwm1Regs.TZCTLDCA.bit.DCAEVT2U        = TZ_NO_CHANGE;
      EPwm1Regs.TZCTLDCB.bit.DCBEVT2D        = TZ_NO_CHANGE;
      EPwm1Regs.TZCTLDCB.bit.DCBEVT2U        = TZ_NO_CHANGE;
      EPwm1Regs.TZCTL.bit.DCBEVT2            = TZ_NO_CHANGE;
      EPwm1Regs.TZCTL.bit.DCBEVT1            = TZ_NO_CHANGE;
      EPwm1Regs.TZCTL.bit.DCAEVT2            = TZ_NO_CHANGE;
      EPwm1Regs.TZCTL.bit.DCAEVT1            = TZ_NO_CHANGE;
      EPwm1Regs.DCACTL.bit.EVT2SRCSEL        = DC_EVT2;         // Configure path to be unfiltered
      EPwm1Regs.DCACTL.bit.EVT2FRCSYNCSEL    = DC_EVT_ASYNC;    // Configure path to be asynchronous
      EPwm1Regs.DCBCTL.bit.EVT2SRCSEL        = DC_EVT2;         // Configure path to be unfiltered
      EPwm1Regs.DCBCTL.bit.EVT2FRCSYNCSEL    = DC_EVT_ASYNC;    // Configure path to be asynchronous

  • Jon,

    Sorry, I was out for a few days.

    Are you any further along?  Or are you still having issues with the CBC trip logic?


    Thanks,
    Brett

  • I'm still having problems, although admittedly I've been busy with other things since my previous post.  I suppose as long as there is no reason why what I'm trying to do is not possible, I should be able to figure it out.

     

    Thanks,
    Jon

  • Jon,

    From what it looks like you are now pretty close.  I don't see anything obviously wrong based on my understanding.

    If you haven't already, I would explicitly set TZSEL's DCAEVT1 and DCBEVT1 (the OSHT-type of trips) to 0 for the time being.

    The other thing I would do is confirm that the OR combination of DCAEVT2 + DCBEVT2 events aren't always high (and therefore they are continually tripping your PWMs).

    Hopefully this helps.


    Thank you,
    Brett