CLA的相关介绍请看上篇 here
CLA使用C语言编程的配置
cmd文件部分
/**********需要定义的变量*************/
CLA_SCRATCHPAD_SIZE = 0x100;
_Cla1Prog_Start = _Cla1funcsRunStart; //cla 程序的起始地址定义
--undef_sym=__cla_scratchpad_end
--undef_sym=__cla_scratchpad_start
/*********************************/
MEMORY
{
PAGE 0 : /* Program Memory */
/* Memory (RAM/FLASH/OTP) blocks can be moved to PAGE1 for data allocation */
RAML0 : origin = 0x008000, length = 0x000800 /* on-chip RAM block L0 */
//RAML1 : origin = 0x008800, length = 0x000400 /* on-chip RAM block L1 */
RAML3 : origin = 0x009000, length = 0x001000 /* on-chip RAM block L3 */
OTP : origin = 0x3D7800, length = 0x000400 /* on-chip OTP */
FLASHH : origin = 0x3D8000, length = 0x004000 /* on-chip FLASH */
FLASHG : origin = 0x3DC000, length = 0x004000 /* on-chip FLASH */
FLASHF : origin = 0x3E0000, length = 0x004000 /* on-chip FLASH */
FLASHE : origin = 0x3E4000, length = 0x004000 /* on-chip FLASH */
FLASHD : origin = 0x3E8000, length = 0x004000 /* on-chip FLASH */
// FLASHC : origin = 0x3EC000, length = 0x004000 /* on-chip FLASH */
FLASHA_B : origin = 0x3F0000, length = 0x007F80 /* on-chip FLASH */
CSM_RSVD : origin = 0x3F7F80, length = 0x000076 /* Part of FLASHA. Program with all 0x0000 when CSM is in use. */
BEGIN : origin = 0x3F7FF6, length = 0x000002 /* Part of FLASHA. Used for "boot to Flash" bootloader mode. */
CSM_PWL_P0 : origin = 0x3F7FF8, length = 0x000008 /* Part of FLASHA. CSM password locations in FLASHA */
FPUTABLES : origin = 0x3FD590, length = 0x0006A0 /* FPU Tables in Boot ROM */
IQTABLES : origin = 0x3FDC30, length = 0x000B50 /* IQ Math Tables in Boot ROM */
IQTABLES2 : origin = 0x3FE780, length = 0x00008C /* IQ Math Tables in Boot ROM */
IQTABLES3 : origin = 0x3FE80C, length = 0x0000AA /* IQ Math Tables in Boot ROM */
ROM : origin = 0x3FF3B0, length = 0x000C10 /* Boot ROM */
RESET : origin = 0x3FFFC0, length = 0x000002 /* part of boot ROM */
VECTORS : origin = 0x3FFFC2, length = 0x00003E /* part of boot ROM */
PAGE 1 : /* Data Memory */
/* Memory (RAM/FLASH/OTP) blocks can be moved to PAGE0 for program allocation */
/* Registers remain on PAGE1 */
BOOT_RSVD : origin = 0x000000, length = 0x000050 /* Part of M0, BOOT rom will use this for stack */
RAMM0 : origin = 0x000050, length = 0x0003B0 /* on-chip RAM block M0 */
RAMM1 : origin = 0x000400, length = 0x000400 /* on-chip RAM block M1 */
RAML1 : origin = 0x008800, length = 0x000400 /* on-chip RAM block L1 */
RAML2 : origin = 0x008C00, length = 0x000400 /* on-chip RAM block L2 */
RAML4 : origin = 0x00A000, length = 0x002000 /* on-chip RAM block L4 */
RAML5 : origin = 0x00C000, length = 0x002000 /* on-chip RAM block L5 */
RAML6 : origin = 0x00E000, length = 0x002000 /* on-chip RAM block L6 */
RAML7 : origin = 0x010000, length = 0x002000 /* on-chip RAM block L7 */
RAML8 : origin = 0x012000, length = 0x001800 /* on-chip RAM block L8 */
USB_RAM : origin = 0x040000, length = 0x000800 /* USB RAM */
FLASHC : origin = 0x3EC000, length = 0x004000 /* on-chip FLASH */
CLATOCPU_MSGRAM :origin = 0x001480, length = 0x000080
CPUTOCLA_MSGRAM :origin = 0x001500, length = 0x000080
}
/* Allocate sections to memory blocks.
Note:
codestart user defined section in DSP28_CodeStartBranch.asm used to redirect code
execution when booting to flash
ramfuncs user defined section to store functions that will be copied from Flash into RAM
*/
SECTIONS
{
/* Allocate program areas: */
.cinit : > FLASHA_B, PAGE = 0
.pinit : > FLASHA_B, PAGE = 0
.text : > FLASHA_B, PAGE = 0
codestart : > BEGIN, PAGE = 0
ramfuncs : LOAD = FLASHD,
RUN = RAML0,
LOAD_START(_RamfuncsLoadStart),
LOAD_END(_RamfuncsLoadEnd),
RUN_START(_RamfuncsRunStart),
LOAD_SIZE(_RamfuncsLoadSize),
PAGE = 0
csmpasswds : > CSM_PWL_P0, PAGE = 0
csm_rsvd : > CSM_RSVD, PAGE = 0
/* Allocate uninitalized data sections: */
.stack : > RAMM0, PAGE = 1
.ebss : > RAML2, PAGE = 1
.esysmem : > RAML2, PAGE = 1
/* Initalized sections to go in Flash */
/* For SDFlash to program these, they must be allocated to page 0 */
.econst : > FLASHA_B, PAGE = 0
.switch : > FLASHA_B, PAGE = 0
/* Allocate IQ math areas: */
IQmath : > FLASHA_B, PAGE = 0 /* Math Code */
IQmathTables : > IQTABLES, PAGE = 0, TYPE = NOLOAD
/* Allocate FPU math areas: */
FPUmathTables : > FPUTABLES, PAGE = 0, TYPE = NOLOAD
DMARAML5 : > RAML5, PAGE = 1
DMARAML6 : > RAML6, PAGE = 1
DMARAML7 : > RAML7, PAGE = 1
DMARAML8 : > RAML8, PAGE = 1
Cla1Prog : LOAD = FLASHE,
RUN = RAML3,
LOAD_START(_Cla1funcsLoadStart),
LOAD_END(_Cla1funcsLoadEnd),
RUN_START(_Cla1funcsRunStart),
LOAD_SIZE(_Cla1funcsLoadSize),
PAGE = 0
Cla1ToCpuMsgRAM : > CLATOCPU_MSGRAM, PAGE = 1
CpuToCla1MsgRAM : > CPUTOCLA_MSGRAM, PAGE = 1
/*CLAscratch作用:
当使用v6.1及以上的编译器时,CLA的代码可以使用C语言,
由于不是汇编,它需要有类似于多余的区间用于存放局部变量等,
你可以理解它为暂存器或者C里的堆栈。如果使用汇编写CLA的代码,则可以忽略。
选择使用在RAML1区中作为CLA的使用内存,需要在C文件配置RAML1映射给CLA。
*/
CLAscratch :
{ *.obj(CLAscratch)
. += CLA_SCRATCHPAD_SIZE;
*.obj(CLAscratch_end) } > RAML1, PAGE = 1
/* Uncomment the section below if calling the IQNexp() or IQexp()
functions from the IQMath.lib library in order to utilize the
relevant IQ Math table in Boot ROM (This saves space and Boot ROM
is 1 wait-state). If this section is not uncommented, IQmathTables2
will be loaded into other memory (SARAM, Flash, etc.) and will take
up space, but 0 wait-state is possible.
*/
/*
IQmathTables2 : > IQTABLES2, PAGE = 0, TYPE = NOLOAD
{
IQmath.lib<IQNexpTable.obj> (IQmathTablesRam)
}
*/
/* Uncomment the section below if calling the IQNasin() or IQasin()
functions from the IQMath.lib library in order to utilize the
relevant IQ Math table in Boot ROM (This saves space and Boot ROM
is 1 wait-state). If this section is not uncommented, IQmathTables2
will be loaded into other memory (SARAM, Flash, etc.) and will take
up space, but 0 wait-state is possible.
*/
/*
IQmathTables3 : > IQTABLES3, PAGE = 0, TYPE = NOLOAD
{
IQmath.lib<IQNasinTable.obj> (IQmathTablesRam)
}
*/
/* .reset is a standard section used by the compiler. It contains the */
/* the address of the start of _c_int00 for C Code. /*
/* When using the boot ROM this section and the CPU vector */
/* table is not needed. Thus the default type is set here to */
/* DSECT */
.reset : > RESET, PAGE = 0, TYPE = DSECT
vectors : > VECTORS, PAGE = 0, TYPE = DSECT
}
/*
//===========================================================================
// End of file.
//===========================================================================
*/
cmd的重点修改地方如下:
CLAShared.h
#ifndef CLA_SHARED_H
#define CLA_SHARED_H
#ifdef __cplusplus
extern "C" {
#endif
//
// Included Files
//
// #include "IQmathLib.h"
#include "DSP28x_Project.h"
//
// Defines
//
#define DS_CLA_DEBUG 1 //需要要调试时置1
extern Uint16 VoltFilt; //在main.c中有定义
extern Uint16 GOTO_CLA[3]; //在main.c中有定义
extern float32 ClaVal; //在main.c中有定义
//
// The following are symbols defined in the CLA assembly code
// Including them in the shared header file makes them
// .global and the main CPU can make use of them.
//
extern Uint16 Cla1Prog_Start; //cla 程序的起始地址
__interrupt void Cla1Task1();
__interrupt void Cla1Task2();
__interrupt void Cla1Task3();
__interrupt void Cla1Task4();
__interrupt void Cla1Task5();
__interrupt void Cla1Task6();
__interrupt void Cla1Task7();
__interrupt void Cla1Task8();
#ifdef __cplusplus
}
#endif /* extern "C" */
#endif // end of CLA_SHARED definition
//
// End of File
//
main.c,里面的ADC模块,ePWM模块请看上一篇介绍。
#include "DSP28x_Project.h"
#include "Usart.h"
#include <stdio.h>
#include "ADC.h"
#include "ePWM.h"
#include "CLAShared.h"
#include <string.h>
/**
* main.c
**/
#pragma DATA_SECTION(VoltFilt, "Cla1ToCpuMsgRAM");
#pragma DATA_SECTION(ClaVal, "Cla1ToCpuMsgRAM");
Uint16 VoltFilt;
#pragma DATA_SECTION(GOTO_CLA, "Cla1ToCpuMsgRAM");
Uint16 GOTO_CLA[3];
float32 ClaVal;
extern Uint16 Cla1funcsLoadStart;
extern Uint16 Cla1funcsLoadEnd;
extern Uint16 Cla1funcsRunStart;
extern Uint16 Cla1funcsLoadSize;
void init_cla(void);//cla初始化函数
interrupt void cla1_isr1(void);//cla 任务1完成后在C28x CPU中触发的中断服务函数
int main(void)
{
InitSysCtrl();
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
init_cla();
Usart_Init(9600); //此函数需要各位自己写
//adc
ADC_Init();
InitAdcConfigAndIO();
#if Interrupt_Allow == 1
OpenAdcInterrupt_PIE();
#endif
ePWM_init();
msg="Hello,CLA TEST!\r\n\0";
UARTa_SendString(msg);
GetChResult(1,9,5);//5-epwm1a SOCa 触发
while(1);
}
void init_cla(void)
{
EALLOW;
//在PCLKCR3寄存器中使能CLA时钟,一般这句话不用写,因为在InitSysCtrl();函数中就已经配置了所有外设的时钟;
SysCtrlRegs.PCLKCR3.bit.CLA1ENCLK=1;
//将CLA的TASK函数绑定到中断向量表上
Cla1Regs.MVECT1 = (Uint16)((Uint32)&Cla1Task1 -(Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT8 = (Uint16)((Uint32)&Cla1Task8 -(Uint32)&Cla1Prog_Start);
//设置每个TASK的触发源,有三种选项,PWM触发、ADC触发以及软件触发
Cla1Regs.MPISRCSEL1.bit.PERINT1SEL=CLA_INT1_ADCINT1;//ADCINT1触发任务1
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;
//将CLA代码拷贝入CLA的代码段,因为CLA的代码需要单独放在一个固定的位置,所以需要执行这一段代码
memcpy(&Cla1funcsRunStart, &Cla1funcsLoadStart, (Uint32)&Cla1funcsLoadSize);
//如果需要使用到软件触发,那么需要执行Cla1Regs.MCTL.bit.IACKE = 1;
Cla1Regs.MCTL.bit.IACKE = 1;//使能软件中断
Cla1Regs.MIER.all = (M_INT1 | M_INT8);//使能2个任务中断
//将CLA的数据段和程序段都映射到CLA空间
Cla1Regs.MMEMCFG.bit.PROGE = 1;//把RAML3映射为CLA的程序空间
Cla1Regs.MMEMCFG.bit.RAM1CPUE=0;//RAML1区,CPU不允许读写
Cla1Regs.MMEMCFG.bit.RAM1E=1;//RAML1区,CLA允许读写
// Enable INT 11.1 in the PIE (CLA Task1)
// Enable INT 11 at the CPU level
// Enable Global interrupts with INTM
// Enable Global realtime interrupts with DBGM
//
EALLOW;
PieVectTable.CLA1_INT1 = &cla1_isr1; //自定义中断函数
EDIS;
PieCtrlRegs.PIEIER11.bit.INTx1 = 1;
IER |= M_INT11;
EINT;
ERTM;
//触发TASK8
Cla1ForceTask8();
}
interrupt void cla1_isr1(void)
{
char NUMCHAR_[64];
AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;//Must clear ADCINT1 flag since INT1CONT = 0
PieCtrlRegs.PIEACK.all = 0xFFFF;
/*串口打印数据*/
sprintf(NUMCHAR_,"CLA TEST: sample time: %d;cla_val:%f V.\r\n",(Uint16)VoltFilt,ClaVal);
UARTa_SendString(NUMCHAR_);
sprintf(NUMCHAR_,"CLA ePWM2 TBPHS: %d.\r\n",EPwm2Regs.TBPHS.half.TBPHS);
UARTa_SendString(NUMCHAR_);
sprintf(NUMCHAR_,"CLA info: %c %c %c.\r\n",GOTO_CLA[0],GOTO_CLA[1],GOTO_CLA[2]);
UARTa_SendString(NUMCHAR_);
}
CLA_Task.cla,在此文件编写CLA的程序,注意保存文件后缀为cla
/*
* CLA_Task.cla
*
* Created on: 2023年3月6日
* Author: chends
*/
#include "DSP28x_Project.h"
#include "CLAShared.h" //直接引用
//#include XSTRINGIZE(XCONCAT(TEXT,CLAShared.h)) //如果使用此方法,注释上一行。此方法是链接到头文件CLAShared.h,TEXT需要在工程属性里面定义。
__interrupt void
Cla1Task1(void) //任务1
{
float phaseVal;
#if DS_CLA_DEBUG ==1
__mdebugstop(); //调试的断点
#endif
VoltFilt +=1; //计数进入Task1的次数
//计算ADC采样结果
ClaVal=AdcResult.ADCRESULT0;
ClaVal +=AdcResult.ADCRESULT1;
ClaVal +=AdcResult.ADCRESULT2;
ClaVal +=AdcResult.ADCRESULT3;
ClaVal +=AdcResult.ADCRESULT4;
ClaVal +=AdcResult.ADCRESULT5;
ClaVal +=AdcResult.ADCRESULT6;
ClaVal +=AdcResult.ADCRESULT7;
ClaVal +=AdcResult.ADCRESULT8;
ClaVal +=AdcResult.ADCRESULT9;
ClaVal +=AdcResult.ADCRESULT10;
ClaVal +=AdcResult.ADCRESULT11;
ClaVal +=AdcResult.ADCRESULT12;
ClaVal +=AdcResult.ADCRESULT13;
ClaVal +=AdcResult.ADCRESULT14;
ClaVal +=AdcResult.ADCRESULT15;
ClaVal /=16;
ClaVal /=4096;
ClaVal *=3.3;
//计算PWM偏移的相位
phaseVal=ClaVal/3.3;
phaseVal = phaseVal*2500;
phaseVal = 2500-phaseVal;
EPwm2Regs.TBPHS.half.TBPHS = (Uint16)phaseVal;
//设置GOTO_CLA的值
if(VoltFilt>20){
GOTO_CLA[0]='C';
GOTO_CLA[1]='L';
GOTO_CLA[2]='A';
}
if(VoltFilt>50)
{
GOTO_CLA[0]='C'+VoltFilt-50;
GOTO_CLA[1]='L'+VoltFilt-50;
GOTO_CLA[2]='A'+VoltFilt-50;
}
}
__interrupt void
Cla1Task2 (void)
{
}
__interrupt void
Cla1Task3 (void)
{
}
__interrupt void
Cla1Task4 (void)
{
}
__interrupt void
Cla1Task5 (void)
{
}
__interrupt void
Cla1Task6 (void)
{
}
__interrupt void
Cla1Task7 (void)
{
}
__interrupt void
Cla1Task8 (void)
{
//任务8用于初始化参数值
VoltFilt=0;
GOTO_CLA[0]='i';
GOTO_CLA[1]='n';
GOTO_CLA[2]='t';
}
//
// End of File
//
- #include XSTRINGIZE(XCONCAT(TEXT,CLAShared.h)) 说明:
TEXT的定义如下,由于我的共享头文件名称就叫CLAShared.h,所以我直接把TEXT定义为空即可。如果你的文件名为demo_CLAShared.h的话,则需要设置 TEXT=demo,文件中写入#include XSTRINGIZE(XCONCAT(TEXT,_CLAShared.h))。这种方法好处是,可以在不修改源代码下,引入不同的头文件,只需要修改工程属性里的TEXT即可。
实验现象
- 串口打印的数据如下:
- PWM波形图如下:
- cla_val=3.3V
- cla_val=0V ~ 3.3V之间
- cla_val=0V
- cla_val=3.3V