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.

TMS320F28P650DK: Global loading with CMPC but lost pulse.

Part Number: TMS320F28P650DK
Other Parts Discussed in Thread: SYSCONFIG

Tool/software:

I’m using EPWM1 and EPWM2 to control a full-bridge circuit, performing only phase shifting without frequency variation. Let’s focus on EPWM1, which controls two complementary switches of one leg. To achieve wide-range phase shifting without pulse loss, I leveraged a new feature of the 28P65 MCU, using CMPC to trigger a global load.

I’m using up-counting mode: the signal goes high at CMPA and low at CMPB, with a 50% duty cycle. CMPC is always set to CMPB + 2, meaning that even if the next control cycle has changed values, the new compare values won’t be loaded until after CMPB executes, specifically at CMPC. CMPA, CMPB, and CMPC all use shadow registers. I am not using the TBPHS register.

Most of the time, this works correctly. However, here’s the abnormal situation:
TBPRD = 6666, CMPA = 4500, CMPB = 2166, CMPC = 2168.
Since my interrupt service routine takes about 10 µs, when the CMPC event occurs very close to the ISR execution time, pulse loss sometimes happens. I suspect this might be because at the CMPC moment, all shadow registers are loaded into the active registers—but simultaneously, the ISR may be writing new values into the shadow registers. Could this cause a conflict? Another possibility is this: if the new CMPC value is slightly greater than the old CMPC value, does that mean a global load could be triggered twice within a single switching cycle? Would that be dangerous?

Here’s my solution: when I detect that CMPB is near 2100, I set CMPC to a fixed value of 3333. After doing this, the pulse loss no longer occurs.

Below is the EPWM1 initialization code generated by SysConfig:

EPWM_enableGlobalLoad(epwm1_Q1Q2_BASE);	
EPWM_setGlobalLoadTrigger(epwm1_Q1Q2_BASE, EPWM_GL_LOAD_PULSE_CNTR_U_CMPC);	
EPWM_setGlobalLoadEventPrescale(epwm1_Q1Q2_BASE, 1);	
EPWM_setClockPrescaler(epwm1_Q1Q2_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);	
EPWM_setTimeBasePeriod(epwm1_Q1Q2_BASE, 6666);	
EPWM_setTimeBaseCounter(epwm1_Q1Q2_BASE, 0);	
EPWM_setTimeBaseCounterMode(epwm1_Q1Q2_BASE, EPWM_COUNTER_MODE_UP);	
EPWM_enablePhaseShiftLoad(epwm1_Q1Q2_BASE);	
EPWM_setPhaseShift(epwm1_Q1Q2_BASE, 0);	
EPWM_setSyncInPulseSource(epwm1_Q1Q2_BASE, EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM7);	
EPWM_setSyncPulseSource(epwm1_Q1Q2_BASE, HRPWM_PWMSYNC_SOURCE_ZERO);	
EPWM_setCounterCompareValue(epwm1_Q1Q2_BASE, EPWM_COUNTER_COMPARE_A, 1);	
EPWM_enableGlobalLoadRegisters(epwm1_Q1Q2_BASE, EPWM_GL_REGISTER_CMPA_CMPAHR);	
EPWM_setCounterCompareShadowLoadMode(epwm1_Q1Q2_BASE, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO);	
EPWM_setCounterCompareValue(epwm1_Q1Q2_BASE, EPWM_COUNTER_COMPARE_B, 1);	
EPWM_enableGlobalLoadRegisters(epwm1_Q1Q2_BASE, EPWM_GL_REGISTER_CMPB_CMPBHR);	
EPWM_setCounterCompareShadowLoadMode(epwm1_Q1Q2_BASE, EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO);	
EPWM_setCounterCompareValue(epwm1_Q1Q2_BASE, EPWM_COUNTER_COMPARE_C, 1);	
EPWM_enableGlobalLoadRegisters(epwm1_Q1Q2_BASE, EPWM_GL_REGISTER_CMPC);	
EPWM_disableCounterCompareShadowLoadMode(epwm1_Q1Q2_BASE, EPWM_COUNTER_COMPARE_D);	
EPWM_setActionQualifierContSWForceShadowMode(epwm1_Q1Q2_BASE, EPWM_AQ_SW_IMMEDIATE_LOAD);	
EPWM_enableGlobalLoadRegisters(epwm1_Q1Q2_BASE, EPWM_GL_REGISTER_AQCTLA_AQCTLA2);	
EPWM_setActionQualifierAction(epwm1_Q1Q2_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);	
EPWM_setActionQualifierAction(epwm1_Q1Q2_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);	
EPWM_setActionQualifierAction(epwm1_Q1Q2_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);	
EPWM_setActionQualifierAction(epwm1_Q1Q2_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);	
EPWM_setActionQualifierAction(epwm1_Q1Q2_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);	
EPWM_setActionQualifierAction(epwm1_Q1Q2_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);	
EPWM_setActionQualifierAction(epwm1_Q1Q2_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);	
EPWM_setActionQualifierAction(epwm1_Q1Q2_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);	
EPWM_setActionQualifierAction(epwm1_Q1Q2_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);	
EPWM_setActionQualifierAction(epwm1_Q1Q2_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);	
EPWM_setActionQualifierAction(epwm1_Q1Q2_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);	
EPWM_setActionQualifierAction(epwm1_Q1Q2_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);	
EPWM_setDeadBandDelayPolarity(epwm1_Q1Q2_BASE, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW);	
EPWM_setDeadBandDelayMode(epwm1_Q1Q2_BASE, EPWM_DB_RED, true);	
EPWM_setRisingEdgeDelayCountShadowLoadMode(epwm1_Q1Q2_BASE, EPWM_RED_LOAD_ON_CNTR_ZERO);	
EPWM_disableRisingEdgeDelayCountShadowLoadMode(epwm1_Q1Q2_BASE);	
EPWM_setRisingEdgeDelayCount(epwm1_Q1Q2_BASE, 40);	
EPWM_setDeadBandDelayMode(epwm1_Q1Q2_BASE, EPWM_DB_FED, true);	
EPWM_setFallingEdgeDelayCountShadowLoadMode(epwm1_Q1Q2_BASE, EPWM_FED_LOAD_ON_CNTR_ZERO);	
EPWM_disableFallingEdgeDelayCountShadowLoadMode(epwm1_Q1Q2_BASE);	
EPWM_setFallingEdgeDelayCount(epwm1_Q1Q2_BASE, 40);	
EPWM_setTripZoneAction(epwm1_Q1Q2_BASE, EPWM_TZ_ACTION_EVENT_TZA, EPWM_TZ_ACTION_LOW);	
EPWM_setTripZoneAction(epwm1_Q1Q2_BASE, EPWM_TZ_ACTION_EVENT_TZB, EPWM_TZ_ACTION_LOW);	
EPWM_enableTripZoneSignals(epwm1_Q1Q2_BASE, EPWM_TZ_SIGNAL_OSHT1);	
EPWM_configureDiodeEmulationTripLowSources(epwm1_Q1Q2_BASE, EPWM_DE_TRIPL_SRC_INPUTXBAR_OUT1);	
EPWM_configureDiodeEmulationTripHighSources(epwm1_Q1Q2_BASE, EPWM_DE_TRIPH_SRC_INPUTXBAR_OUT1);	
EPWM_enableGlobalLoad(epwm2_Q3Q4_BASE);	
EPWM_setGlobalLoadTrigger(epwm2_Q3Q4_BASE, EPWM_GL_LOAD_PULSE_CNTR_U_CMPC);	
EPWM_setGlobalLoadEventPrescale(epwm2_Q3Q4_BASE, 1);	
EPWM_setClockPrescaler(epwm2_Q3Q4_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);	
EPWM_setTimeBasePeriod(epwm2_Q3Q4_BASE, 6666);	
EPWM_setTimeBaseCounter(epwm2_Q3Q4_BASE, 0);	
EPWM_setTimeBaseCounterMode(epwm2_Q3Q4_BASE, EPWM_COUNTER_MODE_UP);	
EPWM_enablePhaseShiftLoad(epwm2_Q3Q4_BASE);	
EPWM_setPhaseShift(epwm2_Q3Q4_BASE, 0);	
EPWM_setSyncInPulseSource(epwm2_Q3Q4_BASE, EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM7);	
EPWM_setSyncPulseSource(epwm2_Q3Q4_BASE, HRPWM_PWMSYNC_SOURCE_ZERO);	
EPWM_setCounterCompareValue(epwm2_Q3Q4_BASE, EPWM_COUNTER_COMPARE_A, 1);	
EPWM_enableGlobalLoadRegisters(epwm2_Q3Q4_BASE, EPWM_GL_REGISTER_CMPA_CMPAHR);	
EPWM_setCounterCompareShadowLoadMode(epwm2_Q3Q4_BASE, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO);	
EPWM_setCounterCompareValue(epwm2_Q3Q4_BASE, EPWM_COUNTER_COMPARE_B, 1);	
EPWM_enableGlobalLoadRegisters(epwm2_Q3Q4_BASE, EPWM_GL_REGISTER_CMPB_CMPBHR);	
EPWM_setCounterCompareShadowLoadMode(epwm2_Q3Q4_BASE, EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO);	
EPWM_setCounterCompareValue(epwm2_Q3Q4_BASE, EPWM_COUNTER_COMPARE_C, 1);	
EPWM_enableGlobalLoadRegisters(epwm2_Q3Q4_BASE, EPWM_GL_REGISTER_CMPC);	
EPWM_disableCounterCompareShadowLoadMode(epwm2_Q3Q4_BASE, EPWM_COUNTER_COMPARE_D);	
EPWM_setActionQualifierContSWForceShadowMode(epwm2_Q3Q4_BASE, EPWM_AQ_SW_IMMEDIATE_LOAD);	
EPWM_setActionQualifierAction(epwm2_Q3Q4_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);	
EPWM_setActionQualifierAction(epwm2_Q3Q4_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);	
EPWM_setActionQualifierAction(epwm2_Q3Q4_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);	
EPWM_setActionQualifierAction(epwm2_Q3Q4_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);	
EPWM_setActionQualifierAction(epwm2_Q3Q4_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);	
EPWM_setActionQualifierAction(epwm2_Q3Q4_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);	
EPWM_enableGlobalLoadRegisters(epwm2_Q3Q4_BASE, EPWM_GL_REGISTER_AQCTLB_AQCTLB2);	
EPWM_setActionQualifierAction(epwm2_Q3Q4_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);	
EPWM_setActionQualifierAction(epwm2_Q3Q4_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);	
EPWM_setActionQualifierAction(epwm2_Q3Q4_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);	
EPWM_setActionQualifierAction(epwm2_Q3Q4_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);	
EPWM_setActionQualifierAction(epwm2_Q3Q4_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);	
EPWM_setActionQualifierAction(epwm2_Q3Q4_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);	
EPWM_setRisingEdgeDeadBandDelayInput(epwm2_Q3Q4_BASE, EPWM_DB_INPUT_EPWMB);	
EPWM_setFallingEdgeDeadBandDelayInput(epwm2_Q3Q4_BASE, EPWM_DB_INPUT_EPWMB);	
EPWM_setDeadBandDelayPolarity(epwm2_Q3Q4_BASE, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW);	
EPWM_setDeadBandDelayMode(epwm2_Q3Q4_BASE, EPWM_DB_RED, true);	
EPWM_setRisingEdgeDelayCountShadowLoadMode(epwm2_Q3Q4_BASE, EPWM_RED_LOAD_ON_CNTR_ZERO);	
EPWM_disableRisingEdgeDelayCountShadowLoadMode(epwm2_Q3Q4_BASE);	
EPWM_setRisingEdgeDelayCount(epwm2_Q3Q4_BASE, 40);	
EPWM_setDeadBandDelayMode(epwm2_Q3Q4_BASE, EPWM_DB_FED, true);	
EPWM_setFallingEdgeDelayCountShadowLoadMode(epwm2_Q3Q4_BASE, EPWM_FED_LOAD_ON_CNTR_ZERO);	
EPWM_disableFallingEdgeDelayCountShadowLoadMode(epwm2_Q3Q4_BASE);	
EPWM_setFallingEdgeDelayCount(epwm2_Q3Q4_BASE, 40);	
EPWM_setDeadBandOutputSwapMode(epwm2_Q3Q4_BASE, EPWM_DB_OUTPUT_A, true);	
EPWM_setDeadBandOutputSwapMode(epwm2_Q3Q4_BASE, EPWM_DB_OUTPUT_B, true);	
EPWM_setTripZoneAction(epwm2_Q3Q4_BASE, EPWM_TZ_ACTION_EVENT_TZA, EPWM_TZ_ACTION_LOW);	
EPWM_setTripZoneAction(epwm2_Q3Q4_BASE, EPWM_TZ_ACTION_EVENT_TZB, EPWM_TZ_ACTION_LOW);	
EPWM_enableTripZoneSignals(epwm2_Q3Q4_BASE, EPWM_TZ_SIGNAL_OSHT1);	
EPWM_configureDiodeEmulationTripLowSources(epwm2_Q3Q4_BASE, EPWM_DE_TRIPL_SRC_INPUTXBAR_OUT1);	
EPWM_configureDiodeEmulationTripHighSources(epwm2_Q3Q4_BASE, EPWM_DE_TRIPH_SRC_INPUTXBAR_OUT1);	

  • Yan Jason,

    Yes your assumption is correct that condition can occur especially when you are near zero counter and need to make sure that all shadow register writing is done before that time. Your resolution is also solving the issue just because its away from zero event.

    To avoid these type of cases, you can use global load which ensures that shadow to active transfer only happens when all shadow are written. If you refer to API function and sysconfig used c2000 example project in which you can put after all shadow writing is done which will enable shadow to active transfer on next zero event.

    Let me know if that resolves the issue.

    Regards,

    Sumit

  • Thank you for your response. I would like to clarify that the pulse drop event occurred at TBPRD = 6666, CMPA = 4500, CMPB = 2166, CMPC = 2168. This event might be very close to the moment when the interrupt service routine writes to the shadow register, but it is far from the moment when TBCTR = 0.

    I set the CMPC event to trigger a global load because performing a global load at 0 would cause a pulse drop issue. EPWM1 and EPWM2 share the same carrier, and phase shift is achieved by adjusting the relative position of CMPA and CMPB. Suppose the current values are CMPA_old = 1 and CMPB_old = 3334, and the newly calculated comparison values for the current control cycle are CMPA_new = 6665 and CMPB_new = 3332. If the global load happens at 0, the CMPA_new event would be missed, and the rising edge would only occur in the next cycle, leading to a long zero voltage level. I have drawn a simple schematic to illustrate this:

  • You can still do the global loading on CMPC, that's not a problem. You can adjust setting accordingly as shown below:

    If you refer the example I shared above you can see that most crucial thing is to call for the following function after all shadow mode writing is done to ensure that you only load from shadow to active during next global load event (CMPC) only when all writing is done. Does that makes sense?

    Regards,

    Sumit

  • Okay, I will give feedback in time after testing, thank you!

  • Okay will wait for feedback.

    Regards,

    Sumit

  • This solved my problem, thanks! 

  • Sounds great!