TI支持很多种方式的boot,内部的ram(saram),flash,sci,但无论哪种启动都遵循下面的流程:
而该流程中的reset,initboot,call selectbootmode, read i/o state, call boot loader这些步骤都是固化在芯片内的程序自己执行的,也就是说这些代码在出厂的时候已经在TI的芯片内。(我们写的程序是从codestart出开始的,其代码在DSP2833x_CodeStartBranch.asm内,其指定位置在CMD文件内定义。下载到flash中时是在0x3f7ff6处,因为复位的时候指向的0x3fffc0,先执行固化的bootloader再跳转到0x3f7ff6。下载到RAM中时是在0处。因为不需执行bootloader。)
在28335中是一段的8k*16的read-only的memory,地址位于0x3fe000-0x3fffff,见下图:
根据上面的流程图,详细的解释一下流程:
1.在3fffc0到3fffff其实是放了中断向量表的地方:系统一开机当然是处于reset中断,因此直接跳至reset的地方执行(0x3fffc0)。而这个地方的两个字节只是放了一条指令,就是跳至initboot函数,也就是3ff34c的地址执行bootloader。
.reset 与reset是不同的,一个在memory,一个在sections中。
.reset只包含一个32位的中断矢量,指向实时支持库rts2800_ml.lib中的C编译器导引函数,即_c_int00子程序。通常我们不用此块,而是另外创建分支指令指向开始代码。如4中介绍。
2.在3ff34c的bootloader的程序,这里主要有initboot, 和SelectBootMode, 以及一些外设引导的函数。SeleteBootMode根据芯片的硬件或软件设置来判断芯片该去哪里寻找程序入口,直接目的是如何找到main,然后执行应用程序。bootloader操作中会去检测外部GPIO口的状态,从而判断是哪种方式的启动:
3.然后根据相应的启动方式跳至相应的入口地址:比如FLASH启动就是0x33fff6, 内部SARAM启动就是0x0。
4.而这里的入口地址就是cmd文件中定义的begin段。因此对于flash启动和ram启动,begin的定义是不同的,在flash启动时begin就是0x33fff6,而ram启动begin就是0x0.这个2个字的区间也就是放了我们程序最初执行的第一条指令(通常是code_start).一条长跳转指令LB刚好占两个字节。
bootloader执行完毕之后会跳到0x3f7ff6处,而codestart被放置到了BEGIN处。故即是执行DSP2833x_CodeStartBranch.asm代码。
codestart包含一条长跳转指令,指向实时支持库rts2800_ml.lib中的C编译器导引函数,即_c_int00子程序。不同的是:如果系统的程序(.text)放在系统内部RAM中仿真运行,则本块应放入片内RAM中,如地址单元0x3F8000;如果是固化程序进FLASH,则.codestart应定位与FLASH中的其实地址为0x3F7FF6中。(一条长跳转指令占2个字)。
ramfuncs作用是程序的搬移。load=allocation(强制地址或存储空间名称)同>allocation:定义输出段将会被装载到哪里。
run= allocation(强制地址或存储空间名称)同>allocation:定义输出段将会在哪里运行。
另:CMD文件中只出现一个关键字load或run时,表示两者的地址时表示两者的地址时重合的。
LOAD_START(_RamfuncsLoadStart)令编译器创建了一个变量RamfuncsLoadStart,该变量指向段ramfuncs的装载地址的首地址(LOAD_ START为编译伪指令,请见CCS的帮助文档);
LOAD_START(_RamfuncsLoadEnd)令编译器创建了一个变量RamfuncsLoadEnd,该变量指向段ramfuncs的装载地址的末地址(LOAD_ END为编译伪指令,请见CCS的帮助文档);
RUN_START(_RamfuncsRunStart)令编译器创建了一个变量RamfuncsRunStart,该变量指向段ramfuncs的运行地址的首地址(LOAD_ START为编译伪指令,请见CCS的帮助文档);
或通过这个方式可以把一些程序放入指定的位置。(放置的位置与执行时的位置不同时,如下载到flash中,但是运行时要在RAM中运行)
学习一款处理器芯片,搞明白芯片的运行过程,特别是程序的启动阶段,对于更好的应用芯片很有帮助。对F28335来讲,它提供的方式很多。首先F28335中有片内flash,可以将程序存储在这里;其次,F28335也提供了bootloader功能;最后,F28335还具有片上OTP,用户可以在这里设定自己的启动方式。
在28335的TI提供的例程中,程序的起始位置是code_start,在这里先禁止看门狗,然后再跳转到c_int00处运行;而在一般的C工程中,这个起始位置一般是c_int00;这个起始位置在编译选项(build options)中设定,在C环境建立之前将看门狗禁止,使得程序更可靠。
查阅到“DSP2833x_CodeStartBranch.asm”中的说明,如下:
For these examples, code_start is thefirst code that is executed after exiting the boot ROM code. The codestart section in the linker cmd fileis used to physically place this code at the correct memory location. Thissection should be placed at the location the BOOT ROM will re-direct the codeto. For example, for boot to FLASH thiscode will be located at 0x3f7ff6.
In addition, the example DSP2833x projectsare setup such that the codegen entry point is also set to the code_startlabel. This is done by linker option -e in the project build options. When thedebugger loads the code,it will automatically set the PC to the "entrypoint" address indicated by the -e linker option. In this case the debugger is simplyassigning the PC, it is not the same as a full reset of the device.
从上面的说明,可以看到,在仿真模式下忽略了启动模式的选择,而是让仿真器直接将程序的起始地址赋给PC的。特别对这个程序来讲,由于在C环境之前,还禁止了看门狗,程序的起始地址是code_start。但是这里有一点还应注意,在仿真模式下,模拟的是将程序引导到M0SARAM中,所以在CMD文件中,将code_start硬件定位到了M0 SARAM的起始位置处,如果固化程序的话,需要更改code_start的位置,将其放在对应方式的位置处。
一种是boot to RAM,即跳到0x000000的RAM中,去开始执行指令,主要针对程序加载在RAM的仿真模式;另外一种是boot to Flash,则跳到0x3F7FF6中去开始执行代码。
相应的,程序会在这两个入口地址0x000000, 0x3F7FF6放一条跳转指令,在codestart.asm源文件中,原因是在Flash的入口地址处只有两个单元的空间,后面是CSM模块,所以需要跳转;而在RAM中之所以也需要跳转,主要是因为在跳转到main之前,需要执行一小段代码_c_int00,该代码会使用0x000003之后的一段RAM,如果代码放在那里,在执行_c_int00之后会损坏代码。下载到RAM中的时候CMD文件有上面的两句,codestart是在文件“DSP2833x_CodeStartBranch.asm”中有定义,实际上codestart段只是包含了一个跳转指令,是程序跳转到_c_int00处,_c_int00在boot.asm in RTS library中有定义,_c_int00的代码最终会调用c的main函数,之后就是main函数的执行。
下载到flash中的时候CMD文件有上面的两句。(而复位的时候指向的是0x3fffc0)
另外就是一些外设引导模式,如SCI引导以及SPI引导等,像我们常使用的C2PROG软件就支持SCI引导,然后通过串口下载程序。
_c_int00 is branch to start of boot.asm in RTS libray //翻译为中文就是:_c_int00是rts2800_ml.lib的入口地址;
· _c_int00是C初始化代码的入口地址
· 在你用C编程的时候,DSP需要执行一段C运行支持库代码以完成C运行环境的初始化,_c_int00就是这段初始化代码的入口地址,
· _c_int00函数在运行支持库(rts,runtime-support library)中。连接器会将这个函数的入口地址放置在复位中断向量处,使其可以在初始化时被调用。c_int0函数进行以下工作以建立C运行环境:为系统堆栈产生.stack块,并初始化堆栈指针。从.cinit块将初始化数据拷贝到.bss块中相应的变量。
· 执行完初始化代码后,就跳转到main函数,开始运行C程序;
· rts2800.lib:C/C++运行支持库;
· rts2800_ml.lib C/C++大内存模式运行支持库.
· rts2800_ml.lib中有大量浮点运算处理的函数而rts2800.lib没有
· 在指针的访问空间上有区别,rts2800.lib中库函数的指针为near,故不能访问3Fxxxx,rts2800_ml.lib可以访问(大小内存模式故名思议就是可以访问的内存的大小有区别,小内存模式只能访问低64k地址,也就是16位地址线)
下面是2812的flash启动流程,可参照学习28335的启动
2812从内部flash启动的详细流程说明:
(a)上电复位
(b) 判断是否从flash启动
(c)复位向量是指向片内Flash的0x3FFFC0,2812有一块flash地址从0x3FF000-0x3FFFFF在出厂时已经固化好了引导程序。在0x3FFFC0处是一条跳转指令,跳到iniboot(地址0x3FFC00)函数处执行iniboot代码,该iniboot代码就是TI在dsp出厂时固化在flash中的
(d)InitBoot assembly Routine将选择SelectBootMode function启动模式函数。这个函数由GPIO 引脚的状态决定启动类型。一旦启动结束,选择启动模式函数返回一入口地址给InitBoot函数。入口地址是退出bootloader之后代码开始执行的起始点。InitBoot接着将会调用ExitBoot子程序,把CPU寄存器的状态恢复到复位状态。比如flash boot模式。
(e)那么initboot执行完后跳转到0x3F7FF6处(codestart处),此位置刚好在128位(CSM)密码位置之前。
(f)你要在0x3F7FF6处放置跳转指令,以跳转到你要去的地方,比如是boot loader或应用代码,通常的跳转去处是_c_int00。
(g)上面代码执行后跳到C初始化的入口_c_int00(0x3F6000) ,在C初始化的入口,_c_int00对一些变量,堆栈和寄存器进行必要的设置。
(h)调用main函数开始运行C程序。