打印
[NXP ARM]

LPC2378在线升级实现

[复制链接]
5939|27
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
开源共享|  楼主 | 2009-8-5 14:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
LPC2378在线升级实现
一、
概述
在线升级要求正在执行的程序对自己进行升级,如何能可靠升级,如升级失败可以回到原来程序继续执行,本文介绍一种简单容易做到不影响应用的方法。
二、
实现方法分析
先看下面的图,把程序空间分为三部分,这是容易理解的分配,
有人问了,这是不是要写一个引导程序,答案是:不用,就用你自己的应用程序,只是巧妙使用分散加载进行编译,把程序分别编译到不同地址就可以了。



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)


}

}

相关帖子

沙发
开源共享|  楼主 | 2009-8-5 14:41 | 只看该作者
一帖放不下,
我们用两个不同的文件编译后:

低地址程序空间占用:

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,复位芯片。

使用特权

评论回复
板凳
开源共享|  楼主 | 2009-8-5 14:41 | 只看该作者
三、升级流程

      













四、通信协议
本文用串口进行在线升级,下面是串口通信协议:
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

使用特权

评论回复
地板
开源共享|  楼主 | 2009-8-5 14:41 | 只看该作者
上位机注意:
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的程序升级,能够可靠运行。

使用特权

评论回复
5
hqgboy| | 2009-8-11 11:32 | 只看该作者
好。。。
支持上去了,就 有人买你们的芯片了 。

使用特权

评论回复
6
mohanwei| | 2009-8-11 15:10 | 只看该作者
不错,但是我总结出来的经验还是工业现场一定要有一个写保护的bootloder才能实现可靠的远程升级……

使用特权

评论回复
7
mm99| | 2009-8-11 15:31 | 只看该作者
不错

使用特权

评论回复
8
bios51| | 2009-8-15 22:36 | 只看该作者
看看

使用特权

评论回复
9
pigeon0411| | 2009-8-20 14:56 | 只看该作者
跟周立功的例程差不多,没有什么实用价值。

都是将FLASH分成两块用,在运行过程中,总有一块是空着的。
就512KB的FLASH来说,很多人选它,是因为编译出来的代码本身可能就有三四百KB,使用这种方式是根本不行的。
倒是可以外扩,或者升级时切换到升级区去升级(升级的时候是禁止用户做其他操作的,所以没有什么影响)

使用特权

评论回复
10
开源共享|  楼主 | 2009-8-20 21:10 | 只看该作者
本帖最后由 开源共享 于 2009-8-20 21:17 编辑

如果仔细看就会看出门道,不管你是否用两块FLASH,还是一块,关键是那个分散加载文件,能让第一个扇区相同是主要的,这点清楚了,如何做升级你自己说了算。上面的方法对客户应用没有任何要求。你可不让一半空着,也一样用这种方法升级。就象9楼最后行说的。

使用特权

评论回复
11
pigeon0411| | 2009-8-20 22:18 | 只看该作者
我在关注这个贴子。
首先声明,在此发言无其他意图,只为跟大家交流,能跟高手多学一些知识,对我这个菜鸟是幸运的。
也请原谅我的迟钝,我确实还没有看出来其中奥秒,希望楼主不吝赐教,再给小弟指点一些,真诚感谢。

使用特权

评论回复
12
bigarmer| | 2009-8-24 14:16 | 只看该作者
没有看出奥秘啊。有没有演示例子?

使用特权

评论回复
13
pigeon0411| | 2009-8-24 16:45 | 只看该作者
好多天了,没人理,好像老板出差了

使用特权

评论回复
14
无冕之王| | 2009-8-24 18:00 | 只看该作者
不错,顶

使用特权

评论回复
15
开源共享|  楼主 | 2009-8-24 18:17 | 只看该作者
本帖最后由 开源共享 于 2009-8-24 18:19 编辑

升级:简单的说,就是把原来的程序擦除,重新写一个代码到FLASH,从这点上说,那用IAP写FLASH不就可以了吗,这不很简单吗,我不知道大家试过没有,就拿上面的例子来说吧,假设不用上面说的分散加载,只是简单的编译两个代码,先把低端的代码用JTAG仿真器或串口烧录到低FLASH中,然后使用升级程序从串口接收数据,写FLASH,一步一步操作下去,因为第一个扇区高低端软件都用,最后我们去把新收到的程序写往第一扇区,发现不能写入成功(如有网友成功,请多赐教),其它部分都写完了,就差第一个扇区没写进去,结果重复位芯片,不能正常工作,原因我不说了。既然这样,升级要成功,升级前的程序和升级后的程序第一扇区的代码相同就OK了,所以写了上面的两个分散加载文件,让两个程序的第一扇区相同,这样升级是不需写第一个扇区,这种方法是让普通用户用自己的代码就可以升级,简单方便,如有网友有更好办法,请不吝赐教。确实无奥妙可言,只是交流,主要是因为太多的人询问此问题,故发该帖。

使用特权

评论回复
16
pigeon0411| | 2009-8-25 11:18 | 只看该作者
楼主的意思是要建立两个工程,分别生成两个BIN文件,一个是带有共享库和升级程序的BIN文件,另一个是需要升级的应用区程序。

那就是说两个工程中除了共享文件,升级程序和应用程序是不能相互包含的,那在启动代码中或者在BOOTLOADER区如何完成代码的切换?

比如升级程序是放在0X8000处的,而应用程序是放在0X40000处的,如果在升级区完成后通过指针调用转向0X40000处去执行应用程序,就出现一个问题:0X40000处虽然存放的是应用程序,但应用程序的主函数入口地址往往不是0X40000,而是偏移若干个地址,比如可能是在0X4001C处才是应用程序的MAIN入口点。

在这种情况下,我认为可以通过__AT 来指定MAIN的地址,从而可以确定它的入口地址,不知道是否可行?

使用特权

评论回复
17
开源共享|  楼主 | 2009-8-25 12:30 | 只看该作者
本帖最后由 开源共享 于 2009-8-25 12:32 编辑

两个工程都要有升级程序,也就是应用程序和升级在一个工程中,只要两个工程把升级程序定位到不同位置,升级时直接覆盖原来的应用程序,复位让程序重新运行就可以了,但用这个程序下次升级时,要重编译(升级程序重定位),不能直接升级刚刚升级的程序。

使用特权

评论回复
18
火箭球迷| | 2009-8-27 12:16 | 只看该作者
不太明白。。。

使用特权

评论回复
19
pigeon0411| | 2009-8-27 14:09 | 只看该作者
今天刚测试OK,使用一个分散加载文件,三个加载区,采用资源共享的思路,成功完成在线升级功能。

感谢楼主提供的思路。

可以使我们进步的是大家的思想拿出来分享。

使用特权

评论回复
20
pigeon0411| | 2009-8-27 17:11 | 只看该作者
测试OK了,但是不稳定,我一会儿把代码贴出来,大家讨论一下。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

41

帖子

0

粉丝