基于STM32单片机BOOTLOADER通过串口升级程序IAP——APP方案

                        此方法前提是你得有一个EEPROM

        我用的单片机是STM32F103ZET6 , 此单片机FLASH容量为512KB;

在此单片机里面FLASH的起始地址是0X8000000,BOOT作为引导加载程序一般都是从这个地址开始,单片机一上点默认会从这个地址开始运行,所以将自己的BOOT程序放在这个地址。

         其实boot也是个程序,只是他的主要功能是处理升级包。

        我将FLASH分成三个块,第一块是BOOT区,第二块是程序缓存区,第三块是APP区

BOOT

                我的boot代码大概33KB左右,所以我预留了40KB作为BOOT区

CODE 

                这个区是代码缓存区,一共160KB,将串口接收到的代码先存放在这个位置,等全部接受完成了,再把code区的代码移到APP区,然后跳转到APP就算完成bootloader

APP

                这一块是我的主要代码运行区,我预留了312KB

程序运行逻辑

BOOT启动—–》读取EEPROM,判断有没有更新: 

如果有—》将CODE区的代码移到APP区,然后跳转到APP区;

 如果没有—–》等待一段时间,如果接收到新的升级包,先把数据存放到CODE区,等全部接受完成了移到APP区。如果没有接收到升级包,直接跳转到APP

APP启动——–》等待接受升级包,如果接收到升级包,重启单片机,回到BOOT

BOOT程序里判断EEPROM状态代码

这个放在main函数里。运行此段之前先初始化串口和EEPROM

    
    uint32_t readAddr ; 	//程序缓存区地址
	uint32_t app_wrinte_addr; 	//APP启动地址
	uint32_t app_size;		//升级包大小
	uint8_t  read_write_buf[1200];
    uint8_t  BOOTloader_ST=0;
    //检查EEPROM
	if(AT24CXX_Check()==0)//检查器件EEPROM已经初始化
	{	
		USART3_Send_Str("------------------------------------------------------\r\n");	
		USART3_Send_Str("---------BOOTLOADER程序正在运行正常--------------------\r\n");	

		
		USART3_Send_Str("EEPROM硬件正常\r\n");		

		//初始化bootloader状态	
		BOOTloader_ST = AT24CXX_ReadOneByte(999);//升级标志位在最后面 
		
		switch(BOOTloader_ST)
			{
				//无需升级
			case 0XA0:	//等待10个心跳时间后如果还是没有收到升级包跳转APP
				//直接跳过
				USART3_Send_Str(" 等待接受升级程序\r\n");
			  //  iap_load_app(0X8032000);

				break;
				//准备升级
			case 0XA1:	//擦除FLASH,准备接受	
				AT24CXX_WriteOneByte(999,0XA0);		//初始化时等于0XA1说明接受失败
				USART3_Send_Str("准备升级--升级失败--等待接受升级程序\r\n");	
				break;
				//正在接受数据
			case 0XA2:	//等待接受完成,超时跳转APP
				AT24CXX_WriteOneByte(999,0XA0);		//初始化时等于0XA2说明接受失败
				USART3_Send_Str("接受中断--升级失败--等待接受升级程序\r\n");	
				break;
				//等待升级命令
			case 0XA3:	//等待开始升级命令
				AT24CXX_WriteOneByte(999,0XA0);	   //初始化时等于0XA3说明接受失败
				USART3_Send_Str("接受完成---等待接受升级命令\r\n");	
				break;
				//接受失败
			case 0XA4:	
				AT24CXX_WriteOneByte(999,0XA0);	   //初始化时等于0XA4说明接受失败
				BOOTloader_ST	= 0XA0;
				USART3_Send_Str("---接受中断--升级失败--等待接受升级程序-----\r\n");
				break;
			//开始升级
			case 0XA5:	//擦除APP区,缓存的升级包移到APP区,跳转到APP区
				AT24CXX_WriteOneByte(999,0XA6);		//升级
				USART3_Send_Str("---------接受完成---开始升级----------\r\n");

				app_size = (AT24CXX_ReadOneByte(1000)<<24) | (AT24CXX_ReadOneByte(1001)<<16)| (AT24CXX_ReadOneByte(1002)<<8)  |AT24CXX_ReadOneByte(1003);
				
				app_wrinte_addr = 0X8032000;	//APP地址
				readAddr  = 0X800A000;	//代码缓存区地址

				while (app_size> 0)
					{
						if (app_size>=1024)
						{
				            System_ReadInteriorFlash (readAddr, read_write_buf, 1024) ;	
				            System_WriteInteriorFlash(app_wrinte_addr,read_write_buf, 1024);
							readAddr+=1024;
							app_size-=1024;
							app_wrinte_addr+= 1024;	//写入地址增加
						}	
						else 
						{
	                        System_ReadInteriorFlash (readAddr, read_write_buf,app_size);	                                                          
                   
      System_WriteInteriorFlash(app_wrinte_addr,read_write_buf,app_size);
							readAddr+=app_size;
							app_size-=app_size;
							app_wrinte_addr+= 1024;	//写入地址增加
								
						}
					}	

				USART3_Send_Str("--------------即将跳转APP----------\r\n");

				iap_load_app(0X8032000);	//跳转到APP

				
				break;
			//升级成功,无需
			case 0XA6:	//回到无需升级
				USART3_Send_Str("--------------升级成功-----------\r\n");
				AT24CXX_WriteOneByte(999,0XA0);	//等待新更新
				break;
			
			default :	//可能是第一次上电,默认回到0XA0状态
				AT24CXX_WriteOneByte(999,0XA0);
				break;
			}
	}

在串口接受协议里面运行的代码

                     //下面这个几个变量是全局变量,不能用局部变量
                     framne_all = uart485buff[6]<<8 | uart485buff[7];	//包总数
					 frame_num  = uart485buff[8]<<8 | uart485buff[9];	//包序号
					 writesize  = uart485buff[10]<<8 | uart485buff[11];	//数据大小
					 
					 if(frame_num==0)	//第一包
						{					
							writeaddr = 0x800A000;
							AT24CXX_WriteOneByte(999,0XA2);		//正在接受数据
                            System_WriteInteriorFlash(writeaddr, &uart485buff[12] , writesize) ;	//写入到内部FLASH
							writeaddr += writesize;
						}
					else if(frame_num == (framne_all-1))	//最后一包
						{
							BOOTloader_ST = 0XA5;
							AT24CXX_WriteOneByte(999,0XA5);	//开始升级
							System_WriteInteriorFlash(writeaddr, &uart485buff[12] , writesize) ;	//写入到内部FLASH
							writeaddr += writesize;
							
							AT24CXX_WriteOneByte(999,0XA5);	//开始升级
							USART3_Send_Str("\r\n");
							USART3_Send_Str("---升级包全部接受完成--即将重启--\r\n");
							writeaddr-=0x800A000;
							AT24CXX_WriteOneByte(1000,((u8)(writeaddr>>24)&0xFF));
							AT24CXX_WriteOneByte(1001,((u8)(writeaddr>>16)&0xFF));
							AT24CXX_WriteOneByte(1002,((u8)(writeaddr>>8)&0xFF));
							AT24CXX_WriteOneByte(1003,((u8)(writeaddr)&0xFF));

							
							reboot();    //重启或者跳转到0X8000000地址

						}	
					else 
						{
	                       System_WriteInteriorFlash(writeaddr,&uart485buff[12] , writesize) ;	//写入到内部FLASH
							writeaddr += writesize;
							
						}

物联沃分享整理
物联沃-IOTWORD物联网 » 基于STM32单片机BOOTLOADER通过串口升级程序IAP——APP方案

发表评论