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.

TMS320F28388D: Using very large dead-time causes missing PWM pulses

Part Number: TMS320F28388D


Tool/software:

I seem to be getting some missed PWM pulses on the low side of my half-bridge when using a very large dead-time. This causes the synchronous bootstrap FET in the half-bridge to never turn on so the high-side FET can't turn on either.

Here's what I'm trying to do:

I'm controlling a 3-phase bidirectional DC-DC converter using a C2000 F28388D microcontroller.
PWM frequency is 500kHz.
Using HRPWM.
Each phase is shifted by 120 degrees to minimize ripple on the output.
The half-bridge IC is an EPC2152 which has a synchronous bootstrap FET which turns on when the low side PWM signal is high to charge the bootstrap capacitor.
There is a back-to-back FET on the output of each phase to disconnect each phase from the load while the converter starts up.
The PWM duty cycle is controlled by a task running on the CLA to maintain the target current.

During converter startup, I want to achieve the following behavior:
1. Start with a very low duty cycle for a short period of time to charge the bootstrap capacitor. Small dead-time during this phase.
2. Set a fixed duty cycle to charge the output capacitors to the same voltage as on the output side of the back-to-back FET (there is a battery connected) to minimize the current transient across the FET when it gets enabled.
3. Set a very large dead-time to reduce the maximum current output of the converter. This dead-time is just under half of a PWM cycle. This large dead-time is set so that during start-up when we 'guess' an initial duty cycle (which is inevitably wrong), then the current flow between the system output and the converter is minimized. I want to have a very long dead-time, but have the on-times of the pulses to the high and low side FETs be proportion according to the duty cycle.
4. Enable the back-to-back FET, connecting the output of the converter to the system (there is a battery connected). At this point, there is a small transient current between the battery and the output capacitors of the converter to equalize the small voltage difference.
5. Enable the CLA task to control the duty cycle of the converter, with a target current of 0A. This task runs at 350kHz. After 1023 iterations of the CLA task (~3ms), an interrupt is generated on CPU1. At this point, the dead-time is still very large.
6. When the interrupt is generated, CPU1 checks the current to ensure it is stable near 0A (make sure the CLA is able to control the load). If the current is near 0, then decrease the dead-time.
7. Eventually, when the dead-time has reached the target dead-time (very small), then converter start-up is finished. We can now set whatever target current we want and the CLA will control the duty cycle to meet the current requirement.

I hope that setup makes sense.

Here's the problem:
When we set a very large dead-time (step 3), then the pulse on the low side of the DC-DC converter disappears, and causes the bootstrap voltage to fall because the synchronous bootstrap FET never turns on to charge it back up.

Any help would be appreciated. My guess is that I'm not using the configuration of the dead-time and duty cycle correctly and there is some setting or limit that I'm violating without knowing it.

  • Hello Micah,

    Thanks for the thorough descriptions! I understand the behavior at a high level- it may also help if you can sketch a quick view of what your desired PWM waveforms would look like for these steps in behavior to ensure our understanding is aligned. 

    To clarify, what are you using HR capability for? Is this for HR duty control? HR deadband? What count mode are you using? If you could send your PWM initializations this will help provide a better picture of what you are trying to implement and where things could be going wrong - please let me know if you are able to do so.

    Best Regards,

    Allison

  • Hi Allison,

    We are using HR for the duty control, with PWM in up-count mode.

    Here is a diagram of the PWM waveform I am trying to achieve during Step 3 with the long dead-time but maintaining the relative on-time duty cycle. Note that the converter would be operating in DCM at this point:

    Then as we decrease the dead-time in Step 6, the on-time will grow and I want to maintain the relative duty cycle.

    I realized that the reason the low pulse disappear with my current configuration is because the on-time set by the duty cycle is shorter than the long dead-time I want to use.
    Would I need to have different dead-times for the high and low sides, and change the dead-time every time I update the duty cycle in order to achieve this waveform?

    Most of the PWM configuration added below.

        //Enable the PWM clock and the PWM peripheral for CPU1
        SysCtl_selectCPUForPeripheral(SYSCTL_CPUSEL0_EPWM, pwm_number, SYSCTL_CPUSEL_CPU1);
        SysCtl_enablePeripheral(periph_clk);
    
        //Clock prescaler set to 100Mhz (output need to match macro PWM_CLK_KHZ)
        EPWM_setClockPrescaler(pwm_base, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
    
        /*TIME-BASE COUNTER AND ACTION QUALIFIER ARE CONFIGURED BELOW*/
        //Stimulus PWM is set to run at WAVEGEN_FREQUENCY_KHZ, in up-count mode only.
        EPWM_setTimeBaseCounterMode(pwm_base, EPWM_COUNTER_MODE_UP);
        EPWM_setTimeBasePeriod(pwm_base, WAVEGEN_PRD_COUNTER);
        EPWM_setCounterCompareValue(pwm_base, EPWM_COUNTER_COMPARE_A, WAVEGEN_PRD_COUNTER/2); //Defaults to 50%, arbitrarily chosen.
        //All registers that are modified in runtime are set to load shadow on counter reset
        EPWM_setCounterCompareShadowLoadMode(pwm_base, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO);
        EPWM_setCounterCompareShadowLoadMode(pwm_base, EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO);
        //Reset the time base counter to zero, disable phase shift for now
        EPWM_disablePhaseShiftLoad(pwm_base);
        EPWM_setTimeBaseCounter(pwm_base, 0U);
        //The action qualifier output is set to go low on timebase reset, and then go high as Counter matches CMPA (i.e. AQ OUT DC will match CMPA's complement0')
        EPWM_setActionQualifierAction(pwm_base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
        EPWM_setActionQualifierAction(pwm_base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    
        /*HRPWM IS CONFIGURED BELOW*/
        //Disable the high-res phase shift load
        HRPWM_disablePhaseShiftLoad(pwm_base);
        //For up-down count mode, the shadow load event must be set to load on zero and period
        HRPWM_setCounterCompareShadowLoadEvent(pwm_base, HRPWM_CHANNEL_A, HRPWM_LOAD_ON_CNTR_ZERO);
        HRPWM_setCounterCompareShadowLoadEvent(pwm_base, HRPWM_CHANNEL_B, HRPWM_LOAD_ON_CNTR_ZERO);
        //For each output, set to control micro-edge position (MEP) on appropriate edge
        HRPWM_setMEPEdgeSelect(pwm_base, HRPWM_CHANNEL_A, HRPWM_MEP_CTRL_RISING_EDGE);
        HRPWM_setMEPEdgeSelect(pwm_base, HRPWM_CHANNEL_B, HRPWM_MEP_CTRL_FALLING_EDGE);
        //For each output, set to "duty-cycle" control mode
        HRPWM_setMEPControlMode(pwm_base, HRPWM_CHANNEL_A, HRPWM_MEP_DUTY_PERIOD_CTRL);
        HRPWM_setMEPControlMode(pwm_base, HRPWM_CHANNEL_B, HRPWM_MEP_DUTY_PERIOD_CTRL);
        //Set normal output path for HRPWM output B:
        HRPWM_setChannelBOutputPath(pwm_base, HRPWM_OUTPUT_ON_B_NORMAL);
        //Don't swap the outputs.
        HRPWM_setOutputSwapMode(pwm_base, false);
        //Enable auto-conversion
        HRPWM_enableAutoConversion(pwm_base);
        //Disable high-res period control
        HRPWM_disablePeriodControl(pwm_base);
    
        /*DEAD-BAND IS CONFIGURED BELOW*/
        //Use full-clock resolution (100MHz)
        EPWM_setDeadBandCounterClock(pwm_base, EPWM_DB_COUNTER_CLOCK_HALF_CYCLE);
        //Set rising edge delay input as EPWMA, and set falling edge delay input as EPWMA as well
        EPWM_setRisingEdgeDeadBandDelayInput(pwm_base, EPWM_DB_INPUT_EPWMA); //IN_MODE bit, S4
        EPWM_setFallingEdgeDeadBandDelayInput(pwm_base, EPWM_DB_INPUT_EPWMA); //IN_MODE bit, S5 and DEDB_MODE S8
        EPWM_setRisingEdgeDelayCountShadowLoadMode(pwm_base, EPWM_RED_LOAD_ON_CNTR_ZERO);
        EPWM_setFallingEdgeDelayCountShadowLoadMode(pwm_base, EPWM_FED_LOAD_ON_CNTR_ZERO);
        HRPWM_setDeadbandMEPEdgeSelect(pwm_base, HRPWM_DB_MEP_CTRL_RED_FED);
        HRPWM_setRisingEdgeDelayLoadMode(pwm_base, HRPWM_LOAD_ON_CNTR_ZERO);
        HRPWM_setFallingEdgeDelayLoadMode(pwm_base, HRPWM_LOAD_ON_CNTR_ZERO);
        //Flip the polarity on the falling-edge only
        EPWM_setDeadBandDelayPolarity(pwm_base, EPWM_DB_RED, EPWM_DB_POLARITY_ACTIVE_HIGH); //POLSEL bit, S2
        EPWM_setDeadBandDelayPolarity(pwm_base, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW); //POLSEL bit, S3
        //Send both the RED and FED blocks to the output
        EPWM_setDeadBandDelayMode(pwm_base, EPWM_DB_RED, true); //OUT_MODE bit, S1
        EPWM_setDeadBandDelayMode(pwm_base, EPWM_DB_FED, true); //OUT_MODE bit, S0
        //Don't swap the outputs
        EPWM_setDeadBandOutputSwapMode(pwm_base, EPWM_DB_OUTPUT_A, false); //OUTSWAP bit, S6
        EPWM_setDeadBandOutputSwapMode(pwm_base, EPWM_DB_OUTPUT_B, false); //OUTSWAP bit, S7
    
        /*Propagate Trip input 4, 5 to DCAH/DCBH and DCAEVT1/DCBEVT1 (both needed to trip high and low pwm).
        *Trip input 4 and 5 are the cell current and voltage ADC trips (respectively)
        *These trip inputs are  ORed together and set as a one-shot trip for ePWM_xA and ePWM_xB to force both to 0
        */
        set_comparator_epwm_trip(pwm_base);
        EPWM_enableDigitalCompareTripCombinationInput(pwm_base, EPWM_DC_COMBINATIONAL_TRIPIN4 | EPWM_DC_COMBINATIONAL_TRIPIN5, EPWM_DC_TYPE_DCAH);
        EPWM_enableDigitalCompareTripCombinationInput(pwm_base, EPWM_DC_COMBINATIONAL_TRIPIN4 | EPWM_DC_COMBINATIONAL_TRIPIN5, EPWM_DC_TYPE_DCBH);
        EPWM_setTripZoneDigitalCompareEventCondition(pwm_base, EPWM_TZ_DC_OUTPUT_A1, EPWM_TZ_EVENT_DCXH_HIGH);
        EPWM_setTripZoneDigitalCompareEventCondition(pwm_base, EPWM_TZ_DC_OUTPUT_B1, EPWM_TZ_EVENT_DCXH_HIGH);
        EPWM_setDigitalCompareEventSource(pwm_base, EPWM_DC_MODULE_A, EPWM_DC_EVENT_1, EPWM_DC_EVENT_SOURCE_ORIG_SIGNAL);
        /*Finally, configure the EPWM module to one-shot trip on DCAEVT1.*/
        EPWM_enableTripZoneSignals(pwm_base, EPWM_TZ_SIGNAL_DCAEVT1 | EPWM_TZ_SIGNAL_DCBEVT1);
        /*Specify that the PWM outputs are both to be set to low upon trip zone event.*/
        EPWM_setTripZoneAction(pwm_base, EPWM_TZ_ACTION_EVENT_TZA, EPWM_TZ_ACTION_LOW);
        EPWM_setTripZoneAction(pwm_base, EPWM_TZ_ACTION_EVENT_TZB, EPWM_TZ_ACTION_LOW);
        EPWM_setTripZoneAction(pwm_base, EPWM_TZ_ACTION_EVENT_DCAEVT1, EPWM_TZ_ACTION_DISABLE);
        EPWM_setTripZoneAction(pwm_base, EPWM_TZ_ACTION_EVENT_DCBEVT1, EPWM_TZ_ACTION_DISABLE);
    
        //Below we enable and set the phase shift upon synchronization:
        EPWM_setPhaseShift(pwm_base, timebase_phase);
        EPWM_enablePhaseShiftLoad(pwm_base);
    
        //Below we apply configuration that is specific to PWM3, namely the sync output from software force.
        if (pwm_number == 3)
        {
         EPWM_enableSyncOutPulseSource(pwm_base, EPWM_SYNC_OUT_PULSE_ON_SOFTWARE);
    
         Hwi_Params_init(&hwi_params);
         hwi_params.enableInt = false;
         Hwi_create(EPWM3_TZ_INT_ID, limit_trip_hwi, &hwi_params, Error_ABORT);
    
         wavegen_disable_tripzone_int();
         Hwi_enableInterrupt(EPWM3_TZ_INT_ID);
    
        }
        //Below we apply configuration that is specific to PWM4 and 5, namely links to EPWM3 and the sync input
        else
        {
         EPWM_setupEPWMLinks(pwm_base, EPWM_LINK_WITH_EPWM_3, EPWM_LINK_COMP_A);
         EPWM_setupEPWMLinks(pwm_base, EPWM_LINK_WITH_EPWM_3, EPWM_LINK_COMP_B);
    
         EPWM_setSyncInPulseSource(pwm_base, EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM3);
        }
    
        EPWM_setEmulationMode(pwm_base, EPWM_EMULATION_FREE_RUN);

        //First we convert the deadtime quantity from nanoseconds to EPWM half clocks, and then store in our global variable.
        g_wavegen_dead_time_count = (uint32_t)(deadtime_length_ns / (float)((float)EPWMCK_PERIOD_NS / 2.0));
        //We then check to make sure the resulting dead time meets our hardware minimum along with the peripheral's maximum.
        if (g_wavegen_dead_time_count < BRIDGE_PWM_MIN_DEAD_TIME_HALF_EPWMCK_CNT){g_wavegen_dead_time_count = BRIDGE_PWM_MIN_DEAD_TIME_HALF_EPWMCK_CNT;}
        if (g_wavegen_dead_time_count > 0x4000U){g_wavegen_dead_time_count = 0x4000U;}
    
        /*Then set the falling and rising edge delays in counts of half EPWM clock periods, such as to apply the above-determined deadtime*/
        EPWM_setRisingEdgeDelayCount(WAVEGEN_PWM_BASE_1, g_wavegen_dead_time_count);
        EPWM_setFallingEdgeDelayCount(WAVEGEN_PWM_BASE_1, g_wavegen_dead_time_count);
        EPWM_setRisingEdgeDelayCount(WAVEGEN_PWM_BASE_2, g_wavegen_dead_time_count);
        EPWM_setFallingEdgeDelayCount(WAVEGEN_PWM_BASE_2, g_wavegen_dead_time_count);
        EPWM_setRisingEdgeDelayCount(WAVEGEN_PWM_BASE_3, g_wavegen_dead_time_count);
        EPWM_setFallingEdgeDelayCount(WAVEGEN_PWM_BASE_3, g_wavegen_dead_time_count);

  • Hi Micah,

    Thanks so much for the diagrams and including your configurations. This helps provide better context for the setup and target PWM output- please allow another day for me to look this over and provide some input. Appreciate your patience!

    Best Regards,

    Allison

  • Hi Micah,

    Apologies for the delay. Yes, you will need to adjust your deadband to avoid this. where are you updating your duty cycle? Is this in an ISR or CLA task perhaps? Have you already tried adjusting the dead time as well? Let me know if there has been an update on your implementation.

    Best Regards,

    Allison