STM32F407 实现在线升级

STM32F407 IAP升级


前言

1、BOOT完成软件更新;
2、APP程序实现备份代码的读入和保存。


一、内存分配说明

1、使用STM32F407VET6内部Flash大小512K,一共分为8个扇区

/*-来自.h文件:stm32f4xx_flash.h-*/
#define FLASH_Sector_0     ((uint16_t)0x0000) 			扇区016K
#define FLASH_Sector_1     ((uint16_t)0x0008)			扇区116K
#define FLASH_Sector_2     ((uint16_t)0x0010)			扇区216K
#define FLASH_Sector_3     ((uint16_t)0x0018)			扇区316K
#define FLASH_Sector_4     ((uint16_t)0x0020)			扇区464K
#define FLASH_Sector_5     ((uint16_t)0x0028)			扇区5128K
#define FLASH_Sector_6     ((uint16_t)0x0030)			扇区6128K
#define FLASH_Sector_7     ((uint16_t)0x0038)			扇区7128K

2、自己的分配说明
我自己分配BOOT使用48K空间,APP程序使用208K,备份空间256K空间,分配的很大目前程序没有使用这么大的空间,大家可以备份控制多分配几个这个可以选择跳转多个程序。

//宏定义
/*---------------------------------------------------------------------------------------------------*/
/*                    BOOT(16K+16K+16K)| APP(16K+64K+128K) | Backups(128K+128K)                    */
/*---------------------------------------------------------------------------------------------------*/
#define ADDR_FLASH_SECTOR_0     ((u32)0x08000000) 	//扇区0起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_1     ((u32)0x08004000) 	//扇区1起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_2     ((u32)0x08008000) 	//扇区2起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_3     ((u32)0x0800C000) 	//扇区3起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_4     ((u32)0x08010000) 	//扇区4起始地址, 64 Kbytes  
#define ADDR_FLASH_SECTOR_5     ((u32)0x08020000) 	//扇区5起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_6     ((u32)0x08040000) 	//扇区6起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_7     ((u32)0x08060000) 	//扇区7起始地址, 128 Kbytes  

#define UPDATA_BOOT_ADDRESS           0x08000000//BOOT程序起始地址
/* BOOT程序 空间48K */
#define UPDATA_APP_ADDRESS            0x0800C000//APP程序起始地址
/* APP程序 空间208K */
#define UPDATA_BACKUPS_ADDRESS        0x08040000//备份程序起始地址
/* Backups程序 空间256K */
#define UPDATA_TIME_ADDRESS           0x0805c000//升级时间(4字节)
#define UPDATA_SIZE_ADDRESS           0x0805c004//升级文件大小(4字节)
#define UPDATA_CRC_ADDRESS            0x0805c008//升级文件校验(4字节)
#define UPDATA_FlAG_ADDRESS           0x0805c00c//升级标注(4字节)
/* 其他数据 空间16K */

二、BOOT程序

1.功能说明

首先说明我程序的升级方式,APP程序在运行时上位机发送bin文件给MCU串口接收,MCU接收到文件存入到备份区域,然后关闭设备重新上电,上电后运行BOOT程序检查是否需要更新,读到更新标志校验备份区域的程序是否正确,正确后进行程序升级擦除APP程序将备份程序写入最后跳转到APP程序再次运行,此时运行的是新程序。

2.BOOT程序

代码如下(示例):
/**************************
 * 设备主任务
 * 参数:00-通用设备
 * 返回值:NULL
 **************************/
void DeviceTask(BYTE TYPE)
{
	while(1)
	{	/*-读取升级标志是否需要升级-*/
		if(STMFLASH_ReadWord(UPDATA_FlAG_ADDRESS) == UPDATA_ALLOW_FLAG)
		{
			if(Load_App() == TRUE)		/*-固件写入成功-*/
				NVIC_SystemReset();
			else						/*-固件写入失败-*/
				JumpTo_APP(UPDATA_APP_ADDRESS);	
		}
		else							/*-跳转APP程序-*/
			JumpTo_APP(UPDATA_APP_ADDRESS);				
	}
}

/*-其他相关函数-*/
/*****************************************
 * 加载APP程序
 * 参数:null
 * 返回值:TRUE-加载完成,FALSE-加载失败
 *****************************************/
BOOL Load_App(void)
{
	DWORD Offset;
	DWORD FirmWareSize;  	//固件大小
	DWORD FirmWareCheck;	//固件校验
	DWORD FirmWareData;  	//固件大小
	DWORD TempData;			//临时数据
	
	/*-读取固件-*/
	FirmWareSize = STMFLASH_ReadWord(UPDATA_SIZE_ADDRESS);
	
	if(FirmWareSize == 0x00000000 || FirmWareSize == 0xFFFFFFFF)
	{
		/*-擦除使用的区域-*/
		//Flash_EraseSectorUser();
		
		/*-固件异常-*/
		TempData = UPDATA_FAIL_FLAG;
		STMFLASH_Write(UPDATA_FlAG_ADDRESS, (unsigned int*)&TempData, 1);
		return FALSE;
	}		
	
	FirmWareCheck = 0x00000000;
	/*-检查数据正确性-*/
	for(Offset = 0; Offset < FirmWareSize; Offset += 4)
	{
		/*读取一遍备份数据累计校验和,对比校验是否正确,异常调回原程序不进行升级-*/
		TempData = STMFLASH_ReadWord(UPDATA_BACKUPS_ADDRESS + Offset);
		
		FirmWareCheck += (BYTE)(TempData>>24) & 0xFF;
		FirmWareCheck += (BYTE)(TempData>>16) & 0xFF;
		FirmWareCheck += (BYTE)(TempData>>8) & 0xFF;
		FirmWareCheck += (BYTE)TempData & 0xFF;
	}
	
	if(FirmWareCheck != STMFLASH_ReadWord(UPDATA_CRC_ADDRESS))   
	{
		/* 固件异常:
		 * 1、传输不完整或者文件损坏
		 * 2、累加校验不正确
		 * 处理方式:
		 * 1、写入升级失败标志
		 * 2、擦除备份区全部数据
		 */
		
		/*-擦除使用的区域-*/
		//Flash_EraseSectorUser();
		
		TempData = UPDATA_FAIL_FLAG;
		STMFLASH_Write(UPDATA_FlAG_ADDRESS, (unsigned int*)&TempData, 1);
		return FALSE;
	}	
	
	/*-升级程序-*/
	for(Offset = 0; Offset < FirmWareSize; Offset += 4)
	{
		/*读取一遍备份数据累计校验和,对比校验是否正确,异常调回原程序不进行升级-*/
		FirmWareData = STMFLASH_ReadWord(UPDATA_BACKUPS_ADDRESS + Offset);
		/*-写入新备份程序-*/
		STMFLASH_Write(UPDATA_APP_ADDRESS + Offset, (unsigned int*)&FirmWareData, 1);
	}
	
	/*-写入升级完成标志-*/
	TempData = UPDATA_SUCCESS_FLAG;
	STMFLASH_Write(UPDATA_FlAG_ADDRESS, (unsigned int*)&TempData, 1);
	return TRUE;
}

/**************************
 * 跳转APP程序
 * 参数:APP程序起始地址
 * 返回值:null
 **************************/
void JumpTo_APP(DWORD appxaddr)
{
	if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)	//检查栈顶地址是否合法.
	{ 
		jump2app=(iapfun)*(vu32*)(appxaddr+4);		//用户代码区第二个字为程序开始地址(复位地址)		
		MSR_MSP(*(vu32*)appxaddr);					//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
		jump2app();									//跳转到APP.
	}
}	
/***************************
 * 写STM32F407内部Flash数据
 ***************************/
 void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)	
{ 
	FLASH_Status status = FLASH_COMPLETE;
	u32 addrx=0;
	u32 endaddr=0;
	
	if(WriteAddr < UPDATA_BOOT_ADDRESS || WriteAddr%4)
		return;	//非法地址
	
	FLASH_Unlock();									//解锁 
	FLASH_DataCacheCmd(DISABLE);					//FLASH擦除期间,必须禁止数据缓存
	
	FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
	
	addrx=WriteAddr;				//写入的起始地址
	endaddr=WriteAddr+NumToWrite*4;	//写入的结束地址
	if(addrx<0X1FFF0000)			//只有主存储区,才需要执行擦除操作!!
	{
		while(addrx<endaddr)		//扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
		{
			if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
			{   
				
				status=FLASH_EraseSector(STMFLASH_GetFlashSector(addrx),VoltageRange_3);//以4字节为单位进行擦除
				if(status!=FLASH_COMPLETE)
					break;	//发生错误了
			}
			else 
				addrx+=4;
		} 
	}
	if(status==FLASH_COMPLETE)
	{
		while(WriteAddr<endaddr)//写数据
		{
			if(FLASH_ProgramWord(WriteAddr,*pBuffer)!=FLASH_COMPLETE)//写入数据
			{ 
				break;	//写入异常
			}
			WriteAddr+=4;
			pBuffer++;
		} 
	}
	FLASH_DataCacheCmd(ENABLE);	//FLASH擦除结束,开启数据缓存
	FLASH_Lock();//上锁
} 


未完再续。。。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值