串口IAP-Bootloader程序总结

                           **IAP-Bootloader程序总结**

IAP-Bootloader程序总结 带详细源码
串口IAP-Bootloader程序就是为程序写一段引导程序方便后续的升级和更新,基本上现在大多数产品都会使用是一定要掌握的技能。具体原理就是在程序开始部分预留2k~20k大小视情况而定的Bootloader程序,正式程序为APP程序在Bootloader程序之后,在上电之后检测是否更新不更新则跳转到APP程序,更新则下载新的APP程序到内部flash之后自动跳转到APP程序。

硬件平台:原子的战舰开发板 MCU STM32F103ZET6内部flash512k 使用串口1
Bootloader程序留64k实际用了11k APP程序用剩余的448k
代码部分为一原子代码为参考修改,同时参考借鉴了
阿卡基猿的文章 下载烧录部分
原文链接:[https://blog.csdn.net/qingzhuyuxian/article/details/80769057]
fandelxin的文章 跳转和原理部分
原文链接:[https://blog.csdn.net/super_demo/article/details/32133257]

主要功能:下载完成以后可以自动检测有没有APP程序没有则等待更新,同时擦除要更新部分的FLASH,擦除完成后等待串口下载程序,下载完成后可以自动跳转,在APP运行的同时只要接受到串口的升级命令可以跳回Bootloader程序进行更新。与原子的源代码不同部分,可以下载超过55K的APP程序,无需按键跳转可以回跳。
特别说明:文章后提供全部源码供大家借鉴参考,若使用的是原子战舰开发板则可以直接下载运行。本人技术经验有限,程序可能还有很多BUG,欢迎大家提出来一起学习,而已串口下载部分也没有校验,容易出错无法用于实际的生产。

![效果演示,上电擦除完成![](https://img-blog.csdnimg.cn/20200126142651330.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xhbXA1NjI5NzYzMzQ=,size_16,color_FFFFFF,t_70)下载完成实现跳转
一共分为几个关键点和难点:
1,Bootloader跳转部分
2,app回跳部分
3,串口下载和烧录部分

结合代码详细讲解
1,Bootloader跳转部分

增加全局变量u16 IAP_UP = 0; 上电检测若IAP_UP = 0则直接跳转到APP,若无程序则把改IAP_UP = 1,进入下载函数。
还需u16 IAP_JP = 0;这个变量是检查是否重APP中跳转到Bootloader的变量在倒数第二个flash地址。
if((((vu32)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)还需要这条语句检查APP地址中是否有程序。IAP_UP变量在上电时要重flash的最后一个地址读取,同时每次更改都要写入到对应的flash中。

Main函数中的代码:

/********************************************************************
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "iap.h"
#include "swtimer.h"

u16 IAP_UP = 0;
u16 IAP_JP = 0;
/*
 增加一个全局变量 IAP_UP 存储在内部flash的最后一个地址 0x807ffff
 若IAP = 1;则需要更新显示"wait update order..." 等待更新完成 显示“update order Successed!!”并且把
 IAP 写为 0,无需更新同时跳转到APP程序
*/
int main(void)
{		
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
	uart_init(115200);	//串口初始化为115200
	delay_init();	   	 	//延时初始化 
	Timer3_init();
	STMFLASH_Write_hw(0x807fffe,IAP_UP);
	while(1)
	{
		IAP_UP = STMFLASH_ReadHalfWord(0x807fffe);
		IAP_JP = STMFLASH_ReadHalfWord(0x807fffc);
		printf("IAP_UP =%d\r\n",IAP_UP);
		printf("IAP_JP =%d\r\n",IAP_JP);
		if((IAP_UP == 1)||(IAP_JP == 1))
	   {
		                IAP_UpdataProgram();
						printf("固件下载完成!\r\n"); 
		if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)			             {		
							printf("固件更新完成!\r\n");
							IAP_UP = 0;//更新完成
							IAP_JP = 0;
							STMFLASH_Write_hw(0x807fffe,IAP_UP);
							STMFLASH_Write_hw(0x807fffc,IAP_UP);
				            iap_load_app(FLASH_APP1_ADDR);			             }
						 else 
						 {
							printf("固件更新失败!\r\n");
							break;
						 }		 
		}
		if((IAP_UP == 0)&&(IAP_JP != 1))//上电运行则直接跳转
		{
			if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)
			{	
				iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
				
			}else 
			{
				printf("非FLASH应用程序,无法执行!\r\n");
                IAP_UP = 1;
				STMFLASH_Write_hw(0x807fffe,IAP_UP);
			}
		}			    
	}   	   
}
跳转部分的核心函数iap_load_app(FLASH_APP1_ADDR);
typedef  void (*iapfun)(void);				//定义一个函数类型的参数.
//跳转到应用程序段
//appxaddr:用户代码起始地址.
void iap_load_app(u32 appxaddr)
{
	if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)	//检查栈顶地址是否合法.
	{ 	
		jump2app=(iapfun)*(vu32*)(appxaddr+4);		//用户代码区第二个字为程序开始地址(复位地址)
		MSR_MSP(*(vu32*)appxaddr);					//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
		jump2app();									//跳转到APP.
	}
	else printf("固件更新失败!\r\n");
}	

程序的开始部分前四个字节放着栈顶地址,接下来的四个字节放着复位地址,if((((vu32)appxaddr)&0x2FFE0000)==0x20000000)检查顶地址是否合法可以避免错误下载或者下载失败后的错误跳转。
//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(u32 addr)
{
MSR MSP, r0 //set Main Stack value
BX r14
}__asm关键字可以执行汇编语句,用于初始化APP堆栈指针
最后jump2app();执行APP程序的服务函数地址,跳转到APP。
2,从APP回跳到Bootloader
SCB->VTOR = FLASH_BASE | 0x10000;
在程序的开始要把APP函数的中断向量表进行偏移大小为你Bootloader程序大小,整个程序是有两张向量表但是必须保证PC指针指向APP程序的中断向量表。
可以用系统复位函数也可以用开门狗复位,

void SoftReset(void)
{
	__set_FAULTMASK(1);      // 关闭所有中端
	IAP_UP[0] = 1;//需更新
	IAP_JP[0] = 1;
	STMFLASH_Write(0x807fffc,IAP_JP,1);//当程序在串口更新完之后改为1;
    NVIC_SystemReset();// 复位 
}

同时不要忘了要把IAP_UP和IAP_JP更新写入flash中,__set_FAULTMASK(1); // 关闭所有中端进入复位函数后关闭全部中断防止程序卡死。
3,串口下载部分
下载部分要用环形缓冲区的思想,同时要把串口下载的8位数据转换成16位半字才能进行烧录。

#define MAXBUFFER 512
u8 UsartBuffer[MAXBUFFER];
u16 UsartWptr = 0;
u16 UsartRptr = 0;	
创建一读一个写两个变量分别进行边下载边写flash的操作,
/*************************************************************
Function : IAP_BufferWrite 
Description: 写缓冲区
Input : none 
return : none 
*************************************************************/
void IAP_BufferWrite(void)
{
	if(UsartWptr == (UsartRptr - 1))//缓冲区存满了 当读速度比较慢时,写不能和读同一个地方前一个数据还没读走不能写入。
	{
	  return;//返回
	}
	UsartBuffer[UsartWptr] = USART1->DR;//存取串口数据
	UsartWptr++;//缓冲写位置值自增
	UsartWptr = UsartWptr%MAXBUFFER;//保证写位置值不溢出
}

/*************************************************************
Function : IAP_BufferRead 
Description: 读缓冲区
Input : none 
return : none 
*************************************************************/
 u8 IAP_BufferRead(u8 *data)
{
	if(UsartRptr == UsartWptr)//无数据可读
	{
	  return 0;
	}
  *data = UsartBuffer[UsartRptr];//读取缓冲区数据
  UsartRptr++;//读位置值自增
  UsartRptr = UsartRptr % MAXBUFFER;//保证读位置值不溢出
  return 1;
}
void USART1_IRQHandler(void)
{
	u8 char_value = 0; //记录数据
	if(USART1->SR&(1<<5))//接收到数据
	{	
		USART1->SR &= ~(1<<5);
		IAP_BufferWrite();
		USART_RX_CNT++;
       timer_enable(1,100,timer0_backcall_func); //接受超时要尽量长一点,避免丢失数据。		
	}
	if(USART1->SR&(1<<4)) //进入空闲中断
	{
		char_value = USART1->DR; //清空空闲中断标志位	
	}
} 
在串口的接受中断函数里面我们要进行写缓存操作,每次写入一个字节UsartWptr则进行加1,每当读走一个字节则UsartWptr加1;
UsartWptr = UsartWptr%MAXBUFFER; 这条语句可以清零。在空闲中断里面我们不做任何操作。
然后就是在主函数中调用烧写函数
/*************************************************************
Function : IAP_UpdataProgram 
Description: 更新程序
Input : none 
return : none 
*************************************************************/
void IAP_UpdataProgram(void)	
{
	u8 n = 0;
    u8 data = 0;
    u8 datalow = 0;
    u8 datahigh = 0;
	u16  pBuffer =0;
	u32 applenth = 0;				//接收到的app代码长度
	
	   
 	u16 Erase = FLASH_APP1_SIZE/ECTOR_SIZE;    //每个扇区2k
	//u32 Erase = FLASH_APP1_ADDR;   //需要擦除的地址空间
	
	rcvTimeout = 0;
	FLASH_EraseOptionBytes (); //关闭flash写保护
	printf("正在擦除扇区!\r\n");
	FLASH_Unlock();//flash解锁
	for(Erase = 0;Erase < FLASH_APP1_SIZE/ECTOR_SIZE;Erase++)
	{
		FLASH_ErasePage(Erase*ECTOR_SIZE+FLASH_APP1_ADDR);//擦除这个APP1扇区
		printf(".");
		delay_ms(150);
	}
	FLASH_Lock();//flash锁
	printf("擦除扇区完成请更新程序!\r\n");
	TIM6->CR1 |= 0x01;    //使能定时器6
	while(1)
	{
			switch(n)
			{
			  case 0:
							if(IAP_BufferRead(&data)) //接收地字节数据
							{
								datalow = data;
								n = 1;
							}	
							else
							{
								break;
							}
			  case 1:
							if(IAP_BufferRead(&data)) //接收高字节数据
							{
								datahigh = data;
								n = 0;
								pBuffer= ((u16)(datalow)) | ((u16)(datahigh << 8));
								IAP_FlashProgramdata(pBuffer);
								
							}
						    if(rcvTimeout)
							{
								datahigh = 0xff;
								n = 0;
								pBuffer= ((u16)(datalow)) | ((u16)(datahigh << 8));
								IAP_FlashProgramdata(pBuffer);
							}
	
				default:
				break;
			}
			if(rcvTimeout)
			{
				TIM6->CR1 &= ~(1<<0);    //使能定时器6
				rcvTimeout = 0;
				applenth = USART_RX_CNT;
				printf("用户程序接收完成!\r\n");
				printf("代码长度:%dBytes\r\n",applenth);
			    return;//结束函数
			}
		}
}

在烧录函数里面我们先进行扇区擦除,把需要烧录的地址的全部扇区都擦除,TIM6->CR1 |= 0x01; //使能定时器6
开启定时器是为了下载完成之后,进行自动结束烧录函数跳转到APP中使用的。

设置全局变量rcvTimeout如果超过500ms没有接受到新的数据了,我们则认为烧录完成了,自动退出该函数。使用的是基本定时器6,代码比较简单我就不讲解了。

比较容易出错的地方有:
1,下载烧录部分要把8位数据转换成16位,这里如果出错会导致跳转到APP程序卡死。
2,写flash部分要记得先要擦除,不然也会烧录失败。
3,超时跳转的定时器函数的中断优先级要比串口的低,而且时间不能太短,不然也会导致出错。详细部分就请下载看源码把。

源码下载:https://download.csdn.net/download/lamp562976334/12120552

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
stm32f10x_iap_bootloader是基于STM32F10x系列微控制器的一个引导程序下载工具。这个工具的作用是用于从外部存储设备(如SD卡)中下载和更新应用程序到系统的Flash内存中。 在进行stm32f10x_iap_bootloader程序下载之前,首先需要准备好一些硬件和软件条件。硬件上,需要一个带有串口或USB接口的STM32F10x系列开发板,以及一个能够供电并适配开发板的电源。软件上,需要一个能够将应用程序转换为可执行文件(如bin或hex格式)的编译器,以及一个支持bootloader功能的下载工具(如ST-Link或Flasher)。 下载stm32f10x_iap_bootloader程序的步骤如下: 1. 将开发板连接到计算机,并确保与计算机的连接正常。 2. 使用编译器编译并生成stm32f10x_iap_bootloader的可执行文件。 3. 将生成的可执行文件保存到外部存储设备(如SD卡)中。 4. 将外部存储设备插入到开发板中的相应插槽中。 5. 打开下载工具,并选择正确的设备和接口。 6. 设置下载参数(如存储设备类型和地址)。 7. 开始下载过程,并等待下载完成。 8. 下载完成后,重启开发板,系统将从外部存储设备中加载并运行新的应用程序。 值得注意的是,下载stm32f10x_iap_bootloader程序之前,应先了解和熟悉stm32f10x_iap_bootloader的使用说明和相关文档,确保正确理解和掌握其功能和操作流程,以避免不必要的错误和损坏。此外,下载过程可能因实际情况而有所差异,请根据具体情况进行相应调整和操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值