1.主函数流程
此程序的作用是实现eCAP(增强型捕获模块)的输入捕获功能,将ECAP2_APWM2设置为输入捕获模式,检测由EPWM1_A管脚输出的方波频率。将EPWMN0_TZ[0](ECAP2_APWM2和EPWMN0_TZ[0]引脚功能复用)和EPWM1_A短接,即可看到串口输出EPWMN0_TZ[0]脚所捕获到的EPWM1_A引脚输入的方波频率信息。主函数如下:
int main(void)
{
// 外设使能配置
PSCInit();
// 初始化串口终端 使用串口2
UARTStdioInit();
// GPIO 管脚复用配置
GPIOBankPinMuxSet();
// DSP 中断初始化
InterruptInit();
// PWM 中断初始化
PWMInterruptInit();
unsigned char i;
unsigned int j;
UARTPuts("Tronlong PWM_ECAP Application......\r\n", -1);
UARTPuts("------------------------------------------------------------\r\n", -1);
UARTPuts(" C6748 PWM Test\r\n\r\n", -1);
// 产生波形
PWM1ABasic(25000,50);
UARTPuts(" C6748 PWM Test Over!\r\n",-1);
UARTPuts("------------------------------------------------------------\r\n", -1);
UARTPuts("------------------------------------------------------------\r\n", -1);
UARTPuts(" C6748 ECAP Test\r\n", -1);
// ECAP 捕获初始化
ECAPInit();
UARTPuts("Initialize ECAP.......\r\n",-1);
for(i=0;i<5;i++)
{
for(j=0x00FFFFFF;j>0;j--); // 延时
ECAPRead();
}
UARTPuts("\r\n",-1);
UARTPuts(" C6748 ECAP Test Over!\r\n",-1);
UARTPuts("------------------------------------------------------------\r\n", -1);
// 主循环
for(;;)
{
}
}
2.外设使能配置
函数首先在PSC模块中使能外设,这里是eHRPWM模块1和eCAP0/1/2。外设使能配置函数PSCInit如下:
void PSCInit(void)
{
// 使能 EHRPWM 和 ECAP 模块
// 对相应外设模块的使能也可以在 BootLoader 中完成
PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_EHRPWM, PSC_POWERDOMAIN_ALWAYS_ON,
PSC_MDCTL_NEXT_ENABLE);
PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_ECAP0_1_2, PSC_POWERDOMAIN_ALWAYS_ON,
PSC_MDCTL_NEXT_ENABLE);
}
函数在PSC中使能HW_PSC_EHRPWM(#17)模块和HW_PSC_ECAP0_1_2(#20)模块,这两个模块的Power Domain是ALWAYS_ON域(POWER DOMAIN 0),PSCModuleControl细节可参考这里:
(指南P163)
3.初始化串口终端
程序初始化串口终端,使用串口2,打印输出PWM波相关信息,UARTStdioInit函数细节参考这里:
4.GPIO管脚复用配置
将EHRPWM模块和ECAP模块所在的引脚的功能配置为EHRPWM功能和ECAP功能,GPIO管脚复用配置函数GPIOBankPinMuxSet函数如下:
void GPIOBankPinMuxSet(void)
{
EHRPWM1PinMuxSetup();
// OMAPL138 / DSP C6748 有三个增强捕获模块(ECAP)
// 作为捕获功能时管脚方向为输入
// 作为辅助脉宽调制时管脚方向为输出
// ECAP2 / APWM2
ECAPPinMuxSetup(2);
// ECAP2 / APWM2方向设置为输入
GPIODirModeSet(SOC_GPIO_0_REGS, 8, GPIO_DIR_INPUT); // GPIO0[7]
}
EHRPWM1PinMuxSetup函数参考这里的第3节:
ECAPPinMuxSetup函数参考这里的第3节:
调用GPIODirModeSet函数,将ECAP2/APWM2管脚方向设置为输入方向,则启用ECAP模块的模式为捕获模式(capture mode)。
5.DSP中断初始化
DSP中断初始化函数InterruptInit如下:
void InterruptInit(void)
{
// 初始化 DSP 中断控制器
IntDSPINTCInit();
// 使能 DSP 全局中断
IntGlobalEnable();
}
函数细节参考这里
6.PWM中断初始化
PWM中断初始化函数PWMInterruptInit可参考这里的第5节:
7.产生波形
产生波形函数PWM1ABasic (25000,50)如下,其中第一个参数25000表示产生的PWM波的频率为25000Hz(25KHz),第二个参数50表示波形占空比为50%。细节可参考这里的第6节。
8.ECAP捕获初始化
ECAP捕获初始化函数ECAPInit如下:
void ECAPInit(void)
{
/*-----设置 ECCTL1-----*/
// 使能CAP寄存器装载
ECAPCaptureLoadingEnable(SOC_ECAP_2_REGS);
// 设置预分频值.
ECAPPrescaleConfig(SOC_ECAP_2_REGS, 0);
// 上升沿触发捕获事件
ECAPCapeEvtPolarityConfig(SOC_ECAP_2_REGS, 0,0,0,0);
// 输入捕获后重新装载计数器值.
ECAPCaptureEvtCntrRstConfig(SOC_ECAP_2_REGS, 1,1,1,1);
/*-----设置 ECCTL2-----*/
// 连续模式
ECAPContinousModeConfig(SOC_ECAP_2_REGS);
// ECAP计数器TSCTR持续计数
ECAPCounterControl(SOC_ECAP_2_REGS,ECAP_COUNTER_FREE_RUNNING);
// 禁用同步输出和同步输入
ECAPSyncInOutSelect(SOC_ECAP_2_REGS, ECAP_SYNC_IN_DISABLE,ECAP_SYNC_OUT_DISABLE);
// 配置 ECAP 2 为 CAPTURE 模式
ECAPOperatingModeSelect(SOC_ECAP_2_REGS, ECAP_CAPTURE_MODE);
// 使能中断
// ECAPIntEnable(SOC_ECAP_2_REGS,
ECAP_ECEINT_CEVT1|ECAP_CEVT2_INT|ECAP_CEVT3_INT|ECAP_CEVT4_INT);
}
8.1 设置ECCTL1
8.1.1 使能CAP寄存器模块
ECAPCaptureLoadingEnable函数设置ECCTL1[8](CAPLDEN)位为1,使能捕获事件(capture event)发生时CAPs寄存器装载(loading)。这里使能的是ECAP2模块。该API如下:
void ECAPCaptureLoadingEnable(unsigned int baseAdd)
{
HWREGH(baseAdd + ECAP_ECCTL1) |= ECAP_ECCTL1_CAPLDEN;
}
(指南P366)
(指南P340)
8.1.2 设置预分频值
ECAPPrescaleConfig函数设置ECCTL1[PRESCALE]位,设置事件的预分频值,这里设为0,即不分频,信号旁通(by-pass)过预分频器(prescaler)。该API如下:
void ECAPPrescaleConfig(unsigned int baseAdd, unsigned int prescale)
{
HWREGH(baseAdd + ECAP_ECCTL1) &= 0xffffc1ff;
HWREGH(baseAdd + ECAP_ECCTL1) |= (prescale << ECAP_ECCTL1_PRESCALE_SHIFT);
}
(指南P341)
(指南P366)
8.1.3 上升沿触发捕获事件
ECAPCapeEvtPolarityConfig函数设置ECCTL1的CAP1POL、CAP2POL、CAP3POL、CAP4POL位,设置CAP1-CAP4的捕获事件CEVT1-CEVT4。这里程序把这四位都设为0,即上升沿触发捕获事件。该API如下:
void ECAPCapeEvtPolarityConfig(unsigned int baseAdd, unsigned int capEvt1pol,
unsigned int capEvt2pol, unsigned int capEvt3pol,
unsigned int capEvt4pol)
{
HWREGH(baseAdd + ECAP_ECCTL1) |= capEvt1pol << 0;
HWREGH(baseAdd + ECAP_ECCTL1) |= capEvt2pol << 2;
HWREGH(baseAdd + ECAP_ECCTL1) |= capEvt3pol << 4;
HWREGH(baseAdd + ECAP_ECCTL1) |= capEvt4pol << 6;
}
(指南P367)
8.1.4 输入捕获后重新装载计数器值
ECAPCaptureEvtCntrRstConfig函数设置ECCTL1的CTRRST1-CTRRST4位,设置计数器(TSCRT,time-stamp counter)在捕获事件(capture event)CEVT1-CEVT4发生时是否复位(即清除为0)。这里程序全部设为1,则全部复位。该API如下:
void ECAPCaptureEvtCntrRstConfig(unsigned int baseAdd, unsigned int CounterRst1,
unsigned int CounterRst2,unsigned int CounterRst3,
unsigned int CounterRst4)
{
HWREGH(baseAdd + ECAP_ECCTL1) |= CounterRst1 << 1;
HWREGH(baseAdd + ECAP_ECCTL1) |= CounterRst2 << 3;
HWREGH(baseAdd + ECAP_ECCTL1) |= CounterRst3 << 5;
HWREGH(baseAdd + ECAP_ECCTL1) |= CounterRst4 << 7;
}
(指南P367)
8.2 设置ECCTL2
8.2.1 连续模式
ECAPContinousModeConfig函数设置ECCTL2[0](CONT/ONESHT)位为0,配置ECAP模块为连续模式。则当捕获完一轮事件(CEVT1-CEVT4)之后,ECAP又继续捕获下一次事件序列(event sequence)。该API如下:
void ECAPContinousModeConfig(unsigned int baseAdd)
{
HWREGH(baseAdd + ECAP_ECCTL2) &= ~ECAP_ECCTL2_CONT_ONESHT;
}
(指南369)
8.2.2 ECAP计数器TSCTR持续计数
ECAPCounterControl函数设置ECCTL2[TSCTRSTOP]位,从而启动或停止计数器TSCTR(time stamp counter),这里程序设置该位为1,即启动TSCTR,TSCTR置位运行状态(free-running)。该API如下:
void ECAPCounterControl(unsigned int baseAdd, unsigned int flag)
{
if(flag)
{
HWREGH(baseAdd + ECAP_ECCTL2) |= ECAP_ECCTL2_TSCTRSTOP;
}
else
{
HWREGH(baseAdd + ECAP_ECCTL2) &= ~ECAP_ECCTL2_TSCTRSTOP;
}
}
(指南P368)
8.2.3 禁用同步输出和同步输入
ECAPSyncInOutSelect函数设置ECCTL2[SYNCO_SEL]位和ECCTL2[SYNCI_SEL]位,配置同步输入和同步输出,这里程序将ECCTL2[SYNCI_SEL]位设为0,即禁用同步输入,将ECCTL2[SYNCO_SEL]位设为10(2进制的10,即2h),禁用同步输出。该API如下:
void ECAPSyncInOutSelect(unsigned int baseAdd, unsigned int syncIn,
unsigned int syncOut)
{
HWREGH(baseAdd + ECAP_ECCTL2) &= 0xffffffdf;
HWREGH(baseAdd + ECAP_ECCTL2) |= syncIn;
HWREGH(baseAdd + ECAP_ECCTL2) &= 0xffffff3f;
HWREGH(baseAdd + ECAP_ECCTL2) |= syncOut;
}
(指南P368)
(指南P343)
8.2.4 配置ECAP2为CAPTURE模式
ECAPOperatingModeSelect函数设置ECCTL2[9]位(CAP/APWM),选择ECAP模块的运行模式(operating mode),这里程序将该位设为0,即选择捕获模式(capture mode)。该API如下:
void ECAPOperatingModeSelect(unsigned int baseAdd, unsigned int modeSelect)
{
if(modeSelect)
{
HWREGH(baseAdd + ECAP_ECCTL2) &= ~ECAP_ECCTL2_CAP_APWM;
}
else
{
HWREGH(baseAdd + ECAP_ECCTL2) |= ECAP_ECCTL2_CAP_APWM;
}
}
(指南P368)
9.取得捕获结果
经过一段延时后,程序调用ECAPRead函数读取捕获结果,ECAPRead函数如下:
unsigned int ECAPRead(void)
{
unsigned int capvalue;
unsigned long frequency;
// Event1 中断标志
if(ECAPIntStatus(SOC_ECAP_2_REGS, ECAP_CEVT1_INT))
{
// 取得捕获计数
EcapContextSave(SOC_ECAP_2_REGS,0,&ECAPResult);
capvalue = ECAPResult.cap1;
// CAPTRUE 模块 228M 时钟主频
frequency = 228000000/capvalue;
UARTprintf("ECAPRead:frequency = %d\r\n",frequency);
ECAPIntStatusClear(SOC_ECAP_2_REGS, ECAP_ECEINT_CEVT1);
// IntEventClear(SYS_INT_ECAP2);
}
return frequency;
}
ECAPIntStatus函数读取ECFLG寄存器,返回指定的中断,这里返回CEVT1事件中断。当CEVT1事件中断标志为1时(即发生了CEVT1),程序读取捕获计数。该API如下:
unsigned int ECAPIntStatus(unsigned int baseAdd, unsigned int flag)
{
return (HWREGH(baseAdd + ECAP_ECFLG) & flag);
}
EcapContextSave函数读取CAP1和CAP2的捕获计数结果,该API如下:
void EcapContextSave(unsigned int ecapBase, unsigned int pwmssBase,
ECAPCONTEXT *contextPtr)
{
contextPtr->pwm0ssclkconfig = HWREG(pwmssBase + PWMSS_CLOCK_CONFIG);
contextPtr->tsctr = HWREG(ecapBase + ECAP_TSCTR);
contextPtr->eceint = HWREGH(ecapBase + ECAP_ECEINT);
contextPtr->ecclr = HWREGH(ecapBase + ECAP_ECCLR);
contextPtr->ecctl2 = HWREGH(ecapBase + ECAP_ECCTL2);
contextPtr->cap1 = HWREG(ecapBase + ECAP_CAP1);
contextPtr->cap2 = HWREG(ecapBase + ECAP_CAP2);
}
然后程序将CAP1的值存到capvalue中,该值即为从ECAP输入引脚捕获的PWM波的一个周期的时钟数(ECAP模块时钟为228MHz)。从而可以计算出捕获的PWM波频率为228000000/capvalue。
最后ECAPIntStatusClear函数清除ECFLG中的标志,这里清除CEVT1位。
10.参考文献
[1] stm32 输入捕获学习(一)