博主学习eCAP的使用主要是用于处理霍尔传感器,计算电机的电角度以及角速度。首先还是看了点哔哩哔哩的学习视频。
eCAP介绍
脉冲量的输入是在数字控制系统中最常见的一类输入量,控制器专门设置了脉冲捕获模块 (eCAP)来处理脉冲量,通过脉冲捕获模块捕获脉冲量的上升沿与下降沿,进而可以计算脉冲的宽度和占空比,可以采用脉冲信号进行相关控制。
捕获单元模块能够捕获外部输入引脚的逻辑状态(电平的高或低、电平翻转时的上升沿或下降沿),并利用内部定时器对外部事件或者引脚状态变化进行处理。
典型应用如下:
1.电机测速
2.测量脉冲电平宽度
3.测量一系列脉冲占空比和周期
4.电流/电压传感器的PWM编码信号的解码
谈一点自己的理解: 比如,配置好了eCAP后,eCAP就有一个定时器在跑了,说白了有个计数器在按照固有的周期在递增的计数,然后当外部输入引脚有一个上升沿的时候,我们的捕获模块,就捕获了,这时候捕获模块会把这个定时器的计数器的值加载到捕获寄存器里面去了。同时,这是可以触发中断的。当第二次上升沿再来的时候,我们又可以捕获到,那两个捕获寄存器都存的是计数值。计数值可以定时器频率换算成时间。 我们用两个计数值之差就能算出两个上升沿之间的间隔时间。
脉冲捕获基本原理
控制器给每个捕获单元模块都分配一个捕获引脚(注意:这个分配动作会在代码中体现哟),在捕获引脚上输入待测脉冲波形,捕获模块会捕获到指定捕获的逻辑状态,如图1中的下降沿,捕获单元记录下定时器的时间,两个下降沿间的时间差就是脉冲周期,同理也可以捕获脉冲的上升沿计算上升沿与下降沿之间的时间差就可以获得占空比,所以捕获单元可以用于测量脉冲周期以及脉冲的宽度。在一些数字脉冲测速场合,如电机的常见测速方法之一,在电机某个固定位置通过光电传感器发出一个脉冲,每周一个脉冲,两个脉冲之间的时间,就是电机的转速。在一些精确控制的场合中公一周当然不止发出一个脉冲,这取决于传感器(光电编码器)的选型与性能。
eCAP主要特性
F28335共有6组eCAP模块,每个eCAP不但具有捕获功能,而且还可用作PWM输出功能F28335捕获模块的主要特征如下:(F28377只会模块更多、功能更强)
- 150MHz系统时钟的情况下,32位时基的时间分辨率为6.67ns;(1/150MHz)
- 4组32位的时间标志寄存器;(时间计数器)
- 4级捕获事件序列,可以灵活配置捕获事件边沿极性;
- 四级触发事件均可以产生中断;
- 软件配置一次捕获可以最多得到4个捕获时间; (也即是有4级深度)
- 可连续循环4级捕获;
- 绝对时间捕获;
- 不同模式的时间捕获:
- 所有捕获都发生在一个输入引脚上:
- 如果eCAP模块不作捕获使用,可以配置成一个单通道输出的PWM模式
eCAP模块中一个捕获通道完成一次捕获任务,需要以下关键资源
- 专用捕获输入引脚;
- 32位时基(计数器);
- 4*32位时间标签捕获寄存器;
- 4级序列器,与外部eCAP引脚的上升/下降沿同步;
- 4个事件可独立配置边沿极性;
- 输入捕获信号预定标 (2-62);
- 一个2位的比较寄存器,一次触发后可以捕获4个时间标签事件;
- 采用4级深度的循环缓冲器以进行连续捕获;
- 4个捕获事件中任意一个都可以产生中断。
值得关注的点
eCAP这部分可能最困惑的,就是对于4级深度的理解。首先当eCAP工作时,肯定会有个定时器会从0开始一直往上计数的。如果定时器的频率是150M,那么每个计数值代表的就是(1/150M)s。然后我们有4个捕获的深度。每一级捕获都可以设置边沿的极性(上升沿/下降沿)。
比如对于双极性-开关型的霍尔传感器,当S级靠近传感器正面的时候,霍尔传感器会产生一个上升沿并保持高电平,当N级靠近传感器正面的时候,霍尔会产生下降沿并保持低电平。 考虑电机是1极对的简单情况,如果电机一直不停的旋转的话, 霍尔传感器对eCAP产生如图2的输入波形。
我们可以把eCAP捕获的4级深度的边沿极性分别配置成: 第一个是上升沿 第二个是下降沿 第三个是上升沿 第四个是下降沿。 当我们完成这4次捕获之后,实际上电机旋转了360°的机械角(若是N极对电机,则是旋转了360°/N的机械角)
咱们的eCAP模块会把这4个边沿信号对应的计数数值存到4个对应的CAP寄存器。 比如,CAP1 = 1000, CAP2 = 2000, CAP3 = 4000, CAP4 = 8000(说明速度在增加)。咱们可以用 T = (CAP3 – CAP1) *(1/150M) | T = (CAP4 – CAP2) *(1/150M)得到电机旋转1圈需要的时间,然后就可以 360°/T得到转速了。 根据上面举例的CAP寄存器计数值易知了两种计算转速的方式算出来的速度是不一样的。
当然我们也可以用 T = (CAP2 – CAP1) *(1/150M) | T = (CAP3 – CAP2) *(1/150M) | T = (CAP4 – CAP3) *(1/150M), 然后180°/T得到速度,这样做的好处是分辨率更高。
我们算速度就是用旋转过的角度除以所用的时间。 旋转过的角度越小,分辨率越高。 比如我电机是10极对,那么我们每次计算速度的时候转过的角度是 360°/10/2 = 18°,也就是每旋转18°就能计算一次角速度。
但! 第二种分辨率更高的计算方式的前提是霍尔传感器的方波高低电平所对应的机械角度的占空比一致。不幸的是,我们这个电机他就不是一致的(前辈讲的),那就不能使用上面说的第二种计算速度的方式了。
eCAP可以设置在这4级捕获的每一级都进入中断, 我们可以在每一级都进入中断,根据中断标志位可判断是从哪一级捕获进入的中断。
eCAP配置(上代码了)
eCAP配置主要包含 3个方面。
引脚复用配置
正式配置之前,我们首先参考一下官方样例提供的代码
/* Reference code
*
* Example ecap_capture_pwm_cpu01's eCAP GPIO initialization code:
*
* InitECap1Gpio(19);
* GPIO_SetupPinOptions(19, GPIO_INPUT, GPIO_ASYNC);
*
* Definition of InitECap1Gpio
*
* void InitECap1Gpio(Uint16 pin)
* {
* EALLOW;
* InputXbarRegs.INPUT7SELECT = pin; // Set eCAP1 source to GPIO-pin
* EDIS;
* }
*
*/
参考代码中我们得知,配置引脚复用之前,我们需要配置InputXbarRegs这个寄存器来指定eCAP模块分配的引脚(在前文有讲相关的内容哟)
InputXbarRegs.INPUT7SELECT对应eCAP1指定的引脚编号
InputXbarRegs.INPUT8SELECT对应eCAP2指定的引脚编号
InputXbarRegs.INPUT9SELECT对应eCAP3指定的引脚编号
那么最终的引脚复用配置代码如下:
void ecap_gpio_init(void){
/* Reference code
*
* Example ecap_capture_pwm_cpu01's eCAP GPIO initialization code:
*
* InitECap1Gpio(19);
* GPIO_SetupPinOptions(19, GPIO_INPUT, GPIO_ASYNC);
*
* Definition of InitECap1Gpio
*
* void InitECap1Gpio(Uint16 pin)
* {
* EALLOW;
* InputXbarRegs.INPUT7SELECT = pin; // Set eCAP1 source to GPIO-pin
* EDIS;
* }
*
*/
// Our eCAP initialization code
EALLOW;
InputXbarRegs.INPUT7SELECT = 24;
InputXbarRegs.INPUT8SELECT = 25;
InputXbarRegs.INPUT9SELECT = 26;
EDIS;
EALLOW;
// eCAP1
GpioCtrlRegs.GPAPUD.bit.GPIO24 = 0; // 使能上拉 0: Enables the Pull-Up
// 1: Disables the Pull-Up
GpioCtrlRegs.GPAGMUX2.bit.GPIO24 = 0; // 复用为GPIO 参考手册 Page 959
GpioCtrlRegs.GPAMUX2.bit.GPIO24 = 0; // 8.7 GPIO and Peripheral Muxing
GpioCtrlRegs.GPADIR.bit.GPIO24 = 0; // 方向配置输入 0: Configures pin as input
// 1: Configures pin as output.
GpioCtrlRegs.GPACSEL4.bit.GPIO24 = 0; // Selects which master's GPIODAT/SET/CLEAR/TOGGLE registers control this GPIO pin
// xx00: CPU1 selected
// xx01: CPU1.CLA1 selected
// xx10: CPU2 selected
// xx11: CPU2.CLA1 selected
GpioCtrlRegs.GPAQSEL2.bit.GPIO24 = 3; // 配置异步输入模式提升精度,example也是设置成GPIO_ASYNC(异步)
// Using synchronized inputs can help with noise immunity
// but will 【affect】 the eCAP's accuracy by ±2 cycles.
// 0,0 Sync
// 0,1 Qualification (3 samples)
// 1,0 Qualification (6 samples)
// 1,1 Async (no Sync or Qualification)
// eCAP2
GpioCtrlRegs.GPAPUD.bit.GPIO25 = 0;
GpioCtrlRegs.GPAGMUX2.bit.GPIO25 = 0;
GpioCtrlRegs.GPAMUX2.bit.GPIO25 = 0;
GpioCtrlRegs.GPADIR.bit.GPIO25 = 0;
GpioCtrlRegs.GPACSEL4.bit.GPIO25 = 0;
GpioCtrlRegs.GPAQSEL2.bit.GPIO25 = 3;
// eCAP3
GpioCtrlRegs.GPAPUD.bit.GPIO26 = 0;
GpioCtrlRegs.GPAGMUX2.bit.GPIO26 = 0;
GpioCtrlRegs.GPAMUX2.bit.GPIO26 = 0;
GpioCtrlRegs.GPADIR.bit.GPIO26 = 0;
GpioCtrlRegs.GPACSEL4.bit.GPIO26 = 0;
GpioCtrlRegs.GPAQSEL2.bit.GPIO26 = 3;
EDIS;
}
寄存器的配置
void ecap_register_init(void){
ECap1Regs.ECCTL1.bit.CAP1POL = 1; // 事件1上升沿 //0--上升沿 1--下降沿
ECap1Regs.ECCTL1.bit.CAP2POL = 0; // 事件2下降沿
ECap1Regs.ECCTL1.bit.CAP3POL = 1; // 事件3上升沿
ECap1Regs.ECCTL1.bit.CAP4POL = 0; // 事件4下降沿
ECap1Regs.ECCTL1.bit.CTRRST1 = 0; // 捕获到事件清空计数器 //0--不清空计数器 1--清空计数器
ECap1Regs.ECCTL1.bit.CTRRST2 = 0; // 捕获到事件清空计数器
ECap1Regs.ECCTL1.bit.CTRRST3 = 0; // 捕获到事件清空计数器
ECap1Regs.ECCTL1.bit.CTRRST4 = 0; // 捕获到事件清空计数器
ECap1Regs.ECCTL1.bit.CAPLDEN = 1; // 使能寄存器装载
ECap1Regs.ECCTL1.bit.PRESCALE = 0; // 输入信号不分频
ECap1Regs.ECCTL2.bit.CAP_APWM = 0; // 配置为捕获模式
ECap1Regs.ECCTL2.bit.CONT_ONESHT = 0; // 连续计数模式
ECap1Regs.ECCTL2.bit.SYNCO_SEL = 2; //
ECap1Regs.ECCTL2.bit.SYNCI_EN = 0;
ECap1Regs.ECEINT.all = 0x0000; // stop all interrupt
ECap1Regs.ECCLR.all = 0xFFFF; // clear all flag
ECap1Regs.ECCTL2.bit.TSCTRSTOP = 1; // 时间戳计数器自由运行
ECap1Regs.ECEINT.bit.CEVT1 = 1; // Enable cevt1 interrupt
// ECap1Regs.ECEINT.bit.CEVT2 = 1; // Enable cevt2 interrupt
ECap1Regs.ECEINT.bit.CEVT3 = 1; // Enable cevt3 interrupt
// ECap1Regs.ECEINT.bit.CEVT4 = 1; // Enable cevt4 interrupt
// ECap1Regs.ECEINT.bit.CTROVF = 1; // Enable Counter Overflow interrupt
// CTROVF Counter Overflow Interrupt Enable
}
中断配置
void interrupt_init(void){
DINT;
EALLOW; //设置中断入口函数
PieVectTable.ECAP1_INT = &Ecap1Handler;
PieVectTable.ECAP2_INT = &Ecap2Handler;
PieVectTable.ECAP3_INT = &Ecap3Handler;
EDIS;
IER |= M_INT4;
PieCtrlRegs.PIEIER4.bit.INTx1 = 1; //使能PIE中断 // ECAP1
PieCtrlRegs.PIEIER4.bit.INTx2 = 1; //使能PIE中断 // ECAP2
PieCtrlRegs.PIEIER4.bit.INTx3 = 1; //使能PIE中断 // ECAP3
EINT; // 使能全局中断
ERTM; // 使能实时仿真中断
}
中断处理函数
interrupt void Ecap1Handler(void)
{
ECap1Regs.ECCLR.all = 0xFFFF; // Clear all flag
PieCtrlRegs.PIEACK.all = PIEACK_GROUP4;
}
interrupt void Ecap2Handler(void)
{
ECap2Regs.ECCLR.all = 0xFFFF; // Clear all flag
PieCtrlRegs.PIEACK.all = PIEACK_GROUP4;
}
interrupt void Ecap3Handler(void)
{
ECap3Regs.ECCLR.all = 0xFFFF; // Clear all flag
PieCtrlRegs.PIEACK.all = PIEACK_GROUP4;
}
感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。