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.

TIDA-010054: HRPWM Phase shift calculation - potential error

Part Number: TIDA-010054

Hi everyone,

I am trying to understand of the implementation of HRPWM phase shift in "DAB_calculatePWMDutyPeriodPhaseShiftTicks()" function under"dab.h" file. The function calculates the shift for either "extended phase shift mode" or "single phase shift mode". Here's a copy for the original function in "dab.h" file.

#pragma FUNC_ALWAYS_INLINE(DAB_calculatePWMDutyPeriodPhaseShiftTicks)
static inline void DAB_calculatePWMDutyPeriodPhaseShiftTicks(void)
{
    uint32_t temp;
    //
    // Calculation for the period is done in high resolution
    // as it is used by the phase shift variable in high resolution
    //
    temp = ((uint32_t)(((float32_t)(DAB_pwmPeriod_pu *
                                   DAB_pwmPeriodMax_ticks) *
                       (float32_t)65536.0)))>> 1;

    DAB_pwmPeriod_ticks = temp & 0xFFFFFF00;

    //
    // In high resolution phase shift,high resolution duty is not available
    // when using HRCFG.CTLMODE as 1 but the calculation below calculates the
    // CMPAHR value, it's easier to do so as the period ticks are in high
    // resolution format
    //
    DAB_pwmDutyAPrim_ticks = (uint32_t)((float32_t)DAB_pwmPeriod_ticks *
                                         (float32_t)
                                         (1.0f - fabsf(DAB_pwmDutyPrim_pu)));

    DAB_pwmDutyASec_ticks = (uint32_t)((float32_t)DAB_pwmPeriod_ticks *
                                         (float32_t)
                                         (1.0f - fabsf(DAB_pwmDutySec_pu)));

    //
    // the below is to make sure CMPAHR is never 0x00,
    //
    if((DAB_pwmDutyAPrim_ticks & 0x00FF00) == 0)
    {
        DAB_pwmDutyAPrim_ticks = DAB_pwmDutyAPrim_ticks | 0x000100;
    }

    if((DAB_pwmDutyASec_ticks & 0x00FF00) == 0)
    {
        DAB_pwmDutyASec_ticks = DAB_pwmDutyASec_ticks | 0x000100;
    }

    //
    // If EPS is enabled, subtract half the added delay (alpha p or alpha S) to get the fundamental phase shift.
    //
    if(DAB_pwmSwState.pwmSwState == pwmSwState_extendedPhaseShiftControl){

        float32_t phi_pu = DAB_pwmPhaseShiftPrimSec_pu - ((DAB_pwmEPSAlphaP_pu + DAB_pwmEPSAlphaS_pu) / 2);

        DAB_pwmEPSPhaseShift_P1_P2_ns = DAB_pwmEPSAlphaP_pu *
                      ((float32_t)1.0 / DAB_pwmFrequency_Hz) *
                                        (1 / ONE_NANO_SEC);

        DAB_pwmEPSPhaseShift_P1_P2_ticks =
                (int32_t)((float32_t)DAB_pwmEPSPhaseShift_P1_P2_ns *
                            DAB_PWMSYSCLOCK_FREQ_HZ * ONE_NANO_SEC *
                        TWO_RAISED_TO_THE_POWER_SIXTEEN) - ((int32_t) 2 << 16);

        if(DAB_pwmEPSPhaseShift_P1_P2_ticks >= 0)
        {
            DAB_phaseSyncP1_P2CountDirection = EPWM_COUNT_MODE_DOWN_AFTER_SYNC;
            //
            // DAB_pwmPhaseShiftPrimSec_ticks has the correct value already
            //
        }
        else
        {
            DAB_phaseSyncP1_P2CountDirection =  EPWM_COUNT_MODE_UP_AFTER_SYNC;
            DAB_pwmEPSPhaseShift_P1_P2_ticks = DAB_pwmEPSPhaseShift_P1_P2_ticks * -1;

            DAB_pwmPhaseShiftP1_P2_HiResticks =  ((uint16_t) 0xFF - ((uint16_t)
                        (DAB_pwmEPSPhaseShift_P1_P2_ticks & 0x0000FFFF) >> 8));

            DAB_pwmEPSPhaseShift_P1_P2_ticks =
                ((DAB_pwmEPSPhaseShift_P1_P2_ticks & 0xFFFF0000) + 0x10000) +
                                    (DAB_pwmPhaseShiftP1_P2_HiResticks << 8);
        }


        DAB_pwmEPSPhaseShift_P1_S1_ns = (phi_pu + DAB_pwmEPSAlphaP_pu) *
                                ((float32_t)1.0 / DAB_pwmFrequency_Hz) *
                                                    (1 / ONE_NANO_SEC);

        DAB_pwmEPSPhaseShift_P1_S1_ticks =
                (int32_t)((float32_t)DAB_pwmEPSPhaseShift_P1_S1_ns *
                            DAB_PWMSYSCLOCK_FREQ_HZ * ONE_NANO_SEC *
                            TWO_RAISED_TO_THE_POWER_SIXTEEN) - ((int32_t)2 << 16);

        if(DAB_pwmEPSPhaseShift_P1_S1_ticks >= 0)
        {
            DAB_phaseSyncP1_S1CountDirection = EPWM_COUNT_MODE_DOWN_AFTER_SYNC;
            //
            // DAB_pwmPhaseShiftPrimSec_ticks has the correct value already
            //
        }
        else
        {
            DAB_phaseSyncP1_S1CountDirection =  EPWM_COUNT_MODE_UP_AFTER_SYNC;
            DAB_pwmEPSPhaseShift_P1_S1_ticks = DAB_pwmEPSPhaseShift_P1_S1_ticks * -1;

            DAB_pwmPhaseShiftP1_S1_HiResticks =  ((uint16_t) 0xFF - ((uint16_t)
                            (DAB_pwmEPSPhaseShift_P1_S1_ticks & 0x0000FFFF)>>8));

            DAB_pwmEPSPhaseShift_P1_S1_ticks =
                    ((DAB_pwmEPSPhaseShift_P1_S1_ticks & 0xFFFF0000) + 0x10000) +
                                        (DAB_pwmPhaseShiftP1_S1_HiResticks << 8);
        }

        DAB_pwmEPSPhaseShift_P1_S2_ns = (phi_pu + DAB_pwmEPSAlphaP_pu + DAB_pwmEPSAlphaS_pu) *
                                                    ((float32_t)1.0 / DAB_pwmFrequency_Hz) *
                                                    (1 / ONE_NANO_SEC);

        DAB_pwmEPSPhaseShift_P1_S2_ticks =
                (int32_t)((float32_t)DAB_pwmEPSPhaseShift_P1_S2_ns *
                            DAB_PWMSYSCLOCK_FREQ_HZ * ONE_NANO_SEC *
                TWO_RAISED_TO_THE_POWER_SIXTEEN) - ((int32_t)2 << 16);

        if(DAB_pwmEPSPhaseShift_P1_S2_ticks >= 0)
        {
            DAB_phaseSyncP1_S2CountDirection = EPWM_COUNT_MODE_DOWN_AFTER_SYNC;
            //
            // DAB_pwmPhaseShiftPrimSec_ticks has the correct value already
            //
        }
        else
        {
            DAB_phaseSyncP1_S2CountDirection =  EPWM_COUNT_MODE_UP_AFTER_SYNC;
            DAB_pwmEPSPhaseShift_P1_S2_ticks = DAB_pwmEPSPhaseShift_P1_S2_ticks * -1;

            DAB_pwmPhaseShiftP1_S2_HiResticks =  ((uint16_t) 0xFF - ((uint16_t)
                        (DAB_pwmEPSPhaseShift_P1_S2_ticks & 0x0000FFFF) >> 8));

            DAB_pwmEPSPhaseShift_P1_S2_ticks =
                    ((DAB_pwmEPSPhaseShift_P1_S2_ticks & 0xFFFF0000) + 0x10000) +
                                        (DAB_pwmPhaseShiftP1_S2_HiResticks << 8);
        }
    }
    else{
        //
        // first the phase shift in pu is converter to ns
        // this is done for better debug and user friendliness
        //
        DAB_pwmEPSPhaseShift_P1_S1_ns = DAB_pwmPhaseShiftPrimSec_pu *
                                  ((float32_t)1.0 / DAB_pwmFrequency_Hz) *
                                   (1 / ONE_NANO_SEC);

        //
        // next this ns is simply converted to ticks
        //
        DAB_pwmEPSPhaseShift_P1_S1_ticks =
                (int32_t)((float32_t)DAB_pwmEPSPhaseShift_P1_S1_ns *
                       DAB_PWMSYSCLOCK_FREQ_HZ * ONE_NANO_SEC *
                       TWO_RAISED_TO_THE_POWER_SIXTEEN) - ((int32_t)2 << 16);

        //
        // due to the delay line implementation depending on whether it is
        // a phase delay or an advance we need to adjust the
        // HR phase shift ticks calculations
        //
        if(DAB_pwmEPSPhaseShift_P1_S1_ticks >= 0)
        {
            DAB_phaseSyncP1_S1CountDirection = EPWM_COUNT_MODE_DOWN_AFTER_SYNC;

            //
            // DAB_pwmPhaseShiftPrimSec_ticks has the correct value already
            //
        }
        else
        {
            DAB_phaseSyncP1_S1CountDirection =  EPWM_COUNT_MODE_UP_AFTER_SYNC;
            DAB_pwmEPSPhaseShift_P1_S1_ticks = DAB_pwmEPSPhaseShift_P1_S1_ticks * -1;

            DAB_pwmPhaseShiftP1_S1_HiResticks =  ((uint16_t) 0xFF - ((uint16_t)
                    (DAB_pwmEPSPhaseShift_P1_S1_ticks & 0x0000FFFF) >> 8));

            DAB_pwmEPSPhaseShift_P1_S1_ticks =
                    ((DAB_pwmEPSPhaseShift_P1_S1_ticks & 0xFFFF0000) + 0x10000) +
                    (DAB_pwmPhaseShiftP1_S1_HiResticks << 8);
        }

        DAB_pwmEPSPhaseShift_P1_P2_ticks = 261888; // Hardcoded offset, equivalent to the phase shift in ticks for input of 0.0ns
        DAB_phaseSyncP1_P2CountDirection = EPWM_COUNT_MODE_UP_AFTER_SYNC; // Hard coded to correct offset
        DAB_pwmEPSPhaseShift_P1_S2_ticks = DAB_pwmEPSPhaseShift_P1_S1_ticks;
        DAB_phaseSyncP1_S2CountDirection = DAB_phaseSyncP1_S1CountDirection;
        DAB_pwmPhaseShiftPrimSec_ns = DAB_pwmEPSPhaseShift_P1_S1_ns; //just for gui
    }
}

My understanding is that the high resolution ticks "DAB_pwmPhaseShiftP1_S1_HiResticks " and "DAB_pwmEPSPhaseShift_P1_S1_ticks" should be calculated for the entire HRPWM phase shift desired, both in positive or negative phase shifts. However, in the code it seems that the calculation only takes place when the phase shift is negative. Is this accurate? Here's a screenshot to what is being implemented. 

Thanks for your help!

  • Hi Mohamed,

    Thanks for reaching out.

    Only EPWPHaseShift_P1_S1_ticks is required. DAB_pwmPhaseShiftP1_S1_HiResticks is just a temporary helper variable.

    What happens is that  in line 83  EPWPHaseShift_P1_S1_ticks is calculated. This can be a positive or negative phase shift. 

    If EPWPHaseShift_P1_S1_ticks is positive, then the value is fine and does not need to be modified and DAB_phaseSyncP1_S1CountDirection is set to EPWM_COUNT_MODE_DOWN_AFTER_SYNC. (line 88  to line 94).

    If the phase shift is negative however, it is converted into the complementary positive phase shift, and DAB_phaseSyncP1_S1CountDirection is set to EPWM_COUNT_MODE_UP_AFTER_SYNC. DAB_pwmPhaseShiftP1_S1_HiResticks is just a temporary helper variable. It is not needed. 
    This is mandatory, since its not possible to write a negative value into the phase shift register.

    In  DAB_HAL_updatePWMDutyPeriodPhaseShift() which is used to write the calculated values into the according registers. The EPWPHaseShift_P1_S1_ticks is used.

    I hope this clarifies your question.

    Best regards,

    Andreas

  • Thanks Andreas! I guess I was confused by the MEP_ScaleFactor calculations in the reference manual and had forgotten that Auto conversion was enabled in that code :)