Hello,
I am trying to implement alternating zero space vector modulation on an f28335. It is working mostly, but I notice glitching at the sector transitions. I looked at the space vector modulation setup example in the Control Suite motor control example, but that is symmetrical space vector modulation and doesn't have the quirks of setup that I have.
Basically, each cycle I need to update the CMPA register for two of my three phase legs, and the other needs to stay in an off or on state. What I do right now is used AQCTLA to setup an event at the PWM counter (using an up/down counter) to force pins high or low depending on which zero vector I need. Then I have the PWM pins in toggle model at the crossing with CMPA, and this gives me the desired pattern. For the third pin that needs to be held off or on, I use AQCSFRC to force it high or low consistent with the other pins, and then it should stay that way.
What I am afraid is happening is that application (or removal, or both) of the software force is happening immediately and not with a shadow buffer at PWM counter = 0. This is kind of the unusual part about what I am doing, and therefore I'm not comfortable it is working correctly. During initialization, I setup AQSFRC.bit.RLDCSF = 0, which I thought would make my use of AQCSFRC happen with a shadow buffer and at PWM counter = 0, consistent with when I load from CMPA.
Does this way of trying to do what I am doing even make sense? And is it even possible? I have posted my initialization code below, and also my update case statement. Any guidance would be most appreciated. Note I have an inversion in my PWM hardware outside of the DSP so I do things that make seem backwards.
Thank you,
Logan
/************************* INITIALIZATION ****************************************/
// EPWM Module 1 config
EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0x0; //No clock division for maximum speed
EPwm1Regs.TBPRD = PWM_PERIOD; // Period = 4800 TBCLK counts
EPwm1Regs.TBPHS.half.TBPHS = 0; // Set Phase register to zero
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;// Symmetrical mode
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Master module
EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW; //Shadow buffer mode
EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // Sync down-stream module
EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; //CMP load double buffering enabled
EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; //CMP load double buffering enabled
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; //Load CMP at CTR = ZERO
EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; //Load CMP at CTR = ZERO
EPwm1Regs.AQCTLA.bit.CAU = AQ_TOGGLE; // set actions for EPWM1A
EPwm1Regs.AQCTLA.bit.CAD = AQ_TOGGLE;
EPwm1Regs.AQCTLA.bit.ZRO = AQ_CLEAR;
EPwm1Regs.AQSFRC.bit.RLDCSF = 0x0; //Load software force events at CTR = ZERO consistent with CMP loads
EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // enable Dead-band module
EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_LOC; // Active low complementary due to need to implement dead time with a hardware inversion
EPwm1Regs.DBFED = DEAD_TIME_AFE; // FED = 300 TBCLKs, or 2us
EPwm1Regs.DBRED = DEAD_TIME_AFE; // RED = 300 TBCLKs, or 2us
EPwm1Regs.ETSEL.bit.SOCAEN = 1; //Enable ADC SOC trigger 1
EPwm1Regs.ETSEL.bit.SOCBEN = 1; //Enable ADC SOC trigger 2
EPwm1Regs.ETSEL.bit.SOCASEL = ET_CTR_ZERO; //Set trigger 1 to occur at PWM counter 0
EPwm1Regs.ETSEL.bit.SOCBSEL = ET_CTR_PRD; //Set trigger 2 to occur at PWM counter peak
EPwm1Regs.ETPS.bit.SOCAPRD = ET_1ST; // Generate trigger 1 pulse on 1st event
EPwm1Regs.ETPS.bit.SOCBPRD = ET_1ST; // Generate trigger 2 pulse on 1st event
// EPWM Module 2 config
EPwm2Regs.TBCTL.bit.HSPCLKDIV = 0x0; //No clock division for maximum speed
EPwm2Regs.TBPRD = PWM_PERIOD; // Period = 4800 TBCLK counts
EPwm2Regs.TBPHS.half.TBPHS = 0; // Set Phase register to zero
EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;// Symmetrical mode
EPwm2Regs.TBCTL.bit.PHSDIR = TB_UP; // Count UP on sync (=0 deg)
EPwm2Regs.TBCTL.bit.PHSEN = TB_ENABLE; // Slave module
EPwm2Regs.TBCTL.bit.PRDLD = TB_SHADOW; //Shadow buffer mode
EPwm2Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN; // sync flow-through
EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; //CMP load double buffering enabled
EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; //CMP load double buffering enabled
EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; //Load CMP at CTR = ZERO
EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; //Load CMP at CTR = ZERO
EPwm2Regs.AQCTLA.bit.CAU = AQ_TOGGLE; // set actions for EPWM2A
EPwm2Regs.AQCTLA.bit.CAD = AQ_TOGGLE;
EPwm2Regs.AQCTLA.bit.ZRO = AQ_CLEAR;
EPwm2Regs.AQSFRC.bit.RLDCSF = 0x0; //Load software force events at CTR = ZERO consistent with CMP loads
EPwm2Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // enable Dead-band module
EPwm2Regs.DBCTL.bit.POLSEL = DB_ACTV_LOC; // Active low complementary due to need to implement dead time with a hardware inversion
EPwm2Regs.DBFED = DEAD_TIME_AFE; // FED = 300 TBCLKs, or 2us
EPwm2Regs.DBRED = DEAD_TIME_AFE; // RED = 300 TBCLKs, or 2us
// EPWM Module 3 config
EPwm3Regs.TBCTL.bit.HSPCLKDIV = 0x0; //No clock division for maximum speed
EPwm3Regs.TBPRD = PWM_PERIOD; // Period = 4800 TBCLK counts
EPwm3Regs.TBPHS.half.TBPHS = 0; // Set Phase register to zero
EPwm3Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;// Symmetrical mode
EPwm3Regs.TBCTL.bit.PHSDIR = TB_UP; // Count UP on sync (=0 deg)
EPwm3Regs.TBCTL.bit.PHSEN = TB_ENABLE; // Slave module
EPwm3Regs.TBCTL.bit.PRDLD = TB_SHADOW; //Shadow buffer mode
EPwm3Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN; // sync flow-through
EPwm3Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; //CMP load double buffering enabled
EPwm3Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; //CMP load double buffering enabled
EPwm3Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; //Load CMP at CTR = ZERO
EPwm3Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; //Load CMP at CTR = ZERO
EPwm3Regs.AQCTLA.bit.CAU = AQ_TOGGLE; // set actions for EPWM3A
EPwm3Regs.AQCTLA.bit.CAD = AQ_TOGGLE;
EPwm3Regs.AQCTLA.bit.ZRO = AQ_CLEAR;
EPwm3Regs.AQSFRC.bit.RLDCSF = 0x0; //Load software force events at CTR = ZERO consistent with CMP loads
EPwm3Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // enable Dead-band module
EPwm3Regs.DBCTL.bit.POLSEL = DB_ACTV_LOC; // Active low complementary due to need to implement dead time with a hardware inversion
EPwm3Regs.DBFED = DEAD_TIME_AFE; // FED = 300 TBCLKs, or 2us
EPwm3Regs.DBRED = DEAD_TIME_AFE; // RED = 300 TBCLKs, or 2us
/************************* Update Code ****************************************************/
//State machine for determining PWM configuration for a given sector
switch (control_block->sector)
{
case 1:
{
// Configure PWM module for sector 1 actions
// Phase A is forced high (recall there is an inversion) using the software force, which is setup to
// have a synchronous load at counter = 0. Phases B and C are setup to go high at zero, and will also load
// the comparator values at 0. They will toggle to generate the expected switching state pattern. Any forcing
// on Phases B and C is removed.
if (control_block->sector != sector_tracker)
{
EPwm1Regs.AQCSFRC.bit.CSFA = 0x1;
EPwm2Regs.AQCSFRC.bit.CSFA = 0x0;
EPwm3Regs.AQCSFRC.bit.CSFA = 0x0;
EPwm2Regs.AQCTLA.bit.ZRO = AQ_CLEAR;
EPwm3Regs.AQCTLA.bit.ZRO = AQ_CLEAR;
sector_tracker = control_block->sector;
}
EPwm2Regs.CMPA.half.CMPA = control_block->Tb*PWM_MAX; //Set Phase B
EPwm3Regs.CMPA.half.CMPA = control_block->Ta*PWM_MAX; //Set Phase C
break;
}
case 2:
{
// Configure PWM module for sector 2 actions
// Phase C is forced low (recall there is an inversion) using the software force, which is setup to
// have a synchronous load at counter = 0. Phases A and B are setup to go low at zero, and will also load
// the comparator values at 0. They will toggle to generate the expected switching state pattern. Any forcing
// on Phases A and B is removed.
if (control_block->sector != sector_tracker)
{
EPwm1Regs.AQCSFRC.bit.CSFA = 0x0;
EPwm2Regs.AQCSFRC.bit.CSFA = 0x0;
EPwm3Regs.AQCSFRC.bit.CSFA = 0x2;
EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET;
EPwm2Regs.AQCTLA.bit.ZRO = AQ_SET;
sector_tracker = control_block->sector;
}
EPwm1Regs.CMPA.half.CMPA = control_block->Tb*PWM_MAX; //Set Phase A
EPwm2Regs.CMPA.half.CMPA = control_block->Ta*PWM_MAX; //Set Phase B
break;
}
case 3:
{
// Configure PWM module for sector 3 actions
// Phase B is forced high (recall there is an inversion) using the software force, which is setup to
// have a synchronous load at counter = 0. Phases A and C are setup to go high at zero, and will also load
// the comparator values at 0. They will toggle to generate the expected switching state pattern. Any forcing
// on Phases A and C is removed.
if (control_block->sector != sector_tracker)
{
EPwm1Regs.AQCSFRC.bit.CSFA = 0x0;
EPwm2Regs.AQCSFRC.bit.CSFA = 0x1;
EPwm3Regs.AQCSFRC.bit.CSFA = 0x0;
EPwm1Regs.AQCTLA.bit.ZRO = AQ_CLEAR;
EPwm3Regs.AQCTLA.bit.ZRO = AQ_CLEAR;
sector_tracker = control_block->sector;
}
EPwm1Regs.CMPA.half.CMPA = control_block->Ta*PWM_MAX; //Set Phase A
EPwm3Regs.CMPA.half.CMPA = control_block->Tb*PWM_MAX; //Set Phase C
break;
}
case 4:
{
// Configure PWM module for sector 4 actions
// Phase A is forced low (recall there is an inversion) using the software force, which is setup to
// have a synchronous load at counter = 0. Phases B and C are setup to go low at zero, and will also load
// the comparator values at 0. They will toggle to generate the expected switching state pattern. Any forcing
// on Phases B and C is removed.
if (control_block->sector != sector_tracker)
{
EPwm1Regs.AQCSFRC.bit.CSFA = 0x2;
EPwm2Regs.AQCSFRC.bit.CSFA = 0x0;
EPwm3Regs.AQCSFRC.bit.CSFA = 0x0;
EPwm2Regs.AQCTLA.bit.ZRO = AQ_SET;
EPwm3Regs.AQCTLA.bit.ZRO = AQ_SET;
sector_tracker = control_block->sector;
}
EPwm2Regs.CMPA.half.CMPA = control_block->Tb*PWM_MAX; //Set Phase B
EPwm3Regs.CMPA.half.CMPA = control_block->Ta*PWM_MAX; //Set Phase C
break;
}
case 5:
{
// Configure PWM module for sector 5 actions
// Phase C is forced high (recall there is an inversion) using the software force, which is setup to
// have a synchronous load at counter = 0. Phases A and B are setup to go high at zero, and will also load
// the comparator values at 0. They will toggle to generate the expected switching state pattern. Any forcing
// on Phases A and B is removed.
if (control_block->sector != sector_tracker)
{
EPwm1Regs.AQCSFRC.bit.CSFA = 0x0;
EPwm2Regs.AQCSFRC.bit.CSFA = 0x0;
EPwm3Regs.AQCSFRC.bit.CSFA = 0x1;
EPwm1Regs.AQCTLA.bit.ZRO = AQ_CLEAR;
EPwm2Regs.AQCTLA.bit.ZRO = AQ_CLEAR;
sector_tracker = control_block->sector;
}
EPwm1Regs.CMPA.half.CMPA = control_block->Tb*PWM_MAX; //Set Phase A
EPwm2Regs.CMPA.half.CMPA = control_block->Ta*PWM_MAX; //Set Phase B
break;
}
case 6:
{
// Configure PWM module for sector 6 actions
// Phase B is forced low (recall there is an inversion) using the software force, which is setup to
// have a synchronous load at counter = 0. Phases A and C are setup to go low at zero, and will also load
// the comparator values at 0. They will toggle to generate the expected switching state pattern. Any forcing
// on Phases A and C is removed.
if (control_block->sector != sector_tracker)
{
EPwm1Regs.AQCSFRC.bit.CSFA = 0x0;
EPwm2Regs.AQCSFRC.bit.CSFA = 0x2;
EPwm3Regs.AQCSFRC.bit.CSFA = 0x0;
EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET;
EPwm3Regs.AQCTLA.bit.ZRO = AQ_SET;
sector_tracker = control_block->sector;
}
EPwm1Regs.CMPA.half.CMPA = control_block->Ta*PWM_MAX; //Set Phase A
EPwm3Regs.CMPA.half.CMPA = control_block->Tb*PWM_MAX; //Set Phase C
break;
}
}
