目录

0.写在前面

1.CLA介绍

2.CLA使用前提

3. 初始化程序

4.内存管理

4.1 RAM运行

4.2 FLASH运行

5. 运行程序

5.库文件

6.最后移植完成后的文件

7. 最后效果


0.写在前面

CLA的整个移植过程非常复杂,如果对于初学者可以从下往上看,先能移植起来再看原理

好多人都在要这份工程,我的工程都开源在gitee上了,链接在下面,如果需要可以自取。如果链接失效等问题可以评论区里告诉我,加油。

TMS320F28377D_AloneCPU_CodeLearn: TMS320F2877D单核程序开发 (gitee.com)

1.CLA介绍

CLA是什么呢?网上有很多说法,什么什么规律加速器,一堆名词着实头疼。其实很简单,在使用DSP的时候,总会有大量的计算,从简单的加减乘除,到正弦,到快速傅里叶,滤波器等都会要计算。此时,如果用CPU就不能操控其他外设了,在这种情况下就可以用CLA了。CLA你可以理解成DSP中专门用于计算的模块,正因如此,CLA不能初始化模块,配置模块,相反在计算是CLA的专场。如果读者用过cortex-M4内核的芯片就知道M4内核的芯片有对DSP库的支持,在DSP里CLA就如同MCU中DSP的作用,是专门用于计算的模块。

2.CLA使用前提

首先在开始前你要对TI的CMD的文件,如果读者是首次接触或是像我一样是STM32开发者转DSP的话,要有一个准备去写CMD文件,那么什么是CMD文件呢?假设芯片内的存储是一个仓库,那么你就是仓库管理员,你需要对仓库的每一部分都很熟悉,哪些地方是可以堆放“危险品”的,哪些地方可以堆放“长期滞留”品的,在STM32中几乎很少会考虑到这些内容,但是在使用DSP的东西是难以避免的。

705c24de1d1e435eae1b6cec66f6ab8d.png

上图是F28377D的内部存储器映射

可以看到有些区域是CLA可以访问,有些区域是DMA访问的所以在这种情况下你要对这些内存区域熟悉,并能合理的管理每一块区域。通过编写CMD文件合理地管理每一块区域。在CLA的使用中随时都需要你关注内存的情况。

3. 初始化程序

/*
 * CLA_init.c
 *
 *  Created on: 2023年5月1日
 *      Author: 18752
 */

#include "CLA_init.h"



#pragma DATA_SECTION(fVal,"CpuToCla1MsgRAM");
float fVal;
#pragma DATA_SECTION(fResult,"Cla1ToCpuMsgRAM");
float fResult;

#pragma DATA_SECTION(IOBuffer,"IOBuffer")
float IOBuffer[(256+1)*2] = {
    #include "ffttest.h"
};


//
// CLA_runTest - Execute CLA task tests for specified vectors
//
void CLA_runTest(unsigned char RTest)
{
    switch(RTest)
    {
        case 1: CLA_forceTasks(CLA1_BASE,CLA_TASKFLAG_1);   break;
        case 2: CLA_forceTasks(CLA1_BASE,CLA_TASKFLAG_2);   break;
    }
    WAITSTEP;
}

void CLA_init()
{
    EALLOW;

    CLA_DSP_initEpie();

    CLA_DSP_configClaMemory();

    CLA_DSP_initCpu1Cla1();

    EDIS;
}

void CLA_DSP_initEpie()
{
    Interrupt_initModule();
    Interrupt_initVectorTable();
}


void CLA_DSP_configClaMemory(void)
{
    extern uint32_t Cla1ProgRunStart, Cla1ProgLoadStart, Cla1ProgLoadSize;
    extern uint32_t CLA1fftTablesRunStart, CLA1fftTablesLoadStart, CLA1fftTablesLoadSize;

    EALLOW;

#ifdef _FLASH
    // Copy over code and tables from FLASH to RAM
    memcpy((uint32_t *)&Cla1ProgRunStart, (uint32_t *)&Cla1ProgLoadStart,
            (uint32_t)&Cla1ProgLoadSize);

    memcpy((uint32_t *)&CLA1fftTablesRunStart, (uint32_t *)&CLA1fftTablesLoadStart,
            (uint32_t)&CLA1fftTablesLoadSize);
#endif //_FLASH

    // Initialize and wait for CLA1ToCPUMsgRAM
    MemCfg_initSections(MEMCFG_SECT_MSGCLA1TOCPU);
    while (!MemCfg_getInitStatus(MEMCFG_SECT_MSGCLA1TOCPU)){};

    // Initialize and wait for CPUToCLA1MsgRAM
    MemCfg_initSections(MEMCFG_SECT_MSGCPUTOCLA1);
    while (!MemCfg_getInitStatus(MEMCFG_SECT_MSGCPUTOCLA1)){};

    // Select LS0-LS1RAM to be the programming space for the CLA
    // First configure the CLA to be the master for LS0 and then
    // set the space to be a program block
    MemCfg_setLSRAMMasterSel(MEMCFG_SECT_LS0,MEMCFG_LSRAMMASTER_CPU_CLA1);
    MemCfg_setCLAMemType(MEMCFG_SECT_LS0,MEMCFG_CLA_MEM_PROGRAM);
    MemCfg_setLSRAMMasterSel(MEMCFG_SECT_LS1,MEMCFG_LSRAMMASTER_CPU_CLA1);
    MemCfg_setCLAMemType(MEMCFG_SECT_LS1,MEMCFG_CLA_MEM_PROGRAM);

    //Next configure LS2-LS5RAM as data spaces for the CLA
    // First configure the CLA to be the master for LSx and then
    // set the spaces to be code blocks

    MemCfg_setLSRAMMasterSel(MEMCFG_SECT_LS2,MEMCFG_LSRAMMASTER_CPU_CLA1);
    MemCfg_setCLAMemType(MEMCFG_SECT_LS2, MEMCFG_CLA_MEM_DATA);

    MemCfg_setLSRAMMasterSel(MEMCFG_SECT_LS3,MEMCFG_LSRAMMASTER_CPU_CLA1);
    MemCfg_setCLAMemType(MEMCFG_SECT_LS3, MEMCFG_CLA_MEM_DATA);

    MemCfg_setLSRAMMasterSel(MEMCFG_SECT_LS4,MEMCFG_LSRAMMASTER_CPU_CLA1);
    MemCfg_setCLAMemType(MEMCFG_SECT_LS4, MEMCFG_CLA_MEM_DATA);

    MemCfg_setLSRAMMasterSel(MEMCFG_SECT_LS5,MEMCFG_LSRAMMASTER_CPU_CLA1);
    MemCfg_setCLAMemType(MEMCFG_SECT_LS5, MEMCFG_CLA_MEM_DATA);

}

void CLA_DSP_initCpu1Cla1(void)
{
    // Compute all CLA task vectors
    // On Type-1 CLAs the MVECT registers accept full 16-bit task addresses as
    // opposed to offsets used on older Type-0 CLAs

//
// Suppressing #770-D conversion from pointer to smaller integer
// The CLA address range is 16 bits so the addresses passed to the MVECT
// registers will be in the lower 64KW address space. Turn the warning
// back on after the MVECTs are assigned addresses
//
#pragma diag_suppress=770
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_1,(uint16_t)&Cla1Task1);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_2,(uint16_t)&Cla1Task2);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_3,(uint16_t)&Cla1Task3);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_4,(uint16_t)&Cla1Task4);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_5,(uint16_t)&Cla1Task5);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_6,(uint16_t)&Cla1Task6);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_7,(uint16_t)&Cla1Task7);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_8,(uint16_t)&Cla1Task8);

#pragma diag_warning=770

    // Enable IACK instruction to start a task on CLA in software
    // for all  8 CLA tasks

    CLA_enableIACK(CLA1_BASE);
    CLA_enableTasks(CLA1_BASE, CLA_TASKFLAG_ALL);

    // Configure the vectors for the end-of-task interrupt for all
    // 8 tasks

    Interrupt_register(INT_CLA1_1, &cla1Isr1);
    Interrupt_register(INT_CLA1_2, &cla1Isr2);
    Interrupt_register(INT_CLA1_3, &cla1Isr3);
    Interrupt_register(INT_CLA1_4, &cla1Isr4);
    Interrupt_register(INT_CLA1_5, &cla1Isr5);
    Interrupt_register(INT_CLA1_6, &cla1Isr6);
    Interrupt_register(INT_CLA1_7, &cla1Isr7);
    Interrupt_register(INT_CLA1_8, &cla1Isr8);
}

这是CLA的存储分配,没错程序里也要有。这是初始化部分,它管理着你内存是如何分配的,没有这部分CLA无法完成初始化。

void CLA_DSP_initEpie()
{
    Interrupt_initModule();
    Interrupt_initVectorTable();
}


void CLA_DSP_initCpu1Cla1(void)
{
    // Compute all CLA task vectors
    // On Type-1 CLAs the MVECT registers accept full 16-bit task addresses as
    // opposed to offsets used on older Type-0 CLAs

//
// Suppressing #770-D conversion from pointer to smaller integer
// The CLA address range is 16 bits so the addresses passed to the MVECT
// registers will be in the lower 64KW address space. Turn the warning
// back on after the MVECTs are assigned addresses
//
#pragma diag_suppress=770
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_1,(uint16_t)&Cla1Task1);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_2,(uint16_t)&Cla1Task2);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_3,(uint16_t)&Cla1Task3);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_4,(uint16_t)&Cla1Task4);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_5,(uint16_t)&Cla1Task5);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_6,(uint16_t)&Cla1Task6);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_7,(uint16_t)&Cla1Task7);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_8,(uint16_t)&Cla1Task8);

#pragma diag_warning=770

    // Enable IACK instruction to start a task on CLA in software
    // for all  8 CLA tasks

    CLA_enableIACK(CLA1_BASE);
    CLA_enableTasks(CLA1_BASE, CLA_TASKFLAG_ALL);

    // Configure the vectors for the end-of-task interrupt for all
    // 8 tasks

    Interrupt_register(INT_CLA1_1, &cla1Isr1);
    Interrupt_register(INT_CLA1_2, &cla1Isr2);
    Interrupt_register(INT_CLA1_3, &cla1Isr3);
    Interrupt_register(INT_CLA1_4, &cla1Isr4);
    Interrupt_register(INT_CLA1_5, &cla1Isr5);
    Interrupt_register(INT_CLA1_6, &cla1Isr6);
    Interrupt_register(INT_CLA1_7, &cla1Isr7);
    Interrupt_register(INT_CLA1_8, &cla1Isr8);
}

这是官方的程序,是对CLA中断之类的初始化

void CLA_init()
{
    EALLOW;

    CLA_DSP_initEpie();

    CLA_DSP_configClaMemory();

    CLA_DSP_initCpu1Cla1();

    EDIS;
}

总初始化

void CLA_runTest(unsigned char RTest)
{
    switch(RTest)
    {
        case 1: CLA_forceTasks(CLA1_BASE,CLA_TASKFLAG_1);   break;
        case 2: CLA_forceTasks(CLA1_BASE,CLA_TASKFLAG_2);   break;
    }
    WAITSTEP;
}

这是运行CLA程序,有点类似ADC软件触发一样

上述部分在官方的例程中都有,基本上只要无脑搬基本也没什么问题。

4.内存管理

关于CLA的内存分配问题上,我们主要关注点是LSx RAM内存区域,因为这个区域是CLA运行区域。

fc9bc54abf4d4bd08e512ce42bef3351.png

可以看到从LS0-LS5的区域CLA是可以存取的所有的CLA程序,运行中所产生的内容都会在这部分区域。除此之外还有一部分就是MSGRAM1和2就是第四行和第五行的内容,这部分内容是CPU与CLA的通信的“桥梁”,通过两个区域,CPU的数据可以转移到CLA内,同时CLA的内容也可以转移到CPU内。

4.1 RAM运行


CLA_SCRATCHPAD_SIZE = 0x100;
--undef_sym=__cla_scratchpad_end
--undef_sym=__cla_scratchpad_start

MEMORY
{
//一般用于存放代码
PAGE 0 :
	BEGIN				: origin = 0x000000, length = 0x000002

	RAMGS0      		: origin = 0x00C000, length = 0x001000
	RAMGS1      		: origin = 0x00D000, length = 0x001000
	RAMGS2      		: origin = 0x00E000, length = 0x001000
	RAMGS3      		: origin = 0x00F000, length = 0x001000
	RAMGS4      		: origin = 0x010000, length = 0x001000
	RAMGS5      		: origin = 0x011000, length = 0x001000


	RESET				: origin = 0x3FFFC0, length = 0x000002
	IQTABLES			: origin = 0x3FE000, length = 0x000B50     /* IQ Math Tables in Boot ROM */
	IQTABLES2			: origin = 0x3FEB50, length = 0x00008C
	IQTABLES3			: origin = 0x3FEBDC, length = 0x0000AA

	FLASHA				: origin = 0x080002, length = 0x001FFE   /* on-chip Flash */
	FLASHB				: origin = 0x082000, length = 0x002000   /* on-chip Flash */
	FLASHC				: origin = 0x084000, length = 0x002000   /* on-chip Flash */
	FLASHD				: origin = 0x086000, length = 0x002000   /* on-chip Flash */
	FLASHE				: origin = 0x088000, length = 0x008000   /* on-chip Flash */
	FLASHF				: origin = 0x090000, length = 0x008000   /* on-chip Flash */
	FLASHG				: origin = 0x098000, length = 0x008000   /* on-chip Flash */


//一般用于存放数据
PAGE 1 :
	BOOT_RSVD         	: origin = 0x000002, length = 0x00004E   /* Part of M0, BOOT rom will use this for stack */

	RAMM0             	: origin = 0x000050, length = 0x0003B0
	RAMM1             	: origin = 0x000400, length = 0x000400

	RAMD0            	: origin = 0x00B000, length = 0x000800
	RAMD1            	: origin = 0x00B800, length = 0x000800

	RAMGS6      		: origin = 0x012000, length = 0x001000
	RAMGS7      		: origin = 0x013000, length = 0x001000
	RAMGS8				: origin = 0x014000, length = 0x001000
	RAMGS9				: origin = 0x015000, length = 0x001000
	RAMGS10				: origin = 0x016000, length = 0x001000
	RAMGS11				: origin = 0x017000, length = 0x001000
	RAMGS12				: origin = 0x018000, length = 0x001000
	RAMGS13				: origin = 0x019000, length = 0x001000
	RAMGS14				: origin = 0x01A000, length = 0x001000
	RAMGS15				: origin = 0x01B000, length = 0x001000

	RAMLS0_1			: origin = 0x008000, length = 0x002000
	RAMLS2_3			: origin = 0x00A000, length = 0x000A00
	RAMLS4_5			: origin = 0x00AA00, length = 0x000600

	CLA1_MSGRAMLOW		: origin = 0x001480, length = 0x000080
	CLA1_MSGRAMHIGH		: origin = 0x001500, length = 0x000080

	CPU2TOCPU1RAM   	: origin = 0x03F800, length = 0x000400
	CPU1TOCPU2RAM   	: origin = 0x03FC00, length = 0x000400

	FLASHH				: origin = 0x0A0000, length = 0x008000   /* on-chip Flash */
	FLASHI				: origin = 0x0A8000, length = 0x008000   /* on-chip Flash */
	FLASHJ				: origin = 0x0B0000, length = 0x008000   /* on-chip Flash */
	FLASHK 				: origin = 0x0B8000, length = 0x002000   /* on-chip Flash */
	FLASHL				: origin = 0x0BA000, length = 0x002000   /* on-chip Flash */
	FLASHM				: origin = 0x0BC000, length = 0x002000   /* on-chip Flash */
	FLASHN				: origin = 0x0BE000, length = 0x002000   /* on-chip Flash */
}

SECTIONS
{
	codestart		: > BEGIN,      				PAGE = 0

	//可存储在flash的字段
	.text			:>> RAMGS0 | RAMGS1 | RAMGS2,	PAGE = 0	//程序段
	.cinit			: > RAMGS4,      				PAGE = 0	//初始化数据
	.const			: > RAMGS4,						PAGE = 0	//在EABI mode下与cinit一致,初始化段上电后会复制到bss
	.bss			: > RAMGS4,						PAGE = 0	//全局变量和静态变量
	.bss:output		: > RAMGS4,						PAGE = 0

	//重要字段
	ramfuncs		: > RAMM0,						PAGE = 1
	.TI.ramfunc		: > RAMM0,						PAGE = 1
	.switch			: > RAMM0,      				PAGE = 1	//switch字段
	.init_array		: > RAMM0,						PAGE = 1	//启动时调用的 C++ 构造函数的表
	.stack			: > RAMM1,      				PAGE = 1	//堆栈,最低至少需要64k
	.data			: > RAMGS7,						PAGE = 1	//程序运行中所产生的数据

	//非重要内存字段
	.econst			: > RAMGS11,					PAGE = 1
	.ebss			: > RAMGS11,					PAGE = 1	//为使用大寄存器模式时的全局变量和静态变量预留的空间,在程序上电时
																//cinit空间中的数据复制出来并存储在.ebss中
	.pinit			: > RAMGS11,					PAGE = 1	//启动时要调用的构造函数表
	.cio			: > RAMGS11,					PAGE = 1	//printf等输入输出函数使用的缓冲区所在的段
	.sysmem			: > RAMGS11,					PAGE = 1	//maclloc所用的段


	//CLA字段
	IOBuffer         : > RAMLS2_3,					PAGE = 1
	Cla1Prog         : > RAMLS0_1,					PAGE = 1
	Cla1Prog:cla_dsp_fft : > RAMLS0_1, HIGH			PAGE = 1

	ramfuncs         : LOAD = FLASHL,
                       RUN = RAMD0,
                       RUN_START(RamfuncsRunStart),
                       LOAD_START(RamfuncsLoadStart),
                       LOAD_SIZE(RamfuncsLoadSize),
                       PAGE = 1

	CLA1fftTables    : LOAD = FLASHM,
                       RUN = RAMLS4_5,
                       RUN_START(CLA1fftTablesRunStart),
                       LOAD_START(CLA1fftTablesLoadStart),
                       LOAD_SIZE(CLA1fftTablesLoadSize),
                       PAGE = 1

	Cla1Prog         : LOAD = FLASHM,
                       RUN = RAMLS0_1,
                       RUN_START(Cla1ProgRunStart),
                       LOAD_START(Cla1ProgLoadStart),
                       LOAD_SIZE(Cla1ProgLoadSize),
                       PAGE = 1


	Cla1ToCpuMsgRAM  : > CLA1_MSGRAMLOW,   PAGE = 1
	CpuToCla1MsgRAM  : > CLA1_MSGRAMHIGH,  PAGE = 1

	/* CLA C compiler sections */
	//
	// Must be allocated to memory the CLA has write access to
	//
	// CLAscratch is the legacy code model scratch pad. use
	// .scratchpad in the new model
	CLAscratch		:
					{ *.obj(CLAscratch)
					. += CLA_SCRATCHPAD_SIZE;
					*.obj(CLAscratch_end) }
                     >  RAMLS4_5,  			PAGE = 1

	.scratchpad		: > RAMLS4_5,			PAGE = 1
	.bss_cla		: > RAMLS4_5,       	PAGE = 1
	.const_cla	    : > RAMLS4_5,			PAGE = 1


	//自定义字段
	ramgs0			: > RAMGS14,			PAGE = 1

	MSGRAM_CPU1_TO_CPU2	: >	CPU1TOCPU2RAM	PAGE = 1
	MSGRAM_CPU2_TO_CPU1	: >	CPU2TOCPU1RAM	PAGE = 1

	.reset			: > RESET,				PAGE = 0,	TYPE = DSECT //未用到
}

4.2 FLASH运行

CLA_SCRATCHPAD_SIZE = 0x100;

MEMORY
{
PAGE 0 :
	BEGIN           	: origin = 0x080000, length = 0x000002

	RAMGS0      		: origin = 0x00C000, length = 0x001000
	RAMGS1      		: origin = 0x00D000, length = 0x001000
	RAMGS2      		: origin = 0x00E000, length = 0x001000

	FLASHA				: origin = 0x080002, length = 0x001FFE	/* on-chip Flash */
	FLASHB				: origin = 0x082000, length = 0x002000	/* on-chip Flash */
	FLASHC				: origin = 0x084000, length = 0x002000	/* on-chip Flash */
	FLASHD				: origin = 0x086000, length = 0x002000	/* on-chip Flash */
	FLASHE				: origin = 0x088000, length = 0x008000	/* on-chip Flash */
	FLASHF				: origin = 0x090000, length = 0x008000	/* on-chip Flash */
	FLASHG				: origin = 0x098000, length = 0x008000	/* on-chip Flash */
	FLASHH				: origin = 0x0A0000, length = 0x008000	/* on-chip Flash */
	FLASHI				: origin = 0x0A8000, length = 0x008000	/* on-chip Flash */

	RESET           	: origin = 0x3FFFC0, length = 0x000002


PAGE 1 : /* Data Memory */
         /* Memory (RAM/FLASH) blocks can be moved to PAGE0 for program allocation */

	BOOT_RSVD         	: origin = 0x000002, length = 0x00004E   /* Part of M0, BOOT rom will use this for stack */

	RAMM0             	: origin = 0x000050, length = 0x0003B0
	RAMM1             	: origin = 0x000400, length = 0x000400

	RAMD0            	: origin = 0x00B000, length = 0x000800
	RAMD1            	: origin = 0x00B800, length = 0x000800

	RAMGS3      		: origin = 0x00F000, length = 0x001000
	RAMGS4      		: origin = 0x010000, length = 0x001000
	RAMGS5      		: origin = 0x011000, length = 0x001000
	RAMGS6      		: origin = 0x012000, length = 0x001000
	RAMGS7      		: origin = 0x013000, length = 0x001000
	RAMGS8				: origin = 0x014000, length = 0x001000
	RAMGS9				: origin = 0x015000, length = 0x001000
	RAMGS10				: origin = 0x016000, length = 0x001000
	RAMGS11				: origin = 0x017000, length = 0x001000
	RAMGS12				: origin = 0x018000, length = 0x001000
	RAMGS13				: origin = 0x019000, length = 0x001000
	RAMGS14				: origin = 0x01A000, length = 0x001000
	RAMGS15				: origin = 0x01B000, length = 0x001000

	RAMLS0_1			: origin = 0x008000, length = 0x002000
	RAMLS2_3			: origin = 0x00A000, length = 0x000A00
	RAMLS4_5			: origin = 0x00AA00, length = 0x000600

	FLASHJ				: origin = 0x0B0000, length = 0x008000	/* on-chip Flash */
	FLASHK				: origin = 0x0B8000, length = 0x002000	/* on-chip Flash */
	FLASHL				: origin = 0x0BA000, length = 0x002000	/* on-chip Flash */
	FLASHM				: origin = 0x0BC000, length = 0x002000	/* on-chip Flash */
	FLASHN				: origin = 0x0BE000, length = 0x001FF0	/* on-chip Flash */

	CPU2TOCPU1RAM		: origin = 0x03F800, length = 0x000400
	CPU1TOCPU2RAM		: origin = 0x03FC00, length = 0x000400

	CLA1_MSGRAMLOW		: origin = 0x001480, length = 0x000080
	CLA1_MSGRAMHIGH		: origin = 0x001500, length = 0x000080
}

SECTIONS
{
	codestart			: >	BEGIN									PAGE = 0,	ALIGN(8)

	.text				: >>FLASHB | FLASHC | FLASHD | FLASHE		PAGE = 0,	ALIGN(8)
	.cinit				: >	FLASHG									PAGE = 0,	ALIGN(8)
	.const				: > FLASHG									PAGE = 0,	ALIGN(8)
	.switch				: > FLASHH									PAGE = 0,	ALIGN(8)
	.init_array			: > FLASHH									PAGE = 0,	ALIGN(8)

	.stack				: > RAMM1									PAGE = 1
	.bss				: > RAMGS14,								PAGE = 1
	.bss:output			: > RAMGS14,								PAGE = 1
	.bss:cio			: > RAMGS14,								PAGE = 1
	.data				: > RAMGS14,								PAGE = 1
	.sysmem				: > RAMGS14,								PAGE = 1

	.TI.ramfunc : {}	LOAD = FLASHJ,
						RUN = RAMGS15,
						LOAD_START(RamfuncsLoadStart),
						LOAD_SIZE(RamfuncsLoadSize),
						LOAD_END(RamfuncsLoadEnd),
						RUN_START(RamfuncsRunStart),
						RUN_SIZE(RamfuncsRunSize),
						RUN_END(RamfuncsRunEnd),
						PAGE = 1, ALIGN(8)

   Cla1Prog:cla_dsp_fft : > RAMLS0_1, HIGH			PAGE = 1

	CLA1fftTables	:	LOAD = FLASHB,
						RUN = RAMLS4_5,
						RUN_START(CLA1fftTablesRunStart),
						LOAD_START(CLA1fftTablesLoadStart),
						LOAD_SIZE(CLA1fftTablesLoadSize),
						PAGE = 1


	Cla1Prog		:	LOAD = FLASHK,
						RUN = RAMLS0_1,
						RUN_START(Cla1ProgRunStart),
						LOAD_START(Cla1ProgLoadStart),
						LOAD_SIZE(Cla1ProgLoadSize),
						PAGE = 1

	CLAscratch		:
					{ *.obj(CLAscratch)
					. += CLA_SCRATCHPAD_SIZE;
					*.obj(CLAscratch_end) } >  RAMLS4_5,	PAGE = 1

	Cla1ToCpuMsgRAM			: > CLA1_MSGRAMLOW,				PAGE = 1
	CpuToCla1MsgRAM			: > CLA1_MSGRAMHIGH,			PAGE = 1

	.scratchpad				: > RAMLS4_5,					PAGE = 1
	.bss_cla				: > RAMLS4_5,       			PAGE = 1
	.const_cla				: > RAMLS4_5,       			PAGE = 1
	IOBuffer				: > RAMLS2_3,					PAGE = 1

	ramgs0					: > RAMGS13,					PAGE = 1

	Filter_RegsFile			: > RAMGS15,					PAGE = 1
	Filter1_RegsFile		: > RAMGS15,					PAGE = 1, fill=0x1111
	Filter2_RegsFile		: > RAMGS15,					PAGE = 1, fill=0x2222
	Filter3_RegsFile		: > RAMGS15,					PAGE = 1, fill=0x3333
	Filter4_RegsFile		: > RAMGS15,					PAGE = 1, fill=0x4444
	Difference_RegsFile		: > RAMGS15,					PAGE = 1, fill=0x3333

	MSGRAM_CPU1_TO_CPU2	: >	CPU1TOCPU2RAM					PAGE = 1
	MSGRAM_CPU2_TO_CPU1	: >	CPU2TOCPU1RAM					PAGE = 1

   GROUP : > CPU1TOCPU2RAM, PAGE = 1
    {
        PUTBUFFER
        PUTWRITEIDX
        GETREADIDX
    }

    GROUP : > CPU2TOCPU1RAM, PAGE = 1
    {
        GETBUFFER :    TYPE = DSECT
        GETWRITEIDX :  TYPE = DSECT
        PUTREADIDX :   TYPE = DSECT
    }

    .reset				: > RESET,							PAGE = 0,	TYPE = DSECT /* not used, */
}

上述程序我就不解释了,如果需要我可以再更新,大家可以留言

5. 运行程序

初始化后,我们如何使用CLA呢?在TI的管理中有一个文件后缀为 xxx.CLA,我们在里面写CLA的运行程序,但是它不同于其他C文件,因为它不允许定义变量,不允许被include,只能写函数和include其他文件。

//
// Included Files
//
#include "CLA_share.h"
#include "cla_cfft.h"
#include "CLAmath.h"

extern float fVal;           //Holds the input argument to the task
extern float fResult;        //The arsine of the input argument

__interrupt void Cla1Task1 ( void )
{
    __mdebugstop();
    CLA_CFFT_run256Pt();
    fResult=
                CLAsin(4.2);
}

interrupt void Cla1Task2 ( void )
{
    fResult=
                    CLAsin(0.5)*4096;
}

interrupt void Cla1Task3 ( void )
{

}

interrupt void Cla1Task4 ( void )
{

}

interrupt void Cla1Task5 ( void )
{

}

interrupt void Cla1Task6 ( void )
{

}

interrupt void Cla1Task7 ( void )
{

}

interrupt void Cla1Task8 ( void )
{

}


这里我就用Task1来介绍了,大家可以先将CLA_CFFT_run256Pt();注释,这是256点的FFT程序。我们先使用CLAsin来做。其作用与math中的sin一致给一个数程序算出sin值,它是用弧度值来计算。

除了上述的CLA文件还有配套的C文件非常重要。所有的中断,

/*
 * CLA_interrupt.c
 *
 *  Created on: 2023年5月1日
 *      Author: 18752
 */

#include "CLA_interrupt.h"

//
// cla1Isr1 - CLA1 ISR 1
//

__interrupt void cla1Isr1 ()
{
    //
    // Acknowledge the end-of-task interrupt for task 1
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP11);

    //
    // Uncomment to halt debugger and stop here
    //
    // asm(" ESTOP0");
}

//
// cla1Isr2 - CLA1 ISR 2
//
__interrupt void cla1Isr2 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr3 - CLA1 ISR 3
//
__interrupt void cla1Isr3 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr4 - CLA1 ISR 4
//
__interrupt void cla1Isr4 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr5 - CLA1 ISR 5
//
__interrupt void cla1Isr5 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr6 - CLA1 ISR 6
//
__interrupt void cla1Isr6 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr7 - CLA1 ISR 7
//
__interrupt void cla1Isr7 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr8 - CLA1 ISR 8
//
__interrupt void cla1Isr8 ()
{
    //
    // Acknowledge the end-of-task interrupt for task 8
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP11);
    //
    // Uncomment to halt debugger and stop here
    //
//    asm(" ESTOP0");
}

这是CLA的中断文件,我就过多介绍了,抄就完了。

在上述内容之外你还需要找一个C文件定义你的变量,如果想让cla使用则必须先对区域定义,相信大家看到就知道是怎么用的了。

#pragma DATA_SECTION(fVal,"CpuToCla1MsgRAM");
float fVal;
#pragma DATA_SECTION(fResult,"Cla1ToCpuMsgRAM");
float fResult;

CPUtoCLA即CPU的变量放到CLA中,另一个就是CLAtoCPU了。

5.库文件

对于CLA还要依赖的lib文件,其路径是两个。

C2000Ware_4_03_00_00\libraries\boot_rom\f2837xd\rev0\rom_symbol_libs

C2000Ware_4_03_00_00\libraries\math\CLAmath\c28\lib

6606f5c76adf4c33a7156dc85493b2b1.png

 如果你使用的是elf文件就和我一样配置,如果是legacy可以看文件的后缀开启你用的文件

6.最后移植完成后的文件

下图是文件结构

0d2ffab828ab4f7ca2163947c85b6b2d.png

CLA.init

/*
 * CLA_init.c
 *
 *  Created on: 2023年5月1日
 *      Author: 18752
 */

#include "CLA_init.h"



#pragma DATA_SECTION(fVal,"CpuToCla1MsgRAM");
float fVal;
#pragma DATA_SECTION(fResult,"Cla1ToCpuMsgRAM");
float fResult;

#pragma DATA_SECTION(IOBuffer,"IOBuffer")
float IOBuffer[(256+1)*2] = {
    #include "ffttest.h"
};


//
// CLA_runTest - Execute CLA task tests for specified vectors
//
void CLA_runTest(unsigned char RTest)
{
    switch(RTest)
    {
        case 1: CLA_forceTasks(CLA1_BASE,CLA_TASKFLAG_1);   break;
        case 2: CLA_forceTasks(CLA1_BASE,CLA_TASKFLAG_2);   break;
    }
    WAITSTEP;
}

void CLA_init()
{
    EALLOW;

    CLA_DSP_initEpie();

    CLA_DSP_configClaMemory();

    CLA_DSP_initCpu1Cla1();

    EDIS;
}

void CLA_DSP_initEpie()
{
    Interrupt_initModule();
    Interrupt_initVectorTable();
}


void CLA_DSP_configClaMemory(void)
{
    extern uint32_t Cla1ProgRunStart, Cla1ProgLoadStart, Cla1ProgLoadSize;
    extern uint32_t CLA1fftTablesRunStart, CLA1fftTablesLoadStart, CLA1fftTablesLoadSize;

    EALLOW;

#ifdef _FLASH
    // Copy over code and tables from FLASH to RAM
    memcpy((uint32_t *)&Cla1ProgRunStart, (uint32_t *)&Cla1ProgLoadStart,
            (uint32_t)&Cla1ProgLoadSize);

    memcpy((uint32_t *)&CLA1fftTablesRunStart, (uint32_t *)&CLA1fftTablesLoadStart,
            (uint32_t)&CLA1fftTablesLoadSize);
#endif //_FLASH

    // Initialize and wait for CLA1ToCPUMsgRAM
    MemCfg_initSections(MEMCFG_SECT_MSGCLA1TOCPU);
    while (!MemCfg_getInitStatus(MEMCFG_SECT_MSGCLA1TOCPU)){};

    // Initialize and wait for CPUToCLA1MsgRAM
    MemCfg_initSections(MEMCFG_SECT_MSGCPUTOCLA1);
    while (!MemCfg_getInitStatus(MEMCFG_SECT_MSGCPUTOCLA1)){};

    // Select LS0-LS1RAM to be the programming space for the CLA
    // First configure the CLA to be the master for LS0 and then
    // set the space to be a program block
    MemCfg_setLSRAMMasterSel(MEMCFG_SECT_LS0,MEMCFG_LSRAMMASTER_CPU_CLA1);
    MemCfg_setCLAMemType(MEMCFG_SECT_LS0,MEMCFG_CLA_MEM_PROGRAM);
    MemCfg_setLSRAMMasterSel(MEMCFG_SECT_LS1,MEMCFG_LSRAMMASTER_CPU_CLA1);
    MemCfg_setCLAMemType(MEMCFG_SECT_LS1,MEMCFG_CLA_MEM_PROGRAM);

    //Next configure LS2-LS5RAM as data spaces for the CLA
    // First configure the CLA to be the master for LSx and then
    // set the spaces to be code blocks

    MemCfg_setLSRAMMasterSel(MEMCFG_SECT_LS2,MEMCFG_LSRAMMASTER_CPU_CLA1);
    MemCfg_setCLAMemType(MEMCFG_SECT_LS2, MEMCFG_CLA_MEM_DATA);

    MemCfg_setLSRAMMasterSel(MEMCFG_SECT_LS3,MEMCFG_LSRAMMASTER_CPU_CLA1);
    MemCfg_setCLAMemType(MEMCFG_SECT_LS3, MEMCFG_CLA_MEM_DATA);

    MemCfg_setLSRAMMasterSel(MEMCFG_SECT_LS4,MEMCFG_LSRAMMASTER_CPU_CLA1);
    MemCfg_setCLAMemType(MEMCFG_SECT_LS4, MEMCFG_CLA_MEM_DATA);

    MemCfg_setLSRAMMasterSel(MEMCFG_SECT_LS5,MEMCFG_LSRAMMASTER_CPU_CLA1);
    MemCfg_setCLAMemType(MEMCFG_SECT_LS5, MEMCFG_CLA_MEM_DATA);

}

void CLA_DSP_initCpu1Cla1(void)
{
    // Compute all CLA task vectors
    // On Type-1 CLAs the MVECT registers accept full 16-bit task addresses as
    // opposed to offsets used on older Type-0 CLAs

//
// Suppressing #770-D conversion from pointer to smaller integer
// The CLA address range is 16 bits so the addresses passed to the MVECT
// registers will be in the lower 64KW address space. Turn the warning
// back on after the MVECTs are assigned addresses
//
#pragma diag_suppress=770
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_1,(uint16_t)&Cla1Task1);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_2,(uint16_t)&Cla1Task2);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_3,(uint16_t)&Cla1Task3);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_4,(uint16_t)&Cla1Task4);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_5,(uint16_t)&Cla1Task5);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_6,(uint16_t)&Cla1Task6);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_7,(uint16_t)&Cla1Task7);
    CLA_mapTaskVector(CLA1_BASE,CLA_MVECT_8,(uint16_t)&Cla1Task8);

#pragma diag_warning=770

    // Enable IACK instruction to start a task on CLA in software
    // for all  8 CLA tasks

    CLA_enableIACK(CLA1_BASE);
    CLA_enableTasks(CLA1_BASE, CLA_TASKFLAG_ALL);

    // Configure the vectors for the end-of-task interrupt for all
    // 8 tasks

    Interrupt_register(INT_CLA1_1, &cla1Isr1);
    Interrupt_register(INT_CLA1_2, &cla1Isr2);
    Interrupt_register(INT_CLA1_3, &cla1Isr3);
    Interrupt_register(INT_CLA1_4, &cla1Isr4);
    Interrupt_register(INT_CLA1_5, &cla1Isr5);
    Interrupt_register(INT_CLA1_6, &cla1Isr6);
    Interrupt_register(INT_CLA1_7, &cla1Isr7);
    Interrupt_register(INT_CLA1_8, &cla1Isr8);
}

CLA_init.h

/*
 * CLA_init.h
 *
 *  Created on: 2023年5月1日
 *      Author: 18752
 */

#ifndef CLA_CLA_INIT_H_
#define CLA_CLA_INIT_H_


//
// Included Files
//

#include "driverlib.h"
#include "device.h"


#define FFTLENGTH 256


//*****************************************************************************
//
// CLA Configurations
//
//*****************************************************************************
#define myCLA0_BASE CLA1_BASE

//
// 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.
//
__attribute__((interrupt)) void Cla1Task1();
__attribute__((interrupt)) void Cla1Task2();
__attribute__((interrupt)) void Cla1Task3();
__attribute__((interrupt)) void Cla1Task4();
__attribute__((interrupt)) void Cla1Task5();
__attribute__((interrupt)) void Cla1Task6();
__attribute__((interrupt)) void Cla1Task7();
__attribute__((interrupt)) void Cla1Task8();
void myCLA0_init();


//*****************************************************************************
//
// INTERRUPT Configurations
//
//*****************************************************************************

// Interrupt Settings for INT_myCLA01
#define INT_myCLA01 INT_CLA1_1
#define INT_myCLA01_INTERRUPT_ACK_GROUP INTERRUPT_ACK_GROUP11
extern __interrupt void cla1Isr1(void);

// Interrupt Settings for INT_myCLA02
#define INT_myCLA02 INT_CLA1_2
#define INT_myCLA02_INTERRUPT_ACK_GROUP INTERRUPT_ACK_GROUP11
extern __interrupt void cla1Isr2(void);

// Interrupt Settings for INT_myCLA03
#define INT_myCLA03 INT_CLA1_3
#define INT_myCLA03_INTERRUPT_ACK_GROUP INTERRUPT_ACK_GROUP11
extern __interrupt void cla1Isr3(void);

// Interrupt Settings for INT_myCLA04
#define INT_myCLA04 INT_CLA1_4
#define INT_myCLA04_INTERRUPT_ACK_GROUP INTERRUPT_ACK_GROUP11
extern __interrupt void cla1Isr4(void);

// Interrupt Settings for INT_myCLA05
#define INT_myCLA05 INT_CLA1_5
#define INT_myCLA05_INTERRUPT_ACK_GROUP INTERRUPT_ACK_GROUP11
extern __interrupt void cla1Isr5(void);

// Interrupt Settings for INT_myCLA06
#define INT_myCLA06 INT_CLA1_6
#define INT_myCLA06_INTERRUPT_ACK_GROUP INTERRUPT_ACK_GROUP11
extern __interrupt void cla1Isr6(void);

// Interrupt Settings for INT_myCLA07
#define INT_myCLA07 INT_CLA1_7
#define INT_myCLA07_INTERRUPT_ACK_GROUP INTERRUPT_ACK_GROUP11
extern __interrupt void cla1Isr7(void);

// Interrupt Settings for INT_myCLA08
#define INT_myCLA08 INT_CLA1_8
#define INT_myCLA08_INTERRUPT_ACK_GROUP INTERRUPT_ACK_GROUP11
extern __interrupt void cla1Isr8(void);

//*****************************************************************************
//
// MEMCFG Configurations
//
//*****************************************************************************

void CLA_init();
// \brief Initialize system clocks
//
void CLA_DSP_initSystemClocks(void);

// \brief Initialize Enhanced PIE
//
void CLA_DSP_initEpie(void);

// \brief Configure CLA memory space
//
void CLA_DSP_configClaMemory(void);

// \brief Intialize the MVECT registers for the CLA
//
void CLA_DSP_initCpu1Cla1(void);
void CLA_runTest(unsigned char RTest);

#define WAITSTEP     asm(" RPT #255 || NOP")

#endif /* CLA_CLA_INIT_H_ */

CLA_initerrupt.c

/*
 * CLA_interrupt.c
 *
 *  Created on: 2023年5月1日
 *      Author: 18752
 */

#include "CLA_interrupt.h"

//
// cla1Isr1 - CLA1 ISR 1
//

__interrupt void cla1Isr1 ()
{
    //
    // Acknowledge the end-of-task interrupt for task 1
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP11);

    //
    // Uncomment to halt debugger and stop here
    //
    // asm(" ESTOP0");
}

//
// cla1Isr2 - CLA1 ISR 2
//
__interrupt void cla1Isr2 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr3 - CLA1 ISR 3
//
__interrupt void cla1Isr3 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr4 - CLA1 ISR 4
//
__interrupt void cla1Isr4 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr5 - CLA1 ISR 5
//
__interrupt void cla1Isr5 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr6 - CLA1 ISR 6
//
__interrupt void cla1Isr6 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr7 - CLA1 ISR 7
//
__interrupt void cla1Isr7 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr8 - CLA1 ISR 8
//
__interrupt void cla1Isr8 ()
{
    //
    // Acknowledge the end-of-task interrupt for task 8
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP11);
    //
    // Uncomment to halt debugger and stop here
    //
//    asm(" ESTOP0");
}

CLA_initerrupt.h

/*
 * CLA_interrupt.h
 *
 *  Created on: 2023年5月1日
 *      Author: 18752
 */

#ifndef CLA_CLA_INTERRUPT_H_
#define CLA_CLA_INTERRUPT_H_


#include "interrupt.h"


#endif /* CLA_CLA_INTERRUPT_H_ */

CLA_share.h

/*
 * CLA_share.h
 *
 *  Created on: 2023年5月1日
 *      Author: 18752
 */

#ifndef CLA_CLA_SHARE_H_
#define CLA_CLA_SHARE_H_

#include <stdint.h>


//
// Defines
//
#define PI                3.141592653589


extern float fVal;
extern float fResult;


__interrupt void Cla1Task1();
__interrupt void Cla1Task2();
__interrupt void Cla1Task3();
__interrupt void Cla1Task4();
__interrupt void Cla1Task5();
__interrupt void Cla1Task6();
__interrupt void Cla1Task7();
__interrupt void Cla1Task8();





#endif /* CLA_CLA_SHARE_H_ */

MyCLA.cla

//
// Included Files
//
#include "CLA_share.h"
#include "cla_cfft.h"
#include "CLAmath.h"

extern float fVal;           //Holds the input argument to the task
extern float fResult;        //The arsine of the input argument

__interrupt void Cla1Task1 ( void )
{
    __mdebugstop();
    CLA_CFFT_run256Pt();
    fResult=
                CLAsin(4.2);
}

interrupt void Cla1Task2 ( void )
{
    fResult=
                    CLAsin(0.5)*4096;
}

interrupt void Cla1Task3 ( void )
{

}

interrupt void Cla1Task4 ( void )
{

}

interrupt void Cla1Task5 ( void )
{

}

interrupt void Cla1Task6 ( void )
{

}

interrupt void Cla1Task7 ( void )
{

}

interrupt void Cla1Task8 ( void )
{

}


7. 最后效果

46d2e0cf22fc4d5b8a5aeb9f2bbc6118.jpg

0362af62d0084f26afa0477baa88cd76.png

可以看到cla初始化后fresult是0

afc343e880bd4072a42222df98ffbb47.png

fe5febd9d431443398c1bac08b808c2a.png

 cla运行完成后是0.707与计算器算的是一样的

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐