第三节:通用串口IAP程序实现
正点原子的IAP例程中,需要通过按键来配合实现程序跳转,更合适的方法是用软件标志位来实现APP与IAP之间的互跳。
3.1 初步设想代码逻辑
具体而言,初步设想的代码逻辑如下所示:
- 当APP程序运行过程中,需要更新时,串口发来更新命令。
- 单片机接收到更新指令之后,在flash中写一个值给更新标志位,然后软复位跳到IAP代码区域。
- IAP程序中,首先读取flash中的更新标志位,如果是需要更新的状态,则向用户请求APP更新包,将APP更新包写到FLASH中APP代码区域,之后将更新标志位清零。
- 再次检查更新标志位,若无需更新,且代码段中存在APP程序【同样通过标志位辨识】,开始执行跳转IAPjump2APP()的跳转过程。
- 开始执行新的APP程序。
3.2 剖析几个代码段
IAPjump2APP()的代码剖析
执行App程序,即需要从IAP代码段跳转至APP代码段,分析过程参考这一篇文章,正点原子的IAP跳转APP地址区域的函数如下所示:
//跳转到应用程序段
//appxaddr:用户代码起始地址.
void iap_load_app(u32 appxaddr)
{
if(((*(vu32*)appxaddr)&0x2FF00000)==0x20000000) //检查栈顶地址是否合法.
{
jump2app=(iapfun)*(vu32*)(appxaddr+4); //用户代码区第二个字为程序开始地址(复位地址)
MSR_MSP(*(vu32*)appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
jump2app(); //跳转到APP.
}
}
第一句: if (((* (__IO uint32_t * )appxaddr) & 0x2FFE0000 ) == 0x20000000) //判断栈顶地址值是否在0x2000 0000 - 0x 2000 2000之间。该如何理解?
- appxaddr是用户APP程序开始的地址,我们会把APP程序的中断向量表放置在appxaddr开始的位置;而中断向量表里第一个放的就是栈顶地址的值
- 也就是说,这句话通过判断栈顶地址值是否正确(是否在0x2000 0000 - 0x 2000 2000之间) 来判断应用程序是否已经下载了。这是由于应用程序的启动文件刚开始就会去初始化栈空间,如果栈顶值对了,说明应用程已经下载了,启动文件的初始化也执行了。
第二句:jump2app=(iapfun)* (vu32* )(appxaddr+4)。该如何理解?
- (vu32* )(appxaddr+4)里面放的是中断向量表的第二项“复位地址”
- iapfun的别名,定义为typedef void (* iapfun)(void); 即 iapfun是类型 void (*)(void)函数指针 的一个别名
- 所以此时,jump2app指向APP复位函数所在的地址
第三句:MSR_MSP(* (vu32* )appxaddr)。该如何理解?
__asm void MSR_MSP(u32 addr)
{