Part Number: TMS320F28377S
Hallo,
I need to extend already existing ePWM configuration. We have implemented FOC based on 3 ePWMs which are synchronized.
Period and dead-time are set once and never change, CMPAx is used for duty cycle. Output EPWMxB is inverted EPWMxA.
Shadow registers of CMPAx are loaded globally in single shot mode.
Additionally the SOC_A is triggered from PWM2:CMPB. This timing is constant.
The problem:
CAMPHR is properly updated what can be seen in debugger view. Unfortunately, no result is seen in output signal (oscilloscope). It works still as ePWM without HR extension.
As I add HRPWM configuration functions the dead-time seems to disappear. If I remove completely dead-time support then HRPWM works correctly.
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM3);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_HRPWM); //sourced from ePWM1 clock source
while (m_sfo_status == SFO_INCOMPLETE) // Call until complete
{
m_sfo_status = SFO();
if (m_sfo_status == SFO_ERROR)
{
ESTOP0; // SFO function returns 2 if an error occurs and number of MEP steps/coarse step exceeds maximum of 255.
}
}
// Disable sync(Freeze clock to PWM as well)
SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_GTBCLKSYNC);
SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
// ePWM1 - master
GPIO_setPadConfig(145, GPIO_PIN_TYPE_STD);
GPIO_setPinConfig(GPIO_145_EPWM1A); // phase UH
GPIO_setPadConfig(146, GPIO_PIN_TYPE_STD);
GPIO_setPinConfig(GPIO_146_EPWM1B);
// ePWM2
GPIO_setPadConfig(147, GPIO_PIN_TYPE_STD);
GPIO_setPinConfig(GPIO_147_EPWM2A); // phase VH
GPIO_setPadConfig(148, GPIO_PIN_TYPE_STD);
GPIO_setPinConfig(GPIO_148_EPWM2B);
// ePWM3
GPIO_setPadConfig(149, GPIO_PIN_TYPE_STD);
GPIO_setPinConfig(GPIO_149_EPWM3A);
GPIO_setPadConfig(150, GPIO_PIN_TYPE_STD);
GPIO_setPinConfig(GPIO_150_EPWM3B);
// master PWM gets no phase shift
set_ePWM_config( EPWM1_BASE, m_period, 0, deadband_delay_rising_edge_in_ticks, deadband_delay_falling_edge_in_ticks );
// slave PWMs get always phase shift 2
set_ePWM_config( EPWM2_BASE, m_period, 2, deadband_delay_rising_edge_in_ticks, deadband_delay_falling_edge_in_ticks );
set_ePWM_config( EPWM3_BASE, m_period, 2, deadband_delay_rising_edge_in_ticks, deadband_delay_falling_edge_in_ticks );
EPWM_setSyncOutPulseMode(EPWM1_BASE, EPWM_SYNC_OUT_PULSE_ON_COUNTER_ZERO); // EPWM 1 is master and olny sync generator
EPWM_setSyncOutPulseMode(EPWM2_BASE, EPWM_SYNC_OUT_PULSE_ON_EPWMxSYNCIN); // slave
EPWM_setSyncOutPulseMode(EPWM3_BASE, EPWM_SYNC_OUT_PULSE_ON_EPWMxSYNCIN); // slave
// ADC trigger offset (EPWM_COUNTER_COMPARE_B)
EPWM_setCounterCompareValue(EPWM2_BASE, EPWM_COUNTER_COMPARE_B, ( adc_trigger_pmwcount ));
EPWM_setADCTriggerSource(EPWM2_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_U_CMPB);
EPWM_setADCTriggerEventPrescale(EPWM2_BASE, EPWM_SOC_A, 1);
EPWM_enableADCTrigger(EPWM2_BASE, EPWM_SOC_A);
EPWM_setCounterCompareShadowLoadMode( EPWM2_BASE,
EPWM_COUNTER_COMPARE_B,
EPWM_COMP_LOAD_ON_CNTR_ZERO);
// Enable global shadow to active load for CMPA registers. See TRM 13.4.7.2 "One-Shot Load Mode"
EPWM_enableGlobalLoad(EPWM1_BASE); //GLDCTL[GLD]=1, individual shadowing is ignored
EPWM_enableGlobalLoadOneShotMode(EPWM1_BASE); // GLDCTL[OSHTMODE] enable one-shot
EPWM_enableGlobalLoadRegisters(EPWM1_BASE, EPWM_GL_REGISTER_CMPA_CMPAHR); // GLDCFG - register to be shadow-loaded
EPWM_setGlobalLoadTrigger(EPWM1_BASE, EPWM_GL_LOAD_PULSE_CNTR_PERIOD); //load on CNT_ZERO - GLDCTL[GLDMODE]
EPWM_setupEPWMLinks(EPWM1_BASE, EPWM_LINK_WITH_EPWM_3, EPWM_LINK_GLDCTL2); //writing to ePWM3 (one shot trigger) causes writing trigger (the same value of GLDCTL2) to ePWM1
EPWM_enableGlobalLoad(EPWM2_BASE);
EPWM_enableGlobalLoadOneShotMode(EPWM2_BASE);
EPWM_enableGlobalLoadRegisters(EPWM2_BASE, EPWM_GL_REGISTER_CMPA_CMPAHR);
EPWM_setGlobalLoadTrigger(EPWM2_BASE, EPWM_GL_LOAD_PULSE_CNTR_PERIOD);
EPWM_setupEPWMLinks(EPWM2_BASE, EPWM_LINK_WITH_EPWM_3, EPWM_LINK_GLDCTL2); //writing to ePWM3 (one shot trigger) causes writing trigger to ePWM1
EPWM_enableGlobalLoad(EPWM3_BASE);
EPWM_enableGlobalLoadOneShotMode(EPWM3_BASE);
EPWM_enableGlobalLoadRegisters(EPWM3_BASE, EPWM_GL_REGISTER_CMPA_CMPAHR);
EPWM_setGlobalLoadTrigger(EPWM3_BASE, EPWM_GL_LOAD_PULSE_CNTR_PERIOD);
// see Technical Reference page 1566: should be enabled after all ePWMs are initialized
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_GTBCLKSYNC);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
void set_ePWM_config(uint32_t epwm_base, uint16_t period, uint16_t offset, uint16_t deadband_delay_rising_edge, uint16_t deadband_delay_falling_edge)
{
// Set-up TBCLK
EPWM_setPeriodLoadMode(epwm_base, EPWM_PERIOD_DIRECT_LOAD); //direct load and never change, shadow is not used for period
EPWM_setTimeBasePeriod(epwm_base, period);
EPWM_setPhaseShift(epwm_base, offset);
EPWM_setTimeBaseCounter(epwm_base, offset);
EPWM_setEmulationMode(epwm_base, EPWM_EMULATION_FREE_RUN);
// Set up counter mode
EPWM_setTimeBaseCounterMode(epwm_base, EPWM_COUNTER_MODE_UP_DOWN);
EPWM_setClockPrescaler(epwm_base,EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
// if offset == 0 then there is master ePWM
if( 0 == offset )
{
EPWM_disablePhaseShiftLoad(epwm_base);
// HRPWM_disablePhaseShiftLoad(epwm_base);
}
else
{
EPWM_enablePhaseShiftLoad(epwm_base);
EPWM_setCountModeAfterSync(epwm_base, EPWM_COUNT_MODE_UP_AFTER_SYNC);
}
// HRPWM_selectPeriodLoadEvent(epwm_base, EPWM_SHADOW_LOAD_MODE_SYNC); //load shadow when sync happens, TODO: no one wants to reload period register
// HRPWM_setCounterCompareShadowLoadEvent(epwm_base, HRPWM_CHANNEL_A, HRPWM_LOAD_ON_CNTR_PERIOD); //slaves do not reach CNTR==0 because of phase shift --check it!
// Set actions
EPWM_setActionQualifierAction(epwm_base,
EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH,
EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// down counting: Output A low
EPWM_setActionQualifierAction(epwm_base,
EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW,
EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
// enable rising and falling edge delay (S0, S1)
EPWM_setDeadBandDelayMode(epwm_base, EPWM_DB_RED, true);
EPWM_setDeadBandDelayMode(epwm_base, EPWM_DB_FED, true);
// set EPWM_A as "lead" signal (S4, S5)
EPWM_setRisingEdgeDeadBandDelayInput(epwm_base, EPWM_DB_INPUT_EPWMA);
EPWM_setFallingEdgeDeadBandDelayInput(epwm_base, EPWM_DB_INPUT_EPWMA);
// invert output logic of B, don't invert A (S2, S3)
EPWM_setDeadBandDelayPolarity(epwm_base, EPWM_DB_RED, EPWM_DB_POLARITY_ACTIVE_HIGH);
EPWM_setDeadBandDelayPolarity(epwm_base, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW);
// set output swapping of out_A/out_B (S6, S7)
EPWM_setDeadBandOutputSwapMode(epwm_base, EPWM_DB_OUTPUT_A, true);
EPWM_setDeadBandOutputSwapMode(epwm_base, EPWM_DB_OUTPUT_B, true);
// set delay counts
EPWM_setFallingEdgeDelayCount(epwm_base, deadband_delay_falling_edge);
EPWM_setRisingEdgeDelayCount(epwm_base, deadband_delay_rising_edge);
// HRPWM_disablePeriodControl(epwm_base);
HRPWM_setMEPControlMode(epwm_base, HRPWM_CHANNEL_A, HRPWM_MEP_DUTY_PERIOD_CTRL); //MEP controlled by value of CMPA
HRPWM_setMEPEdgeSelect(epwm_base, HRPWM_CHANNEL_A, HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE);
HRPWM_setDeadbandMEPEdgeSelect(epwm_base, HRPWM_DB_MEP_CTRL_RED_FED);
// HRPWM_setChannelBOutputPath(epwm_base, HRPWM_OUTPUT_ON_B_INV_A); //dead time is overwritten?
}