Hi,
I have the ePWM1 module set up to Active High Complementary, so that ePWM1A is the master and ePWM1B is the complement. I am using the CMPSS module to use the internal DAC reference compared to an external current signal. The output of the CMPSS flows into T1 of the Action Qualifier Submodule to terminate ePWM1A (and complementarily assert ePWM1B). The idea is to set ePWM1A HI at the beginning of the switching cycle, and then go LO when the current goes higher than the reference.
First, please confirm my following understandings for the approach
- To preserve PWM AHC, I must use the Action Qualifier (in this case, T1); this is so the signal gets processed by the Dead Band (DB) Submodule that implements the AHC. I CANNOT use action directly from a Digital Compare Event (say DCAEVT2), or from the Trip Zone submodule, since these both directly affect the PWM output and bypass the DB. I want to preserve dead time between ePWM1A/B.
- The AQ actuates the PWM based on signal edges; for example, if T1 persists continuously, then when CTR=ZRO happens some time later it will take effect overriding the T1.
I am testing a boundary condition, where current is already too high at the beginning of the switching cycle, so I want the PWM to stay off entirely, not even a blip (note I believe I must use the AQ to preserve dead time). To test this, I set the internal DAC to 0, and the external signal some amount above zero, so that the CMPSS output is already HI at the beginning of the switching cycle. As expected, the CTR=0 seems to be overriding T1 and the output goes HI. To get around this, I am attempting various blanking methods, but am experiencing unexpected behavior.
void main(void) { // Initialize device clock and peripherals InitSysCtrl(); // Initialize GPIO and configure the GPIO pin as a push-pull output InitGpio(); GPIO_SetupPinMux(DEVICE_GPIO_PIN_LED1, GPIO_MUX_CPU1, 0); GPIO_SetupPinOptions(DEVICE_GPIO_PIN_LED1, GPIO_OUTPUT, GPIO_PUSHPULL); GPIO_SetupPinMux(DEVICE_GPIO_PIN_LED2, GPIO_MUX_CPU1, 0); GPIO_SetupPinOptions(DEVICE_GPIO_PIN_LED2, GPIO_OUTPUT, GPIO_PUSHPULL); GpioDataRegs.GPASET.bit.GPIO31 = 1; // left LED GpioDataRegs.GPBSET.bit.GPIO34 = 1; // Right LED // Initialize PIE and clear PIE registers. Disables CPU interrupts. DINT; InitPieCtrl(); // Disable CPU interrupts and clear all CPU interrupt flags IER = 0x0000; IFR = 0x0000; // Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR). InitPieVectTable(); // Enable Global Interrupt (INTM) and realtime interrupt (DBGM) EnableInterrupts(); EINT; ERTM; CMPSS_investigation2(); // Loop Forever for(;;) { } } void CMPSS_investigation2(void) { EALLOW; //////////////////////////// // GPIO // //////////////////////////// // Configure GPIO as ePWM1A/B // ePWM1A (GPIO0) GpioCtrlRegs.GPALOCK.bit.GPIO0 = 0; // unlock GPIO to make changes GpioCtrlRegs.GPAGMUX1.bit.GPIO0 = 0; // Configure as a GPIO, this is default but being explicit anyway GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; // Configure as a GPIO, this is default but being explicit anyway GpioCtrlRegs.GPALOCK.bit.GPIO0 = 1; // lock GPIO to prevent further changes // ePWM1B (GPIO1) GpioCtrlRegs.GPALOCK.bit.GPIO1 = 0; // unlock GPIO to make changes GpioCtrlRegs.GPAGMUX1.bit.GPIO1 = 0; // Configure as a GPIO, this is default but being explicit anyway GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1; // Configure as a GPIO, this is default but being explicit anyway GpioCtrlRegs.GPALOCK.bit.GPIO1 = 1; // lock GPIO to prevent further changes //////////////////////////// // AIO // //////////////////////////// // select appropriate mux for CMPSS inputs AnalogSubsysRegs.CMPHPMXSEL.bit.CMP1HPMXSEL = 2; // CMPSS1 : CMP1_HP2 : IL_POS //////////////////////////// // CMPSS // //////////////////////////// // Use internal DAC with ramp generator // When external signal exceeds DAC, output of CMPSS is asserted // Resets at ePWM1SYNCO (ePWM1 CMPB, sets max duty) // CMPSS1 : CMP1_HP2 : IL_POS Cmpss1Regs.COMPCTL.bit.COMPDACE = 0; // Disable CMPSS1 until finished with init (defualt) Cmpss1Regs.COMPDACCTL.bit.FREESOFT = 2; // Run during debug mode halts Cmpss1Regs.COMPDACCTL.bit.SELREF = 0; // Use internal reference VDDA (default) Cmpss1Regs.COMPCTL.bit.COMPHSOURCE = 0; // COMPH- to use DACHVALA (default) Cmpss1Regs.COMPDACCTL.bit.DACSOURCE = 1; // DACHVALA uses ramp generator Cmpss1Regs.COMPDACCTL.bit.SWLOADSEL = 0; // Load DACHVALA on SYSCLK Cmpss1Regs.COMPDACCTL.bit.RAMPLOADSEL = 1; // Load ramp directly from shadow register RAMPMAXREFS Cmpss1Regs.COMPDACCTL.bit.BLANKSOURCE = 0; Cmpss1Regs.COMPDACCTL.bit.BLANKEN = 1; Cmpss1Regs.COMPSTSCLR.bit.HSYNCCLREN = 1; // Use EPWM1SYNCO to clear CMPSS latch Cmpss1Regs.RAMPMAXREFS = 0; // Will be updated during compensator routine Cmpss1Regs.RAMPDECVALS = 0; // Will be updated during compensator routine Cmpss1Regs.COMPDACCTL.bit.RAMPSOURCE = 0; // RAMPSOURCE = select ramp reset source = EPWM1SYNCO (Ramp Reset PWM) // This assumes SYNCO is sent at CMPB = MAX DUTY Cmpss1Regs.RAMPDLYS.all = 50; // RAMPSTS is updated at SYNCO = MAX DUTY to allow DAC starting point to settle // MAX DUTY + 50 SYSCLK delay = start of new switching cycle, ready to start decrementing Cmpss1Regs.COMPCTL.bit.CTRIPHSEL = 1; // synchronous trip of CMPSS output, so that it can be blanked Cmpss1Regs.COMPCTL.bit.COMPDACE = 1; // Enable CMPSS1 //////////////////////////// // ePWM1A/B // //////////////////////////// // Configure as (AHC w/ DT) Active High Complementary, with Dead Time (Dead time set to 0 for now) // ePWM1A starts HI, goes LO either at max duty or when CMPSS trips. ePWM1B is the inverse. // Use CMPSS Output as T1 to Action Qualifier (AQ), so AHC w/ DT is preserved (Trip Zone directly affects output) // Note: I believe blanking of CMPSS signal is needed, to momentarily turn off CMPSS output, as AQ needs a rising edge to actuate PWM // This will be accomplished using the SYNCO signal, actuating on CMPB (Max Duty) /* Table Counter */ EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0; // 0 = SYSCLK/1, 1 = SYSCLK/2 (default) EPwm1Regs.TBCTL.bit.FREE_SOFT = 2; // run during debug mode halts EPwm1Regs.TBCTL.bit.CTRMODE = 0; // 0 = count up (default)) EPwm1Regs.TBPRD = 714; // Switching period EPwm1Regs.TBCTL.bit.SYNCOSEL = 2; // Send sync signal at Max Duty (CMPB), needed to reset CMPSS Ramp /* ePWM XBAR TRIPIN4 */ // Selects CMPSS to be input to digital comparator EPwmXbarRegs.TRIP4MUX0TO15CFG.bit.MUX0 = 0; // Select CMPSS1H as input to XBAR TRIP MUX EPwmXbarRegs.TRIP4MUXENABLE.bit.MUX0 = 1; // Enable CMPSS1H as input to XBAR TRIP MUX /* Digital Comparator */ EPwm1Regs.DCTRIPSEL.bit.DCAHCOMPSEL = 3; // TRIPIN4 on digital comparator +in EPwm1Regs.DCTRIPSEL.bit.DCALCOMPSEL = 3; // TRIPIN4 on digital comparator -in (not needed) EPwm1Regs.TZDCSEL.bit.DCAEVT2 = 2; // Digital Comparator output DCAEVT2 asserted on +in assertion. /* Action Qualifier */ EPwm1Regs.AQTSRCSEL.bit.T1SEL = 1; // 1 = T1 trips on DCAEVT2 EPwm1Regs.AQCTLA.bit.ZRO = 2; // 2 = force HI on zero, EPwm1Regs.AQCTLA2.bit.T1U = 1; // 1 = force LO on T1 = DCAEVT2 = CMPSS = OCC Trip EPwm1Regs.CMPB.bit.CMPB = 664; // Max Duty EPwm1Regs.AQCTLA.bit.CBU = 1; // Max Duty forces LO /* Trip Zone */ // These registers are active by default, and set PWM output to high impedance on Digital Comparator trip EPwm1Regs.TZCTLDCA.all = 0xFFFF; EPwm1Regs.TZCTLDCB.all = 0xFFFF; EPwm1Regs.TZCTL.all = 0xFFFF; // Force LO /* Dead Band Control */ // Dead band generator creates Active High Complimentary with Dead Time (AHCDT) PWM outputs for ePWM1A (master) and ePWM1B (derived from ePWM1A). // S0 - S8 mentioned below are the Dead Band Control Switches, see Figure 18-33 in the User Guide. EPwm1Regs.DBCTL.bit.IN_MODE = 0; // S4 & S5 in 0 position (default) EPwm1Regs.DBCTL.bit.DEDB_MODE = 0; // S8 in 0 position (default) EPwm1Regs.DBCTL.bit.POLSEL = 2; // S2 in 0 pos, S3 in 1 pos (AHC) EPwm1Regs.DBCTL.bit.OUT_MODE = 3; // S0 & S1 in 1 position, RED & FED Active EPwm1Regs.DBCTL.bit.OUTSWAP = 0; // S6 & S7 in 0 position (default) EPwm1Regs.DBRED.all = 0; // At this point, choose appropriate RED and FED EPwm1Regs.DBFED.all = 0; // At this point, choose appropriate RED and FED EDIS; }
A. EPWMSYNCO
Referring to Figure 16-1 in the user's guide, the first attempt was to use set CTRIPH output to SYNCH, so that it could be cleared using EPWM1SYNCO at CMPB=ZRO. This works. I could pronounce victory but...
To see what would happen, I then set CMPB to some other arbitrary amount (say 200 out of a TBPRD of 714), and I got the following waveform. CH1 YELLOW is ePWM1A, CH2 PINK is ePWM1B. As expected ePWM1A is going HI when CTR=ZRO, but somehow is being terminated 50ns later. I have no idea what is causing this, except perhaps the EPWM1SYNCO is being asserted for all of the remaining TBPRD, and once it is released the blanking ends and CMPSS trips terminating ePWM1A. How long is SYNCO pulse?
B. EPWMBLANK
I plan on using CMPB for MAX DUTY control, and want to reset the ramp generator at that time. So I will need to using the EPWM1BLANK instead. I was able to get it to work using the code below.
EPwm1Regs.DCFCTL.bit.PULSESEL = 1; // TBCTR = 0 EPwm1Regs.DCFOFFSET = 709; // Offset of 709 and Window of 1 seems to work for some reason EPwm1Regs.DCFWINDOW = 1; EPwm1Regs.DCFCTL.bit.BLANKE = 1; // Enable the blanking window
However the DCFOFFSET + DCFWINDOW values were not what I expected. The TBPRD is 714, and only with DCFOFFSET + DCFWINDOW = 710 will this work. Otherwise the timing is off and the result looks the same as the waveform above. Do you have any insight why 710 out of a TBPRD of 714 is required? I had to trial-and-error-hand-tune this to get it to work. The only thing I can think of is some unspecified delay between the CMPSS output and the AQ deciding to take action on the PWM.
This was a long one, so thank you very much for your help!