需要一个升级APP程序功能,但是又不想再Bootloader里面做,因为一开始没有设计BootLoader。 所以只能在APP添加一个Update模块了。
Update的逻辑流程如下:
Update程序通过串口读取要升级的APP程序数据。
然后编写到ROM中。
因为CODE自己就在ROM中,为了防止把自己擦掉,所以Update要先把自己拷贝到RAM中去运行。
把CODE从ROM拷贝到RAM中去本以为要用汇编来写,其实用C语言就OK了。就是简单的Buf拷贝操作。
因为ARM的架构支持统一寻址模型:操作Device和操作RAM没有任何区别。
但是有个非常有趣的现象。
程序类似与:
//ROM中的Update地址
src_addr=(int32u*)Update;
//RAM中的Update地址
dst_addr=(int32u*)(0xXXXXXXXX);
//指针函数
jump_addr=(jump_func_type)dst_addr;
//拷贝update程序
for(i=0; i<CODE_LENGTH; i++)
*dst_addr++=*src_addr++;
//跳转到RAM中去执行Update
(*jump_addr)();
我把程序地址拷贝到偶数地址,就是死活跳转不过去。。。
我想是不是长跳转必须用汇编才行?
偶然间分析一下APP.MAP文件,发现所有的Code都是thumb code。而且所有的函数地址都是奇数地址。
突然间恍然大悟。因为thumb code指令,PC的最低位必须是1,所以跳转地址也必须是奇数才行。
修改之后,果然可以跳转了。本以为这样万事大吉了。
但是发现,只要代码稍微修改一下,就可能宕机(也就是不能跳转到Update中去了),多增加一点或者减少一点代码可能就好了。
很是奇怪。
还好有JTAG可以单步调试。最后发现,跳转的地址都是对的。
又查看了生成的汇编文件。
终于发现了问题的原因了:
虽然函数的跳转地址是奇数地址:比如 0x2000abc1;
但是函数的代码实际开始地址是: 0x2000abc0,也就是偶数地址。
也就是说Code是2字节对齐的。thumb指令是16位的。。所以比然是2字节对齐。
但是为什么代码的调用地址是奇数地址呢。因为ARM为了区分thumb指令和ARM指令,使用PC寄存器的最低位来区分的。如果最低位是1,则是thumb指令,如果是0则是ARM指令。
所以跳转地址是奇数地址,但是实际的代码的开始地址是偶数地址。
所以其实我少拷贝了一个BYTE的代码才导致了这么奇怪的BUG。
把拷贝代码从新修改后就OK了。
src_addr=(int32u*)((int32u)Update - 1); //地址先减去一,拷贝代码的实际开始位置.
dst_addr=(int32u*)(0xXXXXXXXX); //当然dst_addr也是偶数地址。
重新修正jump_addr=((int32u)dst_addr+1); //跳转地址必须是奇数地址(这样CPU才知道是Thumb指令)
for(i=0; i<CODE_LENGTH; i++)
*dst_addr++=*src_addr++;
转载自:http://blog.csdn.net/yuan1125/article/details/7273175
自己增加部分:
一个极其讨厌的人分享给我的,此人已经挂了,呵呵
记录一下思路