本文出自一本北京航空航天大学出版的书籍,摘抄至此,标为转载,仅用来学习交流。
链接文件Project.prm
prm文件主要实现了芯片的RAM和ROM的定义,初始化RAM中的变量、堆栈的大小;定义复位向量,即应用程序的默认入口;还包括了启动代码,即硬件复位后的函数入口。
prm文件有5个组成部分构成:
(1)NAMES~END部分
用于指定在链接时加入除本项目文件列表之外的额外目标代码文件,这种用法不常用,因为在“Libs”栏目中添加可实现同样的功能。
(2)SEGMENTS~END部分
这部分很重要,它定义和划分了芯片所有可用的内存资源,包括程序空间和数据空间。一般将程序空间定义为ROM,把数据空间划分为第0页的Z_RAM和非0页的RAM,这些名字都不是系统保留关键字,可以由用户随意修改,但修改后其他部分用到必须相应更改。
内存划分的具体方式如下:
由SEGMENTS开始到END为止,中间可以添加任意多行内存划分的定义,每一行用分号“;”结尾。定义行的语法格式为:
[块名] = [属性] [起始地址] TO [结束地址];
块名:其定义和C语言变量定义相同,是以英文字母和下划线开头的一个字符串。
属性:可以有三种不同的类型。对于只读的Flash-ROM区属性一定是READ_ONLY;对于可读/写的RAM区属性可以是READ_WRITE,也可以是NO_INIT,他们两者的关键区别是ANSI - C的初始化代码会把定位在READ_WRITE块中的所有全局和静态变量自动清零,而NO_INIT块中的变量将不会被自动清零。对于单片机系统,变量在复位时不被自动清零这一特性有时是很关键的。
起始地址和结束地址:决定了一内存块的物理位置,用16进制表示。
用SEGMENTS只是从MCU的物理内存这一角度对其进行空间划分。源程序本身并不知道内存被分割和属性定义的这些细节。它们两者之间必须通过下面的PLACEMENT建立联系。
(3)PLACEMENT~END部分
指派源程序中所定义的各种段,例如数据段DATA_SEG、CONST_SEG和代码段CODE_SEG被具体放置在哪一个内存块中。它是将源程序中的定义描述和实际物理内存挂钩的桥梁。
PLACEMENT~END内所描述的信息是告诉链接器源程序中所定义的各类段应该被具体放置在哪一个内存块中去。其语法格式为:
[段名1], [段名2],… [段名n] INTO [内存块名];
段名:就是在源程序中用#pragma 声明的数据段、常数段或者代码段的名字。如果用默认名DEFAULT,则默认的数据段名为DEFAULT_RAM,代码段和常数段名为DEFAULT_ROM。若程序中定义的段名没有在PLACEMENT中提及,则将视为DEFAULT。几个相同性质但不同名字的段可以被放在同一个内存块中,相互之间用逗号隔开。INTO是系统保留的关键词,在这里为放入的意思。内存块名就是前面介绍的用SEGMENTS划分好的不同的内存块名字。利用这样直观的定位描述文本可以方便灵活的将数据或代码定位到芯片内存任意可能的位置,实现某些特殊目的的应用。
(4)STACKSIZE 部分
STACKSIZE 部分定义系统堆栈长度,其后给出的长度字节数可以根据实际需要进行修改。堆栈的实际定位取决于RAM内存的划分和使用情况。在常见的RAM线性划分变量连续分配的情况下,堆栈将紧挨在用户所定义的所有变量区域的高端。但如果将RAM区分成几个不同的块,必须确保其中至少有一个块能容纳已经定义的堆栈长度。
(5)VECTOR部分
VECTOR部分定义所有失量入口地址。模板在生成prm文件时已经定义了复位矢量的入口地址。对于各类中断失量用户必须自己按照矢量编号和中断服务函数名相关联。如果中断函数的定义是用”interrupt”加上矢量号,则无需在这里重复定义。
编写中断函数几乎是每一个单片机项目开发必需的一个内容。CodeWarrior针对12系列MCU的中断函数编写有3种方式可以实现,分别是:①关键词interrupt和中断矢量编号;②用关键词interrupt定义中断函数,中断矢量入口由prm文件指定;③用#pragma TRAP_PROC定义中断函数,中断矢量入口由prm文件指定。