文档库 最新最全的文档下载
当前位置:文档库 › dsp28335 在线升级

dsp28335 在线升级

dsp28335 在线升级
dsp28335 在线升级

摘要:为解决特殊场合DSP程序升级困难的问题,以TMS320F28035为例,介绍了一种基于串口通信的适合于TMS320C2000系列DSP实现程序更新的在线升级方法。描述了该在线升级方法的基本思想和实现步骤,给出了关键部分的程序代码。实验证明,该方法简单可靠,可用于嵌入式设备软件程序的升级更新中。

关键词:在线升级; DSP;串口通信; Flash

TMS320C2000系列DSP是美国德州仪器公司(简称TI)推出的集微控制器和高性能DSP特点于一身的DSP系列。该系列的DSP具有强大的控制信号处理能力[1],能够实现复杂的控制算法。随着电子技术的不断发展以及用户需求的不断提升,可能需要经常对已经投入使用的嵌入式设备程序进行更新,而目前一般的程序升级方法是实地取下设备,露出JTAG 端口后通过仿真器来更新程序[2-4]。这种方法虽然简单有效,但对于某些特殊场合,会给程序升级带来了极大的不便[2]。本文以TMS320F28035为例,描述了一种可以脱离JTAG仿真器,不改变DSP上电启动方式,实现TMS320C2000系列DSP应用程序在线更新的方法。

1 在线升级的基本思想

一般的基于DSP的软件程序更新是在CCS环境下通过JTAG接口操作来实现的。基于JTAG接口的方法虽然易于操作,而且调试方便,但经常受空间以及传输距离的限制。例如一台DSP系统安装在复杂、封闭的环境下,当程序需要更新或升级时,利用JTAG接口难以实现程序的在线升级[3]。而基于串口通信的在线升级技术是通过用底层程序烧写应用程序的方法来达到程序升级的目的,该方法则不受复杂系统和复杂环境的限制。另外,在线升级方法不需要改变DSP的启动方式,直接采用DSP默认的内部Flash方式启动[5],从而省去了要对DSP的一些引脚进行硬件设置的麻烦。底层程序指已经固化在DSP指定Flash空间中的程序,不允许用户修改和擦除,主要用于实现在线升级的时机判断、数据接收及代码烧写等功能,该程序中使用了Flash2803x_API库存函数(详见2.2节);应用程序即为用户的升级程序[3]。

F28035 DSP每次上电复位,先运行底层程序,与PC机建立联系,然后根据PC机的指令来判断是否需要升级应用程序。若需要,则将通过串口发送来的应用程序代码烧写至F28035片内Flash指定扇区;否则将继续执行原有的应用程序。当应用程序很大或DSP的RAM空间比较小时,可采用将应用程序代码分批发给DSP,DSP接收并烧写完一批代码后,再进行下一批代码的接收和烧写工作,直到所有的应用程序代码都烧写完毕。

2 在线升级的具体实现

2.1 应用程序

用户的应用程序经过CCS编译连接生成具有模块化格式的目标文件(.out),该文件中的代码和数据分别存放在不同的段中,因而不能直接用来烧写Flash,需将其转换为Flash 能识别的数据格式——二进制文件 (.bin)。本文采用hex2000.exe和FileOshell.exe 工具来实现文件转换。首先,应用程序经过编译连接生成.out文件,然后通过hex2000.exe 把.out文件转换成.hex文件,再通过FileOshell.exe将文件转换成.bin文件。先做一个批处理文件,内容如下:

Example_2803xAdcSoc.out

-map Example_2803xAdcSoc.map

-o Example_2803xAdcSoc.hex

-m

-memwidth 16

-image

ROMS

{

Flash28035: origin = 0x3e8000, len= 0x1000, romwidth=

16, fill=0xFFFF

}

其中,Example_2803xAdcSoc.out 是应用程序经过CCS生成的文件;-map是生成map文件;-o是生成hex文件;-m是Motorola-S 格式;-memwidth 16指存储器位数为16 bit;-image 指选择映像文件;ROMS 是所需要转换的起始地址、长度、位数及填充。本文选择从0x3e8000开始,长度是4 KB,即FlashH,FlashH中未用的部分用0xFFFF填充,本文把这个批处理文件命名为:Example_2803xAdcSoc.cmd。接下来要生成.bin文件,先做一个MS-DOS型批处理文件,其内容如下:IFileIOShell.exe -i Example_2803xAdcSoc.hex -o Example_2803xAdcSoc.bin

注意要把Example_2803xAdcSoc.out、hex2000.exe、FileIO

Shell.exe、Example_2803xAdcSoc.cmd和MS-DOS型批处理文件放在同一目录下,然后双击MS-DOS型批处理文件,即生成所需要的Example_2803xAdcSoc.bin文件。

2.2 底层程序

底层程序用于实现将串口发送的数据烧写至Flash的指定部分,涉及到应用程序的正确定位和复位后的启动过程,是实现整个在线升级的重点。底层程序流程图如图1所示。底层程序主要实现以下功能[3]:

(1)上电复位查询功能。上电复位后通过接收上位机发送的命令判断是否升级。若上位机发送的是升级命令,则跳转到底层程序中升级部分执行;否则,跳转到原有的应用程序处执行。

(2)搬移烧写程序的功能。由于F28035片上Flash不支持在其中一个扇区运行程序去擦除或烧写其他扇区,故完成接收数据和烧写Flash工作的这部分程序(即底层程序中的升级部分程序)需搬移至片内RAM或片外RAM上运行。实现程序搬移的函数为:void MemCopy (Uint16 *SourceAddr, Uint16 *Source End

Addr, Uint16 *DestAddr)

{

while (SourceAddr < SourceEndAddr)

{

*DestAddr++ = *SourceAddr++;

}

return ;

}

其中,SourceAddr为Flash中升级程序的起始地址,SourceEndAddr为Flash中升级程序的结束地址;DestAddr为搬移至内存的首地址。

(3)接收上位机发送的应用程序代码并保存到DSP

指定的内存中(一般为RAM区)。这是通过串口RS232来实现的。并确定用于数据保存的这部分内存未被占用。例如,若需要将应用程序代码暂存到F28035的L0 SARAM区域(地址空间0x3F8000-0x3F8800)。定义数组Uint16 BlockBuffer[2048]用于存储应用程序代码,在底层程序中采用存储器定位语句,将上面的缓冲数组定位到相应的存储空间:

#pragma DATA_SECTION(BlockBuffer,“BlockTransferbuffer”);

在底层程序CMD文件中,采用定位语句,将BlockTransferbuffer定位到DSP的L0 SRAM空间:

BlockTransferBuffer:> L0 SARAM PAGE=2

//地址空间:0x3F8000~0x3F8800 通过以上底层程序的设置,可将应用程序缓存到指定的RAM区域中。

(4)代码接收结束后,将内存中的代码烧写至指定Flash扇区,该步骤通过调用Flash2803x_API库函数完成。底层程序中所用到的Flash2803x_API库函数如下[6]:

①擦除扇区的函数为Uint16 Flash28035_Erase(Uint16 SectorMask,&Fstatus),其中,SectorMask为即将被擦除的扇区;&Fstatus为执行擦除操作后返回的状态值,用来判断擦除操作是否成功。②将程序烧写到Flash扇区的函数为Uintl6 Flash28035_Program(&FlashAddr, &BuffAddr,Length,&Fstatus),其中,&FlashAddr为即将被烧写的Flash扇区的起始地址;&BuffAddr为即将准备烧写的程序当前存放在内存空间的首地址;Length 为程序长度;&Fstatus为执行烧写操作后返回的状态值,用来判断烧写操作是否成功。③校验烧写到Flash中的程序为Uint16 Flash28035_Verify(&FlashAddr,&BuffAddr,Length,&Fstatus),其中,&FlashAddr指定从Flash内开始比较的首地址;&BuffAddr为被比较文件的存储首地址;Length是需要比较的16 bit字的个数,程序长度;&Fstatus是执行校验操作后返回的状态值,用来判断校验操作是否成功。

2.3 底层程序和应用程序的定位

DSP F28035上电复位后,CPU将从内部Boot Rom获得复位向量。复位向量指向Boot Rom并执行其内部的Bootloader程序,执行完毕后确定从内部Flash启动。程序指针跳转到Flash的0x3F7FF6处。由于这个地址是固定的,因此底层程序必须烧写在以这个地址为起始地址的空间内。DSP进入底层软件程序中运行,首先通过接收上位机的命令来判断是否进行在线升级,如果进行在线升级,则跳转到相应升级程序中执行;否则,跳转到原有的应用程序处执行。由底层程序跳转到原有的应用程序处执行时,采用绝对地址跳转。部分程序如下所示:

#define Jumpgxcx (void (*)(void))0x3E8FFE

//定义应用程序的跳转地址 SCI_SendStatus(“upgrade program? (y/n):”)

//向上位机询问是否升级

temp = SCIA_GetByteData_app();

//接收上位机发送来的是否升级命令

if (temp==’y’)

{

main2(); //如果升级,则跳转到升级程序中执行

}

Else

{

(*Jumpgxcx)();

//如果不升级,则采用绝对地址跳转到应用程序中执行

}

}

底层程序的cmd配置与应用程序的cmd配置要保持一致,不能产生地址冲突。同时,要注意底层程序和应用程序的跳转地址配置。

底层程序cmd文件的部分配置如下:

BEGIN : origin = 0x3F7FF6, length = 0x000002

RESET : origin = 0x3FFFC0, length = 0x000002 /*

codestart : > BEGIN PAGE = 0

应用程序cmd文件的部分配置如下:

BEGIN : origin = 0x3E8FFE, length = 0x000002

codestart : > BEGIN PAGE = 0

3 烧写步骤

首先把底层程序通过JTAG接口烧写到F28035中,然后再进行应用程序的烧写。应用程序的烧写步骤为:先把串口调试工具的参数配置为波特率9 600 bit/s、8 bit数据位、1 bit停止位、没有奇偶校验位;选择发送文本文件方式,发送应用程序的.bin文件到DSP。由于F28035的RAM区比较小,可以采取把应用程序代码分为多次发送的方式。烧写过程如图2所示。

本文介绍了一种基于串口通信的DSP应用程序在线升级技术,可以在不打开机箱的条件下实现模块软件的更新升级。经过实验发现,采用在线升级技术来更新程序所耗费的时间比采用JTAG口烧写程序所耗费的时间要长一些,但解决了复杂情况下程序升级困难的问题。总之,该方法简单可靠,可应用于嵌入式设备的软件程序更新升级中。

目标板:C2000的28335/28069

一、主要思路:

1、准备升级程序(相当于一个bootloader),作为上电首先运行的程序。进入升级程序,首先判断需不需要升级,需要升级,进入升级状态,通信完成新的主程序的接收,存入,升级成功后,进入主程序运行。

2、在主程序运行时,收到升级指令,标记升级标志,重启进入升级程序进去升级。

3、板子上电后,会调到flash启动的起始地址0x33FFF6(DSP28335),这个地址存放着程序的codestart的其实地址。所以,修改了0x33FFF6的存放的值,那么就能决定执行那一段程序。还可以通过汇编跳转指令直接跳转到程序codestart执行。

二、升级程序

1、具备能力:具备通信能力和Flash读写能力

2、准备:Flash API移植、上位机的升级配套程序;存储升级标志位的空间(外部EEPROM,不会随便擦除的内部Flash)

3、流程:接收->校验->烧写->跳转

三、升级步骤

1、数据接收:通过CAN/串口等方式接收数据。由于28335内存较小,不适合缓存大量的数据,这里是接收一部分数据,校验完成后烧写进Flash,再去接收一部分数据

2、数据解析:接收到的数据是hex格式的数据,所以需要解析才能放入对应的flash地址。但由于28335能力限制,这里采用先在上位机解析完成,采用先告知地址,然后发送数据的方式完成数据通信和传输。

3、校验:这里采用crc校验。

/******************************************************

*Name : crc16

*Function: crc校验16位

*Params : data(UInt8 *):待操作的数组 len:数据长度

*Return : UInt16:返回CRC值 CRC校验码为2个字节高位在前

*******************************************************/

UInt16 crc16(Uint8 *data, UInt16 len)

{

UInt16 CRC = 0xFFFF;

UInt8 j, TMP = 0;

UInt8 i;

for (i = 0; i < len; i++)

{

CRC ^= data[i];

for (j = 0; j < 8; j++)

{

TMP = CRC & 0x0001;

CRC = CRC >> 1;

if(TMP)

CRC = CRC ^ 0xA001;

}

}

return CRC;

}

4、数据烧写flash:运用flash API提供的接收完成数据的烧写。这里要注意flash API必须运行在RAM中。

5、完成数据烧写后,需要跳转到主程序。一般采用汇编指令。汇编指令asm("LB 0xXXXXXX")或者汇编函数。

这里采用asm的方式,跳转地址为新应用程序的起始地址,这里必须规定每次跟新的新应用程序的起始地址必须固定。

asm(" LB 0x3xxxxx");

如果是使用变动的起始地址,则必须采用汇编函数,把地址作为参数传进函数。

四、主程序

1、接收升级指令后,能够标志升级状态。重启进入升级程序,进行判断,进而升级程序。

2、主程序运行后,升级状态标记为不用升级状态。

五、注意点

1、升级程序与主程序要严格分开,合理分配flash空间,附升级程序和主程序cmd大致分配空间。

主程序cmd文件

/**********************************************************************

* File: f28335_nonBIOS_flash.cmd -- Linker command file for non-DSP/BIOS

* code with DSP in Boot to Flash boot mode.

*

* History: 09/18/07 - original (D. Alter)

**********************************************************************/

MEMORY

{

PAGE 0: /* Program Memory */

BEGIN_M0 : origin = 0x000000, length = 0x000002 /* Part of M0SARAM. Used for "Boot to M0" bootloader mode. */

FLASH_PROGRAMS : origin = 0x310000, length = 0x000010 /* On-chip FLAS H */

FLASH_PROGRAM : origin = 0x310010, length = 0x01FFF0 /* On-chip FLASH */

ZONE7A : origin = 0x200000, length = 0x010000

CSM_RSVD : origin = 0x33FF80, length = 0x000076 /* Part of FLASH Sect or A. Reserved when CSM is in use. */

BEGIN_FLASH : origin = 0x33FFF6, length = 0x000002 /* Part of FLASH Sect or A. Used for "Jump to flash" bootloader mode. */

PASSWORDS : origin = 0x33FFF8, length = 0x000008 /* Part of FLASH Sec tor A. CSM password locations. */

ADC_CAL : origin = 0x380080, length = 0x000009 /* ADC_cal function in Reserved memory */

OTP : origin = 0x380400, length = 0x000400 /* 1Kw OTP */

IQTABLES : origin = 0x3FE000, length = 0x000B50 /* Part of Boot ROM */ IQTABLES2 : origin = 0x3FEB50, length = 0x00008C /* Part of Boot ROM * /

FPUTABLES : origin = 0x3FEBDC, length = 0x0006A0 /* Part of Boot ROM */

BOOTROM : origin = 0x3FF27C, length = 0x000D44 /* 8Kw Boot ROM */ RESET : origin = 0x3FFFC0, length = 0x000002 /* part of Boot ROM */ FLASH_CONST : origin = 0x300000, length = 0x010000

PAGE 1 : /* Data Memory */

M0SARAM : origin = 0x000002, length = 0x0003FE /* 1Kw M0 SARAM */ M1SARAM : origin = 0x000400, length = 0x000400 /* 1Kw M1 SARAM */ DRAM : origin = 0x008000, length = 0x008000

PIEVECT : origin = 0x000D00, length = 0x000100

ZONE7B : origin = 0x210000, length = 0x010000

// FLASH_DATA : origin = 0x330000, length = 0x008000 /* On-chip FLASH */

}

SECTIONS

{

/*** Compiler Required Sections ***/

/* Program memory (PAGE 0) sections */

.text1 : {DSP2833x_CodeStartBranch.obj(.text)}> FLASH_PROGRAMS, PAGE = 0 .text2 : {*(.text)}> FLASH_PROGRAM, PAGE = 0

.cinit : > FLASH_PROGRAM, PAGE = 0

.const : > FLASH_PROGRAM, PAGE = 0

.econst : > FLASH_CONST, PAGE = 0

.pinit : > FLASH_PROGRAM, PAGE = 0

.reset : > RESET, PAGE = 0, TYPE = DSECT /* We are not using t he .reset section */

.switch : > FLASH_PROGRAM, PAGE = 0

.cio : > FLASH_PROGRAM, PAGE = 0

/* Data Memory (PAGE 1) sections */

.bss : > DRAM, PAGE = 1

.ebss : > DRAM, PAGE = 1

.stack : > DRAM, PAGE = 1

.sysmem : > ZONE7B, PAGE = 1

.esysmem : > ZONE7B, PAGE = 1

/*** User Defined Sections ***/

codestart : > BEGIN_FLASH, PAGE = 0 /* Used by file CodeSt artBranch.asm */

csm_rsvd : > CSM_RSVD, PAGE = 0 /* Used by file passwo rds.asm */

internalMemFuncs : > FLASH_PROGRAM, PAGE = 0 /* Used by fil e Xintf.c. Link to internal memory */

passwords : > PASSWORDS, PAGE = 0 /* Used by file pass words.asm */

/* Section secureRamFuncs used by file SysCtrl.c. */

ramfuncs : LOAD = FLASH_PROGRAM, PAGE = 0 /* Should be Fl ash */

RUN = ZONE7A, PAGE = 0 /* Must be CSM secured RAM */

LOAD_START(_RamfuncsLoadStart),

LOAD_END(_RamfuncsLoadEnd),

RUN_START(_RamfuncsRunStart)

/* Allocate ADC_cal function (pre-programmed by factory into TI reserved memo ry) */

.adc_cal : load = ADC_CAL, PAGE = 0, TYPE = NOLOAD

}

/******************* end of file ************************/

升级程序cmd文件

/**********************************************************************

* File: f28335_nonBIOS_flash.cmd -- Linker command file for non-DSP/BIOS

* code with DSP in Boot to Flash boot mode.

*

* History: 09/18/07 - original (D. Alter)

**********************************************************************/

MEMORY

{

PAGE 0: /* Program Memory */

BEGIN_M0 : origin = 0x000000, length = 0x000002 /* Part of M0SARAM. Used for "Boot to M0" bootloader mode. */

FLASH_PROGRAM : origin = 0x330000, length = 0x005000 /* On-chip FLAS H G*/

FLASH_PROGRAM1 : origin = 0x335000, length = 0x001000 /* On-chip FLAS H G*/

FLASH_CONST : origin = 0x336000, length = 0x001000 /* On-chip FLASH G */

ZONE7A : origin = 0x200000, length = 0x010000

CSM_RSVD : origin = 0x33FF80, length = 0x000076 /* Part of FLASH Sect or A. Reserved when CSM is in use. */

BEGIN_FLASH : origin = 0x33FFF6, length = 0x000002 /* Part of FLASH Sect or A. Used for "Jump to flash" bootloader mode. */

PASSWORDS : origin = 0x33FFF8, length = 0x000008 /* Part of FLASH Sec tor A. CSM password locations. */

ADC_CAL : origin = 0x380080, length = 0x000009 /* ADC_cal function in Reserved memory */

OTP : origin = 0x380400, length = 0x000400 /* 1Kw OTP */

IQTABLES : origin = 0x3FE000, length = 0x000B50 /* Part of Boot ROM */ IQTABLES2 : origin = 0x3FEB50, length = 0x00008C /* Part of Boot ROM * /

FPUTABLES : origin = 0x3FEBDC, length = 0x0006A0 /* Part of Boot ROM */

BOOTROM : origin = 0x3FF27C, length = 0x000D44 /* 8Kw Boot ROM */ RESET : origin = 0x3FFFC0, length = 0x000002 /* part of Boot ROM */ PAGE 1 : /* Data Memory */

M0SARAM : origin = 0x000002, length = 0x0003FE /* 1Kw M0 SARAM */ M1SARAM : origin = 0x000400, length = 0x000400 /* 1Kw M1 SARAM */ DRAM : origin = 0x008000, length = 0x008000

PIEVECT : origin = 0x000D00, length = 0x000100

ZONE7B : origin = 0x210000, length = 0x010000

//FLASH_DATA : origin = 0x330000, length = 0x008000 /* On-chip FLASH B*/

}

SECTIONS

{

Flash28_API:

{

-lFlash28335_API_V210.lib(.econst)

-lFlash28335_API_V210.lib(.text)

} LOAD = FLASH_PROGRAM1,

RUN = ZONE7A,

LOAD_START(_Flash28_API_LoadStart), LOAD_END(_Flash28_API_LoadEnd), RUN_START(_Flash28_API_RunStart), PAGE = 0

/*** Compiler Required Sections ***/

/* Program memory (PAGE 0) sections */

.text : > FLASH_PROGRAM, PAGE = 0 .cinit : > FLASH_PROGRAM, PAGE = 0 .const : > FLASH_PROGRAM, PAGE = 0 .econst : > FLASH_CONST, PAGE = 0 .pinit : > FLASH_PROGRAM, PAGE = 0

.reset : > RESET, PAGE = 0, TYPE = DSECT /* We are not using t he .reset section */

.switch : > FLASH_PROGRAM, PAGE = 0

.cio : > FLASH_PROGRAM, PAGE = 0

/* Data Memory (PAGE 1) sections */

.bss : > DRAM, PAGE = 1

.ebss : > DRAM, PAGE = 1

.stack : > DRAM, PAGE = 1

.sysmem : > ZONE7B, PAGE = 1

.esysmem : > ZONE7B, PAGE = 1

/*** User Defined Sections ***/

codestart : > BEGIN_FLASH, PAGE = 0 /* Used by file CodeSt artBranch.asm */

csm_rsvd : > CSM_RSVD, PAGE = 0 /* Used by file passwo rds.asm */

internalMemFuncs : > FLASH_PROGRAM, PAGE = 0 /* Used by fil e Xintf.c. Link to internal memory */

passwords : > PASSWORDS, PAGE = 0 /* Used by file pass words.asm */

/* Section secureRamFuncs used by file SysCtrl.c. */

ramfuncs : LOAD = FLASH_PROGRAM, PAGE = 0 /* Should be Fl ash */

RUN = ZONE7A, PAGE = 0 /* Must be CSM secured RAM */

LOAD_START(_RamfuncsLoadStart),

LOAD_END(_RamfuncsLoadEnd),

RUN_START(_RamfuncsRunStart)

/* Allocate ADC_cal function (pre-programmed by factory into TI reserved memo ry) */

.adc_cal : load = ADC_CAL, PAGE = 0, TYPE = NOLOAD

}

/******************* end of file ************************/

2、固定程序起始地址的方法为,codeStartBranch.asm的其实地址,即codestart的其实地址,这里使用

.text1 : {DSP2833x_CodeStartBranch.obj(.text)}> FLASH_PROGRAMS, PAGE = 0 .text2 : {*(.text)}> FLASH_PROGRAM, PAGE = 0

详见主程序cmd文件描述。

3、升级后会出现跳转到主程序,不能执行的情况,所以必须要提供一个方式,解决这个问题。这里做了几个处理:

(1)进入主程序后,再修改升级标志位

(2)启动升级程序后,未进入主程序前,留有可以与上位机通信方式,可以再次进入升级模式。

(3)启动升级程序后,必须接收到一个指令才跳转至主程序执行

相关文档