CLA特征:
1、与主CPU采用相同的系统时钟
2、单独的架构,具备独立的数据和程序总线;
3、支持最多8个任务或中断,其中任务1优先级最高;
4、可以直接访问PWM、ADC等寄存器,注意28035 CLA0 无法访问 GPIO
故无法通过控制GPIO翻转来通过示波器读取运行时间,但是可以通过配置PWM来输出来查看程序运行时间;
CLA 三代
CLA0 28035 无法访问GPIO 无法直接断点调试,需要通过软件来调试
CLA1 280379 可实现GPIO的直接访问
CLA2 280049 可以直接断点调试
CLA结构图:
从结构介图可以看到,035外围中断ADC1~8、PWM1~7 、定时器0中断都可以作为激发CLA任务的中断源,同时CLA产生的中断1~8又能激发对应中断INT1~2反馈到主中断;
CPU在实际运行过程中是无法直接访问CLA的数据内存的,调试模式下可以访问。所以这里安排了一段通讯数据内存:
CLA to CPU CLA可对该片内存区域可读可写,CPU只能进行读取
CPU to CLA CPU可对该片内存区域可读可写,CLA只能进行读取
所以实际运用中,比如采样完成后,可能要计算一些变量的有效值什么的,就可以在主CPU中进行和累加,将和变量定义到CPU to CLA区域,CLA就可以读取该变量进行开根号的运算(sqrt);
CLA的专门的RAM区,在进行映射后,CPU是无法进行访问修改的。
这里有三个功能位:
Cla1Regs.MMEMCFG.bit.PROGE = 1; // 程序空间映射
asm(" RPT #3 || NOP");
Cla1Regs.MMEMCFG.bit.RAM0E = 1; // 数据1空间映射
asm(" RPT #3 || NOP");
Cla1Regs.MMEMCFG.bit.RAM1E = 1; // 数据2空间映射
asm(" RPT #3 || NOP");
一旦执行这样的配置后,不管是CLA的程序空间,还是数据空间,CPU都无法进行访问设置了。可以理解为这片区域为CLA独有,这部分数据在CLA中进行使用,然后需要传到主cpu的数据通过通讯变量(定义在cpu to cla ,cla to cpu中的变量)来传递数据。
因此开启CLA功能后,定义变量时,我们单独设定一个 cla_shared_data.c 和 对应cla_shared_data.h 文件来 定义相关变量。比如说:
cla_shared_data.c 变量定义内容:
#pragma DATA_SECTION(fVal,"Cla1DataRam0"); // Cla1DataRam1
//Task 1 (C) Variables 通讯区间
// CPU to CLA cpu可读可写
#pragma DATA_SECTION(test_paras,"CpuToCla1MsgRAM"); //
float test_paras[10] = {0};
// CLA to CPU cla可读可写
#pragma DATA_SECTION(test_paras1,"Cla1ToCpuMsgRAM");
float test_paras1[10] = {0}; //Estimated result
cla_shared_data.h 中则对这些变量进行外部声明;
注意:
如果直接在.cla 文件中定义 全局变量,这里实际编译后发现,变量倍分配到cla的数据空间,所以该变量是无法被主cpu利用的,只能被cla调用。
CLA配置中有这么一个位:MSTF寄存器的RND32,这个位配置CLA浮点计算的舍入模式;
当配置为0时,就会在一些运算时直接截断到零,导致截断误差;
当配置为1时,将四舍五入到最接近的偶数值。
网上推荐将该位配置为1进行实验;我实际进行了测试,实际更改bit位发现截断效果几乎没差别。截断误差差不多可以忽略不计。担心截断的话,多项式复合计算时,就分步计算吧。
CLA支持软件强制任务触发,这里有个寄存器配置位:
//使能软件强制
Cla1Regs.MCTL.bit.IACKE = 1;
该位使能后可以直接通过 下列的宏定义函数直接强制开启一次任务;
#define Cla1ForceTask1() __asm(" IACK #0x0001")
#define Cla1ForceTask2() __asm(" IACK #0x0002")
#define Cla1ForceTask3() __asm(" IACK #0x0004")
#define Cla1ForceTask4() __asm(" IACK #0x0008")
#define Cla1ForceTask5() __asm(" IACK #0x0010")
#define Cla1ForceTask6() __asm(" IACK #0x0020")
#define Cla1ForceTask7() __asm(" IACK #0x0040")
#define Cla1ForceTask8() __asm(" IACK #0x0080")
这样子编程的话,灵活性就很强了。
CLA的库使用
如果你下载了TI的controlsuit 那么你可去里面 math/lib库里面找到CLAmath的库文件和头文件。
CLAmath.h
CLAmath.lib
添加两个文件后,就可以直接使用库了支持,除法,开根号,三角运算等。
在网上看到,可能CLA不支持浮点除法的,具体c语言除法是可以运行的,可能就是像定点核上进行浮点运算一样,特别慢,具体时间我没去测试,所以你干脆就直接调用这个CLA的math库吧。当然你调用库的时候,需要将对应库里面的查询table要映射到对应ram区域
MemCopy(&Cla1mathTablesLoadStart, &Cla1mathTablesLoadEnd, &Cla1mathTablesRunStart);
asm(" RPT #3 || NOP");
这个TI里面有对应例程的,可以参考下他的CMD配置。
官方的CMD配置内存分配有点乱,你可以按照自己的需求进行CMD配置。
CLA初始化是很简单的,这里提供下代码以供参考:
大概就是,先配置好任务或中断指针,然后就是选择中断源,然后做程序空间映射数据空间映射和拷贝,最后使能任务,一般使能软件强制任务发生功能(有中断源就不不需要开启了)。
void cla_init(void) // CLA的初始化函数
{
EALLOW; // 寄存器受保护需要使用EALLOW
//中断向量表设置,需要使用多少个TASK就要填入多少个,1-8都写完也没问题
Cla1Regs.MVECT1 = (Uint16)((Uint32)&Cla1Task1 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT2 = (Uint16)((Uint32)&Cla1Task2 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT3 = (Uint16)((Uint32)&Cla1Task3 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT4 = (Uint16)((Uint32)&Cla1Task4 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT5 = (Uint16)((Uint32)&Cla1Task5 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT6 = (Uint16)((Uint32)&Cla1Task6 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT7 = (Uint16)((Uint32)&Cla1Task7 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT8 = (Uint16)((Uint32)&Cla1Task8 - (Uint32)&Cla1Prog_Start);
//中断源设置,这里未配置中断源,通过软件进行触发进入
Cla1Regs.MPISRCSEL1.bit.PERINT1SEL = CLA_INT1_NONE;
Cla1Regs.MPISRCSEL1.bit.PERINT2SEL = CLA_INT2_NONE;
Cla1Regs.MPISRCSEL1.bit.PERINT3SEL = CLA_INT3_NONE;
Cla1Regs.MPISRCSEL1.bit.PERINT4SEL = CLA_INT4_NONE;
Cla1Regs.MPISRCSEL1.bit.PERINT5SEL = CLA_INT5_NONE;
Cla1Regs.MPISRCSEL1.bit.PERINT6SEL = CLA_INT6_NONE;
Cla1Regs.MPISRCSEL1.bit.PERINT7SEL = CLA_INT7_NONE;
Cla1Regs.MPISRCSEL1.bit.PERINT8SEL = CLA_INT8_NONE;
Cla1Regs._MSTF.bit.RNDF32 = 0; // 舍入方式配置
//拷贝CLA程序
//Copy over the CLA code and Tables
MemCopy(&Cla1funcsLoadStart, &Cla1funcsLoadEnd, &Cla1funcsRunStart);
asm(" RPT #3 || NOP");
MemCopy(&Cla1mathTablesLoadStart, &Cla1mathTablesLoadEnd, &Cla1mathTablesRunStart);
asm(" RPT #3 || NOP");
Cla1Regs.MMEMCFG.bit.PROGE = 1; // 程序空间映射
asm(" RPT #3 || NOP");
Cla1Regs.MMEMCFG.bit.RAM0E = 1; // 数据1空间映射
asm(" RPT #3 || NOP");
Cla1Regs.MMEMCFG.bit.RAM1E = 1; // 数据2空间映射
asm(" RPT #3 || NOP");
//使能6个TASK
Cla1Regs.MIER.bit.INT1 = 1; // 使能任务1
Cla1Regs.MIER.bit.INT2 = 1; // 使能任务2
Cla1Regs.MIER.bit.INT3 = 0;
Cla1Regs.MIER.bit.INT4 = 0;
Cla1Regs.MIER.bit.INT5 = 0;
Cla1Regs.MIER.bit.INT6 = 0;
Cla1Regs.MIER.bit.INT7 = 0;
Cla1Regs.MIER.bit.INT8 = 0;
//使能软件中断
Cla1Regs.MCTL.bit.IACKE = 1;
EDIS;
}
这里建议,在执行Memcopy后,还是延时几个机械周期。
CLA的仿真调试
仿真调试,这里步骤:
1、debug将程序下载进去,先不要直接点运行;
2、下载后,切换到view - debug 界面 ,选择 CLA0 核 右击鼠标进行链接操作
3、链接后,点击 load - load symbol (不是 load program) 选择对应。out文件下载
4、先别点击运行,你需要在 debug界面,先鼠标左键点击 切换到 主核,然后再点击仿真执行按钮
5、执行后将会在 _mdebugstop(); 语句处停下,这样子你就可以单步执行程序了。
这里要注意的是,CLA调试下,代码的单步执行时间,是无法进行观察的。所以你仍然需要配置pwm来观察程序运行时间。
CLA调试下,只能执行单步调试,无法直接跳过函数执行,就是遇到函数的时候,必然会跳进去函数内部执行单条语句,如果你使用了CLAmath库,这个时候,你的软件配置里面必须包含对应库函数的源函数文件,否则将会报错,找不到对应文件。这个源文件在controlsuit 里面有提供,直接添加对应路径即可。
CLA大概使用流程就是这样。有什么错误的地方欢迎指正。