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
