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.

TMS320F280049C: CMPSS and AQ PWM Control

Part Number: TMS320F280049C

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

  1. 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.
  2. 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!

  • Hi,

    Your understanding about the usage of T1/T2 in the action qualifer module and using that for generating AHC output is  correct. So, i agree with both the comments in the beginning of your post.

    "How long is SYNCO pulse?"

    If you are referring to the EPWMxSYNCO pulse at the input to the Comparator subsystem - it's same as the event chosen, inside EPWM, as source for SYNCO.
    For ex: in this case Compare event, which is 1 PWM Clock cycle wide pulse.
    Syncout is 8xSYSCLK cycle wide pulse - when sent out to GPIO pin via external Syncout pulse.

    Regarding the DCFOFFSET + DCFWINDOW, Figure 18-55. Blanking Window Timing Diagram - shows the configuration needed.
    I do not think I understand your concern/observation regarding this.


    Here is what you might be missing in your configuration -
    Try to set Pwm1Regs.AQTSRCSEL.bit.T1SEL this to DCEVTFILT - instead of raw DCEVTx.
    Now with the blanking enabled - at the end of blanking window, there should be an event on DCEVTFILT, and that in turn would turn off the PWM.
    If you use the raw DCxEVT in this case there is no edge on the DCxEVT and hence it would not trigger the T1 event inside the action qualifier.





  • Thanks for the reply.


    1. For how long is SYNCO pulse:

    "If you are referring to the EPWMxSYNCO pulse at the input to the Comparator subsystem - it's same as the event chosen, inside EPWM, as source for SYNCO. For ex: in this case Compare event, which is 1 PWM Clock cycle wide pulse."

    Yes that is was I was referring to. The answer is what I was expecting, but the observed behavior remains a mystery. Something is causing the PWM to go LO, I don't know what it is yet but somehow setting SYNCO to trigger mid period instigates the issue.

    2. For Blanking

    "Try to set Pwm1Regs.AQTSRCSEL.bit.T1SEL this to DCEVTFILT - instead of raw DCEVTx... Figure 18-55. Blanking Window Timing Diagram - shows the configuration needed."

    DCEVTFILT will only ignore event occurrences during the window, not clear them. Section 18.3.9.4.2 says "During the blanking window, all events are ignored. Before and after the blanking window ends, events can generate soc, sync, interrupt, and force signals as before."

    I tested it out just to make sure, and I confirmed that it does exactly as expected - the DCEVTx is constantly asserted and the PWM never resets (see the beginning of the original post).

    I think this simply reaffirms that I need to use the blanking feature of the CMPSS, to de-assert the CMPSS output and allow another DCEVTx rising edge to occur for the AQ to take action.

    I am fairly convinced of my observation at this point, namely there is some propagation delay between blanking the CMPSS output and AQ actuation, such that I will need to empirically adjust the blanking timing to get the behavior I want.

  • In the DCFCTL register, what do the following bits do? There doesn't seem to be any information regarding these.

    EDGEMODE

    EDGESTATUS

    EDGEFILTSEL

    Thanks!

  • "I think this simply reaffirms that I need to use the blanking feature of the CMPSS, to de-assert the CMPSS output and allow another DCEVTx rising edge to occur for the AQ to take action."

    That's correct - using DCEVTFILT would inherently do that, it would generate an event at the end of the blanking window - if the event (CompOut) is still active.

    "I am fairly convinced of my observation at this point, namely there is some propagation delay between blanking the CMPSS output and AQ actuation, such that I will need to empirically adjust the blanking timing to get the behavior I want."

    There will be a delay of ~2-3 PWM clock cycles, this is due to the Comparator output synchronization and Action qualifier turning on/off of PWM. It's not instantaneous like PWM Trip action.

  • These bits in the DCFCTL are used for edge filter control on Digital comparator events, to further filter out edges beyond blanking window.
    These details seem to be missing in the TRM - i'll submit an update request.
    You do not have to use these bits for your case.
  • 1. Although I may not need them, can you please provide the details that will be added to the TRM? I still don't know what to do with these bits should I choose to utilize them in the future.

    2. New question. I am trying to disable EPWMSYNCO for resetting the ramp, to evaluate how configuring the EPWMSYNCO within the ePWM module affects the CMPSS ramp reset..

    As you can see in the code in the original post, I am synching on PWM1 CMPB. As a test, I removed all blanking (Cmpss1Regs.COMPSTSCLR.bit.HSYNCCLREN = 0), and removed CMPB from actuating the PWM (only thing actuating the PWM is CTR=ZRO and CMPSS Trip). I attempted to completely disable EPWMSYNCO by setting

    EPwm1Regs.TBCTL.bit.SYNCOSEL = 3 // Defined by TBCTL2
    EPwm1Regs.TBCTL2.bit.SYNCOSELX = 0 // Disable SYNCO Signal

    Here I would expect the ramp to never reset. Since 16.4.2 (pf 1494) of the TRM says only on the rising edge of EPWMSYNCO will the RAMPSTS be loaded with RAMPMAXREFS and start decrementing. I would expect ramp goes to the trip point and sets PWM LO, and then halt since on the rising edge of COMPHSTS RAMPSTS stops decrementing. On the next table counter loop ZRO sets PWM HI, and then it should stay HI indefinitely since the ramp has stopped and there should be no trips.

    Instead what I am seeing is the PWM tripping every switching cycle at the expected trip duty, as if the ramp is being reset at TBCTR=0 and then counting down again. 
     
    Can you please confirm what the expected behavior is here? I cannot seem to confirm that configuring the EPWM1SYNCO within the ePWM module has any effect on the CMPSS ramp reset. It looks to me like the CMPSS ramp is hardwired to reset at TBCTR=0.

    Thank You.

  • Hi,

    1. You can refer to www.ti.com/.../spruhm8g.pdf
    Chapter - 14.11.4.3 Valley Switching

    2. SYNCOUT is not same as PWMSYNC used for resetting the ramp generator.
    I believe, you want to use HRPCTL Register, PWMSYNCSEL/PWMSYNCSELX bits.

    Thank you.
  • Thank you Subrahmanya, HRPCTL did the change I was looking for.

    This new valley switching seems interesting. Is there a more detailed app note explaining how it is intended to be used? It seems like this a valuable feature that TI took some intention on including here, so I am surprised there isn't more detail provided to assist in using it. The one-page description still isn't all that clear to me, although it seems to me like all it is doing is adding a delay to actuating the PWM. 

    Something like: CMPSS trips on current threshold. DC submodule filters the event to wait some register-coded delay to allow resonance to bring the switch voltage to a valley point before actuating the PWM (presumably the time delay is calculated ahead of time and/or adjusted through experimental results, and that is the coded delay that the register is using). 

    There are a handful of registers so I suspect it may be more versatile than that. 

    Thanks again for the help.

  • Hi,

    Regarding "Valley Switching" function -
    There will be a TI design coming soon, in a couple of months, highlighting the capability and usage.
    This logic can potentially provides the hooks to identify the "valley" point and enable switching at that instance.
    Yes - it's based on the CMPSS outputs and identifying the valley point.
    Upcoming TI design should address and showcase these capabilities.
  • Thanks, can I get a high level sneak peak? :)

    Without needing to explain registers and bit settings, just conceptually how can it actually identify the valley point? My previous post assumed the designer had to have knowledge of the valley point timings ahead of time and program in those delays (whether static, look up table, or dynamic calculations).

    If I can just get the general idea of how the CMPSS and Valley Switching functions work together, I think I could put the pieces together from there. This is actually something that could be immediately useful for something I am working on.

    Thanks!
  • I'll tag the Valley Switching designer to respond with details.
  • Hi SRW,

    The figure above just shows a big picture on how to detect the valley point. The threshold can be set through a CMPSS module and the target period can be captured once the designed # of edge is detected. Then a 1/4 of period delay following the final edge in this situation is added to find the valley point. Like you mentioned, the dynamic calculation is implemented to achieve best performance. Hope this helps. 

    Best regards,

    Chen

  • Great, thank you Chen. Makes sense now with that Figure.

    Thank you both for the help.