您好,我在用TMS320F28377D调试PWM过程中遇到了如下问题:
我所用PWM的功能是:将ePWM1作为主时钟(Master),ePWM2,3,10,11,12作为从时钟(Slave),输出互补死区的12路PWM波。
当我在ePWM的中断中修改PWM的占空比(dutycycle)时,原本应当只改变占空比,不改变频率。
PWM实际输出的高低电平时间和实际开关频率如下所示。实际的占空比和给定占空比不相等;当占空比上升时,实际的输出频率也会上升。只有当占空比=0时,输出频率才近似等于所需的40kHz。
其他功能,如互补死区、多路同步均表现正常。
请问我的代码存在哪些问题,应当如何修改,谢谢!

以下为我的配置函数和调用函数:
配置函数为:
// PWM MACRO DEFINE
// SYSCLK = 200MHz
// EPWMCLK = SYSCLK/2(define=2) = 100MHz
// TBCLK = EPWMCLK/(HSPCLKDIV*CLKDIV) = 100MHz
// We want 40kHz, so 2*EPWM_TIMER_TBPRD=100/40*1000=2500, thus EPWM_TIMER_TBPRD=1250
// Tdb = 1/(100MHz/40) = 400ns
#define freq_sw 40000 // Switching frequency, Hz
#define prd_sw 1.0/40000.0 // Switching period, s
#define EPWM_TIMER_TBPRD 100000000/(freq_sw*2)
#define EPWM_MIN_CMPA 50
#define EPWM_MAX_CMPB 1200
#define EPWM_DB 40
//
// InitEPwm1Gpio - Initialize EPWM1 GPIOs
//
void InitEPwm1Gpio(void)
{
EALLOW;
//
// Disable internal pull-up for the selected output pins
// for reduced power consumption
// Pull-ups can be enabled or disabled by the user.
// Comment out other unwanted lines.
//
GpioCtrlRegs.GPAPUD.bit.GPIO0 = 1; // Disable pull-up on GPIO0 (EPWM1A)
GpioCtrlRegs.GPAPUD.bit.GPIO1 = 1; // Disable pull-up on GPIO1 (EPWM1B)
// GpioCtrlRegs.GPEPUD.bit.GPIO145 = 1; // Disable pull-up on GPIO145 (EPWM1A)
// GpioCtrlRegs.GPEPUD.bit.GPIO146 = 1; // Disable pull-up on GPIO146 (EPWM1B)
//
// Configure EPWM-1 pins using GPIO regs
// This specifies which of the possible GPIO pins will be EPWM1 functional
// pins.
// Comment out other unwanted lines.
//
GpioCtrlRegs.GPAGMUX1.bit.GPIO0 = 0; // Configure GPIO0 as EPWM1A
GpioCtrlRegs.GPAGMUX1.bit.GPIO1 = 0; // Configure GPIO1 as EPWM1B
GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; // Configure GPIO0 as EPWM1A
GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1; // Configure GPIO1 as EPWM1B
// GpioCtrlRegs.GPEMUX2.bit.GPIO145 = 1; // Configure GPIO145 as EPWM1A
// GpioCtrlRegs.GPEMUX2.bit.GPIO146 = 1; // Configure GPIO0146 as EPWM1B
EDIS;
}
//
// InitEPwm2Gpio - Initialize EPWM2 GPIOs
//
void InitEPwm2Gpio(void)
{
EALLOW;
//
// Disable internal pull-up for the selected output pins
// for reduced power consumption
// Pull-ups can be enabled or disabled by the user.
// This will enable the pullups for the specified pins.
// Comment out other unwanted lines.
//
GpioCtrlRegs.GPAPUD.bit.GPIO2 = 1; // Disable pull-up on GPIO2 (EPWM2A)
GpioCtrlRegs.GPAPUD.bit.GPIO3 = 1; // Disable pull-up on GPIO3 (EPWM2B)
// GpioCtrlRegs.GPEPUD.bit.GPIO147 = 1; // Disable pull-up on GPIO147 (EPWM2A)
// GpioCtrlRegs.GPEPUD.bit.GPIO148 = 1; // Disable pull-up on GPIO148 (EPWM2B)
//
// Configure EPwm-2 pins using GPIO regs
// This specifies which of the possible GPIO pins will be EPWM2 functional pins.
// Comment out other unwanted lines.
//
GpioCtrlRegs.GPAGMUX1.bit.GPIO2 = 0; // Configure GPIO2 as EPWM2A
GpioCtrlRegs.GPAGMUX1.bit.GPIO3 = 0; // Configure GPIO3 as EPWM2B
GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 1; // Configure GPIO2 as EPWM2A
GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 1; // Configure GPIO3 as EPWM2B
// GpioCtrlRegs.GPEMUX2.bit.GPIO147 = 1; // Configure GPIO147 as EPWM2A
// GpioCtrlRegs.GPEMUX2.bit.GPIO148 = 1; // Configure GPIO148 as EPWM2B
EDIS;
}
//
// InitEPwm1Example - Initialize EPWM1 configuration
//
void InitEPwm1Example()
{
// Setup TBCLK
EPwm1Regs.TBPRD = EPWM_TIMER_TBPRD; // Set timer period 2*EPWM_TIMER_TBPRD TBCLKs
EPwm1Regs.TBPHS.bit.TBPHS = 0x0000; // Phase is 0, change it when carrier phase-shift is used
EPwm1Regs.TBCTR = 0x0000; // Clear counter
// Set Compare values
EPwm1Regs.CMPA.bit.CMPA = EPWM_MIN_CMPA; // Set compare A value
EPwm1Regs.CMPB.bit.CMPB = EPWM_MAX_CMPB; // Set compare B value
// Setup counter mode
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up and down
EPwm1Regs.TBCTL.bit.PHSEN = TB_ENABLE; // Enable phase loading
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // Set synchronous bits
EPwm1Regs.TBCTL.bit.PHSDIR = TB_DOWN; // Count down after synchronization
// Setup shadowing
EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // Load on Zero
EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
// Set actions
EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clear PWM1A on event A, up count
EPwm1Regs.AQCTLA.bit.CAD = AQ_SET; // Set PWM1A on event A, down count
// Set dead-band
EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // Enable Dead-band module
EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // Dead-band Type: AHC
EPwm1Regs.DBFED.bit.DBFED = EPWM_DB;
EPwm1Regs.DBRED.bit.DBRED = EPWM_DB;
// Interrupt where we will change the Compare Values
EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event
EPwm1Regs.ETSEL.bit.INTEN = 1; // Enable INT
EPwm1Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1st event
// Assumes ePWM clock is already enabled (unknown why)
EPwm1Regs.ETSEL.bit.SOCAEN = 1; // Disable SOC on A group
EPwm1Regs.ETSEL.bit.SOCASEL = ET_CTR_ZERO; //
EPwm1Regs.ETPS.bit.SOCPSSEL = 0;
EPwm1Regs.ETPS.bit.SOCAPRD = ET_1ST; // Generate pulse on 1st event
}
//
// InitEPwm2Example - Initialize EPWM2 configuration
//
void InitEPwm2Example()
{
// Setup TBCLK
EPwm2Regs.TBPRD = EPWM_TIMER_TBPRD; // Set timer period 2*EPWM_TIMER_TBPRD TBCLKs
EPwm2Regs.TBPHS.bit.TBPHS = 0x0000; // Phase is 0, change it when carrier phase-shift is used
EPwm2Regs.TBCTR = 0x0000; // Clear counter
// Set Compare values
EPwm2Regs.CMPA.bit.CMPA = EPWM_MIN_CMPA; // Set compare A value
EPwm2Regs.CMPB.bit.CMPB = EPWM_MAX_CMPB; // Set compare B value
// Setup counter mode
EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up and down
EPwm2Regs.TBCTL.bit.PHSEN = TB_ENABLE; // Disable phase loading
EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT
EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1;
EPwm2Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN; // Set synchronous bits
EPwm2Regs.TBCTL.bit.PHSDIR = TB_DOWN; // Count down after synchronization
// Setup shadowing
EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // Load on Zero
EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
// Set actions
EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clear PWM2A on event A, up count
EPwm2Regs.AQCTLA.bit.CAD = AQ_SET; // Set PWM2A on event A, down count
// Set dead-band
EPwm2Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // Enable Dead-band module
EPwm2Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // Dead-band Type: AHC
EPwm2Regs.DBFED.bit.DBFED = EPWM_DB;
EPwm2Regs.DBRED.bit.DBRED = EPWM_DB;
}
调用函数为:
//
// epwm1_isr - EPWM1 ISR
__interrupt void epwm1_isr(void)
{
//--------------------Interrupt User Data Begin--------------------
//PWM
// int i;
// for(i=0;i<=12;i++)
// {
// (*EPWM[i]).TBPRD = MY_EPWM_TIMER_TBPRD;
// }
EPwm1Regs.CMPA.bit.CMPA = (dutycycle[1]*EPWM_TIMER_TBPRD);
EPwm2Regs.CMPA.bit.CMPA = (dutycycle[2]*EPWM_TIMER_TBPRD);
EPwm3Regs.CMPA.bit.CMPA = (dutycycle[3]*EPWM_TIMER_TBPRD);
EPwm10Regs.CMPA.bit.CMPA = (dutycycle[1]*EPWM_TIMER_TBPRD);
EPwm11Regs.CMPA.bit.CMPA = (dutycycle[2]*EPWM_TIMER_TBPRD);
EPwm12Regs.CMPA.bit.CMPA = (dutycycle[3]*EPWM_TIMER_TBPRD);
//--------------------Interrupt User Data End--------------------
// Clear INT flag for this timer and Acknowledge this interrupt to receive more interrupts from group 3
EPwm1Regs.ETCLR.bit.INT = 1;
EPwm1Regs.ETCLR.bit.SOCA = 1;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
}
主函数为:
void main()
{
//
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F2837xD_SysCtrl.c file.
InitSysCtrl();
//
// Step 2. Initialize GPIO: (Cancel)
// This example function is found in the F2837xD_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
// InitGpio();
//
// EALLOW;
// CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;
//// CpuSysRegs.PCLKCR2.bit.EPWM1ENCLK = 1;
// CpuSysRegs.PCLKCR2.bit.EPWM1=1;
// CpuSysRegs.PCLKCR2.bit.EPWM2=1;
// CpuSysRegs.PCLKCR2.bit.EPWM3=1;
// EDIS;
//
// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
DINT;
// Initialize the PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the F2837xD_PieCtrl.c file.
InitPieCtrl();
// Disable CPU interrupts and clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example. This is useful for debug purposes.
// The shell ISR routines are found in F2837xD_DefaultIsr.c.
// This function is found in F2837xD_PieVect.c.
InitPieVectTable();
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.EPWM1_INT = &epwm1_isr;
EDIS; // This is needed to disable write to EALLOW protected registers
// Peripheral Initialization
// PWM
InitEPwm();
// ADC
InitADC();
// Spi+VOFAplus
InitSpi_AD5328();
InitVOFAplus();
// QEP
InitEQepGpio();
QEP_INIT_MACRO(1,qep_test);
freq_speed_cal = 1000; // Frequency of speed calculation, Hz
prd_speed_cal = 1.0/freq_speed_cal; // Period of speed calculation, s
speed_period_cal = freq_sw/freq_speed_cal; // Interrupt intervals of speed calculation
My_Filter_1st_Reset_MACRO(fil_1st_speed, 3141.59265, prd_speed_cal);
// Filter
My_Filter_1st_Reset_MACRO(fil_1st_test, 100000.0, prd_sw);
My_Filter_2nd_Reset_MACRO(fil_2nd_test, 100000.0, prd_sw, 0.707106781);
//
// Step 4. User specific code, enable interrupts:
// User specific code, initialize some key parameters
// e.g. speed & eQEP module, ePWM module
x = 6.28;
//pid
pid_test.Kp = 1.0;
pid_test.Ki = 1.0;
pid_test.Kd = 1.0;
pid_test.out_max = 100.0;
pid_test.out_min = -100.0;
//qep
qep_test.LineEncoder = line;
qep_test.MechScaler = mech_scaler;
qep_test.PolePairs = pole_mot;
qep_test.CalibratedAngle = 100; // Unknown, require static positioning
GpioDataRegs.GPDSET.bit.GPIO99 = 1;
GpioDataRegs.GPCSET.bit.GPIO94 = 1;
// Enable CPU INT3 which is connected to EPWM1-3 INT:
IER |= M_INT3;
// Enable EPWM INTn in the PIE: Group 3 interrupt 1
PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
// Enable global Interrupts and higher priority real-time debug events:
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global real time interrupt DBGM
//
// Step 5. IDLE loop. Just sit and loop forever (optional):
for(;;)
{
//--------------------Test Code Begin--------------------
//Send to VOFA+
vofa_test = vofa_test + 1;
if(vofa_test>1500){vofa_test=0;}
DataSend[0].DataFloat = vofa_test/1000.0;
DataSend[1].DataFloat = 2.12;
DataSend[2].DataFloat = 3.123;
DataSend[3].DataFloat = 4.1234;
BspSendFloatFifo(DataSend,4);
//DAC
//This function will easily cause endless loop, it's better to put this function at the end of for(;;)
// DAC_AD5328(DAC_A, 2048);
//--------------------Test Code End--------------------
}
}