初步学习可以去正点原子视频“串口IAP升级”中了解。
主要做法:
1、通讯接口接收bin文件;
2、写入flash某个区域;
3、跳转到APP。
单片机每次上电首先进入boot loader程序,在boot loader中等待一段时间,若上位机软件在这段时间内发起通讯,则停留在boot loader程序中等待固件升级;若该时间段内无通讯,则跳转到正常的APP程序。该方式每次上电都需要等待一段时间。
注:1、标志位不受复位和掉电影响;
2、boot loader中尽量不使用中断。
巴拉巴拉巴拉巴拉巴拉巴拉~~~~~~~~
代码:
iapfun jump2app;
u32 iapbuf[512]; //2K字节缓存
//跳转到应用程序段
//appxaddr:用户代码起始地址.
static void iap_load_app(u32 appxaddr)
{
if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法.
{
jump2app=(iapfun)*(vu32*)(appxaddr+4); //用户代码区第二个字为程序开始地址(复位地址)
MSR_MSP(*(vu32*)appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
jump2app(); //跳转到APP.
}
}
//appxaddr:应用程序的起始地址
//appbuf:应用程序CODE.
//appsize:应用程序大小(字节).
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
{
u32 t;
u16 i=0;
u32 temp;
u32 fwaddr=appxaddr;//当前写入的地址
u8 *dfu=appbuf;
STMFlash_Erase(appxaddr,appsize);
for(t=0;t<appsize;t+=4)
{
temp=(u32)dfu[3]<<24;
temp|=(u32)dfu[2]<<16;
temp|=(u32)dfu[1]<<8;
temp|=(u32)dfu[0];
dfu+=4;//偏移4个字节
iapbuf[i++]=temp;
if(i==256)
{
i=0;
STMFlash_WriteApp(fwaddr,iapbuf,256);
fwaddr+=1024;//偏移1024 512*2=1024
}
}
if(i)STMFlash_WriteApp(fwaddr,iapbuf,i);//将最后的一些内容字节写进去.
}
extern const uint32_t Crc32Table[ 256 ];
uint32_t iap_check_appbin(u32 appxaddr,u32 appsize)
{
uint32_t nReg = 0xFFFFFFFF;
uint32_t crc32_loop = 0;
for( crc32_loop = 0 ; crc32_loop < appsize ; crc32_loop++ )
{
nReg = (nReg << 8) ^ Crc32Table[(nReg >> 24 ^ (*(uint8_t*)(appxaddr+crc32_loop))) & 0xff];
}
return nReg;
}
void iap_goto_app(void)
{
if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
{
//关闭中断
__set_FAULTMASK(1);
//关闭已使用的全部中断外设
DRV_Timer_DeInit();
DRV_RxTimer_DeInit();
DRV_TxDMA_DeInit();
//跳转执行
iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
}
}
void soft_reset(void)
{
// 关闭所有中断
__set_FAULTMASK(1);
// 复位
NVIC_SystemReset();
}