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