Other Parts Discussed in Thread: SYSCONFIG, C2000WARE
We use TI DSP TMS320F28374S to drive an LLC converter with Buck-Boost stage
During operation, we need to change switching frequency on the fly.
For that reason we want to use the Global Load capability described on page 1756 of the technical reference manual.
Following PWM modules are linked and need to run at the same Frequency:
EPWM1 (Master)
EPWM2 (Slave)
EPWM3 (Slave)
EPWM4 (Slave)
EPWM5 (Slave)
All Counters are configure to run Up&Down, I would like to have all PWM units updating ther PRD and CMPA values from shadow register when PWM1 reaches CTR = 0.
I tested several configurations of Global Load strobes but the PWM Pattern does not match the expectation as a Lag appears between EPWM2,3 and EPWM4,5.
I suspect a configuration issue in our code.
Here is part of the code were we initialize PWM Register
EALLOW;
CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0;
EDIS;
//configure 4 LLC HRPWM modules
for (j=0;j<=3;j++)
{
//TODO think about using trip zone
// EALLOW;
// (*LLC_ePWMArray[j]).TZSEL.bit.DCBEVT1 = TRUE; // Enables DCBEVT1 as a one-shot event source (software TZ)
//// (*LLC_ePWMArray[j]).TZSEL.bit.OSHT3 = TRUE; // Enables \TZ3 as a one-shot event source (hardware TZ)
// (*LLC_ePWMArray[j]).TZFRC.bit.DCBEVT1 = TRUE; // Force TZ interrupt during init
// (*LLC_ePWMArray[j]).TZCTL.bit.TZA = TZ_FORCE_LO; // EPWMxA will be forced LOW on a trip event
// (*LLC_ePWMArray[j]).TZCTL.bit.TZB = TZ_FORCE_LO; // EPWMxB will be forced LOW on a trip event
// EDIS;
(*LLC_ePWMArray[j]).TBPRD = PWM_50KHZ_PRD_CNTUPDOWN; // PWM frequency = 1/(2*TBPRD)
(*LLC_ePWMArray[j]).EPWMXLINK.bit.TBPRDLINK = 0x0; //Link the PRD Register to the settings of EPWM1 unit
//(update of EPWM1 PRD automatically updates PRD value of this module)
//TODO comment in these lines if we do not need the dead times and can use same CMPA values for all bridges
// (*LLC_ePWMArray[j]).EPWMXLINK.bit.CMPALINK = 0x1; //Link the CMPA/CMPAHR register to the settings of EPWM2 unit
// //(update of EPWM2 compare value automatically updates compare value of this module)
(*LLC_ePWMArray[j]).CMPA.bit.CMPAHR = (0 << 8); // initialize HRPWM extension
(*LLC_ePWMArray[j]).TBPHS.all = 0;
(*LLC_ePWMArray[j]).TBCTR = 0;
(*LLC_ePWMArray[j]).TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Select up-down count mode.
//3.
(*LLC_ePWMArray[j]).TBCTL.bit.PRDLD = TB_SHADOW; // set Shadow load
(*LLC_ePWMArray[j]).TBCTL.bit.HSPCLKDIV = TB_DIV1;
(*LLC_ePWMArray[j]).TBCTL.bit.CLKDIV = TB_DIV1; // TBCLK = SYSCLKOUT
(*LLC_ePWMArray[j]).TBCTL.bit.FREE_SOFT = 1;
(*LLC_ePWMArray[j]).CMPCTL.bit.SHDWAMODE = CC_SHADOW;
(*LLC_ePWMArray[j]).CMPCTL.bit.SHDWBMODE = CC_SHADOW;
(*LLC_ePWMArray[j]).CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // LOAD CMPA on ZRO.
(*LLC_ePWMArray[j]).CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
//configure deadband module to be able to use rising and falling edge delay on output A
//see DeadBandModuleConfigLLCPwms.png for more details
(*LLC_ePWMArray[j]).DBCTL.bit.OUTSWAP = 3;
(*LLC_ePWMArray[j]).DBCTL.bit.DEDB_MODE = 1;
(*LLC_ePWMArray[j]).DBCTL.bit.OUT_MODE = 1;
(*LLC_ePWMArray[j]).DBCTL.bit.SHDWDBFEDMODE = 1;
(*LLC_ePWMArray[j]).DBCTL.bit.SHDWDBREDMODE = 1;
if(j == 0 || j == 2)
{
//Action at CMP event:
(*LLC_ePWMArray[j]).AQCTLA.bit.CAU = AQ_CLEAR; // PWM toggle high/low
(*LLC_ePWMArray[j]).AQCTLA.bit.CAD = AQ_CLEAR;
(*LLC_ePWMArray[j]).CMPA.bit.CMPA = PWM_50KHZ_PRD_CNTUPDOWN_50DUTY;// - PWM_DEADTIME_IN_TICKS; // set duty 50% initially
}
else
{
(*LLC_ePWMArray[j]).AQCTLA.bit.CAU = AQ_CLEAR; // PWM toggle high/low
(*LLC_ePWMArray[j]).AQCTLA.bit.CAD = AQ_CLEAR;
(*LLC_ePWMArray[j]).CMPA.bit.CMPA = PWM_50KHZ_PRD_CNTUPDOWN_50DUTY;// + PWM_DEADTIME_IN_TICKS; // set duty 50% initially
}
EALLOW;
(*LLC_ePWMArray[j]).HRCNFG.all = 0x0;
//4.
#ifdef PWM_PHSHR
(*LLC_ePWMArray[j]).HRCNFG.bit.HRLOAD = HR_CTR_ZERO; // Load on CTR = 0 (Needed for HR phase shift)
#else
(*LLC_ePWMArray[j]).HRCNFG.bit.HRLOAD = HR_CTR_ZERO_PRD; // Load on CTR = 0 and PRD (Needed for HR duty cycle)
#endif
(*LLC_ePWMArray[j]).HRCNFG.bit.AUTOCONV = 1; // Enable autoconversion for HR period
(*LLC_ePWMArray[j]).HRCNFG.bit.EDGMODE = HR_BEP; // MEP control on both edges
(*LLC_ePWMArray[j]).HRCNFG.bit.CTLMODE = HR_CMP; // Selects the register (CMP/TBPRD or TBPHS) that controls the MEP //MKh: HR phase shift still works with HR_CMP
//5.
(*LLC_ePWMArray[j]).HRPCTL.bit.TBPHSHRLOADE = 1; // This bit allows you to synchronize ePWM modules with a high-resolution phase on a SYNCIN, TBCTL[SWFSYNC] or digital compare event
//all are slaves...
(*LLC_ePWMArray[j]).TBCTL.bit.PHSEN = TB_ENABLE; // Load the time-base counter with the phase register on a SYNCIN or TBCTL[SWFSYNC] event
(*LLC_ePWMArray[j]).TBCTL.bit.SYNCOSEL = TB_SYNC_IN; // SWFSYNC is valid (operates) only when EPWMxSYNCI is selected by SYNCOSEL = 00.
(*LLC_ePWMArray[j]).TBCTL.bit.PHSDIR = 1; // count up after SYNC event and the new value of the phase (TBPHS) is loaded.
(*LLC_ePWMArray[j]).TBPHS.bit.TBPHS = 2; // initial - coarse phase offset relative to ePWM1 (value from datasheet / manual)
(*LLC_ePWMArray[j]).HRPCTL.bit.HRPE = 1; // 6. Enable high-resolution period control.
//6. Configure Global Load Feature for Shadow Registers of LLC
(*LLC_ePWMArray[j]).TBCTL2.bit.PRDLDSYNC = 0x2; // Shadow to active load when Sync is Received
GlobalLoadConfig(LLC_ePWMArray[j]);
Global Load is configured after in a separate function:
void GlobalLoadConfig(volatile struct EPWM_REGS *ePWM_reg)
{
// Configure Global Load Feature for Shadow Registers
// In basic Config, the Global Load is disabled
EALLOW;
(*ePWM_reg).GLDCFG.bit.TBPRD_TBPRDHR = 0x1; // Allow Global Load on TBRD and TBRDHR
(*ePWM_reg).GLDCFG.bit.CMPA_CMPAHR = 0x1; // Allow Global Load on CMPA and CMPAHR
(*ePWM_reg).GLDCFG.bit.CMPB_CMPBHR = 0x1; // Allow Global Load on CMPA and CMPAHR
(*ePWM_reg).GLDCTL.bit.OSHTMODE = 0x0; // One shot mode disabled
(*ePWM_reg).GLDCTL.bit.GLDMODE = 0x03; // Load Shadow Registers on SYNCEVT Event
(*ePWM_reg).GLDCTL.bit.GLDPRD = 0x1; // Trigger on first event
(*ePWM_reg).GLDCTL.bit.GLD = 0x1; // Use global Load Strobes (Global Load Enabled)
(*ePWM_reg).EPWMXLINK.bit.GLDCTL2LINK = 0x0; // Link GLDCTL2 to ePWM1 -> One Shot Load Synched to ePWM1
//EDIS;
}
When a frequency change occur, the One Shot load is activated and triggered
I would greatly appreciate if you have examples to provide or can explain how to properly link the registers to achieve the requested behaviour.
Our final goal is to have all PWM Registers updated at once (Period and Duty Cycle), without glitch between ePWM modules.
Thank you for your support.