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.

TMS320F28335: 3-Phase SPWM Asymmetrical Pulse Issue in C2000 ePWM with 12-bit Lookup Table

Part Number: TMS320F28335


Tool/software:

HELLO

I'm working on a 3-phase SPWM generation system on a TMS320F28335 DSP using a 12-bit sine lookup table (4096 points).

My goal is to generate a symmetrical sine-triangle PWM waveform.

The system works to an extent, but I’m facing asymmetry issues in the output pulses:

  • For example, when I probe the output waveform, I get 8 pulses on the positive side and 10 pulses on the negative side of the sine wave when I set fundametal 500Hz and Switching 4500Hz.

  • It shall be 9/9.

I am attaching my main file with this thread.

Would greatly appreciate your insights!

#include "DSP28x_Project.h"
#include "math.h"
#include "ksine_table.h"  // 4096 = +1 to 1 = float

#ifndef SYSCLKOUT
#define SYSCLKOUT 100000000
#endif

#define EPWM1_MAX_DB 0x160
#define EPWM2_MAX_DB 0x160
#define EPWM3_MAX_DB 0x160

// Prototypes
void InitEPwmModules(void);
__interrupt void epwm1_isr(void);
void UpdatePWMParameters(float fund_freq, float switch_freq);

// Global variables
#pragma DATA_SECTION(sine_table, "sine_ram")
#define TABLE_SIZE 4096

float  modulation_index = 0.8f;  			// Modulation index (0-1)
float  current_fund_freq = 500.0; 			// Current fundamental frequency (Hz)
float  current_switch_freq = 4500.0; 		// Current switching frequency (Hz)
Uint32 pwm_period;              			// Current PWM period in counts

float phase_acc = 0.0f;
float phase_step;

// Main function
void main(void)
{
    // Step 1. Initialize System Control
    InitSysCtrl();

    // Step 2. Initialize GPIO
    InitEPwm1Gpio();
    InitEPwm2Gpio();
    InitEPwm3Gpio();

    // Step 4. Initialize PIE and interrupts
    DINT;
    InitPieCtrl();
    IER = 0x0000;
    IFR = 0x0000;
    InitPieVectTable();

	// Flash Enable
	memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (Uint32)&RamfuncsLoadSize);
	InitFlash();

	// Initialization PWM
	EALLOW;
	PieVectTable.EPWM1_INT   = &epwm1_isr;
	EDIS;

    // Step 5. Initialize ePWM modules with default frequencies
	pwm_period = 0;
    InitEPwmModules();
    UpdatePWMParameters(current_fund_freq, current_switch_freq);

    // Step 6. Enable interrupts
	PieCtrlRegs.PIECTRL.bit.ENPIE = 1;   	//  Enable the PIE block
	PieCtrlRegs.PIEIER1.bit.INTx4 = 1;   	//  Enable PIE Group 1 INT4
	IER |= M_INT1;                       	//  Enable CPU int1

	PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
	PieCtrlRegs.PIEIER3.bit.INTx2 = 0;
	PieCtrlRegs.PIEIER3.bit.INTx3 = 0;

	IER |= M_INT2;							// Enable CPU INT3 which is connected to EPWM1-3 INT:
	IER |= M_INT3;
	PieCtrlRegs.PIEIER2.bit.INTx1 = 1;		// Enable EPWM INTn in the PIE: Group 2 interrupt 1-3

	EINT;       							// Enable Global interrupt INTM
	ERTM;       							// Enable Global real-time interrupt DBGM

    for(;;)
    {
        // UpdatePWMParameters(current_fund_freq, current_switch_freq);
        __asm(" NOP");
    }
}

void UpdatePWMParameters(float fund_freq, float switch_freq)
{
    // Calculate new PWM period using defined SYSCLKOUT
    pwm_period = (Uint32)((SYSCLKOUT / (4.0f * switch_freq)) - 1);

    phase_step = (float)(TABLE_SIZE * fund_freq)/ switch_freq;

    // Update ePWM modules
    EALLOW;
    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Stop ePWM clocks

    // Update all modules with new period
    EPwm1Regs.TBPRD = pwm_period;
    EPwm2Regs.TBPRD = pwm_period;
    EPwm3Regs.TBPRD = pwm_period;

    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Restart ePWM clocks
    EDIS;
}

// Initialize all ePWM modules
void InitEPwmModules(void)
{
    EALLOW;
    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
    EDIS;

    //=====================================================================
	// Configuration
	//=====================================================================
	// Initialization Time
	//========================// EPWM Module 1 configure
	EPwm1Regs.TBPRD = pwm_period;
	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;
	EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; 		// Sync down-stream module
	EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
	EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
	EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; 		// load on CTR=Zero
	EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; 		// load on CTR=Zero
	EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; 					// set actions for EPWM1A
	EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;
	EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; 		// enable Dead-band module
	EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; 			// Active Hi complementary
	EPwm1Regs.DBFED = 50; 								// FED = 50 TBCLKs
	EPwm1Regs.DBRED = 50; 								// RED = 50 TBCLKs

	// EPWM Module 2 configure
	EPwm2Regs.TBPRD = pwm_period; 						// Period = 1600 TBCLK counts
	EPwm2Regs.TBPHS.half.TBPHS = 0; 					// Set Phase register to zero
	EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; 		// Symmetrical mode
	EPwm2Regs.TBCTL.bit.PHSEN = TB_ENABLE; 				// Slave module
	EPwm2Regs.TBCTL.bit.PRDLD = TB_SHADOW;
	EPwm2Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN; 			// sync flow-through
	EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
	EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
	EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; 		// load on CTR=Zero
	EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; 		// load on CTR=Zero
	EPwm2Regs.AQCTLA.bit.CAU = AQ_SET; 					// set actions for EPWM2A
	EPwm2Regs.AQCTLA.bit.CAD = AQ_CLEAR;
	EPwm2Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; 		// enable Dead-band module
	EPwm2Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; 			// Active Hi complementary
	EPwm2Regs.DBFED = 50; 								// FED = 50 TBCLKs
	EPwm2Regs.DBRED = 50; 								// RED = 50 TBCLKs

	// EPWM Module 3 configure
	EPwm3Regs.TBPRD = pwm_period;
	EPwm3Regs.TBPHS.half.TBPHS = 0; 					// Set Phase register to zero
	EPwm3Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; 		// Symmetrical mode
	EPwm3Regs.TBCTL.bit.PHSEN = TB_ENABLE; 				// Slave module
	EPwm3Regs.TBCTL.bit.PRDLD = TB_SHADOW;
	EPwm3Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN; 			// sync flow-through
	EPwm3Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
	EPwm3Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
	EPwm3Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; 		// load on CTR=Zero
	EPwm3Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; 		// load on CTR=Zero
	EPwm3Regs.AQCTLA.bit.CAU = AQ_SET; 					// set actions for EPWM3A
	EPwm3Regs.AQCTLA.bit.CAD = AQ_CLEAR;
	EPwm3Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; 		// enable Dead-band module
	EPwm3Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; 			// Active Hi complementary
	EPwm3Regs.DBFED = 50; 								// FED = 50 TBCLKs
	EPwm3Regs.DBRED = 50; 								// RED = 50 TBCLKs

	// Interrupt configuration
	EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;
	EPwm1Regs.ETSEL.bit.INTEN = 1;
	EPwm1Regs.ETPS.bit.INTPRD = ET_1ST;

    // Reset all ePWM counters simultaneously
    EPwm1Regs.TBCTL.bit.SWFSYNC = 1;
    EPwm2Regs.TBCTL.bit.SWFSYNC = 1;
    EPwm3Regs.TBCTL.bit.SWFSYNC = 1;

    EALLOW;
    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
    EDIS;
}

// Interrupt service routine - updates PWM duty cycles using 12-bit table
// epwm1_isr -
__interrupt void epwm1_isr(void)
{
    // Calculate indices for three phases (0°, 120°, 240°)
	Uint32 index_u = ((Uint32)phase_acc) % TABLE_SIZE;
	Uint32 index_v = (index_u + TABLE_SIZE / 3) % TABLE_SIZE;
	Uint32 index_w = (index_u + 2 * TABLE_SIZE / 3) % TABLE_SIZE;

	phase_acc += phase_step;
	if (phase_acc >= TABLE_SIZE)
	    phase_acc -= TABLE_SIZE;

    // Get sine values from table
    float sine_u = sine_table[index_u];
    float sine_v = sine_table[index_v];
    float sine_w = sine_table[index_w];

    // Scale by modulation index and convert to timer counts
    Uint16 duty_u = (Uint16)((pwm_period/2) * (1.0f + modulation_index * sine_u));
    Uint16 duty_v = (Uint16)((pwm_period/2) * (1.0f + modulation_index * sine_v));
    Uint16 duty_w = (Uint16)((pwm_period/2) * (1.0f + modulation_index * sine_w));

    // Update compare registers
    EPwm1Regs.CMPA.half.CMPA = duty_u;
    EPwm1Regs.CMPB = duty_u;
    EPwm2Regs.CMPA.half.CMPA = duty_v;
    EPwm2Regs.CMPB = duty_v;
    EPwm3Regs.CMPA.half.CMPA = duty_w;
    EPwm3Regs.CMPB = duty_w;

    // Clear interrupt flag
    EPwm1Regs.ETCLR.bit.INT = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
}

Thanks,

KP