TMS320F28377s配置20khz互补PWM+死区

  学习了一下28377如何配置pwm,写篇文章整理一下,希望可以帮到大家。

  文章涉及ccs和c2000ware,在ti官网可以下载。

1 . 新建一个空工程,具体操作可以参考上一篇文章

https://mp.csdn.net/mp_blog/creation/editor/138989966

(记得改工程名为pwm,我改的是pwm_gpio)

2.在source文件内导入epwm.c文件(这里同样需要gpio.c文件)其余按照第一节标准导入。(可以建立一个模板工程,每次直接复制模板工程,省的次次导入),完成后在source文件内新建main,c文件和pwm_gpio.c文件用来存放主函数和pwm配置相关函数,并在include文件内建立pwm_gpio.h和Myproject.h文件,Myproject.h用来封装pwm.h和其他自己写的.h文件(在主函数里只用声明Myproject.h便于查看,同时也符合ti套娃的习惯)配置完成后如下:

3 . 文件配置完了就要开始写主函数和pwm相关配置

首先要清楚pwm基础的寄存器:

EPWM主模块包含很多子模块,有时基单元,动作,死去,中断等,常用的有TB(时基单元)、CC(比较计数)、AQ(动作)、ET(中断),DB(死区)。

  其中,TB主要控制PWM频率,CC主要控制PWM占空比,AQ为产生反比较后比较器所产生的变化(例如电平变为高电平等),中断和死区很好理解。

  TB寄存器中有:

        TBPRD:周期寄存器 (设置的时钟周期存入此,可通过阴影寄存器缓冲后写入,也可通过活动寄存器立即写入)
        TBCTR:时基计数变值寄存器 (时基当前所计数的值存入,用于和所设定周期值比较)
        TBPHS:时基相位寄存器
        TBSTS:时基状态寄存器
        TBCTL:控制寄存器 (重要)

  AQ寄存器中有:

        CAU:上升沿TBCTL == CMP

        CAD:下降沿TBCTL == CMP

  CC寄存器中有:

        CMPA:比较寄存器A,其值与TBCTR值比较,相同时,事件发送到动作模块。
        CMPB:比较寄存器B,其值与TBCTR值比较,相同时,事件发送到动作模块。
        CMPCTL:控制寄存器(重要)

  AQ寄存器中有:

        AQCTLA:动作限定输出A控制寄存器
        AQCTLB:动作限定输出A控制寄存器

  DB寄存器中有:    

        OUT_MOOD:死区输出模式    

        DBCTL: 输出模式和极性选择等

        DBRED: 高有效互补输出

        DBFED: 低有效互补输出

  这一部分,不清楚的可以参考手册1902页往后。

  清楚寄存器后要根据自己的需求计算相关数据,其中TBCLK由主时钟频率分频而来

这里的EPWMCLK为100Mhz,(SYSCLKOUT为200Mhz系统通过EPWMCLKDIV做了一次二分频)

HSPCLKDIV是高速预分频系数,CLKDIV是预分频系数。

 //
    // Setup TBCLK
    //
    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_DIV1;

  代码中选择计数器模式为增减计数,计算周期时要乘以二。这里高速预分频为1,预分频为1,TBCLK自然就是100Mhz,


 

参考这里咱们主时钟频率为200M,分频后为100M,

Ttbclk = 1 / 100M = 1e-8;

TBPRD = Tpwm / 2 * Ttbclk = 5e-5 / 2 * 1e-8 = 2500

此时频率为20khz。到此时基单元就基本配置完了,剩下依据需求调整相关寄存器即可。

  4 . 时基单元结束后,还需要配置占空比,即比较值CMAP,

    //
    // Setup compare
    //
    EPwm1Regs.CMPA.bit.CMPA = 1250;

  这里依据需求进行配置只要不大于2500即可

  更改寄存器时选择通过影子寄存器加载CMPA,在TBCTL为0时使能,代码如下:


    EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;    // Load registers every ZERO
    EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
    EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

5 . 在TBCTR == CMAP时触发动作,上升沿相等时记高电平下降沿相等时记低电平

    //
    // Set actions
    //
    EPwm1Regs.AQCTLA.bit.CAU = AQ_SET;            // Set PWM1A on Zero
    EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;

    EPwm1Regs.AQCTLB.bit.CAU = AQ_CLEAR;          // Set PWM1A on Zero
    EPwm1Regs.AQCTLB.bit.CAD = AQ_SET;

  这样一个基础的波形就有了,我们只需要再为他添上死区即可。

6 . 对死区进行配置

    //
    // Active Low PWMs - Setup Deadband
    //
    EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE;
    EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_LO;
    EPwm1Regs.DBCTL.bit.IN_MODE = DBA_ALL;
    EPwm1Regs.DBRED.bit.DBRED = EPWM1_MIN_DB;
    EPwm1Regs.DBFED.bit.DBFED = EPWM1_MIN_DB;
    EPwm1_DB_Direction = DB_UP;

__interrupt void epwm1_isr(void)
{
    if(EPwm1_DB_Direction == DB_UP)
    {
        if(EPwm1Regs.DBFED.bit.DBFED < EPWM1_MAX_DB)
        {
            EPwm1Regs.DBFED.bit.DBFED++;
            EPwm1Regs.DBRED.bit.DBRED++;
        }
        else
        {
            EPwm1_DB_Direction = DB_DOWN;
            EPwm1Regs.DBFED.bit.DBFED--;
            EPwm1Regs.DBRED.bit.DBRED--;
        }
    }
    else
    {
        if(EPwm1Regs.DBFED.bit.DBFED == EPWM1_MIN_DB)
        {
            EPwm1_DB_Direction = DB_UP;
            EPwm1Regs.DBFED.bit.DBFED++;
            EPwm1Regs.DBRED.bit.DBRED++;
        }
        else
        {
            EPwm1Regs.DBFED.bit.DBFED--;
            EPwm1Regs.DBRED.bit.DBRED--;
        }
    }
    EPwm1TimerIntCount++;
    //
    // Interrupt where we will change the deadband
    //
    EPwm3Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;      // Select INT on Zero event
    EPwm3Regs.ETSEL.bit.INTEN = 1;                 // Enable INT
    EPwm3Regs.ETPS.bit.INTPRD = ET_1ST;            // Generate INT on 3rd event

  两段代码实现通过对死区标志位EPwm1_DB_Direction的判断进中断来实现死区在MIN_OB到MAX_OB之间跃动(死区时间计算为DBRED * TBCLK 和 DBFED * TBCLK),每一个周期改变一次,也可以取消中断直接给死区时间一个值。

配置代码到这里就结束了。

7 . 下来就是对主函数的配置

#include "MYPROJECT.h"
#include "F28x_Project.h"

//
// Globals
//

//
// Main
//
void main(void)
{
//
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F2837xS_SysCtrl.c file.
//
    InitSysCtrl();

//
// Step 2. Initialize GPIO:
// This example function is found in the F2837xS_Gpio.c file and
// illustrates how to set the GPIO to its default state.
//
//    InitGpio();

//
// enable PWM1, PWM2 and PWM3
//
    CpuSysRegs.PCLKCR2.bit.EPWM1=1;
    CpuSysRegs.PCLKCR2.bit.EPWM2=1;
    CpuSysRegs.PCLKCR2.bit.EPWM3=1;

//
// For this case just init GPIO pins for ePWM1, ePWM2, ePWM3
// These functions are in the F2837xS_EPwm.c file
//
    InitEPwm1Gpio();
    InitEPwm2Gpio();
    InitEPwm3Gpio();

//
// 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 F2837xS_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 F2837xS_DefaultIsr.c.
// This function is found in F2837xS_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;
    PieVectTable.EPWM2_INT = &epwm2_isr;
    PieVectTable.EPWM3_INT = &epwm3_isr;
    EDIS;   // This is needed to disable write to EALLOW protected registers

//
// Step 4. Initialize the Device Peripherals:
//
    EALLOW;
    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =0;
    EDIS;

    InitEPwm1Example();
    InitEPwm2Example();
    InitEPwm3Example();

    EALLOW;
    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =1;
    EDIS;

//
// Step 5. User specific code, enable interrupts:
// Initialize counters:
//

//
// Enable CPU INT3 which is connected to EPWM1-3 INT:
//
    IER |= M_INT3;

//
// Enable EPWM INTn in the PIE: Group 3 interrupt 1-3
//
    PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
    PieCtrlRegs.PIEIER3.bit.INTx2 = 1;
    PieCtrlRegs.PIEIER3.bit.INTx3 = 1;

//
// Enable global Interrupts and higher priority real-time debug events:
//
    EINT;  // Enable Global interrupt INTM
    ERTM;  // Enable Global realtime interrupt DBGM

//
// Step 6. IDLE loop. Just sit and loop forever (optional):
//
    for(;;)
    {
        asm ("          NOP");
    }
}

  这样就可以实现带死区pwm输出。感谢观看。(文章为本人学习内容,至少存在一处错误,希望读者多多包涵,如发现问题,还请指出,谢谢)

  注意:实际测试中发现输出频率 与计算值相差二倍,经检查主时钟频率有问题,咱们选择外部晶振10Mhz,经过40倍频和二分频后应该为200M,实际只有100M,发现这里的判断条件直接进了else。

解决方案:在属性重内定义 _LAUNCHXL_F28377S

便可以解决。

  • 40
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值