我们现在看一下分散加载文件:
分散加载文件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的程序升级,能够可靠运行。