感谢Beatfan_N的无私分享。本文记述的是BootLoader代码从dsPIC33EP256GP506上移植到dsPIC33EP128GP502上的移植过程。前文参阅
1.https://blog.csdn.net/u010875635/article/details/84660611
2.https://blog.csdn.net/u010875635/article/details/84660665
3.https://blog.csdn.net/u010875635/article/details/84660722
4.https://blog.csdn.net/u010875635/article/details/84660792
5.https://blog.csdn.net/u010875635/article/details/85316570
同时感谢老俞的无私分享。
1.http://blog.xueming.org/archives/63
2.http://blog.xueming.org/archives/68
3.http://blog.xueming.org/archives/89
4.http://blog.xueming.org/archives/225
5.http://blog.xueming.org/archives/283
dsPIC33EP64(及以上)的Flash被分段为指令页和行,每个指令页包含1024个指令字(0x400个)。
一个指令页占用的地址空间应该是0x800,共2048个地址。所以第一个指令页的地址范围是0x000-0x7FF。
dsPIC33EP128Flash支持双指令字编程。
dsPIC33EP128每个指令字为24位,实际占用32位(4个字节、2个地址),最高8位为虚字节,总是00。对于大多数应用,24位中的高8位不用于存储数据,建议便成为NOP指令或者非法操作码值。
dsPIC33EP128每个指令字占2个地址,例如0x000和0x001都是表示第一个指令字。地址总是以偶数呈现(0x002/0x004/0x006),读取奇数地址获取到的与读取前一个偶数地址获得到的是一致的,所以读取奇数地址没有意义。这个很好理解,一个指令字才是一个整体,0x000和0x001虽是两个地址,但确是同一个指令字。
dsPIC33E系列若擦除指令页中任意地址,都会擦除该地址所在的整个指令页。之后应在一个写周期内写入一个编程块中的所有数据。
对于dsPIC33E/PIC24E,每个程序存储器地址都是乘了一个2来获取字节地址,即从Hex文件中反推,需要除以2。也就是MPLAB生成的Hex文件,读取之后需要把地址除以2才能还原到真实的地址。
改动分为以下几个部分。
.gld文件需要更换为128GP502的。
路径如下-> C:\Program Files (x86)\Microchip\xc16\v1.35\support\dsPIC33E\gld
之后对内存区域进行修改,这个是原来的:
program (xr) : ORIGIN = 0x200, LENGTH = 0x155EC
改成这样:
program (xr) : ORIGIN = 0x800, LENGTH = 0x6400
下面的__CODE_BASE也要做相应的改动。以下是修改之后的:
__CODE_BASE = 0x800;
__CODE_LENGTH = 0x6400;
...
__DATA_BASE = 0x1000;
__DATA_LENGTH = 0x1000;
DATA_LENGTH这里的修改让人奇怪,为什么修改为0x1000呢?
对擦除函数要进行修改。33EP256GP506擦除3大页,由于配置字在最后一页,不能完全擦除最后一页。对于33EP128GP502因内存减半,只能擦除2大页,且不能完全擦除最后一页。
dsPIC33E系列若擦除页中任意地址,都会擦除该地址所在的页。
这里有一个页和大页的概念。每页包含1024个指令字,一个指令字占用两个地址,但仅有24个位。
因此每个页占用2048个地址,页长度为0x800。
每20个页为一个大页,大页的长度为0x10000。
这里要注意一个逻辑,每次擦除0x400个指令字,实际占用地址为0x800,例如擦除0x0,实际会擦除到0x7ff。所以擦除的首地址的尾部三位只能为0x800和0x000,不会有其他的值。
第二件事,配置字所在的位置不能被擦除,因此这里有讲究了。33EP128GP502的配置字根据.gld文件的描述,位置在0x157F0,所属页的首地址是0x15000,也即这页是断然不能擦的。下面是擦除函数的代码。
void UserFlash_EraseIvtAndUserAppBlock()
{
//擦除0x0000~0x07FE,reset and ivt
EraseLargePage(0); //擦除0x000000-0x00000800,0x008000-0x00FFFF
EraseLargePage(1); //擦除0x010000-0x01FFFE 配置字在15000,所以不能擦除
// EraseLargePage(2); //擦除0x020000-0x02F7FE
//配置字 0x2AFF0~0x2AFFA,处于页0x02A800-0x02AFFE (33EP256GP506)0x02A800之后的地址不能擦除
//配置字 0x157F0~0x157FA, 处于页0x015000-0x0157FE (33EP128GP502))0x015000之后的地址不能擦除
}
EraseLargePage()函数的小分支也需要修改。先看case 0(第0大页)这里,无需修改。从0x8000擦到0xF800(0xF8FE)。
case 0:
//擦除外设配置
flashAddr.Uint16Addr.LowAddr = 0;
InnerFlash_EraseFlashPage(flashAddr);
//第零大页
for(offset=0x8000;offset<=0xF800;offset+=0x800)
{
flashAddr.Uint16Addr.LowAddr = offset;
InnerFlash_EraseFlashPage(flashAddr);
if(offset>=0xF800)
break;
}
break;
第1大页是需要改动的,第2大页是需要删除的。第1大页中的offset限制为小于0x5000,即不能刷0x5000这个页。
case 1:
//第一大页
for(offset=0;offset<0x5000;offset+=0x800) //modify
{
flashAddr.Uint16Addr.LowAddr = offset;
InnerFlash_EraseFlashPage(flashAddr);
}
break;
// case 2:
// //第二大页
// for(offset=0;offset<0xA800;offset+=0x800)
// {
// flashAddr.Uint16Addr.LowAddr = offset;
// InnerFlash_EraseFlashPage(flashAddr);
// }
// break;
default:break;
}
}
定义存储数据所在空间(也即配置字所在空间)的起始地址,为0x015000。
但通过查找用例,发现DataRecord.c中的函数,除了EraseLargePage()都没有用到。
#define DATA_RECORD_START_PAGE 0x0001
#define DATA_RECORD_START_ADDR 0x5000
和BootLoader无关。涉及配置字的修改和Pin脚的设定。
Bootloader烧写时,会擦除中断向量表以及用户软件块。
对于33EP256GP506,在gld文件中,User段程序的起始地址要修改为0x8000,长度要相应的改短。
// 未修改时: program (xr) : ORIGIN = 0x200, LENGTH = 0x2ADEC
// User(二段程序):ORIGIN = 0x8000, LENGTH = 0x7000 (因为0x15000为配置字,不能覆盖)
对于33EP128GP502,也要做出同样的改动。
// 未修改时: program (xr) : ORIGIN = 0x200, LENGTH = 0x155EC
program (xr) : ORIGIN = 0x8000, LENGTH = 0x4000 /*modify*/
......
__CODE_BASE = 0x8000;/*modify*/
__CODE_LENGTH = 0x4000;/*modify*/
__IVT_BASE = 0x4;
__DATA_BASE = 0x1000;
__DATA_LENGTH = 0x1000;/*modify*/
__YDATA_BASE = 0x3000;
之前的情况是能够将User段烧写进去,但是烧写结束后,程序无法跳转到0x8000,而是重新执行BootLoader段的程序。复盘发现,我在第五步的时候忘记修改了program的长度。program的Length一定要修改到0x7000或更少。因为0x15000为配置字所在位置。如果program的长度超了就会导致失败。