[DSP学习笔记]cmd文件的讲解

article/2025/10/2 6:40:29

一、前言

在笔者学习F28335的过程中,发现网上少有对于cmd文件的讲解,而学习DSP,肯定是要编写或修改cmd文件的。故笔者基于自己的学习经验,给出了自己对于cmd文件的理解。

在正式开始学习cmd文件之前,我们首先需要知道什么是cmd文件。cmd文件即链接命令文件(Linker Command Files),以后缀.cmd结尾。cmd文件用于DSP代码的定位,由于DSP编译器的编译结果是未定位的,因此需要用户自定义代码存放和加载位置。而普通的单片机,编译器自身会定位代码地址,故编写cmd文件,也是学习DSP的难点之一。

二、有关cmd文件的基础知识

由于cmd文件是用户用来分配DSP工程中ROM和RAM空间的,所以我们就不得不提一下存储器的相关知识了。而各类存储器基本都可以划分为以下两类:断电后仍然能够保存数据的叫做非易失性存储器(ROM类),断电后数据丢失的叫做易失性存储器(RAM类)。故我们分配存储空间时,就需要将需要永久保存的数据存储到ROM中去,如程序代码。而如果对读写速度要求更高或是暂存数据,则选用RAM,如程序运行时,为了提高速度,就必须在RAM中运行。

DSP的片内存储器很多,用户通过cmd文件来管理、分配系统里的存储器资源。值得一提的是,只要没有被TI占用的,用户都可以全权支配,TI声明的保留空间(Reserved或illegal)是芯片无法访问的,分配资源时,不能涉及这些区域。

cmd文件由MEMORY(即:内存)和SECTIONS(即:段)两部分组成。MEMERY用于定义每个存储器块的名字、起始地址和长度。SECTIONS主要用于描述哪个段映射到了哪段存储空间。MEMORY中又可分为PAGE0(程序存储空间)和PAGE1(数据存储空间),PAGE(即:帧)。

上文所提及的段,又可分为两大类:已初始化的段和未初始化的段。已初始化的段含有真实的指令和数据,存放于程序存储空间。未初始化的段只是保留变量的地址空间,未初始化的段并不具有真实的内容,在程序运行过程中才向变量内写数据进去,存放于数据存储空间。C语言中,有许多定义好的段,如“.text”,“.const”,“.system”。对于这些定义好的段,在网上有许多关于他们的讲解,故这里笔者不再赘述。本文接下来会给读者介绍作为用户,来自己定义段的方法。

三、MEMORY和SECTION

cmd文件中可以写上注释,用"/*"和“*/”,包围起来,但不允许使用“//”,这点与c语言不同。

编写cmd文件我们需要借助两条伪指令MEMORY和SECTIONS(必须大写)。

MEMORY和SECTION的语法可在自行网上查找,本文将结合具体例子对MEMORY和SECTION中的内容进行讲解。

结合笔者使用的F28335的cmd文件对MEMORY进行讲解。

MEMORY
{
PAGE 0:    /* Program Memory *//* Memory (RAM/FLASH/OTP) blocks can be moved to PAGE1 for data allocation */ZONE0       : origin = 0x004000, length = 0x001000     /* XINTF zone 0 */RAML0       : origin = 0x008000, length = 0x001000     /* on-chip RAM block L0 */RAML1       : origin = 0x009000, length = 0x001000     /* on-chip RAM block L1 */RAML2       : origin = 0x00A000, length = 0x001000     /* on-chip RAM block L2 */RAML3       : origin = 0x00B000, length = 0x001000     /* on-chip RAM block L3 */ZONE6       : origin = 0x0100000, length = 0x100000    /* XINTF zone 6 */ ZONE7A      : origin = 0x0200000, length = 0x00FC00    /* XINTF zone 7 - program space */ FLASHH      : origin = 0x300000, length = 0x008000     /* on-chip FLASH */FLASHG      : origin = 0x308000, length = 0x008000     /* on-chip FLASH */FLASHF      : origin = 0x310000, length = 0x008000     /* on-chip FLASH */FLASHE      : origin = 0x318000, length = 0x008000     /* on-chip FLASH */FLASHD      : origin = 0x320000, length = 0x008000     /* on-chip FLASH */FLASHC      : origin = 0x328000, length = 0x008000     /* on-chip FLASH */FLASHA      : origin = 0x338000, length = 0x007F80     /* on-chip FLASH */CSM_RSVD    : origin = 0x33FF80, length = 0x000076     /* Part of FLASHA.  Program with all 0x0000 when CSM is in use. */BEGIN       : origin = 0x33FFF6, length = 0x000002     /* Part of FLASHA.  Used for "boot to Flash" bootloader mode. */CSM_PWL     : origin = 0x33FFF8, length = 0x000008     /* Part of FLASHA.  CSM password locations in FLASHA */OTP         : origin = 0x380400, length = 0x000400     /* on-chip OTP */ADC_CAL     : origin = 0x380080, length = 0x000009     /* ADC_cal function in Reserved memory */IQTABLES    : origin = 0x3FE000, length = 0x000b50     /* IQ Math Tables in Boot ROM */IQTABLES2   : origin = 0x3FEB50, length = 0x00008c     /* IQ Math Tables in Boot ROM */  FPUTABLES   : origin = 0x3FEBDC, length = 0x0006A0     /* FPU Tables in Boot ROM */ROM         : origin = 0x3FF27C, length = 0x000D44     /* 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 */RAML4       : origin = 0x00C000, length = 0x001000     /* on-chip RAM block L1 */RAML5       : origin = 0x00D000, length = 0x001000     /* on-chip RAM block L1 */RAML6       : origin = 0x00E000, length = 0x001000     /* on-chip RAM block L1 */RAML7       : origin = 0x00F000, length = 0x001000     /* on-chip RAM block L1 */ZONE7B      : origin = 0x20FC00, length = 0x000400     /* XINTF zone 7 - data space */FLASHB      : origin = 0x330000, length = 0x008000     /* on-chip FLASH */
}

可以看到MEMORY中通常包含PAGE0和PAGE1,PAGE0中的RAML0代表起始地址为0x008000,存储空间长度为0x001000的存储空间。同理可知其他存储空间名称所代表的含义。

对照TI28335芯片数据手册(仅截取了部分)可以看到,以上cmd文件的编写是基于TI28335芯片数据手册内存映射一节所编写的。我们也可参考芯片数据手册上的内存映射一节进行cmd文件的编写。

 接下来,笔者对SECTION所包含的内容进行讲解,同样以F28335的cmd文件为例

SECTIONS
{/* Allocate program areas: */.cinit              : > FLASHA      PAGE = 0.pinit              : > FLASHA,     PAGE = 0.text               : > FLASHA      PAGE = 0codestart           : > BEGIN       PAGE = 0ramfuncs            : LOAD = FLASHD, RUN = RAML0, LOAD_START(_RamfuncsLoadStart),LOAD_END(_RamfuncsLoadEnd),RUN_START(_RamfuncsRunStart),LOAD_SIZE(_RamfuncsLoadSize),PAGE = 0csmpasswds          : > CSM_PWL     PAGE = 0csm_rsvd            : > CSM_RSVD    PAGE = 0/* Allocate uninitalized data sections: */.stack              : > RAMM1       PAGE = 1.ebss               : > RAML4       PAGE = 1.esysmem            : > RAMM1       PAGE = 1/* Initalized sections go in Flash *//* For SDFlash to program these, they must be allocated to page 0 */.econst             : > FLASHA      PAGE = 0.switch             : > FLASHA      PAGE = 0      /* Allocate IQ math areas: */IQmath              : > FLASHC      PAGE = 0                  /* Math Code */IQmathTables     : > IQTABLES,  PAGE = 0, TYPE = NOLOAD /* 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, IQmathTables2will be loaded into other memory (SARAM, Flash, etc.) and will takeup space, but 0 wait-state is possible.*//*IQmathTables2    : > IQTABLES2, PAGE = 0, TYPE = NOLOAD {IQmath.lib<IQNexpTable.obj> (IQmathTablesRam)}*/FPUmathTables    : > FPUTABLES, PAGE = 0, TYPE = NOLOAD /* Allocate DMA-accessible RAM sections: */DMARAML4         : > RAML4,     PAGE = 1DMARAML5         : > RAML5,     PAGE = 1DMARAML6         : > RAML6,     PAGE = 1DMARAML7         : > RAML7,     PAGE = 1/* Allocate 0x400 of XINTF Zone 7 to storing data */ZONE7DATA        : > ZONE7B,    PAGE = 1/* .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 = DSECTvectors             : > VECTORS     PAGE = 0, TYPE = DSECT/* Allocate ADC_cal function (pre-programmed by factory into TI reserved memory) */.adc_cal     : load = ADC_CAL,   PAGE = 0, TYPE = NOLOAD}

可以看到SECTION中包含了各种段名。以“.text”为例 ,“.text” 为编译后生成的二进制指令代码段,可以看到,我们将“.text”中的内容分配到FLASHA中存储,而FLASHA位于MEMORY中的PAGE0。

SECTION中的ramfuncs与28335的启动有关,其本质就是上电运行时通过“引导程序”把用户代码从FLASH中读出,保存在RAM中并在RAM中运行,从而解决ROM读写速度慢,难以满足高速智能芯片和RAM掉电丢失数据的问题。对于其详细的讲解可查看以下文章

https://blog.csdn.net/E_ROAD_BY_U/article/details/53047443 

四、自定义段

而知道了段的这些信息对于我们用户来说有什么用呢?最直接的用处就是,当编译器提示存储器内存不足时,我们可以通过对应的段名,找到对应的存储空间,修改其存储空间的大小来满足我们程序的需要。甚至我们可以通过自定义段名来存放我们的代码和数据。

通过#pragma DATA_SECTION(函数名或全局变量名,"用户自定义在数据空间的段名")或#pragma CODE_SECTION(函数名或全局变量名,"用户自定义在程序空间的段名")可实现自定义段名,从而自由的分配存储空间。

#pragma DATA_SECTION(用于变量)

#pragma CODE_SECTION(用于函数)

但使用以上指令时需注意:不能在函数体内声明必须在定义和使用前声明,#pragma可以阻止对未调用的函数的优化。

下面结合实际使用例子来具体讲解:

#pragma DATA_SECTION(FFT_output, "FFT_buffer1");
float FFT_output[FFT_SIZE];

笔者声明了一个数据段,段名为FFT_buffer1,段的内容在变量FFT_ouput里。而声明后才定义变量FFT_output的大小。

我们如果想要使用这个自定义的段,接下来我们还要在CMD文件的SECTION中指定FFT_buffer1的存储空间。

FFT_buffer1		: > RAML4,     PAGE = 1

通过以上几条语句,笔者实现了将变量的内容存放入指定的RAML4存储空间的操作。

从上可以得出,当全局变量所占内存过大时,我们可以通过自定义段选择有所余裕的存储空间的方式,从而来解决内存不足的问题。

至此,关于CMD文件的相关基础内容笔者介绍完毕。

由于笔者水平有限,如有不足与错误之处,欢迎指出。


http://chatgpt.dhexx.cn/article/L6438W0S.shtml

相关文章

QT 运行时出现U1077:“cl”返回代码“0x1”报错时的解决思路

作为一个萌新小白&#xff0c;在第一次给QT配置环境并运行时出现了如下错误 遇到这个问题时我上网查找解决办法&#xff0c;但是都没有用&#xff0c;我在这个问题上卡了两三天&#xff0c;试了各种方法&#xff01; 后来我无意中找到了解决办法&#xff0c;现分享给大家。 首…

0x1、寄存器

通用寄存器 8086的所有CPU都是16位的&#xff0c;可以存放两个字节。 AX、BX、CX、DX这四个寄存器通常用来存放数据&#xff0c;被称为通用寄存器。 因为8086CPU上一代都是8为的寄存器。 因此&#xff0c;为了兼容上一代寄存器&#xff0c;AX、BX、CX、DX这四个寄存器都是两个可…

·穷途末路之举·解决VirtualBox启动问题-Error relaunching VirtualBox VM process 5/terminated with exit code1(0x1)

近来需安装linux虚拟机进行一些学习&#xff0c;选择使用VM VirtualBox安装ubuntu系统。 VirtualBox配置完成之后&#xff0c;在启动时&#xff0c;报错&#xff0c;内容如下&#xff1a; “Failed to open a session for the virtual machine exit code 1 (0x1) – E_FAIL (0x…

WIN10设置计划任务执行报(0x1)调用的函数不正确或调用了未知函数

前提&#xff1a;此任务的exe在本地可以正常执行&#xff0c;同时在修改前可以使用计划任务定时执行。排除脚本问题及权限问题。 报错如图&#xff1a; 相比之前可以使用计划任务执行的脚本&#xff0c;新脚本增加了读取配置文件的操作。怀疑是读取不到配置文件导致。 通过查…

进制的转换

通常使用的基本数据类型是十进制的就是0&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6&#xff0c;7&#xff0c;8&#xff0c;9&#xff0c;10&#xff0c;11&#xff0c;12............ 通过八进制表达就是 01&#xff0c;02&#xff0c…

【Python】初学者也可以实现的人脸识别系统-0x1

作者&#xff1a;20岁爱吃必胜客&#xff08;坤制作人&#xff09;&#xff0c;近十年开发经验, 跨域学习者&#xff0c;目前于海外某世界知名高校就读计算机相关专业。荣誉&#xff1a;阿里云博客专家认证、腾讯开发者社区优质创作者&#xff0c;在CTF省赛校赛多次取得好成绩。…

解决windows服务器上定时任务执行时报0x1错误,但是手动执行顺利完成

最近修改定时任务重新部署后&#xff0c;定时运行后运行结果为0x1&#xff0c;但是手动执行后&#xff0c;任务可以顺利完成。 windows官网解释如下&#xff1a; 0x0&#xff1a; 操作已成功完成 0x1&#xff1a; 调用的函数不正确或调用了未知函数。 因为手动可以执行&…

Windows定时执行.py文件报(0x1)错

Windows定时执行.py文件报&#xff08;0x1&#xff09;错 按照博客https://blog.csdn.net/David_jiahuan/article/details/99960427&#xff0c;创建定时任务后报错(0x1)如下图&#xff0c;在终端里运行py文件正常&#xff0c;排除代码问题。 在网上查资料&#xff0c;有因为是…

Windows计划任务出现0x1错误结果

Windows计划任务出现0x1错误结果 现象解决方法结果 现象 参考不少的文章&#xff0c;基本上都是说因为权限的问题&#xff0c;但试了N次都不行,仍然报0x1的错误结果&#xff0c;亲测解决方法说明如下&#xff1b; 1.脚本本身没问题&#xff0c;手动本地可以执行&#xff1b; 2…

JAVA关于基本数据类型之间进行强制转换底层剖析

1.什么是基本类型之间的强制转换 先来聊一聊基本类型 基本数据类型所占用的字节数表示数的范围整型byte1-128~127short2-32768~32767int4-2147483648&#xff5e;2147483647long8比int大浮点型float4 比long大double8比float大字符型char2布尔型boolean 基本类型之间的强制转换…

关于Java中强制转换类型为接口类型

在这里浅浅记录一下自己在Java编程中遇到的问题及理解&#xff1a; 问题背景如下&#xff1a; 自定义JDBC接口&#xff1a; 自定义类MySql实现JDBC接口&#xff1a; 创建JDBC01.properties配置文件如下&#xff1a; key为类名&#xff0c;value为创建Class对象所需类的路径全…

java强制double类型转换int()

写着写着&#xff0c;就又忘了…… 做个实验&#xff0c;存一下吧&#xff1a; 代码&#xff1a; // a litte testdouble asdjf 39.8;double asdjr 39.5;double asdjv 40.1;System.out.println("\nint():");System.out.println("(int)(39.8)" (int) …

java的隐式转换和强制类型转换

一、数据类型转换的场景 当数据类型不一致时进行算术运算操作&#xff0c;需要进行类型转换&#xff08;转成一样的&#xff09;操作。 二、数据类型转换的分类 1.隐式转换 1.取值范围小的转成取值范围大的。 如int转成double 2.byte、short、char类型在进行数据类型转换的…

getdate、dateadd、datediff、datename、datepart关于日期函数的用法及理解

下面是sql server实例&#xff1a; select GETDATE() --getdate这个函数是获取当前系统时间也就是今天的日期时间、看第1个结果select DATEADD(YY,1,GETDATE()) --dateadd这个函数是增加日期、框里mm是月份、1是增加1个月、就是说在今天的日期上再加1个月--对比一下第1个结果…

DATEDIFF() 函数

定义和用法 DATEDIFF() 函数返回两个日期之间的时间。 语法 DATEDIFF(datepart,startdate,enddate)startdate 和 enddate 参数是合法的日期表达式。 datepart 参数可以是下列的值&#xff1a; 实例 例子 1 使用如下 SELECT 语句&#xff1a; SELECT DATEDIFF(day,2008-12-2…

SQL server Date函数之DATEPART()函数

1、定义&#xff1a; DATEPART() 函数用于返回一个日期或者时间的单独部分&#xff0c;比如年、月、日、小时、分钟等等。 2、语法&#xff1a; DATEPART(datepart,date) date 参数是合法的日期表达式。datepart 参数可以是下列的值&#xff1a; datepart缩写年yy, yyyy季…

DatePart 函数

DatePart 函数 适用于: Microsoft Office Access 2007 全部显示 全部隐藏 返回变量型&#xff08;整型&#xff09;&#xff0c;其中包含给定日期的指定部分。 语法 DatePart(interval, date [, firstdayofweek] [, firstweekofyear] ) DatePart 函数的语法包含以下参数 &…

DateAdd函数

在VBA日期时间函数学习中&#xff0c;有几类用到了间隔类型参数&#xff0c;比如 日期/时间增加或减少一个时间间隔&#xff1a;DateAdd(<间隔类型>,<间隔值>,<表达式>) 计算两个日期的间隔值函数&#xff1a; DateDiff(<间隔…

Linux 题库及答案永久开放共同学习进步

Linux 题库&#xff08; 一 ) 一、选择题 (每小题2分&#xff0c;共50分) 4. 下面哪个命令是用来定义shell的全局变量( D ) A. exportfs B. alias C. exports D. export 11. 在vi编辑器里&#xff0c;命令"dd"用来删除当前的( A ) A. 行 B. 变量   C. 字  …

Linux内核设计与实现 Robert Love

第一章 Linux内核简介 通常一个内核由负责响应中断的中断服务程序&#xff0c;负责管理多个进程从而分享处理器时间的调度程序&#xff0c;负责管理进程地址空间的内存管理程序和网络、进程间通信等系统服务程序共同组成。 每个处理器在任何指定时间点上的活动必然概况为下列三…