前言
28377D具有24路PWM输出引脚,14路高分辨率的HRPWM。ePWM是对PWM的加强型。其中一个ePWM通道有2个PWM输出引脚EPWMxA、EPWMxB,可以用于配置两路独立单边沿PWM、两路对称双边沿PWM和一路双边沿PWM。每个ePWM具有1个16位的时基计数器,用于控制周期和频率。
该通过对ePWM0进行配置,复用GPIO0和GPIO1为epwm,输出两路周期相同,占空比不同的PWM波形。在引脚接上LED,通过循环语句改变PWM的占空比,从而实现LED由亮到灭再到亮。
一、TMS320F28377D的ePWM介绍
1.1 PWM的复用引脚
PWM模块的输出引脚见下表,其中每组EPWM都有2组不同的引脚,在实际应用中复用其中一组引脚即可。
EPWM | GPIO |
---|---|
EPWM1A/B | GPIO0/1或GPIO145/146 |
EPWM2A/B | GPIO2/3或GPIO147/148 |
EPWM3A/B | GPIO4/5或GPIO149/150 |
EPWM4A/B | GPIO6/7或GPIO151/152 |
EPWM5A/B | GPIO8/9或GPIO153/154 |
EPWM6A/B | GPIO10/11或GPIO155/156 |
EPWM7A/B | GPIO12/13或GPIO157/158 |
EPWM8A/B | GPIO14/15或GPIO159/160 |
EPWM9A/B | GPIO16/17或GPIO161/162 |
EPWM10A/B | GPIO18/19或GPIO163/164 |
EPWM11A/B | GPIO20/21或GPIO165/166 |
EPWM12A/B | GPIO22/23或GPIO167/168 |
1.2 PWM模块的组成
一个ePWM模块由8个小模块组成,如下图。分别为时基模块(TB)、比较计数模块(CC)、动作模块(AQ)、死区模块(DB)、PWM斩波模块(PC)、时间触发模块(ET)、防联模块(TZ)和数字比较模块(DC)。
其中,配置PWM波形常用的是TB、CC、AQ、DB和ET等模块。接下来介绍TB、CC和AQ模块。
1.3 TB模块
TB模块可以用于设计PWM的周期大小。其中有三种计数方式:向上计数、向下计数和向上-向下计数。其中配置PWM的周期/频率与TBPRD和TBCTRL这两个寄存器有关。TBPRD为时基周期寄存器值,用于储存计数的最大值。TBCTRL为时基计数器的计数模式,其中可以设置以上的三种计数模式。
对于设置为向上-向下计数模式的情况
其中PWM周期等于2倍的TBPRD乘以单个计数的时间。
对于对于设置为向上计数模式或者向下计数模式的情况
其中PWM周期等于TBPRD加一的和,再乘以单个计数的时间。
其中上面两图中T(TBCLK)是经过分频之后,一次计数的时间。频率计算公式为TBCLK=EPWMCLK/(HSPCLKDTV*CLKDIV),再取倒数就是周期。
TB模块配置程序:
// Setup TBCLK
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up
EPwm1Regs.TBPRD = EPWM1_TIMER_TBPRD; // Set timer period,这里设置为20k
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading
EPwm1Regs.TBPHS.bit.TBPHS = 0x0000; // Phase is 0
EPwm1Regs.TBCTR = 0x0000; // Clear counter
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV2; // Clock ratio to SYSCLKOUT,采用2分频
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV2; //TBCLK=EPWMCLK/(HSPCLKDIV*CLKDIV)=200M/(2*2)=50M,所以PWM周期为(20k+1)/50M=400us
其中采用向上计数的模式;EPWM1_TIMER_TBPRD预先宏定义为20k;没有预先相位,相位为;HSPCLKDIV 和CLKDIV 都采用2分频,28377D的系统频率为200M Hz,所以TBCLK为50M Hz,周期为1/50M s;经过计数PWM周期为400us。
1.4 CC模块
CC模块可以用于控制PWM的脉宽
对于向上计数模式或者向下计数模式,在一个PWM周期中,比较只能计数一次,就是单边沿触发;对于向上-向下计数模式,在一个PWM周期中,比较会计数两次,就是双边沿触发。
CC模块配置程序:
// Setup shadow register load on ZERO
EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
// Set Compare values
EPwm1Regs.CMPA.bit.CMPA = EPWM1_MIN_CMPA; // Set compare A value
EPwm1Regs.CMPB.bit.CMPB = EPWM1_MAX_CMPB; // Set Compare B value
这里采用了影子寄存器的方式,给CC寄存器进行配置,当计数器为0时进行载入。同时设置CMPA和CMPB的比较值,当计数器到达这两个比较值时,会发出脉冲给AQ模块,进而调整输出电平。因此CMPA和CMPB的比较值将会影响PWM的脉宽大小。
1.5 AQ模块
AQ模块用于控制输出PWM的动作,当CC模块触发或者软件触发时,可以响应触发,选择对PWM波形进行置高、置底或者翻转等操作。
AQ模块配置程序:
// Set actions
EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET; // Set PWM1A on Zero
EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clear PWM1A on event A, up count
EPwm1Regs.AQCTLB.bit.ZRO = AQ_SET; // Set PWM1B on Zero
EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR; // Clear PWM1B on event B, up count
当计数器为0时,设置EPWM1A为高电平;当计数器等于CMPA的比较值时,设置EPWM1A为低电平。对于EPWM1B的设置也是同理。
// AQCTLA and AQCTLB (Action Qualifier Control)
//=============================================
// ZRO, PRD, CAU, CAD, CBU, CBD bits
#define AQ_NO_ACTION 0x0
#define AQ_CLEAR 0x1
#define AQ_SET 0x2
#define AQ_TOGGLE 0x3
在ti官方给的F2837xD_EPwm_defines.h中可以看到,AQ动作有4种方式。其中AQ_NO_ACTION为无事发生;AQ_CLEAR为置低;AQ_SET为置高;AQ_TOGGLE为翻转。AQ可以动作的时间也有很多,还包括计数器计满等情况。
二、程序介绍
#include "F28x_Project.h"
#define EPWM1_TIMER_TBPRD 20000
#define EPWM1_MAX_CMPA 19500
#define EPWM1_MIN_CMPA 500
#define EPWM1_MAX_CMPB 19500
#define EPWM1_MIN_CMPB 500
void InitEPwm1Example(void);
void main(void)
{
//初始化系统时钟
InitSysCtrl();
//使能PWM1
CpuSysRegs.PCLKCR2.bit.EPWM1=1;
//初始化pwm1的gpio
InitEPwm1Gpio();
//Disable CPU interrupts
DINT;
//Initialize the PIE control registers to their default state.
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).
InitPieVectTable();
EALLOW;
CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =0;
EDIS;
//初始化EPWM
InitEPwm1Example();
EALLOW;
CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =1;
EDIS;
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
int duty_cycle = 0; //用于控制pwm0的占空比
int num = 0; //用于记录duty_cycle是增加还是减少
while(1)
{
if(num == 0) //duty_cycle处于增长
{
duty_cycle++;
if(duty_cycle == 100)
{
num = 1;
}
}
else //duty_cycle处于减少
{
duty_cycle--;
if(duty_cycle == 0)
{
num = 0;
}
}
EPwm1Regs.CMPA.bit.CMPA = (int) EPWM1_TIMER_TBPRD /100 * duty_cycle; // Set compare A value
EPwm1Regs.CMPB.bit.CMPB = (int) EPWM1_TIMER_TBPRD /100 * (100-duty_cycle); // Set Compare B value
DELAY_US(40 * 1000); //延迟20ms
}
}
void InitEPwm1Example(void)
{
// Setup TBCLK
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up
EPwm1Regs.TBPRD = EPWM1_TIMER_TBPRD; // Set timer period,这里设置为20k
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading
EPwm1Regs.TBPHS.bit.TBPHS = 0x0000; // Phase is 0
EPwm1Regs.TBCTR = 0x0000; // Clear counter
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV2; // Clock ratio to SYSCLKOUT,采用2分频
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV2; //TBCLK=EPWMCLK/(HSPCLKDIV*CLKDIV)=200M/(2*2)=50M,所以PWM周期为(20k+1)/50M=400us
// Setup shadow register load on ZERO
EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
// Set Compare values
EPwm1Regs.CMPA.bit.CMPA = EPWM1_MIN_CMPA; // Set compare A value
EPwm1Regs.CMPB.bit.CMPB = EPWM1_MAX_CMPB; // Set Compare B value
// Set actions
EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET; // Set PWM1A on Zero
EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clear PWM1A on event A, up count
EPwm1Regs.AQCTLB.bit.ZRO = AQ_SET; // Set PWM1B on Zero
EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR; // Clear PWM1B on event B, up count
}
呼吸灯的主程序,其中在while循环中每20ms改变PWM的占空比,由0逐渐增加1至100,再减一至0,另一路则相反。
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 = 0; // enable pull-up on GPIO0 (EPWM1A)
GpioCtrlRegs.GPAPUD.bit.GPIO1 = 0; // enable 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.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;
}
在配置GPIO的时候需要注意的是,GPIO的状态可以设置为上拉状态或者非上拉状态,二者都可以。一般来说为了避免功率浪费,默认为非上拉状态,但是这次实验要求GPIO作为输出引脚控制LED的亮灭,所以需要设置为上拉状态。将GpioCtrlRegs.GPAPUD.bit.GPIO0设置为0.