TMS320F280049C 学习笔记7 ePWM
总结TI与ePWM相关的例程。
前几天TI官方更新了C2000Ware_3_01_00_00,添加了不少新的例程,之后的博客将根据这个版本的支持库展开。
ePWM模块可以说是学习TI DSP必须熟练掌握的内容,本文测试并总结了官方的例程,例程文件可以在 C:\ti\c2000\C2000Ware_3_01_00_00\driverlib\f28004x\examples\epwm 找到。
例程1 epwm_ex1_trip_zone
第一个例程可以熟悉TZ模块,TZ模块可以工作在Cycle-by-Cycle、One-Shot两种模式下,这两种状态的区别是:
- One-Shot是永久起作用的,恢复它只有人工清除;
- Cycle-by-Cycle却是本周期有用,下一周期自动恢复。
其实实现上只差了一句代码,就是是否把标志位清除掉。
EPWM_clearTripZoneFlag(EPWM2_BASE, (EPWM_TZ_INTERRUPT | EPWM_TZ_FLAG_CBC));
该例程还使用了Input X-Bar。配置起来并不困难。
// _____________ __________________
// | | | |
// GPIO4 -----| I/P X-BAR |-----TZ1-----| ePWM TZ Module |-----TZ-Event
// |___________| |________________|
//
例程2 epwm_ex2_updown_aq
例程的功能是产生25kHz的PWM,在中断程序中不断更改其占空比。
与一些旧DSP不同,280049C可以设置每15个PWM周期触发一次中断,而旧处理器上限3个。
贴一份精简过的代码:
#include "F28x_Project.h"
#include "device.h"
#include "math.h"
#define EPWM1_TIMER_TBPRD 2000U
#define EPWM1_MAX_CMPA 1950U
#define EPWM1_MIN_CMPA 50U
#define EPWM1_MAX_CMPB 1950U
#define EPWM1_MIN_CMPB 50U
#define EPWM_CMP_UP 1U
#define EPWM_CMP_DOWN 0U
typedef struct
{
uint32_t epwmModule;
uint16_t epwmCompADirection;
uint16_t epwmCompBDirection;
uint16_t epwmTimerIntCount;
uint16_t epwmMaxCompA;
uint16_t epwmMinCompA;
uint16_t epwmMaxCompB;
uint16_t epwmMinCompB;
}epwmInformation;
// Globals to hold the ePWM information used in this example
epwmInformation epwm1Info;
void initEPWM1(void);
__interrupt void epwm1ISR(void);
void updateCompare(epwmInformation *epwmInfo);
void main(void)
{
// 初始化时钟和外设 Initialize device clock and peripherals
Device_init();
// InitSysCtrl(); //本工程不能使用寄存器的InitSysCtrl();函数初始化。
Device_initGPIO();
Interrupt_initModule();
Interrupt_initVectorTable();
Interrupt_register(INT_EPWM1, &epwm1ISR);
// 设置 GPIO0/1 为 ePWM1A/1B
GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
GPIO_setPinConfig(GPIO_0_EPWM1A);
GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);
GPIO_setPinConfig(GPIO_1_EPWM1B);
// 关同步 Disable sync(Freeze clock to PWM as well)
SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
initEPWM1();
// 开同步 Enable sync and clock to PWM
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
// 使能中断
Interrupt_enable(INT_EPWM1);
EINT;
ERTM;
for(;;)
{
NOP;
}
}
__interrupt void epwm1ISR(void) // 中断服务程序
{
// 更新比较值 Update the CMPA and CMPB values
updateCompare(&epwm1Info);
// Clear INT flag for this timer
EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
// Acknowledge interrupt group
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}
// 初始化 initEPWM1 - Configure ePWM1
void initEPWM1()
{
// 设置ePWM的时钟TBCLK 在100MHz的主频下,每一个TBCLK对应 10ns
EPWM_setTimeBasePeriod(EPWM1_BASE, EPWM1_TIMER_TBPRD);
EPWM_setPhaseShift(EPWM1_BASE, 0U);
EPWM_setTimeBaseCounter(EPWM1_BASE, 0U);
// 设置CMPA和CMPB
EPWM_setCounterCompareValue(EPWM1_BASE,
EPWM_COUNTER_COMPARE_A,
EPWM1_MIN_CMPA);
EPWM_setCounterCompareValue(EPWM1_BASE,
EPWM_COUNTER_COMPARE_B,
EPWM1_MAX_CMPB);
// 设置为增减计数模式,所以PWM的周期是 10ns*2000*2=40us,对应25kHz
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP_DOWN);
EPWM_disablePhaseShiftLoad(EPWM1_BASE);
EPWM_setClockPrescaler(EPWM1_BASE,
EPWM_CLOCK_DIVIDER_1,
EPWM_HSCLOCK_DIVIDER_1);
// 设置影子寄存器,在计数为0时装载
EPWM_setCounterCompareShadowLoadMode(EPWM1_BASE,
EPWM_COUNTER_COMPARE_A,
EPWM_COMP_LOAD_ON_CNTR_ZERO);
EPWM_setCounterCompareShadowLoadMode(EPWM1_BASE,
EPWM_COUNTER_COMPARE_B,
EPWM_COMP_LOAD_ON_CNTR_ZERO);
// 设置ePWM动作方式
// 例:对于EPWM1A,当增计数==CMPA时输出高,当减计数==CMPA时输出低
EPWM_setActionQualifierAction(EPWM1_BASE,
EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH,
EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
EPWM_setActionQualifierAction(EPWM1_BASE,
EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW,
EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
EPWM_setActionQualifierAction(EPWM1_BASE,
EPWM_AQ_OUTPUT_B,
EPWM_AQ_OUTPUT_HIGH,
EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
EPWM_setActionQualifierAction(EPWM1_BASE,
EPWM_AQ_OUTPUT_B,
EPWM_AQ_OUTPUT_LOW,
EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
// 设置触发中断的时刻,这里设置为计数器为0时触发。
// 使能中断。
// 设置每隔3次触发一次中断,上限15次。
EPWM_setInterruptSource(EPWM1_BASE, EPWM_INT_TBCTR_ZERO);
EPWM_enableInterrupt(EPWM1_BASE);
EPWM_setInterruptEventCount(EPWM1_BASE, 3U);
//
// Information this example uses to keep track of the direction the
// CMPA/CMPB values are moving, the min and max allowed values and
// a pointer to the correct ePWM registers
//
epwm1Info.epwmCompADirection = EPWM_CMP_UP;
epwm1Info.epwmCompBDirection = EPWM_CMP_DOWN;
epwm1Info.epwmTimerIntCount = 0U;
epwm1Info.epwmModule = EPWM1_BASE;
epwm1Info.epwmMaxCompA = EPWM1_MAX_CMPA;
epwm1Info.epwmMinCompA = EPWM1_MIN_CMPA;
epwm1Info.epwmMaxCompB = EPWM1_MAX_CMPB;
epwm1Info.epwmMinCompB = EPWM1_MIN_CMPB;
}
// 更新比较值
void updateCompare(epwmInformation *epwmInfo)
{
uint16_t compAValue;
uint16_t compBValue;
compAValue = EPWM_getCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_A);
compBValue = EPWM_getCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_B);
//
// Change the CMPA/CMPB values every 10th interrupt.
//
if(epwmInfo->epwmTimerIntCount == 10U)
{
epwmInfo->epwmTimerIntCount = 0U;
//
// If we were increasing CMPA, check to see if we reached the max
// value. If not, increase CMPA else, change directions and decrease
// CMPA
//
if(epwmInfo->epwmCompADirection == EPWM_CMP_UP)
{
if(compAValue < (epwmInfo->epwmMaxCompA))
{
EPWM_setCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_A,
++compAValue);
}
else
{
epwmInfo->epwmCompADirection = EPWM_CMP_DOWN;
EPWM_setCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_A,
--compAValue);
}
}
//
// If we were decreasing CMPA, check to see if we reached the min
// value. If not, decrease CMPA else, change directions and increase
// CMPA
//
else
{
if( compAValue == (epwmInfo->epwmMinCompA))
{
epwmInfo->epwmCompADirection = EPWM_CMP_UP;
EPWM_setCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_A,
++compAValue);
}
else
{
EPWM_setCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_A,
--compAValue);
}
}
//
// If we were increasing CMPB, check to see if we reached the max
// value. If not, increase CMPB else, change directions and decrease
// CMPB
//
if(epwmInfo->epwmCompBDirection == EPWM_CMP_UP)
{
if(compBValue < (epwmInfo->epwmMaxCompB))
{
EPWM_setCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_B,
++compBValue);
}
else
{
epwmInfo->epwmCompBDirection = EPWM_CMP_DOWN;
EPWM_setCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_B,
--compBValue);
}
}
//
// If we were decreasing CMPB, check to see if we reached the min
// value. If not, decrease CMPB else, change directions and increase
// CMPB
//
else
{
if(compBValue == (epwmInfo->epwmMinCompB))
{
epwmInfo->epwmCompBDirection = EPWM_CMP_UP;
EPWM_setCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_B,
++compBValue);
}
else
{
EPWM_setCounterCompareValue(epwmInfo->epwmModule,
EPWM_COUNTER_COMPARE_B,
--compBValue);
}
}
}
else
{
epwmInfo->epwmTimerIntCount++;
}
}
贴一下代码的效果:
例程3 epwm_ex3_monoshot_mode
280049C ePWM模块的AQ子模块多了两个事件,T1和T2,可以直接操作PWM的输出状态。
在手册的18.6节有详细的介绍。
这个例子涉及了比较多的新功能。ePWM2负责产生触发脉冲,通过X-bar直接路由到PWM的同步信号,该同步信号用于触发ePWM1的事件T1,ePWM接收到T1上升沿事件时,发出一个设定好的脉冲。
示例中信号的传递通过X-bar等功能在内部传递,不需要外部连线。
贴个实验结果图,手边设备没有很高的分辨率,所以可能不太准。
参考文献
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)