(一)CLA综述:
F2837X存在两个CLA,CPU1.CLA1
CPU2.CLA1
CLA是32位浮点运算器(浮点内核),主要作用为控制PWM,CAP,读取控制结果,
以及控制一些重要外设(CMPSS、DAC、SDFM、SPI、McBSP(多通道缓冲串行口)、GPIO、uPP(多通道高速并行接口)),从而分担CPU通信负载(通用外设:SPI),内核运算负载,非配中断,优先级较高(CLA不支持中断嵌套,必须执行完现有的中断任务才能进行下一个)。
(二)结构特性:
有独立地址总线(独立于CPU总线之外,用于独立寻址目标操作寄存器),数据总线(用于独立接收,发送控制量以及运算结果);
独立与CPU交互的RAM(任务完成时触发对应CPU中断);
独立状态机,用于判断CLA的工作状态,并置位中断FLAG,使能不同的任务;
有八个任务结构,优先级依次提高,可以理解为中断,但不支持中断嵌套;
可分配的LS0——LS5 RAM控制区域,LS0——LS5由CPU初始化并且交由CLA控制,初始化应分为两个部分:1、Data
Memory(用于存放CLA程序需要的的数据以及采集得到的处理数据),2、Program Memory(用于读取Data中的数据并且执行算法响应)每个至少2K,初始化说明见下文;
两个CPU与CLA的128word的MSG RAM(不用在乎MSG RAM的大小,只是用来与CPU做中断交互以及结果的传送)
总之,CLA差不多相当于CPU这个老板的助理,能力不是太强,也就打打杂啥的,力挺大(毕竟跟着老板混),可以跟外设要数据,控制PWM输出和捕获,也可以帮着CPU算个sin,读个AD,做个采样,做完以后告诉老大一声,他就可以歇着了。不过他当然不只是简单地算个sin,一般是采集ADC的数据,预处理PWM波(提高PWM的精确度,如果不是要求精确的电机控制的话,也没必要)
另外关于CLA数据和控制总线可以达到的区域,查看datasheet Memory部分的内存地址表;关于任务触发源的部分,参看2837x的CLA部分CLA Task and Interrupt表格,主要就是CLA的bus可以达到的地方。
如果想把CLA的功能发挥到极致,最好使用汇编语言,对于实时性控制性较高,CCS支持C+汇编混合编程,比如说asm(“IACK
#0x0008”)就是置位MIFRC的bit3,开始任务4的中断。
Attention:CLA不支持任何64位的数据定义以及计算,long long 或long double型,在CLA里面都会被定义成32bit。
CLA禁止使用函数指针以及递归调用,
(三)CLA重要寄存器及其说明:
MCTL 控制寄存器 主要就是配置中断响应(IACK)以及软硬件复位功能;
MIFR 任务中断寄存器 配置任务中断:INTx;
MVECTx任务中断向量寄存器 存储任务中断的任务地址;
MIER 任务中断使能寄存器 对应使能不同任务中断;
MIFR 中断置位寄存器
(其实对于寄存器更深入的理解确实应该用汇编去写)
(四)CLA寄存器配置流程:
基本上分成以下几个方面:
1、配置CLA的程序运行RAM以及数据储存的RAM,首先互配CPU与CLA的MSG RAM指令寄存器:(关于配置LSx不用考虑过多,一般来说顺序配下来就好,不过为了程序可读性,可以考虑将Programme与Data分组定义)
MemCfgRegs.MSGxINIT.bit.INIT_CLA1TOCPU = 1;
while(MemCfgRegs.MSGxINITDONE.bit.INITDONE_CLA1TOCPU != 1){}; // 判断CPU与CLA控制请求
MemCfgRegs.MSGxINIT.bit.INIT_CPUTOCLA1 = 1;
while(MemCfgRegs.MSGxINITDONE.bit.INITDONE_CPUTOCLA1 != 1){}; // 确定CPU与cla的控制连接.
MemCfgRegs.LSxMSEL.bit.MSEL_LS5 = 1; // 将RAM管理权移交给CLA
MemCfgRegs.LSxCLAPGM.bit.CLAPGM_LS5 = 1; // 将LS5设定为Programme区域
MemCfgRegs.LSxMSEL.bit.MSEL_LS0 = 1;
MemCfgRegs.LSxCLAPGM.bit.CLAPGM_LS0 = 0; // 配置LS0为Data区域.
MemCfgRegs.LSxMSEL.bit.MSEL_LS1 = 1;
MemCfgRegs.LSxCLAPGM.bit.CLAPGM_LS1 = 0; // 配置LS1为Data区域.
一般来说普通的sin运算以及逻辑算术运算定义两个RAM作为Data就行。并且MemCfgRegs需要EALLOW解一下寄存器保护锁,建议将以上的Init配置封装到一个函数里。如果CLA空间不足,不过一般不会出现这种问题,解决方法很简单,查看datasheet发现,CLA部分的程序和数据在RAM中的存储都必须在LSxRAM地址空间内。将LS3RAM的空间从默认0x0800扩大到0x1800,并且注释掉LS4RAM和LS5RAM,避免地址冲突。最关键的是,在进行CLA初始化时,即使注释掉了LS4RAM和LS5RAM,但是这两个部分的空间仍旧需要被初始化,才能够被CLA使用,OK!有些TI例程中#fdef了_FLASH,其实不需要,cmd里空间已经定义了。
2、设置CLA的中断源以及任务流程表:(同样ClaRegs受到EALLOW的保护,用的时候需要先解一下)
Cla1Regs.MVECT1 = (uint16_t)(&Cla1Task1); // 初始化CLA任务中断向量.
Cla1Regs.MVECT2 = (uint16_t)(&Cla1Task2);
Cla1Regs.MVECT3 = (uint16_t)(&Cla1Task3);
Cla1Regs.MVECT4 = (uint16_t)(&Cla1Task4);
Cla1Regs.MVECT5 = (uint16_t)(&Cla1Task5);
Cla1Regs.MVECT6 = (uint16_t)(&Cla1Task6);
Cla1Regs.MVECT7 = (uint16_t)(&Cla1Task7);
Cla1Regs.MVECT8 = (uint16_t)(&Cla1Task8);
Cla1Regs.MCTL.bit.IACKE = 1; // 使能中断响应信号.对应于全部八个任务.
Cla1Regs.MIER.all = (M_INT8 | M_INT7); // 使用任务中断7、8.
PieVectTable.CLA1_1_INT = &cla1Isr1; // 初始化中断向量表. //
取中断向量的地址.放入CPU中断向量表中。
PieVectTable.CLA1_2_INT = &cla1Isr2;
PieVectTable.CLA1_3_INT = &cla1Isr3;
PieVectTable.CLA1_4_INT = &cla1Isr4;
PieVectTable.CLA1_5_INT = &cla1Isr5;
PieVectTable.CLA1_6_INT = &cla1Isr6;
PieVectTable.CLA1_7_INT = &cla1Isr7;
PieVectTable.CLA1_8_INT = &cla1Isr8; // 给中断向量表对应CLA的任务中断取中断函数的地址。F28379D的CLA中断都在Group11里面。
PieCtrlRegs.PIEIER11.all = 0xFFFF; // 使能group 11 中断组. // 选定中断源.
IER
|= (M_INT11 ); // 配置CPU的PIE第十一组中断。
每个任务都有特定的中断源去触发CLA,比如说ADC的ADCINT1(ADC一共有四个中断送进PIE外设中断扩展模块),和PWM的EPWM_1,这是外设中断的硬件触发CLA中断,
可以使用DMA跨过优先级直接强制触发选定的任务,比如强制触发任务7:
DmaClaSrcSelRegs.CLA1TASKSRCSEL2.bit.TASK7 = 1; // DMA 触发 task7 中断源,向CPU请求指令.
关于在主函数里进入CLA中断进行相关运算的ClaxForceTaskxandWait()的函数,参看
“F2837xD_Cla_defines.h”文件,下面贴一个TI例程的简单除法运算:
void CLA_runTest(void)
{
int i, error;
for(i=0; i
3、初始化也就这样了,然后最关心的还是主函数的配置,前面的初始化系统步骤就不多说了,千篇一律(F28379x把狗给放了还是挺耐人寻味的):
void main(void)
{
InitSysCtrl();
CpuSysRegs.PCLKCR2.bit.EPWM1 = 1;
CpuSysRegs.PCLKCR2.bit.EPWM2 = 1;
InitEPwm1Gpio();
InitEPwm2Gpio(); // 使能对应的GPIO.
DINT;
// 关中断.
InitPieCtrl(); // 初始化中断控制寄存器.
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
// 初始化中断向量表.
CLA_configClaMemory(); // 配置运行所需内存区.
CLA_initCpu1Cla1(); // 初始化CPU1 与
CLA1的控制连接.
Cla1ForceTask8(); // 重点是这几句,要按顺序来。(这是强制进入TASK8)然后从Task8跳到Task7执行ADC的数据采集。
主函数开始之前一定要定义中断函数,先将中断任务的地址空间取好。
之后再始化你要操作的模块,比如说ADC,PWM:
ADC_initAdcA();
EPWM_initEpwm(); // 初始化PWM模块。
EINT;
ERTM;
// 初始化全局中断。
EALLOW;
CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;
EPwm1Regs.TBCTL.bit.CTRMODE = 0;
EPwm2Regs.TBCTL.bit.CTRMODE = 0;
EDIS;
4、压轴戏当然是中断的配置,其实不用把中断服务函数全部写上,例程只是做一个示范,单步调试的时候可以查看CLA任务中断的执行位置。
大概是这样:
__interrupt void cla1Isr1 () // isr1
{
//asm(" ESTOP0");
}
__interrupt void cla1Isr2 () // isr2
{
//asm(" ESTOP0");
}
__interrupt void cla1Isr3 () // isr3
{
//asm(" ESTOP0");
}
__interrupt void cla1Isr4 () // isr4
{
//asm(" ESTOP0");
}
__interrupt void cla1Isr5 () // isr5
{
//asm(" ESTOP0");
}
__interrupt void cla1Isr6 () // isr6
{
//asm(" ESTOP0");
}
__interrupt void cla1Isr7 () // isr7
{
// 关闭中断以及中断响应.
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //make sure INT1 flag is cleared
PieCtrlRegs.PIEACK.all = (PIEACK_GROUP1 | PIEACK_GROUP11);//响应PIE的第十一组中断。
AdcBuf[SampleCount] = AdcaResultRegs.ADCRESULT0; // ADC运算结果寄存器.
AdcFiltBuf[SampleCount] = voltFilt;
// 防止出现数据溢出的现象.
SampleCount++;
if( SampleCount == ADC_BUF_LEN )
{
SampleCount = 0;
}
}
__interrupt void cla1Isr8 () // isr8.
{
PieCtrlRegs.PIEACK.all = M_INT11;
}
每个中断可以用汇编写上中断调试点,没有太大的必要,如果要仔细DEBUG的话还是要加上的。
(五)CLA调试:
工欲善其事必先利其器,调不好CCS编译器自然要和CLA说拜拜,首先打开工程属性,在Processor Option里面把cla-support选定cla2,之后从controSuite里选定2837xD_FLASH_lnk_cpu1_far的cmd文件并且导入工程文件中(cmd文件必须要加,不然MSG RAM没有定义,bios里只是CLA的工作空间定义)。
至此CLA的基础配置部分基本就差不多了,之后就是一个头文件cla.h,可以和bsp.h写在一起,声明一下MVECT用的ClaTaskx就行,基本上像这样:
__interrupt void Cla1Task1();
__interrupt void Cla1Task2();
__interrupt void Cla1Task3();
__interrupt void Cla1Task4();
__interrupt void Cla1Task5();
__interrupt void Cla1Task6();
__interrupt void Cla1Task7();
__interrupt void Cla1Task8();
最后,将下面这些汇编(最好用汇编写CLA,我是没看懂)写成.asm文件import进工程文件里(工程里直接创建也行),大概是将ClaTaskx在CLA里面配置好。其实CLA是
只支持汇编编程的。
.cdecls
C, LIST, “cla_adc_fir32_shared.h”
CLA_DEBUG
.set
1
.sect
“Cla1Prog”
_Cla1Prog_Start
.align
2
_Cla1Task1:
MSTOP
MNOP
MNOP
MNOP
_Cla1T1End:
_Cla1Task2:
MSTOP
MNOP
MNOP
MNOP
_Cla1T2End:
_Cla1Task3:
MSTOP
MNOP
MNOP
MNOP
_Cla1T3End:
_Cla1Task4:
MSTOP
MNOP
MNOP
MNOP
_Cla1T4End:
_Cla1Task5:
MSTOP
MNOP
MNOP
MNOP
_Cla1T5End:
_Cla1Task6:
MSTOP
MNOP
MNOP
MNOP
_Cla1T6End:
_Cla1Task7:
.if CLA_DEBUG == 1
MDEBUGSTOP
.endif
_X4 .set _X+8
_X3 .set _X+6
_X2 .set _X+4
_X1 .set _X+2
_X0 .set _X+0
_A4 .set _A+8
_A3 .set _A+6
_A2 .set _A+4
_A1 .set _A+2
_A0 .set _A+0
;
MMOV32
MR0,@_X4 ;1 Load MR0 with X4
MMOV32
MR1,@_A4 ;2 Load MR1 with A4
MNOP ;3 Wait till I8 to read result
MNOP ;4 Wait till I8 to read result
MNOP ;5 Wait till I8 to read result
MNOP ;6 Wait till I8 to read result
MNOP ;7 Wait till I8 to read result
MUI16TOF32 MR2,
@_AdcaResultRegs.ADCRESULT0 ;8 Read ADCRESULT0 and convert to
float
MMPYF32
MR2, MR1, MR0 ; MR2 (Y) = MR1 (A4) * MR0 (X4)
|| MMOV32 @_X0, MR2
MMOVD32
MR0,@_X3 ; Load MR0 with X3, Load X4 with
X3
MMOV32
MR1,@_A3 ; Load MR1 with A3
MMPYF32
MR3, MR1, MR0 ; MR3 (Y) = MR1 (A3) * MR0 (X3)
|| MMOV32 MR1,@_A2 ; Load MR1 with A2
MMOVD32
MR0,@_X2 ; Load MR0 with X2, Load X3 with
X2
MMACF32
MR3, MR2, MR2, MR1, MR0 ; MR3 = A3X3 + A4X4
|| MMOV32 MR1,@_A1 ; MR2 = MR1 (A2) * MR0
(X2)
MMOVD32
MR0,@_X1 ; Load MR0 with X1, Load X2 with
X1
MMACF32
MR3, MR2, MR2, MR1, MR0 ; MR3 = A2X2 + (A3X3 + A4*X4)
|| MMOV32 MR1,@_A0 ; MR2 = MR1 (A1) * MR0
(X1)
MMOVD32
MR0,@_X0 ; Load MR0 with X0, Load X1 with
X0
MMACF32
MR3, MR2, MR2, MR1, MR0 ; MR3 = A1X1 + (A2X2 +A3X3 +
A4X4)
|| MMOV32 MR1,@_A0 ; MR2 = MR1 (A0) * MR0
(X0)
MADDF32
MR3, MR3, MR2 ; MR3 = A0X0 + (A1X1 + A2X2
+A3X3 + A4*X4)
MF32TOUI16 MR2, MR3 ; Get back to Uint16 value
MMOV16
@_voltFilt, MR2 ; Output
MSTOP ; End task
_Cla1T7End:
_Cla1Task8:
.if CLA_DEBUG == 1
MDEBUGSTOP
.endif
MMOVIZ MR0, #0.0
MUI16TOF32 MR0,
MR0
MMOV32
@_X0, MR0
MMOV32
@_X1, MR0
MMOV32
@_X2, MR0
MMOV32
@_X3, MR
CLA模块简略讲解
(一)CLA综述:
F2837X存在两个CLA,CPU1.CLA1
CPU2.CLA1
CLA是32位浮点运算器(浮点内核),主要作用为控制PWM,CAP,读取控制结果,
以及控制一些重要外设(CMPSS、DAC、SDFM、SPI、McBSP(多通道缓冲串行口)、GPIO、uPP(多通道高速并行接口)),从而分担CPU通信负载(通用外设:SPI),内核运算负载,非配中断,优先级较高(CLA不支持中断嵌套,必须执行完现有的中断任务才能进行下一个)。
(二)结构特性:
有独立地址总线(独立于CPU总线之外,用于独立寻址目标操作寄存器),数据总线(用于独立接收,发送控制量以及运算结果);
独立与CPU交互的RAM(任务完成时触发对应CPU中断);
独立状态机,用于判断CLA的工作状态,并置位中断FLAG,使能不同的任务;
有八个任务结构,优先级依次提高,可以理解为中断,但不支持中断嵌套;
可分配的LS0——LS5 RAM控制区域,LS0——LS5由CPU初始化并且交由CLA控制,初始化应分为两个部分:1、Data
Memory(用于存放CLA程序需要的的数据以及采集得到的处理数据),2、Program Memory(用于读取Data中的数据并且执行算法响应)每个至少2K,初始化说明见下文;
两个CPU与CLA的128word的MSG RAM(不用在乎MSG RAM的大小,只是用来与CPU做中断交互以及结果的传送)
总之,CLA差不多相当于CPU这个老板的助理,能力不是太强,也就打打杂啥的,力挺大(毕竟跟着老板混),可以跟外设要数据,控制PWM输出和捕获,也可以帮着CPU算个sin,读个AD,做个采样,做完以后告诉老大一声,他就可以歇着了。不过他当然不只是简单地算个sin,一般是采集ADC的数据,预处理PWM波(提高PWM的精确度,如果不是要求精确的电机控制的话,也没必要)
另外关于CLA数据和控制总线可以达到的区域,查看datasheet Memory部分的内存地址表;关于任务触发源的部分,参看2837x的CLA部分CLA Task and Interrupt表格,主要就是CLA的bus可以达到的地方。
如果想把CLA的功能发挥到极致,最好使用汇编语言,对于实时性控制性较高,CCS支持C+汇编混合编程,比如说asm(“IACK
#0x0008”)就是置位MIFRC的bit3,开始任务4的中断。
Attention:CLA不支持任何64位的数据定义以及计算,long long 或long double型,在CLA里面都会被定义成32bit。
CLA禁止使用函数指针以及递归调用,
(三)CLA重要寄存器及其说明:
MCTL 控制寄存器 主要就是配置中断响应(IACK)以及软硬件复位功能;
MIFR 任务中断寄存器 配置任务中断:INTx;
MVECTx任务中断向量寄存器 存储任务中断的任务地址;
MIER 任务中断使能寄存器 对应使能不同任务中断;
MIFR 中断置位寄存器
(其实对于寄存器更深入的理解确实应该用汇编去写)
(四)CLA寄存器配置流程:
基本上分成以下几个方面:
1、配置CLA的程序运行RAM以及数据储存的RAM,首先互配CPU与CLA的MSG RAM指令寄存器:(关于配置LSx不用考虑过多,一般来说顺序配下来就好,不过为了程序可读性,可以考虑将Programme与Data分组定义)
MemCfgRegs.MSGxINIT.bit.INIT_CLA1TOCPU = 1;
while(MemCfgRegs.MSGxINITDONE.bit.INITDONE_CLA1TOCPU != 1){}; // 判断CPU与CLA控制请求
MemCfgRegs.MSGxINIT.bit.INIT_CPUTOCLA1 = 1;
while(MemCfgRegs.MSGxINITDONE.bit.INITDONE_CPUTOCLA1 != 1){}; // 确定CPU与cla的控制连接.
MemCfgRegs.LSxMSEL.bit.MSEL_LS5 = 1; // 将RAM管理权移交给CLA
MemCfgRegs.LSxCLAPGM.bit.CLAPGM_LS5 = 1; // 将LS5设定为Programme区域
MemCfgRegs.LSxMSEL.bit.MSEL_LS0 = 1;
MemCfgRegs.LSxCLAPGM.bit.CLAPGM_LS0 = 0; // 配置LS0为Data区域.
MemCfgRegs.LSxMSEL.bit.MSEL_LS1 = 1;
MemCfgRegs.LSxCLAPGM.bit.CLAPGM_LS1 = 0; // 配置LS1为Data区域.
一般来说普通的sin运算以及逻辑算术运算定义两个RAM作为Data就行。并且MemCfgRegs需要EALLOW解一下寄存器保护锁,建议将以上的Init配置封装到一个函数里。如果CLA空间不足,不过一般不会出现这种问题,解决方法很简单,查看datasheet发现,CLA部分的程序和数据在RAM中的存储都必须在LSxRAM地址空间内。将LS3RAM的空间从默认0x0800扩大到0x1800,并且注释掉LS4RAM和LS5RAM,避免地址冲突。最关键的是,在进行CLA初始化时,即使注释掉了LS4RAM和LS5RAM,但是这两个部分的空间仍旧需要被初始化,才能够被CLA使用,OK!有些TI例程中#fdef了_FLASH,其实不需要,cmd里空间已经定义了。
2、设置CLA的中断源以及任务流程表:(同样ClaRegs受到EALLOW的保护,用的时候需要先解一下)
Cla1Regs.MVECT1 = (uint16_t)(&Cla1Task1); // 初始化CLA任务中断向量.
Cla1Regs.MVECT2 = (uint16_t)(&Cla1Task2);
Cla1Regs.MVECT3 = (uint16_t)(&Cla1Task3);
Cla1Regs.MVECT4 = (uint16_t)(&Cla1Task4);
Cla1Regs.MVECT5 = (uint16_t)(&Cla1Task5);
Cla1Regs.MVECT6 = (uint16_t)(&Cla1Task6);
Cla1Regs.MVECT7 = (uint16_t)(&Cla1Task7);
Cla1Regs.MVECT8 = (uint16_t)(&Cla1Task8);
Cla1Regs.MCTL.bit.IACKE = 1; // 使能中断响应信号.对应于全部八个任务.
Cla1Regs.MIER.all = (M_INT8 | M_INT7); // 使用任务中断7、8.
PieVectTable.CLA1_1_INT = &cla1Isr1; // 初始化中断向量表. //
取中断向量的地址.放入CPU中断向量表中。
PieVectTable.CLA1_2_INT = &cla1Isr2;
PieVectTable.CLA1_3_INT = &cla1Isr3;
PieVectTable.CLA1_4_INT = &cla1Isr4;
PieVectTable.CLA1_5_INT = &cla1Isr5;
PieVectTable.CLA1_6_INT = &cla1Isr6;
PieVectTable.CLA1_7_INT = &cla1Isr7;
PieVectTable.CLA1_8_INT = &cla1Isr8; // 给中断向量表对应CLA的任务中断取中断函数的地址。F28379D的CLA中断都在Group11里面。
PieCtrlRegs.PIEIER11.all = 0xFFFF; // 使能group 11 中断组. // 选定中断源.
IER
|= (M_INT11 ); // 配置CPU的PIE第十一组中断。
每个任务都有特定的中断源去触发CLA,比如说ADC的ADCINT1(ADC一共有四个中断送进PIE外设中断扩展模块),和PWM的EPWM_1,这是外设中断的硬件触发CLA中断,
可以使用DMA跨过优先级直接强制触发选定的任务,比如强制触发任务7:
DmaClaSrcSelRegs.CLA1TASKSRCSEL2.bit.TASK7 = 1; // DMA 触发 task7 中断源,向CPU请求指令.
关于在主函数里进入CLA中断进行相关运算的ClaxForceTaskxandWait()的函数,参看
“F2837xD_Cla_defines.h”文件,下面贴一个TI例程的简单除法运算:
void CLA_runTest(void)
{
int i, error;
for(i=0; i
3、初始化也就这样了,然后最关心的还是主函数的配置,前面的初始化系统步骤就不多说了,千篇一律(F28379x把狗给放了还是挺耐人寻味的):
void main(void)
{
InitSysCtrl();
CpuSysRegs.PCLKCR2.bit.EPWM1 = 1;
CpuSysRegs.PCLKCR2.bit.EPWM2 = 1;
InitEPwm1Gpio();
InitEPwm2Gpio(); // 使能对应的GPIO.
DINT;
// 关中断.
InitPieCtrl(); // 初始化中断控制寄存器.
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
// 初始化中断向量表.
CLA_configClaMemory(); // 配置运行所需内存区.
CLA_initCpu1Cla1(); // 初始化CPU1 与
CLA1的控制连接.
Cla1ForceTask8(); // 重点是这几句,要按顺序来。(这是强制进入TASK8)然后从Task8跳到Task7执行ADC的数据采集。
主函数开始之前一定要定义中断函数,先将中断任务的地址空间取好。
之后再始化你要操作的模块,比如说ADC,PWM:
ADC_initAdcA();
EPWM_initEpwm(); // 初始化PWM模块。
EINT;
ERTM;
// 初始化全局中断。
EALLOW;
CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;
EPwm1Regs.TBCTL.bit.CTRMODE = 0;
EPwm2Regs.TBCTL.bit.CTRMODE = 0;
EDIS;
4、压轴戏当然是中断的配置,其实不用把中断服务函数全部写上,例程只是做一个示范,单步调试的时候可以查看CLA任务中断的执行位置。
大概是这样:
__interrupt void cla1Isr1 () // isr1
{
//asm(" ESTOP0");
}
__interrupt void cla1Isr2 () // isr2
{
//asm(" ESTOP0");
}
__interrupt void cla1Isr3 () // isr3
{
//asm(" ESTOP0");
}
__interrupt void cla1Isr4 () // isr4
{
//asm(" ESTOP0");
}
__interrupt void cla1Isr5 () // isr5
{
//asm(" ESTOP0");
}
__interrupt void cla1Isr6 () // isr6
{
//asm(" ESTOP0");
}
__interrupt void cla1Isr7 () // isr7
{
// 关闭中断以及中断响应.
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //make sure INT1 flag is cleared
PieCtrlRegs.PIEACK.all = (PIEACK_GROUP1 | PIEACK_GROUP11);//响应PIE的第十一组中断。
AdcBuf[SampleCount] = AdcaResultRegs.ADCRESULT0; // ADC运算结果寄存器.
AdcFiltBuf[SampleCount] = voltFilt;
// 防止出现数据溢出的现象.
SampleCount++;
if( SampleCount == ADC_BUF_LEN )
{
SampleCount = 0;
}
}
__interrupt void cla1Isr8 () // isr8.
{
PieCtrlRegs.PIEACK.all = M_INT11;
}
每个中断可以用汇编写上中断调试点,没有太大的必要,如果要仔细DEBUG的话还是要加上的。
(五)CLA调试:
工欲善其事必先利其器,调不好CCS编译器自然要和CLA说拜拜,首先打开工程属性,在Processor Option里面把cla-support选定cla2,之后从controSuite里选定2837xD_FLASH_lnk_cpu1_far的cmd文件并且导入工程文件中(cmd文件必须要加,不然MSG RAM没有定义,bios里只是CLA的工作空间定义)。
至此CLA的基础配置部分基本就差不多了,之后就是一个头文件cla.h,可以和bsp.h写在一起,声明一下MVECT用的ClaTaskx就行,基本上像这样:
__interrupt void Cla1Task1();
__interrupt void Cla1Task2();
__interrupt void Cla1Task3();
__interrupt void Cla1Task4();
__interrupt void Cla1Task5();
__interrupt void Cla1Task6();
__interrupt void Cla1Task7();
__interrupt void Cla1Task8();
最后,将下面这些汇编(最好用汇编写CLA,我是没看懂)写成.asm文件import进工程文件里(工程里直接创建也行),大概是将ClaTaskx在CLA里面配置好。其实CLA是
只支持汇编编程的。
.cdecls
C, LIST, “cla_adc_fir32_shared.h”
CLA_DEBUG
.set
1
.sect
“Cla1Prog”
_Cla1Prog_Start
.align
2
_Cla1Task1:
MSTOP
MNOP
MNOP
MNOP
_Cla1T1End:
_Cla1Task2:
MSTOP
MNOP
MNOP
MNOP
_Cla1T2End:
_Cla1Task3:
MSTOP
MNOP
MNOP
MNOP
_Cla1T3End:
_Cla1Task4:
MSTOP
MNOP
MNOP
MNOP
_Cla1T4End:
_Cla1Task5:
MSTOP
MNOP
MNOP
MNOP
_Cla1T5End:
_Cla1Task6:
MSTOP
MNOP
MNOP
MNOP
_Cla1T6End:
_Cla1Task7:
.if CLA_DEBUG == 1
MDEBUGSTOP
.endif
_X4 .set _X+8
_X3 .set _X+6
_X2 .set _X+4
_X1 .set _X+2
_X0 .set _X+0
_A4 .set _A+8
_A3 .set _A+6
_A2 .set _A+4
_A1 .set _A+2
_A0 .set _A+0
;
MMOV32
MR0,@_X4 ;1 Load MR0 with X4
MMOV32
MR1,@_A4 ;2 Load MR1 with A4
MNOP ;3 Wait till I8 to read result
MNOP ;4 Wait till I8 to read result
MNOP ;5 Wait till I8 to read result
MNOP ;6 Wait till I8 to read result
MNOP ;7 Wait till I8 to read result
MUI16TOF32 MR2,
@_AdcaResultRegs.ADCRESULT0 ;8 Read ADCRESULT0 and convert to
float
MMPYF32
MR2, MR1, MR0 ; MR2 (Y) = MR1 (A4) * MR0 (X4)
|| MMOV32 @_X0, MR2
MMOVD32
MR0,@_X3 ; Load MR0 with X3, Load X4 with
X3
MMOV32
MR1,@_A3 ; Load MR1 with A3
MMPYF32
MR3, MR1, MR0 ; MR3 (Y) = MR1 (A3) * MR0 (X3)
|| MMOV32 MR1,@_A2 ; Load MR1 with A2
MMOVD32
MR0,@_X2 ; Load MR0 with X2, Load X3 with
X2
MMACF32
MR3, MR2, MR2, MR1, MR0 ; MR3 = A3X3 + A4X4
|| MMOV32 MR1,@_A1 ; MR2 = MR1 (A2) * MR0
(X2)
MMOVD32
MR0,@_X1 ; Load MR0 with X1, Load X2 with
X1
MMACF32
MR3, MR2, MR2, MR1, MR0 ; MR3 = A2X2 + (A3X3 + A4*X4)
|| MMOV32 MR1,@_A0 ; MR2 = MR1 (A1) * MR0
(X1)
MMOVD32
MR0,@_X0 ; Load MR0 with X0, Load X1 with
X0
MMACF32
MR3, MR2, MR2, MR1, MR0 ; MR3 = A1X1 + (A2X2 +A3X3 +
A4X4)
|| MMOV32 MR1,@_A0 ; MR2 = MR1 (A0) * MR0
(X0)
MADDF32
MR3, MR3, MR2 ; MR3 = A0X0 + (A1X1 + A2X2
+A3X3 + A4*X4)
MF32TOUI16 MR2, MR3 ; Get back to Uint16 value
MMOV16
@_voltFilt, MR2 ; Output
MSTOP ; End task
_Cla1T7End:
_Cla1Task8:
.if CLA_DEBUG == 1
MDEBUGSTOP
.endif
MMOVIZ MR0, #0.0
MUI16TOF32 MR0,
MR0
MMOV32
@_X0, MR0
MMOV32
@_X1, MR0
MMOV32
@_X2, MR0
MMOV32
@_X3, MR0
MMOV32
@_X4, MR0
MSTOP
_Cla1T8End:
_Cla1Prog_End:
.end
(六)结语
CLA作为一个CPU运算加速器,和AD,PWM处理器,如果不是面向及其精确的电机控制和对CPU要求极高的大型运算,其实没有太大的必要去研究、开发它,以上只是个人的一点浅见,缺乏真正的实践操作去验证。之后,关于CLA单独编译,直接烧写整个工程就行,运行一下然后暂停,连接上CLA模块,之后就可以在右边的变量观察窗里查看不同寄存器的值。