程序从FLASH中拷贝到RAM中执行的方法
DSP的程序下载执行方式有两种:一种是下载到RAM中在线执行,一种是下载到FLASH中执行。在RAM中执行时,具有执行速度快,可以无限次下载的特点,但是RAM的特点是掉电丢失数据。FLASH具有掉电不丢失数据的特点,但是同时存在执行速度慢和擦写次数有限的缺点。因此综合两者的特点,在DSP的开发过程中一般会结合使用两者。在前期程序调试过程,由于需要频繁的擦写,所以一般选择在RAM中进行。而程序调试完成后,由于需要脱离下载器而独立执行,因此需要烧写到掉电不丢失数据的FLASH中。下面将以利用CCS5.2对TMS320F28335进行程序在FLASH中的烧写为例,介绍一下将程序烧写到FLASH中的操作过程。
程序从在RAM中执行改为下载到FLASH中需要对工程文件做一些修改。而程序烧写到FLASH中后,又根据程序执行时的存储区间的不同,分为程序部分拷贝到RAM中执行和程序整体拷贝到RAM中执行两种,两种执行需要对工程作不同的修改和设置。
一、程序部分拷贝到RAM中执行
一般当程序过大,大于DSP的RAM空间或者对程序执行的速率要求不高时,一般将程序下载到FLASH中执行,并且上电后程序在FLASH中执行,仅仅将个别对时间要求比较高的程序拷贝到RAM中去执行。此时需要作如下修改 :
1、首先删除掉工程文件中的28335_RAM_link.cmd文件,改为F28335.cmd文件。如果在自己原来的工程中有对28335_RAM_link.cmd的存储区有特殊修改,可以在F28335.cmd中作同样的修改(仅限于不包括FLASH存储区的部分)。
2、在工程文件中加入文件DSP2833x_MemCopy.c,该文件提供代码赋值的函数。
3、在SECTION中定义ramfuncs段如下所示。段中定义程序下载的区间LOAD(自己指定)、执行的区间RUN(自己指定)、下载开始地址、下载结束地址、执行开始地址(不用改)。
ramfuncs : LOAD = FLASHD,
RUN = RAML123,
LOAD_START(_RamfuncsLoadStart),
LOAD_END(_RamfuncsLoadEnd),
RUN_START(_RamfuncsRunStart),
PAGE = 0
该段定义的作用在于将需要从FLASH中拷贝到RAM的程序归入到该段中从而实现程序从下载地址到执行地址的拷贝。
4、在主程序的main之前定义需要拷贝到RAM中的函数,定义语句如下所示
#pragma CODE_SECTION(cpu_timer1_isr,"ramfuncs");
#pragma CODE_SECTION(cpu_timer2_isr,"ramfuncs");
其作用是将该子函数定义在ramfuncs段中。然后定义下载开始地址、下载结束地址、执行开始地址变量:
extern Uint16 RamfuncsLoadStart;
extern Uint16 RamfuncsLoadEnd;
extern Uint16 RamfuncsRunStart;
5、在main函数内还需要添加两行代码。添加的位置是在InitPieVectTable();之后,代码如下(不用修改):
MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart);
InitFlash();
6、最后需要将拨码开关调到1111的地方,然后编译烧写即可。
二、程序整体拷贝到RAM中执行
有些时候程序的执行对于速度要求很高,此时就需要将程序整体拷贝到RAM中去执行。程序整体拷贝同样需要进行特殊修改和设置。要想详细了解下面设置的原理,可以查找相关资料来详细了解程序启动的过程。
1、程序启动的过程一般为:
code_start->wd_disable->c_int00->mian()
为了完成程序的拷贝,需要在C语言初始化之前插入一个程序拷贝的环节,修改之后的流程为:
code_start->wd_disable->copy_sections->c_int00->mian()
为此在DSP2833x_CodeStartBranch.asm中将所有的c_int00替换为copy_sections。
2、在DSP2833x_CodeStartBranch.asm中将该文件中的wd_disable前的 .text改为 .sect "wddisable",从而将该段程序归入到段wddisable中,并在F28335.cmd文件中定义该段:
wddisable : > FLASHA, PAGE = 0
之所以这么定义,是因为.text段是需要拷贝到RAM执行的,而在程序拷贝之前首先需要关闭看门狗,从而避免出现错误。如果仍然将程序放在.text段中,则看门狗禁止程序无法执行,会出现错误,因此在FLASH中定义一个新的段,从而让看门狗关闭的程序在FLASH中提前执行,
3、在工程中添加DSP28xxx_SectionCopy_nonBIOS.asm文件,该文件提供对各个段进行拷贝的程序,十分重要。这部分代码不需要修改,直接使用就行。
4、将文件DSP2833x_usDelay.asm中的.sect "ramfuncs"改为 .text。从而将该段代码归入到.text段中,随段拷贝到RAM中执行。
5、删除F28335_sysctrlinit.c文件中的代码:
#pragma CODE_SECTION(InitFlash, "ramfuncs");
从而将InitFlash代码归到.text段中。
6、在F28335.cmd文件中定义相应的段,代码如下。定义codestart、wddisable、copysections 三段在FLASH中执行,定义初始化段的各段的下载区间LOAD、执行区间RUN(前两者存储区间自己选择)、下载开始地址、执行开始地址、段大小(后三者名字不可改变)。注意下面代码、格式以及标点符号必须严格不错。
codestart : > BEGIN PAGE = 0
wddisable : > FLASHA, PAGE = 0
copysections : > FLASHA, PAGE = 0
.cinit : LOAD = FLASHD, PAGE =
0
RUN = RAML123, PAGE = 0
LOAD_START(_cinit_loadstart),
RUN_START(_cinit_runstart),
SIZE(_cinit_size)
.pinit : LOAD = FLASHD, PAGE =
0
RUN = RAML123, PAGE = 0
LOAD_START(_pinit_loadstart),
RUN_START(_pinit_runstart),
SIZE(_pinit_size)
.text : LOAD = FLASHD, PAGE =
0
RUN = RAML123, PAGE = 0
LOAD_START(_text_loadstart),
RUN_START(_text_runstart),
SIZE(_text_size)
.const : LOAD = FLASHD, PAGE =
0
RUN = RAML123, PAGE = 0
LOAD_START(_const_loadstart),
RUN_START(_const_runstart),
SIZE(_const_size)
.econst : LOAD = FLASHD, PAGE = 0
RUN = RAML123, PAGE = 0
LOAD_START(_econst_loadstart),
RUN_START(_econst_runstart),
SIZE(_econst_size)
.switch : LOAD = FLASHD, PAGE = 0
RUN = RAML123, PAGE = 0
LOAD_START(_switch_loadstart),
RUN_START(_switch_runstart),
SIZE(_switch_size)
7、最后需要将拨码开关调到1111的地方,然后编译烧写即可。
三、程序烧写到FLASH中方法
工程经过上面修改后可以进行编译,编译无错误后就可以烧写到FLASH中了。CCS5.2已经继承了烧写插件,所以无需再下载任何插件,极大的方便了程序的烧写。工程编译后还需要进行一些设置。在project——property——debug——F28335 Flash Settings里作如下图所示的设置:上部根据你所使用的时钟的真实情况设置晶振频率,分频系数和倍频系数。第二部分勾选不变,第三部分可以只勾选自己用到的存储区间,最下方不要更改,以免FLASH误锁后找不到密码。
上面设置完成后就可以直接点击debug按钮,则程序自动烧写到FLASH中,烧写完成后可以在线调试。也可以将下载器拔掉,重新上电,则程序会自动在FLASH中执行。
经过上面的处理,程序烧写到FLASH中就完成了。