1 概述
最近负责项目代码升级这一部分,在这里做一个小结。要实现程序的远程升级,需要用到两个程序,一个是Bootloader,另一个就是APP。单片机开机首先执行Bootloader,然后对APP进行引导。
2 流程图
在我们的项目中两个程序的流程图大致如下:
开始BootLoader需要更新?app循环更新代码?接收,写入更新代码yesnoyesno
说明:需要更新时,通过GPRS模块向单片机发送代码更新指令和数据,然后单片机依次从模块中取出发开的代码数据,写入到flash中。然后写入相关更新数据到指定flash,重启单片机,在Bootloader中读取相关地址数据,获取更新程序的地址等信息,然后对程序进行跳转。
3 功能实现
需要把单片机flash,分成4个部分,分别是Bootloader,APP1,APP2,参数区。其中参数区一般几十个字节就够用,用于保存是否更新标识等信息,当前demo参数区信息为:
#define FLASH_UPDATE_FLAG_ADDR FLASH_CONFIGDATA_ADDR
#define FLASH_APP1_VISION_ADDR FLASH_UPDATE_FLAG_ADDR+HALFWORD
#define FLASH_APP2_VISION_ADDR FLASH_APP1_VISION_ADDR+VISION_SIZE
#define FLASH_APP1_LENGTH_ADDR FLASH_APP2_VISION_ADDR+VISION_SIZE
#define FLASH_APP2_LENGTH_ADDR FLASH_APP1_LENGTH_ADDR+HALFWORD
#define FLASH_APP1_CRC_ADDR FLASH_APP2_LENGTH_ADDR+HALFWORD
#define FLASH_APP2_CRC_ADDR FLASH_APP1_CRC_ADDR+HALFWORD
#define FLASH_CURRENTAPP_FLAG_ADDR FLASH_APP2_LENGTH_ADDR+HALFWORD
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.1 Bootloader主要代码
在Bootloader中主要是开机读取flash参数区用于更新,然后对程序进行引导,其跳转程序为:
void iap_load_app(u32 appxaddr)
{
if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //判断地址合法
{
__set_CONTROL(0); //特权模式
__ASM("CPSID I"); //关中断
jump2app=(iapfun)*(vu32*)(appxaddr+4); //程序开始地址为代码区第二字
MSR_MSP(*(vu32*)appxaddr); //初始化堆栈指针
jump2app(); //跳转
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
3.2 APP主要代码
在APP,和平常不同的主要是两个方面,一个是代码存放的地址,如果是通过JLink升级,下载的地址需要更改
二是,程序开始时需要加上,这两句代码
SCB->VTOR = FLASH_BASE | 0x04000; //修改中断向量表
__ASM("CPSIE I"); //开中断
- 1
- 2
4 其他
这里有几个需要注意的细节
1.在用到RTOS时,在跳转时一般都要在跳转前开启特权模式以及关中端,然后在APP中一开始打开中断。
2.由于中断向量的关系,跳转程序的起始位置需要是512字节的倍数。
3.flash的读取和写入一般都是半字操作的。
4.大容量的stm32每个扇区为2k,中容量为1k,这个在写入更新代码时需要注意。