关于瑞萨RL78系列单片机在线升级

最近在使用瑞萨的RL78FC0907芯片,用这个芯片做了一各在线升级的小程序.芯片基本资料请参考G13,链接如下:https://www2.renesas.cn/cn/zh/doc/products/region/rtcn/mpumcu/r01uh0146cj0320_rl78g13.pdf?key=1ee8684a42ed9660902b74808580e43a   中文资料。基本上涵盖了907的所有内容。

首先先来看下芯片的内存分布:

可以看到,该芯片共有32K的rom,2K的RAM。在ROM中0000-7FFF,一些固定地址的内容无法用作APP或者BOOT程序区,比如向量表区、CALLT区、选项字节等等,当你使用Boot cluster功能的时候,同样的,你在1000地址开始的标注的表区也无法使用,请注意.该芯片有4K的内部数据闪存,可以使用官方的FDL库操作。2K的RAM中包含32字节的通用寄存器,请注意这32各字节请不要使用.镜像区是ROM区镜像过去的,除了其他的表区之外剩余的24K,因为其他被特殊功能寄存器,内存等映射了地址.对于这个镜像区,有一点要注意,程序中声明的只读数据,const,一定要布置在镜像区,否则编译器会报错,也就是说,比如你顶一个只读数组 u8 const DataTable[10]={1,2,3,4,5,6,7,8,9,0};  那么这个数组你如果把它放在镜像区,他就不会报错,你把它放在非镜像区,比如你把它放在0X1000的地址处,它就会编译报错。遇到这个问题,可以这么解决,将段定义中的.const删除,然后把u8 const DataTable 改为 u8 __far const DataTable,使得存放在.constf段中.还有一种就是将.const数据段整个放置到镜像区中,0x2000地址开始.

然后程序主要分APP区和BOOT区。boot区的程序分配如下.APP区定义从0x2000开始.

数据段分段如图,CODE_IN_ROM_n 这个数据段是存放boot区中断函数的,.text段是存放__near 声明的函数,比如说启动例程,rlib,slib是使用库代码部分分别是运行库代码和标准库代码..textf是__far 声明的函数部分,大部分函数都在这个段。.constf是__far声明的只读数据. .data是初始化的变量存放在ROM的数据,.sdata是初始化的数据,短直接寻址,具有SADDR属性的数据,存放在ROM中.  其他的pfdl fsl什么的都是需要用到的操作库,FDL是用于操作数4K据存储区的,fsl是用于在线自编程的.下面的0XFF700开始的是内存区,CODE_IN_RAM就是上面的CODE_IN_ROM_n的函数复制到内存中,可以在RAM中执行,主要是boot区使用中断用到的..dataR 是初始化的变量,.bss是未初始化的变量,.sdataR和.sbss 都是具有saddr属性的内存段。

BOOT区需要把中断重映射,我这边把中断映射到了0x2000的地址开始

因为单片机中断的中断向量表是只存放跳转的地址的,所以,每个中断向量都只有两个字节,改变之后,每个需要预留4各字节,要注意.相应的APP区需要设置如图所示,从0x2000的地址开始,设置相应的跳转函数,我这边只有定时器的中断函数.设置完中断跳转函数,接下来就是APP区的入口函数了,APP区的入口函数地址为0x2200,请把.text这个段放在最前面,因为这个段放着启动函数。

所以,APP程序的启动函数入口地址为0x2200,BOOT区最后跳转

//示例
#define APP_Start_Addr 0x2200
void ( *pfunc)(void);  //申明一个函数指针

// BOOT 区的main函数

void main ()
{
    pfunc = 0; 
    pfunc = ( void(*)(void))(APP_Start_Addr);  // 指针指向0x2200的地址
    /*
     这边存放boot区程序
    */
    pfunc();  //boot区最后调用函数跳转APP程序启动代码
}

自编程使用瑞萨的自编程操作库FSL。具体的步骤如下图:

可以选择使用中断也可以选择不使用中断,使用FSL_ChangeInterruptTable()函数会将中断映射到内存中,

此时,原来存在ROM中的中断向量无法正常跳转,所以程序中断会直接跳转到内存,所以上面需要把存放在ROM中的中断处理函数段_CODE_IN_ROM_n 先复制到内存CODE_IN_RAM中.为了不让程序出错,这个中断处理函数需要和普通的中断函数类似,下代码段

//示例

#pragma interrupt r_uart0_interrupt_receive(vect=0x2)  // 这边需要和正常中断声明一样


#pragma  section text CODE_IN_ROM   //将中断函数(boot区中使用)放置到固定段中
 void __near r_uart0_interrupt_receive(void)
{ 
	func1();
	 
	if(STIF0)
	{
		STIF0 = 0;
		 //  TXD0 = 0x56;
	}
	if(SRIF0)
	{
		SRIF0 = 0;
		boot.step = 0;
		boot.DelayCnt = 0;
		Data_Table[boot.ReceiveCnt] = RXD0;
		if(SSR01L&0x07)
		{
				SIR01 = 0X07;  //清除故障标志
				boot.ReceiveCnt	 = 0;
		}
		if(boot.ReceiveCnt == 0)
			boot.CheckSum = 0;
		if(boot.ReceiveCnt==3)
			boot.CheckSum = Data_Table[boot.ReceiveCnt];
		else if((boot.ReceiveCnt>3)&&(boot.ReceiveCnt<131))
			boot.CheckSum += Data_Table[boot.ReceiveCnt];
		boot.ReceiveCnt++;
		
	}

 	// __RETI();
	func2();
}
#pragma section

需要注意的是,boot区使用的中断入口函数只有一个,就是说所有的中断都会在这个函数里面处理,根据不同的中断标志位,处理相对应的中断程序.要注意,在进入APP区程序之前,如果使用了FSL_ChangeInterruptTable()这个功能,那么必须使用FSL_RestorInterruptTable()函数使得中断恢复正常中断向量表.

猜你喜欢

转载自blog.csdn.net/dwcsunshine/article/details/89306134