STM32的IAP升级笔记
IAP升级主要分为在线升级与本地升级两种方式,核心都是将升级程序的BIN文件写入到MCU的内部FLASH中,并使程序从升级程序的的地址开始运行。
再进行升级之前,这些一定要搞清楚:
1.MCU的内部FLASH大小(A KByte)
2.启动程序(就是引导程序,这部分是不能被擦除的)的大小(B KByte)
3.应用程序(即升级程序)的大小(C KByte)
为保证升级成功,这里要注意:
A > B+C(最好在预留1K空间,即A>B+C+1)
我使用的是STM32F051系列的,闪存大小64K,引导程序5K,预留6K空间,应用程序55K,内存大小足够。下面讲一讲具体思路及实现函数。
主要思路:
先将升级程序写入到外部FLASH中进行备份,写入完成后,给MCU一个升级信号,然后开始读外部FLASH,写内部FLASH,按页操作,写完之后,进行地址跳转,跳转至升级程序的开始地址。
STM32库里面提供了内部FALSH的读写函数,我们只需要找到自己需要的调用即可。
内部FLASH写入步骤:
解锁——清除标志位——擦除——写FLASH——上锁
内部FLASH结构:
库里擦除函数提供了全部擦除和页擦除两种方式:
1.FLASH_Status FLASH_ErasePage(uint32_t Page_Address) //页擦除,每次擦除1K,参数为起始地址
2.FLASH_Status FLASH_EraseAllPages(void) //全部擦除
写FLASH函数:
1.FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data) //写一个字,即4个字节
2.FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) //写半字,即2个字节
写入函数代码如下:
void Flash_Task_Write(u32 write_addr,u16 *pBuff,u16 len)
{
FLASH_Unlock(); //解锁OPTWRE
/* Clear pending flags (if any) */
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
_delay_us(10);
FLASH_ErasePage(write_addr);
_delay_us(10);
STMFLASH_Write_NoCheck(write_addr,pBuff,len);
_delay_us(10);
FLASH_Lock();//上锁
} 不加延时的话数据写入会出现错误,可能是由于擦除还没完成就开始写入了
void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
u16 i;
for(i=0;i<NumToWrite;i++)
{
FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
WriteAddr+=2;
}
}
注意:
因为我使用的是半字函数FLASH_ProgramHalfWord,即每次写入2个字节,假设实际数据
长度是LEN,此处实际上len=LEN/2
写完之后需要映射中断向量表,在你的MCU手册中找到中断向量表,如下:
这里我只贴出了一部分,我的一共是38个,每个占4个字节,共计38*4=152字节
memcpy((void*)0x20000000, (void*)0x08001C00, 152);
SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
0x08001C00这个是我的应用程序起始地址,将中断向量152个字节复制到0x20000000地址
在执行完以上两行代码后,若发生中断,CPU就会去SRAM(即0x2000 0000处)取中断向量
了,所以,以0x20000000作为起始地址之后的152个字节就不能被改动了。
接下来需要地址跳转,需要让程序跳转至升级程序起始地址即0x8001C00处开始执行,使用函数指针。
uint32_t *p = (uint32_t *)FLASH_WRITE_START;
__set_MSP(*p);
jump2app = (void(*)())*(uint32_t *)(FLASH_WRITE_START+4);
jump2app();
jump2app 是个函数指针,FLASH_WRITE_START+4这里为什么要+4,大家可以去百度
一下BIN文件结构。
至此,整个升级过程结束,MCU开始跑新程序了。
在线升级与本地升级无非就是升级程序存储介质以及传输方式不同,这一部分是共用的。
最后还有一个小BUG还没解决,有知道的大神指点一下,谢谢谢谢~
每次我写完之后,内部FLASH第一页数据总会全部变成0,不知道怎么回事