欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32的IAP升级笔记

程序员文章站 2022-07-04 20:07:49
...

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结构:
STM32的IAP升级笔记
库里擦除函数提供了全部擦除和页擦除两种方式:
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手册中找到中断向量表,如下:
STM32的IAP升级笔记
这里我只贴出了一部分,我的一共是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,不知道怎么回事