摘 要:本文介绍了在TMS320C32 DSP系统中通过对FLASH的在线系统编程来实现DSP的BOOTLOADER的一个方案,给出了一个简单的测试用实例及相应的源代码。
关键词:TMS320C32; BOOTLOADER; 在系统编程; 引导表
现在,数字信号处理器(DSP)正越来越多地应用到各种场合,而Flash存储器已成为DSP系统的一个基本配置,主要用来存放用户程序代码。FLASH具有容量大、单电压供电、可以在线编程的特点,并且可以利用现成的DSP通过软件编程来实现同样的Flash的在线烧写。
在脱机运行的DSP系统中,用户代码需要在加电后自动装载运行。DSP系统的引导装载(BOOTLOADER)是指在系统加电时,DSP将一段存储在外部的非易失性存储器的代码转移到内部的高速存储器单元中去执行。这样既利用了外部的存储单元扩展DSP本身有限的ROM资源,又充分发挥了DSP内部资源的效能。笔者结合自己的实际开发经验,设计并实现了一个引导装载系统的模型,给出一个简单的测试用的实例用来实现对FLASH的读写操作并有相应的源代码。整个方案有较大的灵活性和实用性,并且在实时数据处理系统中得到了实际应用。
系统描述
本系统由DSP(TMS320C32)及外部的Flash(AM29F400B)和外部高速RAM及相关的扩展单元如FPGA、双口RAM、16位高速DA等构成。DSP与FLASH的连接如图1所示。DSP与FLASH是主从关系,由DSP的相关输出管脚控制FLASH的擦除和读写。
Flash用于存放引导程序段和用户代码,由DSP软件编程来写入。当系统处于MCBL模式上电复位和带电复位时,DSP首先从外部FLASH指定的引导程序段的起始位置处开始执行引导装载。
所谓引导装载,就是将原先存储在Flash中的用户代码移植到DSP内部的高速RAM执行,然后将程序指针PC设置为用户代码的起始地址。这样,接下来就可以利用DSP资源高速执行用户代码了。
图1 硬件电路原理图(略)
DSP对FLASH的操作
DSP及FLASH简介
TMS320C3X系列芯片是美国TI公司推出的第一代浮点DSP芯片,具有丰富的指令集、较高的运算速度、较大的寻址空间和较高的性价比,在各领域得到了广泛的应用。TMS320C32在TMS320C30和TMS320C31的基础上进行了简化和改进。在结构上的改进主要包括可变宽度的存储器接口、更快速的指令周期时间、可设置优先级的双通道DMA处理器、灵活的引导程序装入方式、可重新定位的中断向量表以及可选的边缘/电平触发中断方式等。
AM29F00B是AMD公司的FLASH,容量为4Mbit,支持8位或16位操作模式。通过特殊的命令字序列可以对FLASH进行擦除和读写。与以往的FLASH相比,它由外部单电压供电,即无需额外提供高电压即可实现擦除及写入,因而在系统设计上无需考虑特殊的电平匹配。基于快速存取的考虑,本方案采用16位模式。
地址映射方式
由于用DSP操作FLASH,必然涉及到FLASH的实际地址在DSP中的映射方式。在擦除或读写FLASH之前,必须先执行相应的命令字序列,即在指定的FLASH地址处写入指定的指令代码。由于C32采用统一编址方式,整个FLASH地址空间可以和DSP的地址空间一一对应,所以不需要考虑地址的重映射。
根据命令字序列表1,现以对FLASH写入为例,命令字序列如下。
表1:命令字序列(略)
ldi 0555h,ar0
ldi 0aah,r0
sti r0,*ar0; //1st cycle
nop
nop
ldi 02aah,ar0
ldi 055h,r0
sti r0,*ar0; //2nd cycle
nop
nop
ldi 0555h,ar0
ldi 0a0h,r0
sti r0,*ar0; //program command
nop
nop
ldi ar4,r5; //*ar4 store the data of my program
sti r5,*ar3++; //ar3 store the address of my program
这样,在DSP中就可以对外部FLASH进行写入操作了。擦除和读操作也类似,不再累述。
Flash操作过程
在DSP将数据写入Flash之前,先要删除数据所在块,然后才能重新写入。擦除和写操作之前都要执行相应的命令字序列,而读操作则可以直接进行。而且要写入的数据部分应为引导程序段以及用户代码是经过编译、连接后的目标代码,且为Flash可识别的HEX格式。
引导装载模型设计
引导装载原理
加电前,DSP设置为微处理器模式(MCBL=1),INT0=0。加电后,DSP首先根据中断向量表起始处的跳转命令,转向0x45h处的引导程序段并实现代码移植功能。完毕后,再次跳转到移植后的用户程序段的起始地址并执行。
建立引导表的步骤
编写相应的asm文件(wave.asm)和cmd(lnk.cmd)文件,程序经过仿真器仿真无误以后,就要建立引导表,使系统能够脱机运行。下面介绍建立系统引导表的步骤:
1.编译文件。编写完程序代码以后,对源程序进行编译,生成.obj文件。本系统中采用C32 DSP,因此加上-v32选项,汇编asm源文件:d:\asm30
-v32 wave.asm wave.obj生成wave.obj文件。
2.链接文件,将.obj文件生成.out文件。链接目标文件: d:\lnk30 wavelnk.cmd. 生成wave.out和wave.map文件
。
3.使用数制转换工具生成.HEX文件或.BIN文件,C32使用的数据转换工具为hex30.exe,d:\hex30 wavehex.cmd
,生成wave.hex文件。命令文件的编写很重要,下面分别例举了C32系统引导的CMD命令文件。 Wavelnk.cmd文件:
- wave.OBJ
-o wave.out
-m wave.map
-stack 50
-e main /*程序入口地址*/
MEMORY
{ EXTERNRAM: org = 0x920000, len = 0x1000 }
SECTIONS
{ .data : {} > EXTERNRAM
.text : {} > EXTERNRAM }
wavehex.cmd文件:
wave.OUT
-a
-BOOT
-BOOTORG 01000h
-DATAWIDTH 32
-MEMWIDTH 16
-ROMWIDTH 16
-IOSTRB 0000000F8h
-STRB0 0700E8h
-STRB1 0F0008h
-e 920000h /*指定Bootload完成后PC地址*/
-MAP wavehex.MAP
-o wavehex.hex
ROMS
{ FALSH: org = 01000h, len=40000h /* the flash memory space on board
*/ }
逻辑功能分块
引导装载系统包括引导程序段、用户程序段、中断向量表和连接命令文件四部分。引导程序段负责将用户程序段和中断向量表装载到目标地址,用户程序段是实现用户系统功能的核心代码,中断向量表包括加电后的跳转处理和中断服务程序的入口,连接命令文件则是分配各个程序段在DSP地址空间中的位置。
具体代码实现
具体代码分析
通过ultraedit等文本编辑软件打开wavehex.hex文件可以看到引导表的源数据流结构内容包含如下几个方面:
1)Flash存储器宽度设定(010h = 16bit);
2)控制寄存器STRB0、STRB1、IOSTRB的设定 (0000F8H 0700E8H 0F0008H) ;
3)第一段代码的长度(0FH);
4)第一段代码的起始址址 (0920000H) ;
5)第一段代码的目的存储空间配置字段(0F000868H);
6)第二段代码的长度;
7)第二段代码的起始址址;
8)第二段代码的目的存储空间配置字段;
… …
9)结束符(00H)。
由此可以知道引导表包含以下几部分:一个包含引导表数据宽度和其他数据总线控制寄存器值的文件头COFF文件中各个段的数据,其中每个段又包含一个该段的文件头来指示该段的代码长度和目标地址,最后有一个结束段,表明程序代码的结尾。
写入目标代码
上述引导程序经过CCS编译及连接后,生成的目标文件boot.out是DSP能够识别的COFF格式。但是FLASH不支持这种模式,所以不能直接写入FLASH中。CCS自带有多种HEX类型的转换程序,比如常见的有Intel格式等。但是不同的HEX类型有不同的格式和头尾开销,比如Intel格式中除了数据之外还有起始符、字节个数、起始地址、类型以及校验位等各种信息,并非纯粹数据的HEX格式表示。我们一般通过了解了ASCII格式的文件结构之后,就可以从中提取出需要写入FLASH中的代码的HEX格式相应的地址,即对应上面提到的mydata和myaddress。然后就可以利用上面的方法,用DSP将引导系统各个部分的代码脱机运行前写入FLASH。
fill10h: ldi 010h,r4
call writeinflashheader
;fill the value of STRBx
;iostrb
iostrb: ldi 0f8h,r4 ;000f8h
call writeinflashheader
strb0: ldp @valofstrb0
ldi @valofstrb0,r4 ;700e8h
call writeinflashheader
strb1: ldp @valofstrb1 ;f0008h
ldi @valofstrb1,r4
call writeinflashheader
;^^^^^^T^E^X^T^^^^^^^^^^^^^^^^
ldi 0fh,r4 ;fill length of text=0fh
call writeinflashheader
ldi @addroftext,r4 ;fill 0920000h
call writeinflashheader
ldi @configflash,r4 ;fill config
call writeinflashheader
ldi @addroftext,ar4 ;fill code of text
;writein from the first word to the last word TEXT
ldi @lenoftext,rc
rptb programend
call writeinflashcode
programend:
nop
;^^^^^^D^A^T^A^^^^^^^^^^^^^
… …
;end flag
ldi 0h,r4
call writeinflashheader
简单测试实例
利用上述方法,使得系统在脱机状态下实现引导装载,并且从DSP的DX0端口输出均匀脉冲波形,程序代码如下。
main:ldi 060h,r0
ldp @serialportx
ldi @serialportx,ar0
sti r0,*ar0
ldi 020h,r0
ldp @serialportx
ldi @serialportx,ar0
sti r0,*ar0
bu main
经过编译、连接、格式转换以及写入FLASH之后,系统就可以实际脱机运行了。加电一段时间后,可以通过示波器测量得到DX0端口的均匀脉冲波形,证明引导装载成功。
结束语
通过DSP对外部Flash编程实现DSP的BOOTLOASDER在整个DSP嵌入式系统开发中有着至关重要的作用。如果开发者在开发之初就掌握这项技术,就会大大方便系统的调试,缩短开发时间。
|