SECTIONS {...
codestart : > BEGIN PAGE = 0 ...}
与此同时,底层程序所有程序代码段应全部烧写到FLASH A中: MEMORY {
PAGE 0 :
FLASHA : origin = 0x338000, length = 0x007F80 /* on-chip FLASH */ ... }
SECTIONS {...
.cinit : > FLASHA PAGE = 0 .pinit : > FLASHA, PAGE = 0 .text : > FLASHA PAGE = 0 ...}
1.2 应用程序cmd配置
采用绝对地址跳转实现由底层程序到应用程序的跳转,为保证程序正常执行,其跳转地址必须固定,且该地址在应用程序中的位置必须固定。将应用程序的首地址作为跳转地址,即跳转地址固定为FLASHE的起始地址:0x318000,如图4.2所示。
Code StartApplication Program (FLASH E)
图4.2应用程序FLASH示意图
采用绝对地址跳转实现从底层程序跳转到应用程序。跳转指令为:
#define Jump_App_Program (void(*)(void))0x318000 /*use the Flash E sector to save the application program */
(*Jump_App_Program)(); /*Jump to the application program */
同时应配置Prog App的程序起始地址为从(FLASH E)起始地址0x318000开始,对应CMD配置为:
MEMORY {
PAGE 0 :
BEGIN : origin = 0x318000, length = 0x000002 /*0x318000 is the start address of FLASH E */ ...
}
SECTIONS {...
codestart : > BEGIN PAGE = 0/*codestart is the start address of the program*/ ...}
与此同时,底层程序所有程序代码段应全部烧写到FLASH E中: MEMORY {
PAGE 0 :
FLASHE : origin = 0x318002, length = 0x007F80 /* on-chip FLASH */ ... }
SECTIONS {...
.cinit : > FLASHEPAGE = 0 .pinit : > FLASHE, PAGE = 0 .text : > FLASHEPAGE = 0 ...}
附录2: 如何将程序和变量放到指定位置
在CCS编程中,如果我们不指定变量的存放位置,编译器会自动的给变量分配一个位置,但是如果有时候需要把变量放在一个特定的空间内,我们应该如何操作呢,CCS提供了如下的两个指令:
#pragma CODE_SECTION #pragma DATA_SECTION
其中DATA_SECTION是针对数据空间的,CODE_SECTION是针对程序空间的,具体的使用办法是:
#pragma DATA_SECTION(buffer, ”DATA_sect”) char buffer[512];//buffer为一数组
#pragma CODE_SECTION(fun, ”CODE_sect”) Int fun(); //fun 为任意函数
与此同时,在CMD文件中为DATA_sect、CODE_sect开辟空间: DATA_sect : > RAML2 PAGE = 1
CODE_sec : > FLASHE PAGE = 0
附录3:如何将FALSH中程序搬移到RAM中运行
CCS中经常会遇到如下语句:
MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart)
它的作用是将ramfuncs段复制到内存中然后运行。 CMD文件中ramfuncs的定义如下; ramfuncs : LOAD = FLASHD,
RUN = RAML0,
LOAD_START(_RamfuncsLoadStart), LOAD_END(_RamfuncsLoadEnd), RUN_START(_RamfuncsRunStart), PAGE = 0
第1行表示该段的装载在PAGA0的FLASHD中 第2行表示该段的运行地址在PAGE0的RAML0中
LOAD_ START(_RamfuncsLoadStart)令编译器创建了一个变量RamfuncsLoadStart,该变量指向段ramfuncs的装载地址的首地址(LOAD_ START为编译伪指令,请见CCS的帮助文档); LOAD_ START(_RamfuncsLoadEnd)令编译器创建了一个变量RamfuncsLoadEnd,该变量指向段ramfuncs的装载地址的末地址(LOAD_ END为编译伪指令,请见CCS的帮助文档); LOAD_ START(_RamfuncsRunStart)令编译器创建了一个变量RamfuncsRunStart,该变量指向段ramfuncs的运行地址的首地址(LOAD_ START为编译伪指令,请见CCS的帮助文档); 从第1和2行可以看出,段ramfuncs中的函数DSP28x_usDelay()的装载地址和运行地址是不同的,本程序中装载在Flash的块 FLASHD中,而在SARAM L0中运行,这只是目标,实际运行时DSP并不会自动将Flash中的代码拷贝到SARAM中,因此需要手动添加代码来完成。 在C函数中,为了使用变量RamfuncsLoadStart、RamfuncsLoadEnd和RamfuncsRunStart,必须先声明,本工程在文件DSP2833x_GlobalPrototypes.h中做了如下声明: extern Uint16 RamfuncsLoadStart; extern Uint16 RamfuncsLoadEnd; extern Uint16 RamfuncsRunStart;
然后就可以使用了。在Main.c中,使用MemCopy()函数将段ramfuncs中的函数DSP28x_usDelay()的代码从装载地址 RamfuncsLoadStart—RamfuncsLoadEnd拷贝到RamfuncsRunStart开始的SARAM空间中。之后在程序运行时,只要调用DSP28x_usDelay()函数,都会自动地指向SARAM中相应的函数入口地址,这一点是自动完成的。MemCopy()函数原型在 MemCopy.c中,DSP2833x_GlobalPrototypes.h声明。
附录4:十六进制数据流文件(Hex文件)
十六进制数据流(Hex)是规律性极强的一种文件格式,该类文件是由‘行’组成的,一行即是一个单元。
Hex文件的‘行’单元由以下6部分组成: :LLAAAARRDD…DDCC ① 行的开端: ‘ : ’ 标志一个新的‘行’的开端;
② 数据长度: ‘LL’ 表示后面DDDD的长度(单位Byte);
③ 存储地址: ‘AAAA’ 表十六位地址,当记录类型是‘04’时表高十六位地址,记录类型是
‘00’时表低十六位地址;
④ 记录类型: ‘RR’ 共有‘00’‘01’和‘04’三种记录类型;
‘00’:表该行携带数据信息 ‘01’:表Hex文件结束 ‘04’:表高十六位地址有变化 ⑤ 数据内容: ‘DDDD’ 是数据内容;
⑥ 校验内容: ‘CC’ 是该行除去 ‘ : ’ 和 ‘CC’ 之外的数据的校验值。校验规律是:所有值
加和后取反。
附录5:TMS320F28335-启动过程
1.DSP reset后运行的起始地址是多少? 0x3FFFC0
2.仿真器烧写程序的步骤是?
根据cmd文件把程序烧到指定位置,然后执行。 3.DSP的Flash启动过程是什么?
首先假设硬件配置GPIO84~87上拉为1,即处于Flash启动过程。当DSP复位后,会从复位向量0x3FFFC0处取得复位向量,并跳转到 InitBoot处开始执行,InitBoot会读GPIO84~87的值,当值全为1后,判断为Flash启动方式。然后会跳到0x33FFF6处执行。在 CCS5.2工程的cmd文件中有如下代码: MEMORY {
PAGE 0 :
BEGIN : origin = 0x33FFF6, length = 0x000002 /* Boot to M0 will go here */ ... }
SECTIONS {...
codestart : > BEGIN PAGE = 0 ...}
即表示把codestart段放到0x33FFF6位置处,文件“DSP2833x_CodeStartBranch.asm”中有 codestart段的定义,实际上codestart段只是包含了一个跳转指令,是程序跳转到_c_int00处,_c_int00在boot.asm in RTS library中有定义,_c_int00的代码最终会调用c的main函数,之后就是main函数的执行。
附录6:Hex2000使用:
CCS软件默认生成的是.out格式的文件,而很多应用场合往往需要的是纯二进制代码,TI提供了一个小工具HEX2000能帮助实现格式的转化,具体的说明还是请参看TMS320C28x Assembly Language Tools手册。这里简单的说明下该工具的使用: 1.hex2000是在ccs安装目录下的。
2.hex2000 转化工具支持多种输出格式,至于用那种格式,通常是由所用的烧写器来决定的。常见的有:
Ascii hex: 这种格式其实是会将所有的code转化为字符形式,比如本来的0x3132, 它就用'3' '1' '3' '2'来表示,当中有空格,这种格式比较使用通过串口等工具来更新数据。
binary:-b 选项,纯二进制格式。它还支持intel,motorola-s, ti-tagged, tektronix等格式。
3.hex2000 有memory width的概念,输入文件的(--memwidth),一般来说都是16bit的(因为编译出来就是这样的),输出格式--romwidth,可以指定为8或者16(有些格式不支持16)。如果输入16,输出是8,hex工具会自动生成两个文件,一个放低8位的数据,一个放高8位的数据。当然你也可以自己制定这两个文件的名字。
4. -image选项:打开该选项,系统会产生一个和你在roms中指定大小一样的文件,不足部分用fill的值来替代,多余部分被忽略。
6.hex2000工具,可以通过命令行通过一句话将所有的参数和输入输出写在一起来运行,比如:hex2000 -t firmware -o firm.lsb -o firm.msb
也可以通过ROMS指令写一个脚本文件,这种脚本文件的好处是可以编写比较复杂的要求,而且易于修改。
hex2000转换的具体方法见附件。