2009-07-21
注册 | 登录 | 网站地图
 内容管理 > 论坛精华 2009-8-28

LPC2378在线升级实现

关键字:LPC2378
人气: 255

一、概述
在线升级要求正在执行的程序对自己进行升级,如何能可靠升级,如升级失败可以回到原来程序继续执行,本文介绍一种简单容易做到不影响应用的方法。
二、实现方法分析
先看下面的图,把程序空间分为三部分,这是容易理解的分配,
有人问了,这是不是要写一个引导程序,答案是:不用,就用你自己的应用程序,只是巧妙使用分散加载进行编译,把程序分别编译到不同地址就可以了。
0x00040000
高地址区(HighAddr)256k
0x00008000
低地址区(LowAddr)224k
0x00000000
共用代码 32k
我们现在看一下分散加载文件:
分散加载文件1 ------低端地址
ROM_LOAD 0x00000000 0x1000
{

ROM_EXEC 0x00000000{
;中断向量表

Startup.o (RESET, +First);//*.o (RESET, +First)

}
}
ROM_LOAD1 0x00004000 0x2000
{

ROM_EXEC1 0x00004000{


__main.o(+RO)

__scatter.o
(+RO)

__scatter_zi.o(+RO)

lib_init.o(+RO)

irq.o(+RO)

target.o(+RO)

timer.o(+RO)

swi_handler.o(+RO)

comm_arm.o(+RO)

}
}

ROM_LOAD2 0x00008000
0x40000;
//加载映像文件,从第0x00001000开始
{

ROM_EXEC2 0x00008000 {

* (+RO)

}

RW_IRAM1 0x40000000 0x00008000
{
; RW data


* (+RW +ZI)

}
}

分散加载文件2 ------高端地址

ROM_LOAD 0x00000000 0x1000
{

ROM_EXEC 0x00000000{
;中断向量表

Startup.o (RESET, +First)

}
}
ROM_LOAD1 0x00004000 0x2000
{

ROM_EXEC1 0x00004000{


__main.o(+RO)

__scatter.o
(+RO)

__scatter_zi.o(+RO)

lib_init.o(+RO)

irq.o(+RO)

target.o(+RO)

timer.o(+RO)

swi_handler.o(+RO)

comm_arm.o(+RO)

}
}

ROM_LOAD2 0x00040000
0x40000 ;加载映像文件,从第0x00040000开始
{

ROM_EXEC2 0x00040000 {

* (+RO)

}

RW_IRAM1 0x40000000 0x00008000
{
; RW data


* (+RW +ZI)

}
}
我们用两个不同的文件编译后:

低地址程序空间占用:

0x0000 0000 --- 0x0000 0FFF   4k  和高端重用   B1
0x0000 1000 --- 0x0000 1FFF   4K              B2
0x0000 2000 --- 0x0000 3FFF   8k未用          B3
0x0000 4000 --- 0x0000 5FFF   8k和 高端重用   B4
0x0000 6000 --- 0x0000 7FFF   8k未用          B5
0x0000 8000 --- 0x0003 FFFF   224K  低端      B6
0x0004 0000 --- 0x0007 FFFF   256k未用        B7
低端用:B1、B4、B6

高地址程序空间占用:

0x0000 0000 --- 0x0000 0FFF   4k和低端重用   B1
0x0000 1000 --- 0x0000 1FFF   4K             B2
0x0000 2000 --- 0x0000 3FFF   8k未用         B3
0x0000 4000 --- 0x0000 5FFF   8k和低端重用   B4
0x0000 6000 --- 0x0000 7FFF   8k未用         B5
0x0000 8000 --- 0x0003 FFFF   224K 未用      B6
0x0004 0000 --- 0x0007 FFFF   256k高端       B7
   高端用:B1、B4、B7
   
为什么要这么做?我们对比两个编译好的文件发现:
1、 B1 的内容两个文件完全一样。
2、 B4的内容有个别不同, 两个文件B4内容放在同一块内的目的是为让B1相同
3、 B6和B7不同。

这样编译好的两个文件就可以互相升级,因为两个文件第一个扇区相同,向量表一样,升级时第一扇区不用改写,低端的B4可以备份到B3, 高端的B4可以备份到B5, 这样两个程序同时存在,B2来标识正在运行的程序是高端还是低端。 如想改变高低端的程序运行,只要把备份的B3或B5重写到B4然后复位芯片就可以了。
所以升级时写FLASH过程如下:
1、 收到B4的部份,如为高端写在B5,低端则写在B3
2、 B6或B7内容直接按地址写入
3、 全部校验成功后,把B3或B5的内容复制B4,复位芯片。
三、升级流程
四、通信协议
本文用串口进行在线升级,下面是串口通信协议:
1、帧格式
格式 CMD+ADDR+LEN+DATA
代  码        字节数        说  明
CMD        1        命令
ADDR        4        FLASH地址
LEN        2        写长度,512字节
FLAHDATA        变长        数据
2、协议
A:下行数据
CMD+ADDR+LEN+DATA
1、升级开始 (让MCU做升级准备,包括擦除FLASH等)
0X01+ 0X00+0X01+0X00
2、写FLASH   
0X02+ ADDR+LEN+DATA
3、发送CRC-32
0X0C+ ADDR+LEN+DATA
        0X0C+ ADDR +0X04+DATA
4、写结束,可以复位系统
0X03+ ADDR+LEN+DATA
5、放弃本次升级
0X04+ ADDR +0X01+0X00
6、获得目前运行程序地址(用于验证升级是否成功,也可用于测试连接)
  0X05+ ADDR +0X01+0X00
7、切换程序块(用于升级后程序不正常,切换回旧版程序, 回复”准备复位系统”)
  0X06+ ADDR +0X01+0X00
上位机注意:
1、收到写成功返回数据时,要验证,如果和所发不符,重发。
2、升级时,需记录每一段程序的升级记录,全部成功时,才下发复位指令。
3、写失败20次,直接报错,停止升级。     
    4、发数据后5秒无返回数据,报超时,停止升级。
B、上行数据
收到数据做完工作后,发返回数据(5除外)
DATA区域: CMD+ADDR+LEN+DATA
1、开始升级 准备工作完成
0x0F+ 0X00+0X01+0X00
2、写成功返回数据格式:
    0X0A + ADDR+0X01+0X00
3、接收数据有错误(校验不对或不完整,地址错误)返回数据格式:
0X0E + ADDR+0X01+0X00
4、写失败返回数据格式:
0XEE + ADDR+0X01+0X00
5、CRC-32收到和计算值相同后返回:
    0XCC + ADDR +0X04+CRC-32
6、CRC-32收到和计算值不同后返回:
    0XEC + ADDR +0X04+CRC-32(计算值)   
7、准备复位系统:
0X0B + ADDR +0X01+0X00
8、返回当前程序运行区域:   
0x0C + ADDR+0x01+0x00   //ADDR: 0x00002000 / 0x00040000
9、已放弃升级
    0X0D+ ADDR +0X01+0X00

注:1、不需要发ADDR的发四字节的0X00
2、CRC-32 为循环冗余校验码32位
g(x) = x32+ x26 + x23+ x22+ x16+ x12+ x11+ x10+ x8+ x7+ x5
+ x4+ x2+ x + 1; (X=0,或=2 决定于当前数据)
把待运算字节后添32个0  除以上式结果的余就是CRC-32
五、结束语
通信协议用户可以自己选择用什么方式,本文只是一个建议,但一定要有校验方式,本文介绍的方法已经在GPRS上测试200K的程序升级,能够可靠运行。

相关资源
版权所有:华荣汇电子科技(北京)有限公司
COPYRIGNT(C) 2006 FORIC.COM.CN