IAP升级问题

IAP IAP(in application programming)在应用编程,一些概念什么的不在详细叙述了,百度,Google都有。这里主要记录一些曾经遇到的一些问题和解决方案。IAP升级方案曾在stm32平台和GD32(国产的,108M,兼容st)平台上实现过,不过速度并不快,方法也很简单,看了不少网上的例子,自己也做了个上位机实现传输。
【IAP升级问题】IAP升级的要点
一、解决传输问题。
用蓝牙之类的自然方便许多,不过这里要备注一下:gd32的108M倍频需要修改HSE_SATUP_TIMEOUT 为0xffff,保证HSE_VALUE 值为对应的晶振值,PLL倍频超过16的需要修改stm32f10x_rcc.c 库文件,具体的可参考GD32F103XX 108M时钟配置,否则串口可能乱码。
二、flash读写。
建议使用官方的库读写。写入flash是只能写入内容为0xffffffff的地址单元,擦除要擦除一页。当然可以单字写入,也可以128字写入,前者方便省事,后者速度明显提高不少但相应的程序也要做修改。

FLASH_Unlock(); FLASH_ProgramWord(FLASH_APP1_ADDR+APP_CurAddress,((c1<<0)|(c2<<8)|(c3<<16)|(c4<<24))); APP_CurAddress+=4; FLASH_Lock();

u8 flash_write(u32 StartAddr,u32 *p_data,u32 size) { volatile FLASH_Status FLASHStatus; u32 EndAddr = StartAddr + 4*size; u32 Address = 0x0; int MemoryProgramStatus = 1,i; FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); FLASHStatus = FLASH_COMPLETE; Address = StartAddr; for(i = 0 ; (Address < EndAddr) && (FLASHStatus==FLASH_COMPLETE); Address += 4)//+=2 { FLASHStatus=FLASH_ProgramWord(Address,p_data[i++]); //FLASHStatus=FLASH_ProgramHalfWord(Address,p_data[i++]); if(FLASHStatus!=FLASH_COMPLETE) { __breakpoint(1); } } FLASH_Lock(); Address = StartAddr; for(i = 0 ; (Address < EndAddr) && (MemoryProgramStatus != 0); Address += 4) { if((*(vu32*)Address != p_data[i++])) { __breakpoint(1); MemoryProgramStatus = 0; return 1; } } return 0; }

三、程序跳转问题。
这可能是遇到的最多也是最复杂的问题了,至今仍有一些问题还未找到答案。首先中断问题,在IAP,APP互相跳转之前一定要将程序中用到过的中断,包括总中断全关掉,最好是使能也一起关掉,并且跳转的程序不应放在中断中,否则跳转之后中断不能正常工作。千万不要认为关掉总中断就可以解决一切,还是那句话现在遇到的麻烦都是当初脑子进的水。
其次还有一个问题是我遇到过的,在IAP跳转APP时或APP跳转IAP时,程序进入HardFault问题。先说IAP到APP,具体情况是在GD中虽然跳转过去,但进去就死在HardFault中,解决方法,使用RCC_DeInit(),NVIC_DeInit()初始化,并将可能对程序产生影响的硬件寄存器重新赋初值。APP跳转IAP,这里虽然程序可以跳转,但中断并不能用,特别是触发串口中时,会跳转HardFault。经过跟踪调试,发现在触发串口中断后,硬件自动将R0,R1,R2,R3,R12,LR,PC,xPSR压入堆栈,由于中断中库函数或者说处理比较多,反汇编后可以看到程序将R2-R10,LR也压入堆栈当中,导致堆栈的数据被覆盖掉,即PC值被替换,那么当中断处理结束时,pop数据是PC指向一个未知的地址单元,从而用法Fault触发,上升为HardFault。PC指向不明,可以在Fault report中看一下INVPC有没有被置位。但神奇的是在APP跳转IAP之后这种情况才会发生,正常执行IAP程序则没有这种情况。还是要去查一下MSP,PSP堆栈指针,及向量表,多数问题发生在这里。
先说一下解决方法吧,软件复位,这真的是很方便快捷。
__set_FAULTMASK(1); NVIC_SystemReset();

开关总中断的方法
__ASM("CPSIEI"); //开总中断 __ASM("CPSIDI"); //关总中断//有兴趣可以看看这下面这种更彻底的方法 __ASM ("cpsie f"); __ASM ("cpsid f"); //类似函数 __ASM void __set_PRIMASK(uint32_t priMask); __ASM void __set_FAULTMASK(uint32_t faultMask);

    推荐阅读