DSP

总结——在CCS5.5.0中如何将代码烧写到DSP28335的Flash中

2019-07-13 10:42发布

/******************************************************17.6.10更新*************************************************************/ 发现之前想的有点小问题,现在想的是,在烧写程序前不必将Boot mode选择为1111,只需要将cmd文件替换为F28335.cmd,然后load程序,之后再将Boot mode选为1111,即FLASH启动,个人猜测,未验证。 /********************************************************************************************************************************/ 把一个原来是烧写到DSP的片内RAM的程序修改成是烧写到DSP片内FLASH的程序,需要以下几个步骤:

1.添加DSP2833x_CodeStartBranch.asm文件

添加D: idcsc28DSP2833xv131DSP2833x_commonsourceDSP2833x_CodeStartBranch.asm文件,此文件负责上电后程序执行顺序跳转的;

2.添加DSP281x_Headers_nonBIOS.cmd文件

添加D: idcsc28DSP2833xv131DSP2833x_headerscmdDSP2833x_Headers_nonBIOS.cmd文件,用于将DSP28头文件中的外设结构与存储器地址对应起来;

3.删除28335_RAM_lnk.cmd文件

把28335_RAM_lnk.cmd文件从project中移除,用右键选择28335_RAM_lnk.cmd然后选delete;

4.添加F28335.cmd文件

右键选择project名称,然后选add file to project,然后出现浏览框,在D: idcsc28DSP2833xv131DSP2833x_commoncmd这个子文件夹下,选择F28335.cmd,点OK,至此可以在project的文件列表内看到F28335.cmd被添加到project中;

5.添加两行代码

在main()函数中添加如下语句: MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart); InitFlash(); 上述两句话添加在InitPieVectTable();这句的下面的一行,添加语句的时候,注意不要添加错了,每一个字母都要正确,括号也要用英文括号;

6.添加DSP2833x_MemCopy.c文件

右键选择project名称,然后选add file to project,然后出现浏览框,找到D: idcsc28DSP2833xv131DSP2833x_commonsource文件夹中的DSP2833x_MemCopy.c文件,然后点OK;

7.选择Boot mode

DSP开发板上的拨码开关都拨到ON,本质含义是:将F28335的GPIO84、GPIO85、GPIO86、GPIO87这四个引脚用1k到10k之间电阻上拉到3.3V,这样就把Boot mode选为从DSP内部FLASH处boot程序的模式;

8.编译后进行Debug

编译没有错误后即可进行Debug,此时将代码烧写到FLASH中,而不是RAM中,如下图所示:

9.注意事项

(1)下载完如果想要脱离仿真器重新上电运行,必须断掉仿真器与板子的JTAG连接,否则运行程序会出错,之前我只把仿真器上的USB和电脑断开,而JTAG接口未断开,所以出现运行不正常的现象,这一点很重要! (2)不是RAM中运行正确的程序,就在FLASH中运行也一定正确。 这是因为同样的程序在DSP的RAM中运行消耗的时间要远远短于在FLASH中运行的时间。假如,有一个中断函数cpu_timer_isr10ms(),这个函数每隔10ms由CPU定时器1产生中断触发,自动跳转进入执行一次。这个cpu_timer_isr1ms()内部包括三个子函数依次是adc_sanple(),pwm_update(),gpio_toggle(): cpu_timer_isr1ms() { adc_sanple(); pwm_update(); gpio_toggle(); } 其中假设adc_sanple()这个子函数在RAM中的执行时间是1ms,pwm_update()这个子函数在RAM中的执行时间是2ms,gpio_toggle()这个子函数在RAM中的执行时间是3ms,那么1+2+3=6<10,所以完全没有问题,在RAM中上面这些程序都可以运行很好。
但是,如果把上面这些程序放到FLASH中运行,很有可能adc_sanple()这个子函数在FLASH中的执行时间是3ms,pwm_update()这个子函数在FLASH中的执行时间是7ms,这是因为同样的程序在DSP的RAM中运行消耗的时间要远远短于在FLASH中运行的时间。这样前两个函数就把10ms都用掉了,根本轮不上gpio_toggle()这个子函数被执行,就被DSP强制终止了,所以看不到gpio_toggle()的现象;

(3)可以Load program到RAM的Out文件和可以固化(烧写)到FLASH的out文件内容是不同的; (4)一般使用CCS仿真器时,我们把程序烧进RAM中运行,这样运行速度快,方便实际项目的开发与调试,此时用的是28335_RAM_lnk.cmd文件;当项目完成时,我们会选择将程序烧进Flash中,以摆脱仿对真器的依赖,当我们用f28335.cmd连接文件时,会把程序烧进28335内部的Flash中,此时,就可以脱离仿真器运行了,从Flash启动。 (5)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    
...
}
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)cmd中以下代码如何解释?
   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的帮助文档);
RUN_ 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声明。