F28335共有6个独立的捕获通道,如下表:
eCAP | GPIO | 结构体变量 |
---|---|---|
1 | 5/24/34 | ECap1Regs |
2 | 7/25/37 | ECap2Regs |
3 | 9/26 | ECap3Regs |
4 | 11/27 | ECap4Regs |
5 | 3/48 | ECap5Regs |
6 | 1/49 | ECap6Regs |
对应CMD中地址分配为:
ECAP1 : origin = 0x006A00, length = 0x000020 /* Enhanced Capture 1 registers */
ECAP2 : origin = 0x006A20, length = 0x000020 /* Enhanced Capture 2 registers */
ECAP3 : origin = 0x006A40, length = 0x000020 /* Enhanced Capture 3 registers */
ECAP4 : origin = 0x006A60, length = 0x000020 /* Enhanced Capture 4 registers */
ECAP5 : origin = 0x006A80, length = 0x000020 /* Enhanced Capture 5 registers */
ECAP6 : origin = 0x006AA0, length = 0x000020 /* Enhanced Capture 6 registers */
关于CMD文件更多知识,可以参见——F28335第四篇——存储器及CMD文件
除此之外,每个捕获通道还具有以下资源:
eCAP可以工作在两种模式:
在APWM模式下,CAP1到CAP4分别用作:
对CAP1及CAP2进行写操作,同样的内容也会被写入到CAP3和CAP4中。如果对CAP3或CAP4进行写操作,将会启动映射模式。
在初始化过程中,必须首先当前寄存器。在程序运行过程中,可以通过写入映射寄存器来修改占空比或PWM周期。
在APWM模式中,可触发两种中断事件:
捕获模式分成单次捕获和连续捕获两种模式。可以通过ECCTL2[CONT/ONESHT]寄存器来选择模式类型。
直接由系统时钟SYSCLKOUT驱动。相位寄存器通过软件或者硬件的方式将多个eCAP模块计数器进行同步。
寄存器的输入端直接与32位时钟计数器相连。当捕获事件发生时,直接将时钟计数器的值装载入对应的CAP寄存器中。通过ECCTCL1[CAPLDEN]寄存器可以开启/禁止装载功能。
通过ECCTL1[PRESCALE]控制。一般选择不分频,以提高捕获精度。
可以分别将4个捕获事件配置成上升沿或者下降沿。在ECCTL1寄存器中设定。
eCAP模块共可以产生7种中断事件:
其中,前5种工作在捕获模块,后2种工作在APWM模块。
struct ECAP_REGS
{
Uint32 TSCTR; // 时钟计数器:可读写,默认值0
Uint32 CTRPHS; //计数器相位寄存器:可读写,默认值0
Uint32 CAP1; // 捕获寄存器1:可读写,默认值0
Uint32 CAP2; // 捕获寄存器2:可读写,默认值0
Uint32 CAP3; // 捕获寄存器3:可读写,默认值0
Uint32 CAP4; // 捕获寄存器4:可读写,默认值0
Uint16 rsvd1[8]; // reserved
union ECCTL1_REG ECCTL1; // 捕获控制寄存器1
union ECCTL2_REG ECCTL2; // 捕获控制寄存器2
union ECEINT_REG ECEINT; // ECAP中断使能寄存器
union ECFLG_REG ECFLG; // ECAP中断标志寄存器
union ECFLG_REG ECCLR; // ECAP中断标志清除寄存器
union ECEINT_REG ECFRC; // ECAP中断强制寄存器(测试)
Uint16 rsvd2[6]; // reserved
};
struct ECCTL1_BITS
{
Uint16 CAP1POL:1; // 0[R/W-0] 捕获事件1触发极性选择。0:上升沿触发,1:下降沿触发
Uint16 CTRRST1:1; // 1[R/W-0] 捕获事件1计数器复位控制。0:捕获发生不复位计数器(绝对时间模式),1:捕获发生复位计数器(相对时间模式)
Uint16 CAP2POL:1; // 2[R/W-0] 捕获事件2触发极性选择
Uint16 CTRRST2:1; // 3[R/W-0] 捕获事件2计数器复位控制
Uint16 CAP3POL:1; // 4[R/W-0] 捕获事件3触发极性选择
Uint16 CTRRST3:1; // 5[R/W-0] 捕获事件3计数器复位控制
Uint16 CAP4POL:1; // 6[R/W-0] 捕获事件4触发极性选择
Uint16 CTRRST4:1; // 7[R/W-0] 捕获事件4计数器复位控制
Uint16 CAPLDEN:1; // 8[R/W-0] 控制捕获事件发生时是否装载CAP1-CAP4。0:禁止装载,1:使能装载
Uint16 PRESCALE:5; // 13:9[R/W-0] 事件预分频控制位。0:不分频,0000-1111(k):2k分频
/*
* 仿真控制位。
* 00:仿真挂起时,TSCTR立即停止
* 01:仿真挂起时,TSCTR计数到0停止
* 1x:TSCTR不受影响
*/
Uint16 FREE_SOFT:2; //15:14[R/W-0]
};
struct ECCTL2_BITS
{
Uint16 CONT_ONESHT:1; // 0[RW-0] 连续/单次捕获模式。0:连续模式,1:单次模式
/*
*00-11(k):
* 在单次模式下,捕获k+1次后停止。
* 在连续模式下,捕获k+1次后,mod4计数器归0。
* 总结:mod4计数器的最大值。即只使用到CAP(K+1)寄存器
*/
Uint16 STOP_WRAP:2; // 2:1[RW-11] 单次模式下停止值。
Uint16 REARM:1; // 3[RW-0] 重新装载控制位。0:无反应,1:将mod4复位到0,解冻mod4计数器,重新捕获
Uint16 TSCTRSTOP:1; // 4[RW-0] 时钟计数器使能。0:计数器停止;1:计数器继续计数
Uint16 SYNCI_EN:1; // 5[RW-0] 时钟计数器同步使能。0:禁止同步功能;1:使能同步功能
Uint16 SYNCO_SEL:2; // 7:6[RW-00] 同步输出使能。00:将SYNC_IN作为同步输出SYNC_OUT。
//01:CTR=PRD作为同步输出SYNC_OUT。1x:禁止同步输出
Uint16 SWSYNC:1; // 8[RW-0] 软件强制同步。0:无反应;1:产生一次强制同步信号
Uint16 CAP_APWM:1; // 9[RW-0] 工作模式选择。0:工作在铺货模式。1:工作在APWM模式。
Uint16 APWMPOL:1; // 10[RW-0] APWM输出极性选择。0:高电平有效。1:低电平有效
Uint16 rsvd1:5; // 15:11[R-0] 保留
};
寄存器中除了保留位,所有都是可读写。0:禁止对应中断,1:使能对应中断。
struct ECEINT_BITS { // bits description
Uint16 rsvd1:1; // 0 reserved
Uint16 CEVT1:1; // 1 Capture Event 1 Interrupt Enable
Uint16 CEVT2:1; // 2 Capture Event 2 Interrupt Enable
Uint16 CEVT3:1; // 3 Capture Event 3 Interrupt Enable
Uint16 CEVT4:1; // 4 Capture Event 4 Interrupt Enable
Uint16 CTROVF:1; // 5 Counter Overflow Interrupt Enable
Uint16 CTR_EQ_PRD:1; // 6 Period Equal Interrupt Enable
Uint16 CTR_EQ_CMP:1; // 7 Compare Equal Interrupt Enable
Uint16 rsvd2:8; // 15:8 reserved
};
中断标志位。所有位都是只读的。0:无中断发生;1:有中断发生。
struct ECFLG_BITS { // bits description
Uint16 INT:1; // 0 Global Flag
Uint16 CEVT1:1; // 1 Capture Event 1 Interrupt Flag
Uint16 CEVT2:1; // 2 Capture Event 2 Interrupt Flag
Uint16 CEVT3:1; // 3 Capture Event 3 Interrupt Flag
Uint16 CEVT4:1; // 4 Capture Event 4 Interrupt Flag
Uint16 CTROVF:1; // 5 Counter Overflow Interrupt Flag
Uint16 CTR_EQ_PRD:1; // 6 Period Equal Interrupt Flag
Uint16 CTR_EQ_CMP:1; // 7 Compare Equal Interrupt Flag
Uint16 rsvd2:8; // 15:8 reserved
};
中断标志清除位。除了保留位,都是可读写。默认值为0。0:无反应,读取始终返回0;1:清除响应的中断标志位。寄存器位定义和ECFLG完全相同。
将eCAP1配置为APWM模式。输出PWM的频率为15K Hz,占空比为30%,并通过GPIO5输出。
将eCAP2配置为捕获模式。其中,CAP1和CAP3寄存器配置为上升沿捕获,CAP2和CAP4寄存器配置为下降沿捕获。使用绝对时间模式。使用GPIO25做为输入。
将GPIO5和GPIO25短接。通过eCAP2捕获eCAP1发出PWM波,获得每个PWM周期内的高电平与低电平时间。
/*
* main.c
*
* 主程序实现两种功能:
* 1.利用CAP模块发出PWM
* 2.利用CAP捕捉到PWM
*/
int main(void)
{
//1.系统初始化
InitSysCtrl();
//2.中断
//2.1关闭中断
DINT;
IER = 0x0000;
IFR = 0x0000;
InitPieCtrl();
InitPieVectTable();
//2.2开CAP2中断
EALLOW;
PieVectTable.ECAP2_INT = &IsrEcap2; //写入中断服务函数
EDIS;
PieCtrlRegs.PIECTRL.bit.ENPIE = 1; //使能PIE向量表
PieCtrlRegs.PIEIER4.bit.INTx2 = 1; //打开第四组第二个中断
IER |= M_INT4; //打开CPUj级第四组中断
EINT;//打开全局中断
//3.初始化GPIO
InitECap1Gpio(); //用于生成PWM波
InitECap2Gpio(); //用于捕捉PWM
//4.自定义功能
InitECap();
while (1);
}
void InitECap1Gpio(void)
{
EALLOW;
GpioCtrlRegs.GPAPUD.bit.GPIO5 = 0; //上拉电阻使能
GpioCtrlRegs.GPAQSEL1.bit.GPIO5 = 0; //系统时钟同步输入
GpioCtrlRegs.GPAMUX1.bit.GPIO5 = 3; //功能选择为eCAP1
EDIS;
}
void InitECap2Gpio(void)
{
EALLOW;
GpioCtrlRegs.GPAPUD.bit.GPIO25 = 0; // 上拉电阻使能
GpioCtrlRegs.GPAQSEL2.bit.GPIO25 = 0; //系统时钟同步输入
GpioCtrlRegs.GPAMUX2.bit.GPIO25 = 1; // 功能选择为eCAP2
EDIS;
}
void InitECap(void)
{
/*CAP1配置输出PWM波*/
ECap1Regs.ECCTL2.bit.CAP_APWM = 1; //工作在APWM模式
ECap1Regs.ECCTL2.bit.APWMPOL = 0; //高电平有效(比较值决定高电平的时间,先高后低)
ECap1Regs.ECCTL2.bit.SYNCI_EN = 0; //禁止同步功能
ECap1Regs.ECCTL2.bit.SYNCO_SEL = 2; //禁止同步输出
ECap1Regs.ECCTL2.bit.TSCTRSTOP = 1; //使能计数器开始计数
ECap1Regs.TSCTR = 0; //时钟清零
//设置周期和占空比
ECap1Regs.CAP1 = 10000; //PWM周期为10K个时钟周期
ECap1Regs.CAP2 = 3000; //设置占空比
/*CAP2配置计数PWM波*/
ECap2Regs.TSCTR = 0; //时钟清零
ECap2Regs.ECCTL1.bit.PRESCALE = 0; //计时器使用系统时钟,不分频
ECap2Regs.ECCTL1.bit.CAPLDEN = 1; //使能捕获装载CAP
ECap2Regs.ECCTL1.bit.CTRRST1 = 0; //绝对时间试
ECap2Regs.ECCTL1.bit.CTRRST2 = 0; //绝对时间试
ECap2Regs.ECCTL1.bit.CTRRST3 = 0; //绝对时间试
ECap2Regs.ECCTL1.bit.CTRRST4 = 0; //绝对时间试
ECap2Regs.ECCTL1.bit.CAP1POL = 0; //上升沿触发捕获
ECap2Regs.ECCTL1.bit.CAP2POL = 1; //下降沿触发捕获
ECap2Regs.ECCTL1.bit.CAP3POL = 0; //上升沿触发捕获
ECap2Regs.ECCTL1.bit.CAP4POL = 1; //下降沿触发捕获
ECap2Regs.ECCTL2.bit.CAP_APWM = 0; //工作在捕获模式
ECap2Regs.ECCTL2.bit.SYNCI_EN = 0; //禁止同步功能
ECap2Regs.ECCTL2.bit.SYNCO_SEL = 2; //禁止同步输出信号
ECap2Regs.ECCTL2.bit.CONT_ONESHT = 0; //工作在连续模式下
ECap2Regs.ECCTL2.bit.TSCTRSTOP = 1; //计数器开始计数
//中断控制
ECap2Regs.ECEINT.all = 0x10; //只打开CEVT4中断
}
Uint32 t1, t2, t3, t4;
long T1, T2, T3, T4;
interrupt void IsrEcap2()
{
PieCtrlRegs.PIEACK.bit.ACK4 = 1; //第四组已经响应中断
ECap2Regs.ECCLR.all = 0xFFFF; //将所有中断清除
t1 = ECap2Regs.CAP1;
T4 = t1 - t4;//上一次的第二个低电平时间
t2 = ECap2Regs.CAP2;
t3 = ECap2Regs.CAP3;
t4 = ECap2Regs.CAP4;
T1 = t2 - t1;//本次第一个高电平时间
T2 = t3 - t2;//本次第二个低电平时间
T3 = t4 - t3;//本次第二个高电平时间
}
关于APWM配置时候,TI官方文档有一处有问题。我花了一整天才找到问题所在,所以才下了决心写这篇博客。
其中,配置程序中,先设置PWM的周期时间,再配置其他寄存器是错误的。
//错误写法
//=======================
// ECAP module 1 config
//先配置PWM周期
ECap1Regs.CAP1 = 0x1000; // Set period value
ECap1Regs.CTRPHS = 0x0; // make phase zero
//配置其他寄存器
ECap1Regs.ECCTL2.bit.CAP_APWM = EC_APWM_MODE;
ECap1Regs.ECCTL2.bit.APWMPOL = EC_ACTV_HI; // Active high
ECap1Regs.ECCTL2.bit.SYNCI_EN = EC_DISABLE; // Synch not used
ECap1Regs.ECCTL2.bit.SYNCO_SEL = EC_SYNCO_DIS; // Synch not used
ECap1Regs.ECCTL2.bit.TSCTRSTOP = EC_RUN; // Allow TSCTR to run
正确的写法,应该是eCAP功能初始化中的设定方式。摘取如下:
/*CAP1配置输出PWM波*/
ECap1Regs.ECCTL2.bit.CAP_APWM = 1; //工作在APWM模式
ECap1Regs.ECCTL2.bit.APWMPOL = 0; //高电平有效(比较值决定高电平的时间,先高后低)
ECap1Regs.ECCTL2.bit.SYNCI_EN = 0; //禁止同步功能
ECap1Regs.ECCTL2.bit.SYNCO_SEL = 2; //禁止同步输出
ECap1Regs.ECCTL2.bit.TSCTRSTOP = 1; //使能计数器开始计数
ECap1Regs.TSCTR = 0; //时钟清零
//设置PWM周期和占空比
ECap1Regs.CAP1 = 10000; //PWM周期为10K个时钟周期
ECap1Regs.CAP2 = 3000; //设置占空比