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.

CCS/LAUNCHXL-F28379D: Issues while enabling High resolution mode

Part Number: LAUNCHXL-F28379D

Tool/software: Code Composer Studio

Hello,

This post is not exactly a request but instead, I would like to share some issues that I did not found mentionned on the spruhm8i technical reference manual (I may have missed them).

So, the goal is to set a fast PWM with a fixed duty cycle of 50% and a period that could be trimmed. The main problem I meet is a jitter of about 1 EPWMCLK cycle appearing randomly. What I discovered is that it was due to numerous factor:

- I can't use a divider of 1 between PLLSYSCLK and EPWMCLK (EPWMCLKDIV=1 is mandatory) (page 115 of the manual)

- If I do not wait for SFO() to complete its first cycle, the jitter appears and does not disappear after the completion of the function. The following code solved the problem

        while(status == 0) // Call until complete
        {
            status = SFO();
            if (status == 2)
            {
                ESTOP0;
            }
        }

- Finally, the fact that I use an up and down counter with set and reset on 0 and TBPRD leads to the jitter appearing but I don't know why. I solved this by comparing with the example from hrpwm_prdupdown_sfo_v8 which uses CMPA/B and it's the only thing that differ from the programms that affect the results.

Also, if find it strange that when SYNCOSEL=0, the external sync signal which synchronises the different EPWM comes from Input5 X-bar which is connected to .... EPWM1A by default (page 1967 it's written in the footnotes that a sync pulse will introduce jitter). But maybe I didn't understand well ?

Thanks for reading and If you have comments/help/hints, I would be glad to hear them.

From here, a simple code that was used:

// La doc utilise comme indicateur est: TMS320F2837xD Dual-Core Microcontrollers Technical Reference Manual

#include "F28x_Project.h"

//Include pour la mise en place de la pwm haute resolution
#include "F2837xD_Device.h"         // F28x7x Headerfile
#include "F2837xD_EPwm_defines.h"   // init defines
#include "SFO_V8.H"                 // SFO lib functions (needed for HRPWM)


// Function Prototypes
void InitEPwm1Example(void);

int i=0;
int status=0;

Uint16 periode = 50;              //FPWM=FTBCLK/(2*periode) avec FTBCLK=100MHz tel que regle actuellement
Uint16 dureeDeadBand=15;
int MEP_ScaleFactor = 0; //scale factor value
volatile struct EPWM_REGS *ePWM[] = {0, &EPwm1Regs};


void main(void)
{

    EALLOW;

        InitSysCtrl();


        CpuSysRegs.PCLKCR2.bit.EPWM1=1;
        CpuSysRegs.PCLKCR0.bit.HRPWM=1; //On active l'horloge de la PWM haute resolution
        EDIS;

        InitEPwm1Gpio();
        EALLOW;
        GpioCtrlRegs.GPAMUX1.bit.GPIO6 = 3; //On envoie le bit de synchro sur P6 au lieu de PWM4
        EDIS;

        DINT;

        InitPieCtrl();

        EALLOW;
        IER = 0x0000;
        IFR = 0x0000;

        InitPieVectTable();

        while(status == 0) // Call until complete
        {
            status = SFO();
            if (status == 2)
            {
                ESTOP0;
            }
        }

        InitEPwm1Example();

        EPwm1Regs.TBPRDHR=0x3333;
        //EPwm1Regs.TBPRDHR=0x4333;

        SFO();

        IER |= M_INT3;

        PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
        PieCtrlRegs.PIEIER3.bit.INTx2 = 1;
        PieCtrlRegs.PIEIER3.bit.INTx3 = 1;
        PieCtrlRegs.PIEIER3.bit.INTx4 = 1;

        EINT;  // Enable Global interrupt INTM
        ERTM;  // Enable Global realtime interrupt DBGM


// Step 6. IDLE loop. Just sit and loop forever (optional):
    for(;;)
    {

    }
}


/*########################################################################################*/

//Routine de configuration
void InitEPwm1Example()
{
    int period=periode;

    EALLOW;                                             //Ne pas oublier que le registre est protege !!!
    ClkCfgRegs.PERCLKDIVSEL.bit.EPWMCLKDIV=1;           //On ne divise PAS par 2 l'horloge EPWMCLK par rapport à PLLSYSCLK (voir page 115)
    SyncSocRegs.SYNCSELECT.bit.SYNCOUT=0;               //On envoie le top de synchronisation de PWM1 sur le Xbar de sortie (debug purpose)
    InputXbarRegs.INPUT5SELECT=22;                      //Le GPIO 22 est connecte sur extsyncin1 plutot que la P0 qui etait la pwm1 et foutait le boxon en faisant apparaitre des tops de synchro
    EDIS;


    if (0) //Part that doesn't work because of toogling method that doesn't use CMPA register (jitter appear if selected)
    {

        EPwm1Regs.TBPRD = periode;                          // On compte jusqu'a 50

        // Setup TBCLK
        EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;      // Compte en montant puis en descendant
        EPwm1Regs.TBPHS.bit.TBPHS =0;                       // Dephasage de 0

        EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;            // Clock ratio to SYSCLKOUT -> Attention, le systeme utilise une horloge SYSCLOCKOUT qui donne une horloge EPWMCLK (via le registre EPWMCLKDIV) qui donne une horloge TBCLK
        EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;               // Attention a bien mettre les 2: HSPCLKDIV et CLKDIV (page 1983  TBCLK = EPWMCLK / (HSPCLKDIV x CLKDIV).)
        EPwm1Regs.TBCTL.bit.PRDLD=0;                        // Permet d'ecrire au bon moment dans le registre pour ne pas perturber le module (shadow sur mise a jour de TBPRD, page 1874)
        EPwm1Regs.TBCTL.bit.SYNCOSEL=0;                     // On genere un top synchro lorsque le registre vaut 0

        // Set actions
        // Pareil ici, on defini les actions a faire lorsque le compteur atteint les valeurs CMPA. Comme ce n'est pas utilise, je vais plutot definir les actions lorsqu'il atteint TBPRD et 0
        // page 2022 de la doc
        EPwm1Regs.AQCTLA.bit.PRD=AQ_CLEAR;                 //On toogle la sortie de la PWMA lorsque le commpteur atteint la valeur de la periode.
        EPwm1Regs.AQCTLA.bit.ZRO=AQ_SET;                   //Pareil lorsqu'il atteint 0
        EPwm1Regs.AQCTLB.bit.PRD=AQ_CLEAR;                 //On toogle la sortie de la PWMB
        EPwm1Regs.AQCTLB.bit.ZRO=AQ_SET;

//        // Active Low PWMs - Setup Deadband (it works properly)
//        EPwm1Regs.DBCTL.bit.HALFCYCLE=1;                    //Permet d'etre 2* plus precis sur la gestions des temps morts
//        EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE;      //On active les temps morts à la monte et à la descente (page 1994)
//        EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC;           //Inverse sortie B (pages 1905 et 1994 de la doc)
//        EPwm1Regs.DBCTL.bit.IN_MODE = DBA_ALL;              //La PWMA est utilisee comme reference pour avoir le rising edge et le falling edge  (page 1993) (situation par defaut)
//        EPwm1Regs.DBCTL.bit.SHDWDBREDMODE=1;                //On active le shadow mode qui sert de buffer pour eviter de modifier les valeurs au mauvais moment
//        EPwm1Regs.DBCTL.bit.SHDWDBFEDMODE=1;
//
//        // Gestion de la duree des temps morts
//        EPwm1Regs.DBRED.bit.DBRED = dureeDeadBand;
//        EPwm1Regs.DBFED.bit.DBFED = dureeDeadBand;

        // Configuration des registres haute resolution
        EALLOW;
        EPwm1Regs.HRCNFG.all = 0x0;

        //imaginons que l'on veuille mettre au milieu du pas disponible en mode normal, il faut ajouter un nombre de pas MEP=0.5*67=34 puis decaller de 8:
        EPwm1Regs.TBPRDHR=0x3333;                               // En considerant un pas MEPS de 180ps (56 position par coup d'horloge EPWMCLK), cela doit augmenter la periode de 20*180=7.2ns
        EPwm1Regs.CMPCTL.bit.LOADAMODE=2;
        EPwm1Regs.HRCNFG.bit.HRLOAD=2;
        EPwm1Regs.HRCNFG.bit.AUTOCONV=1;
        EPwm1Regs.HRCNFG.bit.EDGMODE=3;
        EPwm1Regs.HRPCTL.bit.TBPHSHRLOADE=1;
        EPwm1Regs.TBCTL.bit.PHSEN =1;                       // Prise en compte du dephasage
        EPwm1Regs.HRPCTL.bit.HRPE=1;                        // Enable high resolution period control
    }




//################################################################################################################

if (1) //Part which works (comes from hrpwm_prdupdown_sfo_v8)
{

     EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW;  // set Shadow load
     EPwm1Regs.TBPRD = period;               // PWM frequency = 1/(2*TBPRD)
         EPwm1Regs.CMPA.bit.CMPA = period / 2;   // set duty 50% initially
         EPwm1Regs.CMPA.bit.CMPAHR = (1 << 8);   // initialize HRPWM extension
         EPwm1Regs.CMPB.bit.CMPB = period / 2;   // set duty 50% initially
         EPwm1Regs.CMPB.all |= 1;
     EPwm1Regs.TBPHS.all = 0;
     EPwm1Regs.TBCTR = 0;

     EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Select up-down
     // count mode
     EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE;
     EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
     EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;          // TBCLK = SYSCLKOUT
     EPwm1Regs.TBCTL.bit.FREE_SOFT = 11;

     EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;  // LOAD CMPA on CTR = 0
     EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
     EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
     EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;

         EPwm1Regs.AQCTLA.bit.CAU = AQ_SET;             // PWM toggle high/low
         EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;
         EPwm1Regs.AQCTLB.bit.CBU = AQ_SET;             // PWM toggle high/low
         EPwm1Regs.AQCTLB.bit.CBD = AQ_CLEAR;

     EALLOW;
     EPwm1Regs.HRCNFG.all = 0x0;
     EPwm1Regs.HRCNFG.bit.EDGMODE = HR_BEP;          // MEP control on
     // both edges.
     EPwm1Regs.HRCNFG.bit.CTLMODE = HR_CMP;          // CMPAHR and TBPRDHR
     // HR control.
     EPwm1Regs.HRCNFG.bit.HRLOAD = HR_CTR_ZERO_PRD;  // load on CTR = 0
     // and CTR = TBPRD
     EPwm1Regs.HRCNFG.bit.EDGMODEB = HR_BEP;         // MEP control on
     // both edges
     EPwm1Regs.HRCNFG.bit.CTLMODEB = HR_CMP;         // CMPBHR and TBPRDHR
     // HR control
     EPwm1Regs.HRCNFG.bit.HRLOADB = HR_CTR_ZERO_PRD; // load on CTR = 0
     // and CTR = TBPRD
     EPwm1Regs.HRCNFG.bit.AUTOCONV = 1;        // Enable autoconversion for
     // HR period

     EPwm1Regs.HRPCTL.bit.TBPHSHRLOADE = 1;    // Enable TBPHSHR sync
     // (required for updwn
     //  count HR control)
     EPwm1Regs.HRPCTL.bit.HRPE = 1;            // Turn on high-resolution
     // period control.
}


     CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;      // Enable TBCLK within
     // the EPWM
     EPwm1Regs.TBCTL.bit.SWFSYNC = 1;          // Synchronize high
     // resolution phase to
     // start HR period
     EDIS;



}

  • Benjamin,

    With the default configuration EPWM1 will indeed resynchronize on its own output, the workaround you implemented using GPIO22 is one which was suggested by Texas Instruments for this issue here.

    Regarding your other issue, using the CTR=ZRO and CTR=PRD events leads to undefined behaviour on the EPWM outputs when HRPCTL[HRPE] is enabled, because these events generate edges which fall whithin the restricted range, described in the manual in the chapter titled Duty Cycle Range Limitation.

    Regards,

    Pierre

  • Hi,

    I agree with Pierre above.
    Default path for sync through xbar is gpio0 which in turn is configured as EPWM1A. YOu can use the workaround suggested above.
    Also, the duty cycle range limitations exist in high resolution mode as described in the user guide chapter mentioned above.
    Hope Pierre's response resolves your issue.
    Feel free to post any updates if you need help in debug further.

  • Pierre,

    Thank you for your answer. Indeed it is written in the chapter you mentionned. But (and it is my mistake), I didn't took it into account as it was in the part that deals with the CMP registers. As I used a fixed duty cycle about 50%, and a set/reset strategy only based on counter=period and counter=0, I didn't consider it.

    All in all, thank you for your help,

    Regards,

    Benjamin