stm32f103通过USART分批(2KByte/批)量写入flash进行IAP升级

步骤一:建立两个工程。①APP程序工程;②BOOT升级工程;这两个工程最终都是要烧录进MCU的。

不过需要注意芯片地址的设置,下图是我所设置的 BOOT升级工程 的需要空间,地址就从起始地址0x08000000开始(这是由芯片手册得到),因为芯片一启动,就是从这个地址开始往下运行。由于升级文件不大,我只用了0x2800大小空间(这里记得要是某个数值的倍数大小,太久忘了,下次用的时候再百度好了,如果有博友知道的话,还请留言评论一下,感谢!)。

下图则是APP程序的预留空间了。

步骤二:开始写BOOT工程

读取标志位(预先再 备份寄存器中写好的,因为配合外接电池的话关电不丢失)

if(标志为BOOT更新)
{
    开始更新APP程序,然后跳转进APP代码段
}
else if(标志为直接进入APP)
{
    跳转进APP代码段
}

例:
	Read_Bkp(1,&flag);//判断是进入BOOT更新,还是直接进入APP
	printf("\r\nK2_STM32F103_BOOT!\r\n\r\n");
 	while(1)
	{
		if(flag == FLAG_TO_BOOT)
		{
			ReceiveUsartData();
			count++;
			if(count == 1000000)//开始进入更新模式的时候,需等待一段时间,防止垃圾数据出现
			{
				count = 0;
				USART2SendRespondToA64(SERIAL_CODE_STM32_UPDATE_PREPAR_BOOT_OK);//向上位机发送准备进入BOOT
//				printf("\r\nqwer\r\n");
			}
		}
		else if(flag == FLAG_TO_APP)
		{
			iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
		}					
	} 	
}

上述代码段就是简易的BOOT更新逻辑。

重点来了,我的RAM只有20K,而我的APP程序不止20K。不能一次将其全部缓存成一个数组,于是我只能分批的通过USART接收,然后写入flash。

void ReceiveUsartData(void)
{
	u8 CheckSum = 0;
	u8 CodeData = 0;
	int i;
	u32 tempAddr = FLASH_APP1_ADDR;
    
	if(UsartReceiveFlag == 1) //串口接完数据
	{
		UsartReceiveFlag = 0; 	
		CodeData = USART_Receive[4];		
		for(i = 0; i < USART_RECEIVE_SIZE; ++i)
    	{
			CheckSum = CheckSum + USART_Receive[i];
    	}
		if((CheckSum == 0) && (USART_Receive[0] == 0x55) && (USART_Receive[1] == 0xaa) && (USART_Receive[2] == 0x01))
		{
			switch(CodeData)
			{
				case SERIAL_CODE_SET_STM32_TO_UPDATE:
				{
					UpdateFlag = 1;//置1之后,USART接收将一直接收.BIN文件
					nPageTotal = USART_Receive[5]; //获取总包数
					USART2SendRespondToA64(SERIAL_CODE_STM32_UPDATE_PREPAR_OK);//向上位机发送准备开始更新信号
					while(1)
					{//等待一包数据接收完成
						if(UpdateFlag == 1 && NextPageFlag == 1)
						{
							NextPageFlag = 0;
							if((USART_ReCodeData[0] == 0x55) && (USART_ReCodeData[1] == 0xaa) && (USART_ReCodeData[2] == 0x01))
							{//判断发送包是否数据准确                  
								nPageCount++;//统计写入次数        
								STMFLASH_Write(tempAddr, (u16*)(USART_ReCodeData + 5), (sizeof(USART_ReCodeData)/sizeof(USART_ReCodeData[0]) - 6) / 2);
//			STMFLASH_Read(tempAddr,(u16*)USART_ReCodeData,(sizeof(USART_ReCodeData)/sizeof(USART_ReCodeData[0]) - 6) / 2);
//			for(i = 0;i<((sizeof(USART_ReCodeData)/sizeof(USART_ReCodeData[0]) - 6)); i++)
//			{
//				if(x%16 == 0)
//				{
//					printf("\r\n");
//					printf("%08x:",y);
//					y += 16;
//				}
//				printf("%.2x ",USART_ReCodeData[i]);
//				x++;
//			}
//			printf("\r\n\r\n");
								tempAddr += FLASH_APP_ADDR_OFFSET;
								USART2SendRespondToA64(SERIAL_CODE_STM32_UPDATE_NEXT_PACKEG);//向上位机发送本次数据写入成功,准备下一次接收写入
								if(nPageCount == nPageTotal)//判断写入次数与总包数是否相同
								{
									UpdateFlag = 0;  //只能升级完成后置此标志
									nPageCount = 0;
									tempAddr = FLASH_APP1_ADDR;
									Write_Bkp(1, FLAG_TO_APP);
									USART2SendRespondToA64(SERIAL_CODE_STM32_UPDATE_SUCCESS);  
									
									if(((*(vu32*)(FLASH_APP1_ADDR + 4)) & 0xFF000000) == 0x08000000)//判断是否为0X08XXXXXX.
									{	 
										printf("\r\nwrite flash successful!\r\n");
										iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
			
									}
								}
							}
							else
							{//如果不对,给上位机发送再发一次信号
								USART2SendRespondToA64(SERIAL_CODE_STM32_UPDATE_CURRENT_PACKEG);
							}
							UsartRxCodeCount = 0;
							memset(USART_ReCodeData, 0, sizeof(USART_ReCodeData)/sizeof(USART_ReCodeData[0]));
						}
					}           
				}break;
				default: break;
			}				
		}
		UsartRxCount = 0;
		memset(USART_Receive, 0, sizeof(USART_Receive)/sizeof(USART_Receive[0]));
	}
}

串口这边代码

void USART2_IRQHandler(void)
{
	u8 res = 0;	
#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntEnter();    
#endif
	if(USART2->SR&(1<<5))	//接收到数据
	{	
		res=USART2->DR;   
		//更新的.BIN文件太大,而SRAM空间太小(20K)。需要分成多次接收,接一次便写入flash一次,然后清空数组,准备下一次接收。
		if(UpdateFlag == 1)//升级程序bin文件接收
		{
			USART_ReCodeData[UsartRxCodeCount] = res;
            UsartRxCodeCount++;
            if(UsartRxCodeCount == USART_RECEIVE_CODE_DATA_SIZE)
            {           
                NextPageFlag = 1;               
                UsartReceiveFlag = 1;          
            }		 									     
		}
		else//命令接收
		{
			USART_Receive[UsartRxCount] = res; 
            UsartRxCount++;              
            if(UsartRxCount == USART_RECEIVE_SIZE)
            {
                UsartReceiveFlag = 1;
            }
		}
		

	}
}

步骤三:对APP工程做一个判断代码,主要是为了在使用过程中,方便直接进行在线更新。

读取标志位(预先再 备份寄存器中写好的,因为配合外接电池的话关电不丢失)

if(标志为BOOT更新)
{
   SystemReset();			//系统直接复位
}
else if(标志为直接进入APP)
{
    跳转进APP代码段
}

步骤四:就是另外比较重要的一部分了。由C++编写的下载器了,没有这个下载器,那写好编译生成的APP的hex/bin文件就不知道如何通过已经约定好(即ReceiveUsartData()函数)的协议来通过串口发送给MCU了。

详情见百度网盘 路径(我的资源>软件>STM32_Update.rar)百度网盘-免费云盘丨文件共享软件丨超大容量丨存储安全

猜你喜欢

转载自blog.csdn.net/qq_39608070/article/details/82964982
今日推荐