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.

TMS320F28027: High Resolution Phase Control Mode using Driver Libraries

Part Number: TMS320F28027
Other Parts Discussed in Thread: C2000WARE, CONTROLSUITE

In another post (https://e2e.ti.com/support/microcontrollers/c2000/f/171/t/677071), I learned how to accomplish High Resolution Phase Control using the "structs" code. Here, I would like to convert to using the "drivers" code to use the driver libraries. Not a single example in the C2000Ware uses high resolution phase control, they all use "PWM_HrControlMode_Duty".

I have followed my structs code almost exactly, but it seems there is not a function to explicitly change the high resolution phase value. There is a function for coarse phase, i.e. PWM_setPhase(myPwm2, 0), but I do not know how to directly change the HR Phase value (in the structs version, I use EPwm2Regs.TBPHS.half.TBPHSHR = 100 << 8).

Here is the relevant code. Can someone help me achieve high resolution phase shift with the driver libraries?

CLK_disableTbClockSync(myClk);

Uint16 period = 120;

CLK_enablePwmClock(myClk, PWM_Number_1);

PWM_setPeriodLoad(myPwm1, PWM_PeriodLoad_Immediate);
PWM_setPeriod(myPwm1, period-1);    // Set timer period
PWM_setCmpA(myPwm1, period / 2);

PWM_setPhase(myPwm1, 0x0000);   // Phase is 0 initially
PWM_setCount(myPwm1, 0x0000);   // Clear counter

PWM_setCounterMode(myPwm1, PWM_CounterMode_Up);     // Count up
PWM_disableCounterLoad(myPwm1);                     // ePWM1 is the master
PWM_setSyncMode(myPwm1, PWM_SyncMode_CounterEqualZero);
PWM_setHighSpeedClkDiv(myPwm1, PWM_HspClkDiv_by_1); // Clock ratio to SYSCLKOUT
PWM_setClkDiv(myPwm1, PWM_ClkDiv_by_1);

PWM_setShadowMode_CmpA(myPwm1, PWM_ShadowMode_Shadow);  // Load registers every ZERO
PWM_setLoadMode_CmpA(myPwm1, PWM_LoadMode_Zero);

PWM_setActionQual_Zero_PwmA(myPwm1, PWM_ActionQual_Set); 
PWM_setActionQual_CntUp_CmpA_PwmA(myPwm1, PWM_ActionQual_Clear); 

PWM_setHrEdgeMode(myPwm1, PWM_HrEdgeMode_Both);
PWM_enableAutoConvert(myPwm1);
PWM_setHrControlMode(myPwm1, PWM_HrControlMode_Phase); 
PWM_setHrShadowMode(myPwm1, PWM_HrShadowMode_CTR_EQ_0);
PWM_enableHrPhaseSync(myPwm1);


CLK_enablePwmClock(myClk, PWM_Number_2);

PWM_setPeriodLoad(myPwm2, PWM_PeriodLoad_Immediate);
PWM_setPeriod(myPwm2, period-1);    // Set timer period
PWM_setCmpA(myPwm2, period / 2);

PWM_setPhase(myPwm2, 0);   // Phase is 0 initially
PWM_setCount(myPwm2, 0x0000);   // Clear counter

PWM_setCounterMode(myPwm2, PWM_CounterMode_Up);     // Count up
PWM_enableCounterLoad(myPwm2);
PWM_setSyncMode(myPwm2, PWM_SyncMode_EPWMxSYNC);
PWM_setHighSpeedClkDiv(myPwm2, PWM_HspClkDiv_by_1); // Clock ratio to SYSCLKOUT
PWM_setClkDiv(myPwm2, PWM_ClkDiv_by_1);

PWM_setShadowMode_CmpA(myPwm2, PWM_ShadowMode_Shadow);  // Load registers every ZERO
PWM_setLoadMode_CmpA(myPwm2, PWM_LoadMode_Zero);

PWM_setActionQual_Zero_PwmA(myPwm2, PWM_ActionQual_Set); 
PWM_setActionQual_CntUp_CmpA_PwmA(myPwm2, PWM_ActionQual_Clear);

PWM_setHrEdgeMode(myPwm2, PWM_HrEdgeMode_Both);
PWM_setHrControlMode(myPwm2, PWM_HrControlMode_Phase); 
PWM_setHrShadowMode(myPwm2, PWM_HrShadowMode_CTR_EQ_0);
PWM_enableHrPhaseSync(myPwm2);
PWM_enableAutoConvert(myPwm2);

PWM_setPhase(myPwm2, 1);   // In sync with ePWM1 and phase shifted by 16.67ns

CLK_enableTbClockSync(myClk);

  • It looks like we don't have a driver that covers that functionality, although the TBPHSHR register is already in the PWM_Obj structure. You should be able to write something like myPwm2->TBPHSHR = 100 << 8.

    Whitney
  • Whitney, 

    I thought so too, however when I tried that I receive the following error: 

    I also tried something like:

    PWM_Obj *pwm3 = (PWM_Obj *)myPwm3;
    pwm3->HRMSTEP = 255;
    pwm3->TBPHSHR = 50 << 8;

    This code compiled and uploaded, however the PWM was not phase shifted at all, as if I'd never even added those lines of code.

    I appreciate any help with figuring this out.

    Thanks,

    Jeff

  • HRMSTEP is a write protected register so you'll need to use ENABLE_PROTECTED_REGISTER_WRITE_MODE (or EALLOW--same thing) to write to it.

    The way you wrote to TBPHSHR seems okay. Can you check in the CCS Register window that the expected value is being written to it though?

    Whitney
  • Whitney,

    When I set the coarse phase to 2, the first 16 bits of TBPHS change to 0000000000000010

    Next, when I change the value to 50 << 8, I see 0011001000000000. This is what I should be expecting however I don't measure any fine phase shift on the oscilloscope.

    Jeff
  • You said you had a working structure-based example working. Could you take some screen captures of the PWM module in the registers window in the working scenario and compare it to the register window in the driver application? Should help you find what you're missing.

    Whitney
  • Whitney,

    I think I have found my issue. I cannot get the HRMSTEP value in the ePWM1 module registers to change, even when using ENABLE_PROTECTED_REGISTER_WRITE_MODE (I also tried EALLOW). 

    The code is show below. When I step through the program in debug mode, I observe the HRMSTEP register unchanged. However, this method of manipulating registers works for registers that are not protected, such as TBPHSHR. There is no driver function available that changes the HRMSTEP value. How can I change this value?

        PWM_Obj *pwm1 = (PWM_Obj *)myPwm1;
        ENABLE_PROTECTED_REGISTER_WRITE_MODE;
        pwm1->HRMSTEP = 255;
        DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
        PWM_Obj *pwm2 = (PWM_Obj *)myPwm2;
        pwm2->TBPHSHR = 100 << 8;

  • Hi Jeff,

    In your older E2E post, I recommended you to use the SFO library and enabling auto-conversion, so that the calibration routine computes the appropriate MEP scale factor and automatically updates HRMSTEP register.
    It is documented in the HRPWM user's guide. www.ti.com/.../spruge8e.pdf
    Here's a drivers example using the SFO: C:\ti\c2000\C2000Ware_1_00_04_00\device_support\f2802x\examples\drivers\hrpwm_duty_sfo_v6

    Regards,
    Elizabeth
  • Hello Elizabeth,

    Is there not a way to do this by setting HRMSTEP manually? I would like to set the HRMSTEP once, then later in the program, update the TBPHSHR based on certain conditions. Setting the HRMSTEP once manually for my application would be simpler than using SFO.

    Thanks,
    Jeff
  • Hi Jeff,

    It is undocumented behavior to write to HRMSTEP in application code, so you should allow the SFO library to write to it. For an application that will not have significant temperature or voltage variations, the application can complete SFO calibration once along with the initialization code.

    From the HRPWM user's guide:

    "High Resolution MEP Step
    When auto-conversion is enabled (HRCNFG[AUTOCONV] = 1), This 8-bit field contains the
    MEP_ScaleFactor (number of MEP steps per coarse steps) used by the hardware to
    automatically convert the value in the CMPAHR, TBPHSHR, or TBPRDHR register to a scaled
    micro-edge delay on the high-resolution ePWM output.
    The value in this register is written by the SFO calibration software at the end of each calibration
    run."

    Regards,
    Elizabeth
  • Elizabeth,

    When giving SFO a try, I get the error below. I included the "f2802x_common/include/sfo_v6.h" header as the examples do, and added the SFO_TI_Build_V6.lib to the project. Can you help me resolve this error?

  • Hi Jeff,

    Can you confirm in the Project Explorer that C:\ti\c2000\C2000Ware_1_00_04_00\libraries\calibration\hrpwm\f2802x\include is listed when 'Includes' tab is expanded? If it isn't, it can be added by going to Properties->Build->Include Options-> Add to search path.

    Regards,
    Elizabeth
  • Elizabeth, 

    My mistake, I am using ControlSuite, not C2000Ware. I don't have such file directory. I've been trying to setup my project like the following below: 

    I have made appropriate changes to my project by adding the SFO_TI_BUILD_V6 and including the necessary files in the code:

    #include "DSP28x_Project.h"

    #include "f2802x_common/include/sfo_v6.h"

    Here is what my project looks like: 

    If I can't figure it out, I suppose I can try to resort to copying this example and going from there, but I'd like to figure out how to make my current project correct.

    Thanks,

    Jeff

  • Hi Jeff,

    Using ControlSUITE is fine and it looks like the SFO header file's path is being included based on your screenshot.

    Can you check you have this code in your project's C file?

    volatile struct EPWM_REGS *ePWM[PWM_CH] =
    { &EPwm1Regs, &EPwm1Regs, &EPwm2Regs, &EPwm3Regs, &EPwm4Regs};

    The SFO library expects an array with pointers to the register structs as it uses bit-field programming as opposed to Driverlib programming that you have in your project.

    Regards,
    Elizabeth
  • Elizabeth,

    Yes, that was it. I eventually figured that out after adding in all the code from the example until my project compiled. Thanks for your support!

    Jeff