前言
DSP28377D 的PWM调试
应用场景:直流无刷电机(BLDC)的驱动。
提示:以下是本篇文章正文内容,下面调试记录供参考
一、初始化
1.main()初始化
主程序中初始化代码如下:
//初始化PWM
EALLOW;
CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =0; //关闭 pwm-时钟
EDIS;
InitEPwm(); //初始化PWM
PWM_Stop();
EALLOW;
CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =1; //重新打开 pwm-时钟
EDIS;
初始化前需要关闭时钟PCLK
待初始化完成后重新开启时钟,PWM运行。
如需要开启中断,根据向量表增加如下代码:
// Enable pwm1-3 interrupts
PieCtrlRegs.PIEIER3.bit.INTx3 = 1;
//EPWMIER
IER |= M_INT3;
EINT;
//EPWM中断程序入口
EALLOW;
PieVectTable.EPWM1_INT = &EPWM1_ISR;
PieVectTable.EPWM2_INT = &EPWM2_ISR;
PieVectTable.EPWM3_INT = &EPWM3_ISR;
EDIS;
2.PWM配置
void InitEPwm(void)
{
InitEPwm1Gpio();
InitEPwm2Gpio();
InitEPwm3Gpio();
InitEPwm5Gpio();
InitEPwm1Example();
InitEPwm2Example();
InitEPwm3Example();
InitEPwm5Example();
}
//初始化引脚
void InitEPwm1Gpio(void)
{
EALLOW;
GpioCtrlRegs.GPAPUD.bit.GPIO0 = 1; // Disable pull-up on GPIO0 (EPWM1A)
GpioCtrlRegs.GPAPUD.bit.GPIO1 = 1; // Disable pull-up on GPIO1 (EPWM1B)
GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; // Configure GPIO0 as EPWM1A
GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1; // Configure GPIO1 as EPWM1B
EDIS;
}
//PWM配置
void InitEPwm1Example(void)
{
//一个周期约等于16.7Khz
EPwm1Regs.TBPRD = EPWM_PRD; // Set timer period 一个大周期有6250小周期
EPwm1Regs.TBPHS.bit.TBPHS = 0x0000; // Phase is 0 关闭TBPHS功能,TBPHS决定是否使用同步信号EPWMxSYNCI
EPwm1Regs.TBCTR = 0x0000; // Clear counter
// Setup TBCLK TBCLK = EPWMCLK/(HSPCLKDIV * CLKDIV):如果是上下计数,即需要再/2
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up 上下计数
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV2;
//SYSCLK/HSPCLKDIV/CLKDIV
EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; // CMPA 双缓冲操作,所有的写操作通过CPU访问影子(映射)寄存器
EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; // CMPB 双缓冲操作,所有的写操作通过CPU访问影子(映射)寄存器
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // 当时间基准计数器等于0(TBCTR = 0)时,CMPA 从影子寄存器中加载
EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; // 当时间基准计数器等于0(TBCTR = 0)时,CMPB 从影子寄存器中加载
// Setup compare
EPwm1Regs.CMPA.bit.CMPA = DutyCycle; //用于设置占空比 3000/6000
EPwm1Regs.CMPB.bit.CMPB = 0; //用于设置占空比 3000/6000
// Set actions
EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // When TBCTR = CMPA on Up Count, force EPWMxA output high
EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR; // When TBCTR = CMPA on Down Count , force EPWMxA output low
EPwm1Regs.AQCTLB.bit.CAU = AQ_CLEAR; // When TBCTR = CMPB on Up Count, force EPWMxB output low
EPwm1Regs.AQCTLB.bit.CAD = AQ_CLEAR; // When TBCTR = CMPB on Down Count , force EPWMxA output high
// Active Low PWMs - Setup Deadband
EPwm1Regs.DBCTL.bit.OUT_MODE = 0; //DB_FULL_ENABLE:0x3 Bit 1 controls the S1 switch and bit 0 controls the S0 switch.
EPwm1Regs.DBCTL.bit.POLSEL = 0; //DB_ACTV_LO:0x3,Bit 3 controls the S3 switch and bit 2 controls the S2 switch
EPwm1Regs.DBCTL.bit.IN_MODE = 0; //DBA_ALL:0x0,Bit 5 controls the S5 switch and bit 4 controls the S4 switch shown
/* 死区上升沿延时时间 */
//EPwm1Regs.DBRED.bit.DBRED = 75; //Rising edge delay value
/* 死区下降沿延时时间 */
//EPwm1Regs.DBFED.bit.DBFED = 75; //Falling Edge Delay Count
/* Tdb=DBRED*TBCLK*/
// Event Trigger Selection Register Interrupt where we will change the Deadband
//EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Enable Event time-base counter equal to zero. (TBCTR = 0x00)
//EPwm1Regs.ETSEL.bit.INTEN = 1; // Enable ePWM Interrupt
// Event Trigger Pre-Scale Register
// EPwm1Regs.ETPS.bit.INTPRD = ET_3RD; // 0x03,Generate interrupt on ETPS[INTCNT] = 1,1 (third event),第三个事件发生时中断
EALLOW;
EPwm1Regs.ETSEL.bit.SOCAEN = 1; // Disable SOC on A group
EPwm1Regs.ETSEL.bit.SOCASEL = 2; // 010: Enable event time-base counter equal to period (TBCTR =TBPRD)
EPwm1Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event 第一次即发生SOCA事件
EDIS;
}
- 周期计算:
TBCLK = EPWMCLK/(HSPCLKDIV * CLKDIV)
如果是上下计数模式,即需要再/2,
即 TBCLK = EPWMCLK/(HSPCLKDIV * CLKDIV) /2 - 死区
BLDC驱动不需要设置死区时间,故注释死区,如需设置死区,参考下图并对DBCTL寄存器进行配置,使PWM信号经过死区延时。
二、BLDC 驱动函数
1.六步换向
霍尔与三相输出关系图如下:
驱动PWM变化一般有两种方式(2选1)
1、修改动作模式,即AQCTLA寄存器的值,改变占空比条件满足后的低电平或高电平表达,并马上改变计数值,即 EPwm1Regs.CMPA。
2、强制输出 AQCSFRC,令output强制输出高/低电平。此方法输出响应会更快,但要考虑切回占空比控制输出时的电平瞬时变化问题。
附六步换向驱动代码:
void Motor_PWMChange(Motor_Sta_t *pMt)
{
if(pMt->Dir == MT_DIR_CW )//MT_DIR_CW
{
switch(pMt->HallNow)
{
case 1://001 CB
EPwm1Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm1Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
EPwm2Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm2Regs.AQCSFRC.bit.CSFB= 2 ; //10,强制拉高
EPwm3Regs.AQCSFRC.bit.CSFA= 0; //00,恢复
EPwm3Regs.AQCTLA.all = 0x90; //1001 0000,PWM设置
EPwm3Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
break;
case 2://010 BA
EPwm1Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm1Regs.AQCSFRC.bit.CSFB= 2 ; //10,强制拉高
EPwm2Regs.AQCSFRC.bit.CSFA= 0; //00,恢复
EPwm2Regs.AQCTLA.all = 0x90; //1001 0000,PWM设置
EPwm2Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
EPwm3Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm3Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
break;
case 3: //011 CA
EPwm1Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm1Regs.AQCSFRC.bit.CSFB= 2 ; //10,强制拉高
EPwm2Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm2Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
EPwm3Regs.AQCSFRC.bit.CSFA= 0; //00,恢复
EPwm3Regs.AQCTLA.all = 0x90; //1001 0000,PWM设置
EPwm3Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
break;
case 4: //100 AC
EPwm1Regs.AQCSFRC.bit.CSFA= 0; //00,恢复
EPwm1Regs.AQCTLA.all = 0x90; //1001 0000,PWM设置
EPwm1Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
EPwm2Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm2Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
EPwm3Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm3Regs.AQCSFRC.bit.CSFB= 2 ; //10,强制拉高
break;
case 5: //101 AB
EPwm1Regs.AQCSFRC.bit.CSFA= 0; //00,恢复
EPwm1Regs.AQCTLA.all = 0x90; //1001 0000,PWM设置
EPwm1Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
EPwm2Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm2Regs.AQCSFRC.bit.CSFB= 2 ; //10,强制拉高
EPwm3Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm3Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
break;
case 6: //110 BC
EPwm1Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm1Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
EPwm2Regs.AQCSFRC.bit.CSFA= 0; //00,恢复
EPwm2Regs.AQCTLA.all = 0x90; //1001 0000,PWM设置
EPwm2Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
EPwm3Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm3Regs.AQCSFRC.bit.CSFB= 2 ; //10,强制拉高
break;
}
}
}
2.其他函数
电机运行:
Result_t Motor_Run(Motor_Sta_t *pMt)
{
if(pMt->sta == MT_STA_STOP) //当电机处于停止时可运行
{
pMt->HallNow = (char) (GpioDataRegs.GPBDAT.all >>26 &0x7); //更新当前霍尔状态
Motor_PWMChange(&Mt1_Sta); //执行一次换向动作
return RESULT_OK;
}
else
return RESULT_ERROR;
}
软停机:
void PWM_Stop(void)
{
EPwm1Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm1Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
EPwm2Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm2Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
EPwm3Regs.AQCSFRC.bit.CSFA= 1 ; //01,强制拉低
EPwm3Regs.AQCSFRC.bit.CSFB= 1 ; //01,强制拉低
}
总结
换向前需要更新一次霍尔值,换向函数可以放在ECAP中断中进行。
ECAP的配置在另一章中记录。