TMS320F28335DSP—CMD解读在DSP28335工程文件里(不用BIOS产生CMD文件),手写CMD文件一般有两个,在RAM里调试时用的两个CMD文件分别为DSP2833x_Headers_nonBIOS.cmd和28335_RAM_lnk.cmd,烧写到flash里时用的两个CMD文件分别为DSP2833x_Headers_nonBIOS.cmd和F28335.cmd,其中DSP2833x_Headers_nonBIOS.cmd文件可以在所有工程文件中通用,主要作用是把外设寄存器产生的数据段映射到对应的存储空间,可以跟DSP2833x_GlobalVariableDefs.c文件对照一下看看。下面通过一个简单例子,比如向CpuTimer0Regs.TIM.all写数据,来解读一下CMD文件是如何把寄存器里的值准确映射到所在存储器的位置的。先在DSP2833x_GlobalVariableDefs.c文件里找到以下几行代码:#ifdef__cplusplus#pragmaDATA_SECTION(CpuTimer0RegsFile)#else#pragmaDATA_SECTION(CpuTimer0Regs,CpuTimer0RegsFile);#endifvolatilestructCPUTIMER_REGSCpuTimer0Regs;由上可知CpuTimer0Regs是一个结构体变量名(其定义在DSP2833x_CpuTimers.c文件里),通过预处理命令#pragma为这个结构体定义了一个名称为CpuTimer0RegsFile的数据段。接着在DSP2833x_Headers_nonBIOS.cmd文件里找到如下代码:SECTIONS{PieVectTableFile:PIE_VECT,PAGE=1DevEmuRegsFile:DEV_EMU,PAGE=1FlashRegsFile:FLASH_REGS,PAGE=1CsmRegsFile:CSM,PAGE=1AdcMirrorFile:ADC_MIRROR,PAGE=1XintfRegsFile:XINTF,PAGE=1CpuTimer0RegsFile:CPU_TIMER0,PAGE=1......}红字体代码的作用就是,通过SECTIONS伪指令把CpuTimer0RegsFile数据段装载到名称为CPU_TIMER0的存储空间。同样在DSP2833x_Headers_nonBIOS.cmd文件里找到如下代码:MEMORY{PAGE0:PAGE1:DEV_EMU:origin=0x000880,length=0x000180FLASH_REGS:origin=0x000A80,length=0x000060CSM:origin=0x000AE0,length=0x000010ADC_MIRROR:origin=0x000B00,length=0x000010XINTF:origin=0x000B20,length=0x000020CPU_TIMER0:origin=0x000C00,length=0x000008......}CPU_TIMER0存储空间通过MEMORY伪指令指示了其起始地址和长度,也就等于间接确定了结构体CpuTimer0Regs的具体位置,所以通过以上几层映射关系,当向CpuTimer0Regs.TIM.all写数据时就可以准确的写入DSP内部寄存器所在的存储器的位置。由此看见,CMD的作用就是为程序代码和数据分配存储空间。本节先针对DSP2833x_Headers_nonBIOS.cmd文件做一下解读,后续再分别解读一下CMD用于调试和烧写时需要注意哪些问题。另外有关volatile关键字的解读可参考:在nonBIOS情况下,CMD文件不外乎就三个:28335_RAM_lnk.cmd(用于仿真调试)、DSP2833x_Headers_nonBIOS.cmd、F28335.cmd(用于flash烧写)。仿真调试时只用前两个,用于flash烧写时只用后两个,且不管在何种方式下28335_RAM_lnk.cmd和F28335.cmd不能同时用,也不能代替用。在DSP28335—CMD文件解读(1)中,已经介绍过DSP2833x_Headers_nonBIOS.cmd。在用28335_RAM_lnk.cmd时,一般情况下直接用TI给的,不需要做修改即可满足调试用,模式较固定,当然你也可以做相应的修改用到哪块RAM存储空间,在CMD文件里做相应的分配即可。MEMORY{PAGE0:BEGIN:origin=0x000000,length=0x000002BOOT_RSVD:origin=0x000002,length=0x00004ERAMM0:origin=0x000050,length=0x0003B0RAML:origin=0x008000,length=0x004000ZONE7A:origin=0x200000,length=0x00FC00CSM_RSVD:origin=0x33FF80,length=0x000076CSM_PWL:origin=0x33FFF8,length=0x000008ADC_CAL:origin=0x380080,length=0x000009RESET:origin=0x3FFFC0,length=0x000002IQTABLES:origin=0x3FE000,length=0x000b50IQTABLES2:origin=0x3FEB50,length=0x00008cFPUTABLES:origin=0x3FEBDC,length=0x0006A0BOOTROM:origin=0x3FF27C,length=0x000D44PAGE1:RAMM:origin=0x000400,length=0x000400RAMH:origin=0x00C000,length=0x004000ZONE6B:origin=0x13FC00,length=0x000400ZONE7B:origin=0x20FC00,length=0x000400}SECTIONS{codestart:BEGIN,PAGE=0ramfuncs:RAML,PAGE=0.text:RAML,PAGE=0.cinit:RAML,PAGE=0.pinit:RAML,PAGE=0.switch:RAML,PAGE=0.stack:RAMM,PAGE=1.ebss:RAMH,PAGE=1.econst:RAMH,PAGE=1.esysmem:RAMM,PAGE=1IQmath:RAML,PAGE=0IQmathTables:IQTABLES,PAGE=0,TYPE=NOLOADIQmathTables2:IQTABLES2,PAGE=0,TYPE=NOLOADFPUmathTables:FPUTABLES,PAGE=0,TYPE=NOLOADZONE7DATA:ZONE7B,PAGE=1ZONE6DATA:ZONE6B,PAGE=1.reset:RESET,PAGE=0,TYPE=DSECTcsm_rsvd:CSM_RSVDPAGE=0,TYPE=DSECTcsmpasswds:CSM_PWLPAGE=0,TYPE=DSECT.adc_cal:load=ADC_CAL,PAGE=0,TYPE=NOLOAD}而编写用于flash烧写的F28335.cmd文件时相对来说较复杂些,根据不同的情况需要做一些修改。1、不需要把部分代码copy到RAM里,一般情况不需要外扩RAM等时直接用TI的F28335.cmd即可。2、需要把部分代码从flash复制到RAM里,如延时函数DSP2833x_usDelay.asm等,这时CMD文件需要做相应的修改,具体参考博文:、从时间开销方面考虑,需要把整个程序从flash复制到RAM里,这时程序及CMD文件都要做相应的修改,具体参考博文(翻译自TI应用手册SPRAAU8)摘要这个应用报告和相关的代码提供了一种把编译后的程序段从TMS320F28xxx的flash复制到ram的功能,这样可以提高代码的运行速度。这个解决方案在直接启动之后,进入c_int00——C语言代码运行之前实现此功能。本应用报告中所讨论的项目内容和源代码可以从以下网址下载:引言:在许多应用中,代码的执行速度是至关重要的。例如在医疗,监控,电机控制等等一些对时间有严格要求的终端设备。许多应用使用TMS320F28xxxDSCs是因为它的内置flash储存器。内置flash是TMS320F28xxx的一个优势,因为它使得设计者不需要外接flash来储存代码。使用内部flash缺点是访问Flash需要等待状态,这使得程序的运行变慢。在大多数应用中,这不是一个问题。其他一些应用中可能会为了获得最高的运行速度要求无等待状态。内部RAM存储器具有零等待状态,它是易失性存储器。所以,引导的初始化代码段不可以存储在此存储器中。现在提供的解决方案,使得设计者能够在运行时把被编译器初始化的代码段从flash复制到ram里,获得最大的运行速度。这使代码执行从多达15个等待状态的提升到0等待状态。另一种解决方案是只将某些函数从Flash复制到RAM。详见:《RunninganApplicationfromInternalFlashMemoryontheTMS320F28xxDSP》(SPRA958)。这种方法应该使用在大多数使用C2000™DSC的应用上,其他要求严格的时序和连续的零等待状态的应用程序应采用这里提出的解决方案。编写汇编程序来完成代码从Flash到RAM的复制。该汇编代码在复位向量后调用c_int00之前执行。这保证了在c_int00调用mian()之前完成复制。有一些工程比较小,可以把所有初始化了的段都复制到ram。然而,其他一些工程的初始化了的段比所有的内部ram还要大。这些工程可能不可以把所有的初始化了的段都复制到ram,但是用这种方法复制其中一部分段。2.编译的代码段:编译器生成的包含代码和数据的多个部分,称为段。这下段被分为两个不同的组:初始化了的和没被初始化的,初始化的部分是由所有的代码,常量和初始化表组成的。下表列出了由编译器产生的初始化段。初始化段段名内容限制.cinit显式初始化的全局变量和静态变量表代码.const显式初始化的全局和静态的const变量和字符串常量不超过64K长度.econst长调用的常量数据中的任何地方.pinit全局对象的构造函数表代码.switchswitch语句产生的表代码或者数据.text可执行代码和常数代码没初始化的段是由未初始化的变量,堆栈和malloc产生的内存。下表列出了由编译器产生的没初始化段。没初始化段段名内容限制.bss全局和静态变量不超过64K长度.ebss长调用的全局或静态变量数据中的任何地方.stack堆栈空间不超过64K长度.sysmemmalloc函数产生的内存不超过64K长度.esysmemfar_malloc函数产生的内存数据中的任何地方一旦编译器生成的这些段,连接器会从各个源文件中取出这些段,并结合它们来创建一个输出文件。连接器命令文件(.cmd)就是用来告诉连接器去哪里找这些段的。初始化段必须分配到非易失性存储器,如flash/ROM,当电源被撤除时,程序不会消失。未初始化的段可以被分配到RAM中,因为它们是在代码执