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.

Issue with PWMDRV_PSFB DP Library Macro (v3.3) F28035

Other Parts Discussed in Thread: CONTROLSUITE

So I put together code based on the DP Library template to create a controller for a phase shift controlled converter.  I modified the code to digitize a waveform and feed the corresponding input into the PWMDRV_PSFB assembly code macro.  I am getting the 100kHz 50 percent duty cycle signal I expect on the master ePWM channel, but the slave output isn't correct at all.  Sometimes I get the appropriate phase shifted output, but most of the time the output on the slave ePWM is stuck either high or low.  Any ideas on the root cause of this? 

I looked at the configuration/settings files for the project and I haven't noticed any issues there.  I also looked at the HVPSFB example available through controlSUITE and what I have in my code is very similar to that set of example code.  I am using the 28035 experiment kit as a test platform.  I put hardware breakpoints in and I can see that the ISR is being run; beyond that I'm not sure what to do in terms of debug. 


Lance

  • Here is a bit of a code dump; may or may not be useful; but it should be all of the code relevant to the problem.

    Configuration File Code

    #include "PeripheralHeaderIncludes.h"
    #include "DSP2803x_EPWM_defines.h" // useful defines specific to EPWM

    extern volatile struct EPWM_REGS *ePWM[];


    void PWM_PSFB_CNF(int16 n, int16 Period)
    {
    // n = the ePWM module number, i.e. selects the target module for init.
    // ePWM(n) init. Note EPWM(n) is the Master

    //Time Base SubModule Register
    (*ePWM[n]).TBCTL.bit.PRDLD = TB_IMMEDIATE; // set Immediate load
    (*ePWM[n]).TBPRD = Period-1;
    (*ePWM[n]).TBPHS.half.TBPHS = 0;
    (*ePWM[n]).TBCTR = 0;

    (*ePWM[n]).TBCTL.bit.CTRMODE = TB_COUNT_UP;
    (*ePWM[n]).TBCTL.bit.PHSEN = TB_DISABLE;
    (*ePWM[n]).TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; //used to sync EPWM(n+1) "down-stream"
    (*ePWM[n]).TBCTL.bit.HSPCLKDIV = TB_DIV1;
    (*ePWM[n]).TBCTL.bit.CLKDIV = TB_DIV1;

    // Counter compare submodule registers
    (*ePWM[n]).CMPA.half.CMPA = Period/2; // Fix duty at 50%

    // Action Qualifier SubModule Registers
    (*ePWM[n]).AQCTLA.bit.ZRO = AQ_SET;
    (*ePWM[n]).AQCTLA.bit.CAU = AQ_CLEAR;

    // DeadBand Control Register
    (*ePWM[n]).DBCTL.bit.OUT_MODE = DB_FULL_ENABLE;
    (*ePWM[n]).DBCTL.bit.POLSEL = DB_ACTV_HIC; // Active Hi Complimentary
    (*ePWM[n]).DBRED = 50; // dummy value for now
    (*ePWM[n]).DBFED = 50; // dummy value for now

    // ePWM(n+1) init. EPWM(n+1) is a slave

    //Time Base SubModule Register
    (*ePWM[n+1]).TBCTL.bit.PRDLD = TB_IMMEDIATE; // set Immediate load
    (*ePWM[n+1]).TBPRD = Period;
    (*ePWM[n+1]).TBPHS.half.TBPHS = 0; // zero phase initially
    (*ePWM[n+1]).TBCTR = 0;

    (*ePWM[n+1]).TBCTL.bit.CTRMODE = TB_COUNT_UP;
    (*ePWM[n+1]).TBCTL.bit.PHSEN = TB_ENABLE;
    (*ePWM[n+1]).TBCTL.bit.SYNCOSEL = TB_SYNC_IN; // Sync "flow through" mode
    (*ePWM[n+1]).TBCTL.bit.HSPCLKDIV = TB_DIV1;
    (*ePWM[n+1]).TBCTL.bit.CLKDIV = TB_DIV1;

    // Counter compare submodule registers
    (*ePWM[n+1]).CMPA.half.CMPA = Period/2; // Fix duty at 50%

    // Action Qualifier SubModule Registers
    (*ePWM[n+1]).AQCTLA.bit.ZRO = AQ_SET;
    (*ePWM[n+1]).AQCTLA.bit.CAU = AQ_CLEAR;

    (*ePWM[n+1]).DBCTL.bit.OUT_MODE = DB_FULL_ENABLE;
    (*ePWM[n+1]).DBCTL.bit.POLSEL = DB_ACTV_HIC; // Active Hi Complimentary
    (*ePWM[n+1]).DBRED = 50; // dummy value for now
    (*ePWM[n+1]).DBFED = 50; // dummy value for now


    // Trip Zone submodule registers
    EALLOW;

    ePWM[n]->TZSEL.all = 0x0;
    ePWM[n]->TZSEL.bit.OSHT4 = TZ_ENABLE; // Enable TZ4 -- FB Overcurrent Trip
    ePWM[n]->TZCTL.bit.TZA = TZ_FORCE_LO; // Low on shutdown
    ePWM[n]->TZCTL.bit.TZB = TZ_FORCE_LO; // Low on shutdown

    ePWM[n+1]->TZSEL.all = 0x0;
    ePWM[n+1]->TZSEL.bit.OSHT4 = TZ_ENABLE; // Enable TZ4 -- FB Overcurrent Trip
    ePWM[n+1]->TZCTL.bit.TZA = TZ_FORCE_LO; // Low on shutdown
    ePWM[n+1]->TZCTL.bit.TZB = TZ_FORCE_LO; // Low on shutdown

    EDIS;

    }

    PWMDRV_PSFB Code

    ;======================
    PWMDRV_PSFB_INIT .macro n,m
    ;======================
    ; variable Declarations
    _PWMDRV_PSFB_Phase:n: .usect "PWMDRV_PSFB_Section",2,1,1 ; Input Terminal 1, Phase
    _PWMDRV_PSFB_DbLeft:n: .usect "PWMDRV_PSFB_Section",2,1,1 ; Input Terminal 2, DbLeft
    _PWMDRV_PSFB_DbRight:n: .usect "PWMDRV_PSFB_Section",2,1,1 ; Input Terminal 3, DbRight

    ;Publish Terminal Pointers for access from the C environment
    ;===========================================================
    .def _PWMDRV_PSFB_Phase:n:
    .def _PWMDRV_PSFB_DbLeft:n:
    .def _PWMDRV_PSFB_DbRight:n:

    ; set terminal to point to ZeroNet
    MOVL XAR2, #ZeroNet
    MOVW DP, #_PWMDRV_PSFB_Phase:n:
    MOVL @_PWMDRV_PSFB_Phase:n:, XAR2
    MOVL @_PWMDRV_PSFB_DbLeft:n:, XAR2
    MOVL @_PWMDRV_PSFB_DbRight:n:, XAR2

    .endm
    ;--------------------------------------------------------------------------------
    ;======================
    PWMDRV_PSFB .macro n,m
    ;======================

    ; Phase Adjustment between Left and Right Legs
    MOVW DP, #_PWMDRV_PSFB_Phase:n: ; load DP for net pointer
    MOVL XAR0, @_PWMDRV_PSFB_Phase:n: ; Load net pointer address to XAR0
    MOVL XAR1, @_PWMDRV_PSFB_DbLeft:n:
    MOVL XAR2, @_PWMDRV_PSFB_DbRight:n:
    MOVW DP, #_EPwm:m:Regs.TBPRD ; Load DP for EPWMPRD Register, Note use Mirror register for 32 bit read
    MOVL XT,@_EPwm:m:Regs.TBPRD ; Load XT = Duty (Q24)
    MOV TL,#0
    QMPYL ACC,XT,*XAR0 ; ACC= (I8Q24) * (I16Q0) = (I24Q24): upper 32-bits -> P = (I24Q8)
    LSL ACC,#8 ; ACC>>8 = I32Q0
    MOV @_EPwm:m:Regs.TBPHS.half.TBPHS,AL

    ; Deadband Adjustment for Right leg ePWM Module(module EPWM(m) )
    MOV AL,*XAR1
    MOV @_EPwm:m:Regs.DBRED, AL
    MOV @_EPwm:m:Regs.DBFED, AL

    ; Deadband Adjustment for Left leg ePWM module(module EPWMn)
    MOV AL, *XAR2
    MOVW DP, #_EPwm:n:Regs.DBRED
    MOV @_EPwm:n:Regs.DBRED, AL
    MOV @_EPwm:n:Regs.DBFED, AL


    .endm

    Build Options

    //----------------------------------------------------------------------
    #if (INCR_BUILD == 2) // Open loop PSFB PWM Driver
    //----------------------------------------------------------------------

    //Configure PWMDRV_PSFB Block PWM1 for 100kHz, @60MHz
    PWM_PSFB_CNF(1,600);

    // Configure ADC to be triggered from EPWM1 Period event
    //Map channel to ADC Pin
    ChSel[0]=1; //Map channel 0 to pin ADC-A1
    // for additional ADC conversions modify below
    ChSel[1]=1; //An
    /*ChSel[2]=n; //An
    ChSel[3]=n; //An
    ChSel[4]=n; //An
    ChSel[5]=n; //An
    ChSel[6]=n; //An
    ChSel[7]=n; //An
    ChSel[8]=n; //An
    ChSel[9]=n; //An
    ChSel[10]=n; //An
    ChSel[11]=n; //An
    ChSel[12]=n; //An
    ChSel[13]=n; //An
    ChSel[14]=n; //An
    ChSel[15]=n; //An
    */

    // Select Trigger Event for ADC conversion
    TrigSel[0]= ADCTRIG_EPWM1_SOCA;
    // associate the appropriate peripheral trigger to the ADC channel
    TrigSel[1]= ADCTRIG_EPWM1_SOCA;
    /*TrigSel[2]= ADCTRIG_EPWMn_SOCA;
    TrigSel[3]= ADCTRIG_EPWMn_SOCA;
    TrigSel[4]= ADCTRIG_EPWMn_SOCA;
    TrigSel[5]= ADCTRIG_EPWMn_SOCA;
    TrigSel[6]= ADCTRIG_EPWMn_SOCA;
    TrigSel[7]= ADCTRIG_EPWMn_SOCA;
    TrigSel[8]= ADCTRIG_EPWMn_SOCA;
    TrigSel[9]= ADCTRIG_EPWMn_SOCA;
    TrigSel[10]= ADCTRIG_EPWMn_SOCA;
    TrigSel[11]= ADCTRIG_EPWMn_SOCA;
    TrigSel[12]= ADCTRIG_EPWMn_SOCA;
    TrigSel[13]= ADCTRIG_EPWMn_SOCA;
    TrigSel[14]= ADCTRIG_EPWMn_SOCA;
    TrigSel[15]= ADCTRIG_EPWMn_SOCA;*/

    // Configure the ADC with auto interrupt clear mode
    // ADC interrupt after EOC of channel 0
    ADC_SOC_CNF(ChSel,TrigSel,ACQPS,0,0);

    // Configure the EPWM1 to issue the SOC
    EPwm1Regs.ETSEL.bit.SOCAEN = 1;
    EPwm1Regs.ETSEL.bit.SOCASEL = ET_CTR_ZERO; // Use ZERO event as trigger for ADC SOC
    EPwm1Regs.ETPS.bit.SOCAPRD = ET_1ST; // Generate pulse on every event

    // Digital Power CLA(DP) library initialization
    //DPL_CLAInit();
    DPL_Init();


    //ADC Block Connections
    ADCDRV_1ch_Rlt1=&Phase2;

    //Initialize ADC Values
    Phase2=_IQ24(0.0);


    //PSFB block connections
    PWMDRV_PSFB_Phase1 = &Phase2;
    PWMDRV_PSFB_DbLeft1 = &DbLeft;
    PWMDRV_PSFB_DbRight1 = &DbRight;

    //Initialize PSFB net variables
    Phase2=_IQ24(0.0);
    DbLeft=0;
    DbRight=0;


    //CLA_Init();

    #endif // (INCR_BUILD == 2)

    ISR Initialization

    EALLOW;
    GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; // 0=GPIO, 1=EPWM1A, 2=Resv, 3=Resv
    GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1; // 0=GPIO, 1=EPWM1B, 2=SPISIMO-D, 3=Resv
    GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 1; // 0=GPIO, 1=EPWM2A, 2=Resv, 3=Resv
    GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 1; // 0=GPIO, 1=EPWM2B, 2=SPISOMI-D, 3=Resv
    GpioCtrlRegs.GPAMUX1.bit.GPIO6 = 1; // 0=GPIO, 1=EPWM4A, 2=SYNCI, 3=SYNCO
    GpioCtrlRegs.GPAMUX1.bit.GPIO7 = 1; // 0=GPIO, 1=EPWM4B, 2=SPISTE-D, 3=ECAP2
    //All enabled ePWM module clocks are started with the first rising edge of TBCLK aligned
    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
    EDIS;


    EALLOW;
    PieVectTable.EPWM1_INT = &DPL_ISR; // Map Interrupt
    PieCtrlRegs.PIEIER3.bit.INTx1 = 1; // PIE level enable, Grp3 / Int1
    EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // INT on ZERO event
    EPwm1Regs.ETSEL.bit.INTEN = 1; // Enable INT
    EPwm1Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on every event

    IER |= M_INT3; // Enable CPU INT3 connected to EPWM1-6 INTs:
    EINT; // Enable Global interrupt INTM
    ERTM; // Enable Global realtime interrupt DBGM
    EDIS;
  • Scope capture of the ADC input (yellow); ePWM1A  Output (Blue) and ePWM2B (Green)

    I have also looked at ePWM1B and ePWM2A, they are the respective complements of the waveforms shown on the scope capture above.

    I figure this gives a better picture of what is going on.

  • I did some more debugging and I think I understand the root cause of this.  I put in break points at the beginning and the end of the ISR.  That code is very consistent, but I've noticed that the ISR doesn't execute when I expect. I would expect the ISR to execute every 600 clock cycles, but I'm seeing that vary switching cycle to switching cycle.