DSP

CLA模块简略讲解

2019-07-13 17:53发布

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 +
A4
X4) || MMOV32 MR1,@_A0 ; MR2 = MR1 (A0) * MR0
(X0) MADDF32 MR3, MR3, MR2 ; MR3 = A0X0 + (A1X1 + A2X2
+A3
X3 + 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 +
A4
X4) || MMOV32 MR1,@_A0 ; MR2 = MR1 (A0) * MR0
(X0) MADDF32 MR3, MR3, MR2 ; MR3 = A0X0 + (A1X1 + A2X2
+A3
X3 + 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模块,之后就可以在右边的变量观察窗里查看不同寄存器的值。