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.

TMS320F2808 ePWM phase-syncing

Other Parts Discussed in Thread: CONTROLSUITE

Hello everyone!

I am designing a Fuel Engine ECU (injection type) with this controller.

So far, so good, everythings works fine, but I came to a point where I could not do what I wanted. I am using ePWM1A, 2A, 3A and 4A to drive my injection circuitry which works great. I can control all of them easily in Duty Cycle and Period. But now I have to.. how to say this.. "position them in time". What I mean is that my pulses have to be at the exact moment I need them to be. I know when to generate my first one, but now I have to synchronize the others with this one, so I have 90 degrees between each ePWM's pulse. And then I have my Ignition signal which is also an ePWM and that needs to be generated a little before the first pulse..

Anyways, my point is, I am trying to find what values to put in the phase registers, because I can't get any consistent results.

Here is what I have so far.

PWM1A init:


         usCount = (unsigned short) ((float)(ulPeriod / 7.6666666667));

         // DutyCycle = DutyCycle(%) * Period = DutyCycle(%) * Count
         usPWMDutyCycle = (ucDutyCycle * (usCount / 100)) ;    
 
         // Duty Cycle Register = Period Value - Duty Cycle value
         usPWMDutyCycle = usCount - usPWMDutyCycle;

 

         EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;                  // Set Compare A Descending to SET PWM  ("ON" time)
         EPwm1Regs.AQCTLA.bit.CAU = AQ_SET;                    // Set Compare A Ascending to CLEAR PWM ("OFF" time)
         EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;        // Time base counter counts up then down (permits symmetrical waveform)
         EPwm1Regs.TBPRD = usCount;                            // Set time base period
         EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;               // Disable phase loading
         EPwm1Regs.TBPHS.half.TBPHS = 0x0000;                  // Phase is 0
         EPwm1Regs.TBCTR = 0x0000;                             // Clear counter
        
         #ifdef SYSCLK_100
         EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV2;              // Clock ratio to SYSCLKOUT
         EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV2;
         if(ulPeriod > 5200)
         {
              EPwm1Regs.TBCTL.bit.HSPCLKDIV = 3;              // Clock ratio to SYSCLKOUT (DIV by 6)
             EPwm1Regs.TBCTL.bit.CLKDIV = 6;                 // div by 64
         }
         #endif
         #ifdef SYSCLK_40
         EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;              // Clock ratio to SYSCLKOUT
         EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
         #endif
         
         EPwm1Regs.CMPA.half.CMPA = usPWMDutyCycle;            // Set compare A value
         EALLOW;
         GpioCtrlRegs.GPAPUD.bit.GPIO0 = 0;
         GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;
         EDIS;

 

PWM2A is initialized in the same fashion.

Then I set the phase relationship between the two:

 

    // Phase shift in Counts = PhaseInDegrees/360 x PW1A_Period
    EPwm2Regs.TBPHS.half.TBPHS = 1418; //(unsigned short) ((float)((usPhase / 360) * EPwm1Regs.TBPRD));
    EPwm2Regs.TBPRD = EPwm1Regs.TBPRD;
    EPwm2Regs.CMPA.half.CMPA = EPwm1Regs.CMPA.half.CMPA;
    EPwm2Regs.TBCTL.bit.PHSEN = 1;
    EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;
    EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO;
    EPwm2Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;

 

So, I have usPhase equal to 180 and there is no phase shift. I put 360, I have 180 degrees phase shift. I put 540, still 180...

Is there something I have been missing.. ? Hope my question is clear.

 

Edit: To make it simple, i want, for example, ePWM5A's pulse to be 20 degrees before PWM1A's (that can vary a little, but something like that) . I also want PWM2-3-4A to be 90 spaced by 90 degrees.

  • Alexandre,

    The first thing I noticed is that:
    usCount = (unsigned short) ((float)(ulPeriod / 7.666666667));
    should probably be:
    usCount = (unsigned short) (((float)ulPeriod) / 7.666666667);

    Outside of that I would recommend trying to edit EPwm2Regs.TBPHS.half.TBPHS bits directly while the processor is running by using the C2000 processor's real-time mode.  This will allow you to make sure the device is working as you expect, and then you can work on getting the code 100% correct.  If you aren't already familiar with the feature, take a look at the video at the following link.  It's a very useful feature.
    http://processors.wiki.ti.com/index.php/Real-Time_Interrupts_with_CCSv4

    Your assumption on what you should put into the TBPHS register looks to be correct.  It is:
    TBPHS of slave PWM = TBPRD of master PWM * (phase shift / 360)
    this assumes the PWM synch pulse has been passed from PWM1 to PWM2 correctly.


    Thank you,
    Brett

  • Hello Brett, thank you for your advice, but I actually managed to make it work using some code snippet I found in the ePWM user guide (something like 3-phase DC-DC switching).
    I don't see much difference besides the use of shadow registers. I removed the unnecessary features (like deadband) and got it to work. But I still don't understand why it does.

    So now it works flawlessly and smoothly too (i can change the engine speed quite quickly and it responds well).

    As for the debugger, I use it a lot as long as it is not for timing debugging, since I have much difficulties to get it to work.

    For example, I have some variables that change throughout the program. I halt the program to insert a breakpoint and when it does get to it, I often have "0" in said variable when i know that this is not true (I also send value through serial port to my computer and I see the real values). Maybe I just don't get it!

    Anyways, thanks for your advices! I am still very grateful for it!

    Have a nice day.

  • Alexandre,

    I am glad to hear that you were able to get the PWMs to work correctly.  Good job tracking down the issue.

    The issue where CCS doesn't show the correct value when a breakpoint is odd.  What version of CCS are you using?


    Thank you,
    Brett

  • I am using

    Code Composer Studio Core Edition

    Version: 4.2.1.00004

  • And maybe one more thing...

    I can set the phase shift between PWM 1 and 2, 1 and 3, 1 and 4. Can i also set a phase shift between 1A and 1B ? I really can't see....
    If there is an example or something related to this, that would be great or the register configuration. Here is what I have currently...:

     

    unsigned short usDivider;
    unsigned short usPeriod_1A, usPeriod_2A, usPeriod_3A, usPeriod_4A;

    usPeriod_1A = EPwm1Regs.TBPRD;
    usPeriod_2A = EPwm2Regs.TBPRD;
    usPeriod_3A = EPwm3Regs.TBPRD;
    usPeriod_4A = EPwm4Regs.TBPRD;

    //usDivider = (unsigned short) ((float) (360 / usPhase));

    // EPWM 1A
    EPwm1Regs.TBPHS.half.TBPHS = 0;                                      // Set Phase register to zero, master
    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;                       // Symmetrical mode
    EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;                              // Master module
    EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW;
    EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO;                          // Sync down-stream module
    EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;                        // load on CTR=Zero
    EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;                        // load on CTR=Zero

    // EPWM 2A
    // PhaseShift(count) = Period / [360 deg/PhaseShift(deg)]
    // But we have to substract because we get a value higher than the period (phase is next period)


    EPwm2Regs.TBPHS.half.TBPHS = ((2 * usPeriod_2A * 3) / 4)-usPeriod_2A;        // 270 degrees   
    EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;                              // Symmetrical mode
    EPwm2Regs.TBCTL.bit.PHSEN = TB_ENABLE;                                                     // Slave module
    EPwm2Regs.TBCTL.bit.PHSDIR = TB_DOWN;                                                       // Count DOWN on sync
    EPwm2Regs.TBCTL.bit.PRDLD = TB_SHADOW;
    EPwm2Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;                                             // sync flow-through
    EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;                        // load on CTR=Zero
    EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;                        // load on CTR=Zero

    // EPWM 3A
    EPwm3Regs.TBPHS.half.TBPHS = 2 * usPeriod_3A / 4;                                // 90 degrees
    EPwm3Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;                       // Symmetrical mode
    EPwm3Regs.TBCTL.bit.PHSEN = TB_ENABLE;                                           // Slave module
    EPwm2Regs.TBCTL.bit.PHSDIR = TB_UP;                                                // Count UP on sync
    EPwm3Regs.TBCTL.bit.PRDLD = TB_SHADOW;
    EPwm3Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;                                 // sync flow-through
    EPwm3Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm3Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm3Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;                        // load on CTR=Zero
    EPwm3Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;                        // load on CTR=Zero

    // EPWM 4A
    EPwm4Regs.TBPHS.half.TBPHS = 2 * usPeriod_4A / 2;               //  180 degrees
    EPwm4Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;                       // Symmetrical mode
    EPwm4Regs.TBCTL.bit.PHSEN = TB_ENABLE;                               // Slave module
    EPwm3Regs.TBCTL.bit.PHSDIR = TB_DOWN;                                  // Count UP on sync
    EPwm4Regs.TBCTL.bit.PRDLD = TB_SHADOW;
    EPwm4Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;                           // sync flow-through
    EPwm4Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
    EPwm4Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm4Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;                        // load on CTR=Zero
    EPwm4Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;                        // load on CTR=Zero

     

    Syncosel seems to link 2 different PWM module, not 2 of the same.. am i right ?

     

    thank you again!

  • Alexandre,

    SYNCOSEL will synchronize one PWM module (n) with the PWM module before it (n-1).  Like you've done you can have 2 synch with 1, and then have 3 synch with 2, ... so that you can have a fully synchronized system.  Synchronizing the A and B channels of a PWM module will happen automatically (they're using the same timer), but you'll need to do some extra initialization code to create a phase shift.  The easiest thing method is to use the up-down count mode of the PWM module and have CAU and CAD control the A channel of the PWM module and have CBU and CBD control the B channel of the PWM module.  This will create a fixed 180 degree phase shift.

    The configuration described above is in controlSUITE, if you have it installed.  See:
    C:\TI\controlSUITE\libs\app_libs\digital_power\f2803x_v3.2\C\PWM_DualUpDwnCnt_Cnf.c


    Thank you,
    Brett

  • Thank you, it saves me a tough  patch on my PCB, i was supposed to have all 4 injectors on separated PWM modules, but I have them on 1A/1B, 2A/2B.