STM32L152xx通过串口 IAP在线升级(在程序中升级)固件,Bootloader+app

我用的芯片是STM32L152RET6

       IAP(在程序中升级)一般是需要写一个Bootloader引导程序,对程序进行引导。但因项目需要,不能单独烧写bootloader程序,所以采用在程序中升级,通过读写Flash,跳转的方法,省去了单独烧写bootloader。(其实只是把Bootloader加入app中,在程序中去引导)

IAP在线升级流程图:思路

APP1:

print(USART1, " APP1 is running! ");
  while (1)
  {
		if (UP_flag==1)
		{
		iap_start(0x8040000);   //写入Flash memory Bank 2
		}
	LL_mDelay(5000);
  }

串口1输出:APP1 is runing!    main函数直接进入大循环,等待升级指令,当指令下发,进入串口中断,标志位置1

void USART1_IRQHandler(void)
{

 uint8_t res;	
	if(LL_USART_IsActiveFlag_RXNE(USART1))
	{	 		
		if(LL_USART_IsActiveFlag_RXNE(USART1))
		{
			if(U_RX_CNT<U_RECC_LEN)
			{		   
				res=LL_USART_ReceiveData8(USART1);
				U_RX_BUF[U_RX_CNT]=res;
				U_RX_CNT++;	
			}
		}
		
	}
			if(U_RX_BUF[0]==0x04)      //0x04表示升级指令
			{
				UP_flag = 1;        //标志位置1
			}

}

标志位置1后进入iap_start()函数,函数参数为要写入Flash地址即程序跳转执行地址。在这个函数里等待串口中断接收APP2升级程序文件,接收完成后写入Flash Bank 2,并将程序跳转到Flash Bank 2执行。

void iap_start(int FLASH_APP_ADDR)
{
	u16 oldcount=0;				//原串口接收数据值
	u16 applenth=0;				//接收到的APP代码长度
	u16 page_num = 0;
	print(USART1,"iapstart\r\n");
	USART1_CLR_RecvBuf();
	U_RX_CNT=0;
	print(USART1,"等待接收完成\r\n");             //从这里进入大循环,等待串口中断接收待升级的APP2数据文件
	 while (1)
   {
		LL_mDelay(100);
		if(U_RX_CNT)
		{
			if(oldcount==U_RX_CNT)//新周期内,没有收到任何数据,认为本次数据就收完成
			{
				applenth=U_RX_CNT;
				oldcount=0;
				U_RX_CNT=0;
				print(USART1,"用户程序接收完成\r\n");
				print(USART1,"开始更新固件库...\r\n");
				/**************************擦除FLASH**************************/
				HAL_FLASH_Unlock(); //解锁FLASH
				page_num = applenth/256 + 1;	//计算需要擦除的页数,L152RE每页256字节
				FLASH_EraseInitTypeDef f;			
				f.TypeErase = FLASH_TYPEERASE_PAGES;	// 擦除页
				f.PageAddress = FLASH_APP_ADDR;		//擦除起始地址
				f.NbPages = page_num;			// 擦除的页数
				uint32_t PageError = 0;			// 接收错误返回值
				HAL_FLASHEx_Erase(&f, &PageError);		//擦除FLASH
				HAL_FLASH_Lock();	//锁Flash									
                                print(USART1,"等待更新...\r\n");
				iap_write_appbin(FLASH_APP_ADDR,U_RX_BUF,applenth);
			        print(USART1,"更新固件完成...\r\n");
				if(((*(volatile u32*)(FLASH_APP_ADDR+4))&0xFF000000)==0x08000000)  //判断是否为0x08xxxxxxx,程序开始地址(复位地址)
				{	 			
					iap_load_app(FLASH_APP_ADDR);          //跳转到Flash Bank 2,执行APP2
				}else  
				{
				print(USART1,"非Flash应用程序,无法执行!\r\n");   
				}		
				}else oldcount=U_RX_CNT;			
		}
   }
}

下发升级指令:    等待接收

发送APP2 bin文件:

bin文件传输完成后等待更新,并跳转执行APP2,从串口助手可以看到,程序已经跳转执行APP2了

现在我把掉电源,重新上电,看看是执行的哪个程序。  升级成功!

APP2:

在APP2程序中需要将Flash Bank 2 读出并写入Flash Bank 1中。这样子,在芯片掉电以后就会执行APP2,而不是APP1,升级成功  (我程序里规定的是读30K,够用了)

   for(ii=0;ii<30720;ii++)
	 {
     teemp[ii]=Flash_read_data(adderrr+ii);
	 }
	 writeFlashTest(0x8000000,(u8*)teemp,7680);
	 print(USART1, " copy ok2! ");   //调试语句,表示已经将Flash Bank 2 读出并写入了Flash Bank 1

另外APP2生成bin文件时,工程配置的起始地址需要改动

上面是APP1起始地址为:0x800 0000     下面是APP2起始地址:0x804 0000

 

有问题欢迎留言讨论哈,表达能力欠缺,有不清楚的可以问我

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值