您好,我在用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-------------------- } }