首页 » 技术分享 » CLA模块简略讲解

CLA模块简略讲解

 

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<BUFFER_SIZE; i++)

{

     Num = (float)(BUFFER_SIZE - i);

     Den = (float)(BUFFER_SIZE + i);

     Cla1ForceTask1andWait();         // 从这里进入CLA中断进行数据处理

     y[i] = Res;

     error = fabs(div_expected[i]-y[i]);

     if (error < 0.01)

     {

        pass++;

     }

     else

     {

        fail++;

     }

}

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<BUFFER_SIZE; i++)

{

     Num = (float)(BUFFER_SIZE - i);

     Den = (float)(BUFFER_SIZE + i);

     Cla1ForceTask1andWait();         // 从这里进入CLA中断进行数据处理

     y[i] = Res;

     error = fabs(div_expected[i]-y[i]);

     if (error < 0.01)

     {

        pass++;

     }

     else

     {

        fail++;

     }

}

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模块,之后就可以在右边的变量观察窗里查看不同寄存器的值。

转载自原文链接, 如需删除请联系管理员。

原文链接:CLA模块简略讲解,转载请注明来源!

0