STM32F1移植IAP+Ymodem+备用区app详细笔记(四)

一,备用区app

这个看个人,备用区可以固定放哪个app。

我是直接升级成功就将主程序app放备用区里了,通过flash读写直接把整块复制粘贴进备用区app。如果升级失败就将备用区的flash数据复制到主程序区。所以至始至终我们的跳转程序的起始地址都是0x8003000.

二,flash接口,看个人这个咋写的,我随便抄的

1.flash读数据

//读取指定地址的半字(16位数据)
//faddr:读地址(此地址必须为2的倍数!!)
//返回值:对应数据.
u16 STMFLASH_ReadHalfWord(u32 faddr)
{
	return *(vu16*)faddr; 
}
//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)   	
{
	u16 i;
	for(i=0;i<NumToRead;i++)
	{
		pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.
		ReadAddr+=2;//偏移2个字节.	
	}
}

2.flash写数据

#if STM32_FLASH_WREN	//如果使能了写   
//不检查的写入
//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数   
void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)   
{ 			 		 
	u16 i;
	for(i=0;i<NumToWrite;i++)
	{
		FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
	    WriteAddr+=2;//地址增加2.
	}  
} 
//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
#if STM32_FLASH_SIZE<256
#define STM_SECTOR_SIZE 1024 //字节
#else 
#define STM_SECTOR_SIZE	2048
#endif		 
u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节
s16 STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)	
{
	u32 secpos;	   //扇区地址
	u16 secoff;	   //扇区内偏移地址(16位字计算)
	u16 secremain; //扇区内剩余地址(16位字计算)	   
 	u16 i;    
	u32 offaddr;   //去掉0X08000000后的地址
	if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))
	{
		return 1;//非法地址
	}
	FLASH_Unlock();						//解锁
	offaddr=WriteAddr-STM32_FLASH_BASE;		//实际偏移地址.
	secpos=offaddr/STM_SECTOR_SIZE;			//扇区地址  0~127 for STM32F103RBT6
	secoff=(offaddr%STM_SECTOR_SIZE)/2;		//在扇区内的偏移(2个字节为基本单位.)
	secremain=STM_SECTOR_SIZE/2-secoff;		//扇区剩余空间大小   
	if(NumToWrite<=secremain)
	{
		secremain=NumToWrite;//不大于该扇区范围

	}
	while(1) 
	{	
		STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
		for(i=0;i<secremain;i++)//校验数据
		{
			if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除  	  
		}
		if(i<secremain)//需要擦除
		{
			FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区
			for(i=0;i<secremain;i++)//复制
			{
				STMFLASH_BUF[i+secoff]=pBuffer[i];	  
			}
			STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区  
		}else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间. 				   
		if(NumToWrite==secremain)break;//写入结束了
		else//写入未结束
		{
			secpos++;				//扇区地址增1
			secoff=0;				//偏移位置为0 	 
		   	pBuffer+=secremain;  	//指针偏移
			WriteAddr+=(secremain*2);	//写地址偏移	   
		   	NumToWrite-=secremain;	//字节(16位)数递减
			if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
			else secremain=NumToWrite;//下一个扇区可以写完了
		}	 
		return 0;
	};	
	FLASH_Lock();//上锁
}
#endif

3.flash擦除

//按字节数除以2擦除

void STMFLASH_Erase(u32 EraseAddr,u16 NumToErase)	
{
	u32 secpos;	   //扇区地址
	u16 secoff;	   //扇区内偏移地址(16位字计算)
	u16 secremain; //扇区内剩余地址(16位字计算)	   
 	u16 i;    
	u32 offaddr;   //去掉0X08000000后的地址
	if(EraseAddr<STM32_FLASH_BASE||(EraseAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址
	FLASH_Unlock();						//解锁
	offaddr=EraseAddr-STM32_FLASH_BASE;		//实际偏移地址.
	secpos=offaddr/STM_SECTOR_SIZE;			//扇区地址  0~127 for STM32F103RBT6
	secoff=(offaddr%STM_SECTOR_SIZE)/2;		//在扇区内的偏移(2个字节为基本单位.)
	secremain=STM_SECTOR_SIZE/2-secoff;		//扇区剩余空间大小   
	if(NumToErase<=secremain)
		secremain=NumToErase;//不大于该扇区范围
	while(1) 
	{	FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区		
		if(NumToErase==secremain)
			break; //擦除结束了
		else     //擦除未结束
		{
			secpos++;				//扇区地址增1
			secoff=0;				//偏移位置为0 	 
			EraseAddr+=secremain;	//地址偏移	   
		  NumToErase-=secremain;	//字节(16位)数递减
			if(NumToErase>(STM_SECTOR_SIZE/2))
				secremain=STM_SECTOR_SIZE/2;//下一个扇区还是擦除不完
			else secremain=NumToErase;//下一个扇区可以擦除完了
		}	 
	};	
	FLASH_Lock();//上锁
}
三,主程序区到备用程序区的复制
// 函数:从主应用程序复制到备份应用程序
void copy_app_to_backup(void) {
	u16 key[256]={0};
	u32 k = 0;
						
	STMFLASH_Erase(BAK_ApplicationAddress,0xFFFF)	;
	
	for(k = 0; k < 256; k++)
	{
		STMFLASH_Read(ApplicationAddress + 512*k ,key,256);
		STMFLASH_Write( BAK_ApplicationAddress + 512*k ,key,256)	;
		*key=0;
	}
}

这里要注意数组大小不能太大否则可能内存不足啥的不能运行。

ApplicationAddress:0x8003000

BAK_ApplicationAddress:0x8023000

四,主程序区到备用程序区的复制
// 函数:从备份应用程序复制到主程序
void copy_backup_to_app(void) {
	u16 key[256]={0};
	u32 k = 0;
						
	STMFLASH_Erase(ApplicationAddress,0xFFFF)	;

	for(k = 0; k < 256; k++)
	{
		STMFLASH_Read(BAK_ApplicationAddress + k*512 ,key,256);
		STMFLASH_Write( ApplicationAddress +  k*512 ,key,256)	;
		
		*key=0;
	}
}

大小我们之前就订好了0x20000,所以很好确认,进行一些计算就可以了。

ApplicationAddress:0x8003000

BAK_ApplicationAddress:0x8023000

五,第一次烧录程序判断
// 检查是否第一次烧录flash
static u8 CheckfirstFlash() {
	u16 key[3]={0};
	STMFLASH_Read(BAK_ApplicationAddress,key,3);
	if(key[0] ==  0xFFFF && key[1] ==  0xFFFF && key[2] ==  0xFFFF)
	{
		return 1;
	}
	return 0;
}

BAK_ApplicationAddress:0x8023000

直接查备用区的flash数据,看是否有东西,没有的话执行copy_app_to_backup();这样就能确保备用区一直有备用程序。

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32F429串口IAP(Ymodem)升级是一种在STM32F429上通过串口进行最小系统升级的方法。其中,IAP全称为In-Application Programming,可以实现对单片机程序在应用程序的控制下进行在线升级的功能;而Ymodem则是一种通用的串行数据传输协议,可以保证数据的可靠性。 该方法的使用过程如下: 1.使用对应的工具(如ST-LINK Utility)将应用程序和BOOTLOADER程序分别烧录至单片机Flash中。其中,BOOTLOADER程序一定要占用Flash的起始位置,并且大小应该尽量小。 2.编写在应用程序中调用的IAP程序,该程序通过解析Ymodem数据包的方式将更新数据升级到Flash中。同时,IAP程序需要包含一些自我保护措施以避免出现卡死等问题。 3.通过串口将更新数据以Ymodem协议的方式发送给单片机。在发送数据之前,需要保证串口配置正确(比如波特率、数据位等)。 4.单片机收到数据后,进行解析并将数据写入Flash中。在写入数据时需要判断支持Flash的型号和大小,以及使用哪个扇。 该方法的优点在于可以实现在线升级,并且对于不同的Flash型号和大小都有较好的兼容性。同时,采用Ymodem协议可以保证了数据的可靠性,避免了出现数据出错、丢失等问题。缺点则在于需要编写一定的IAP程序,并且在升级时存在一定的安全风险。 ### 回答2: STM32F429作为一款高性能的微控制器,具有多种升级方式。其中比较常用的方式为串口IAP和Ymodem升级。 串口IAP(In-Application Programming)是通过串口通信升级系统的一种简单可行的方法。在程序中添加IAP函数库,修改引脚配置,通过串口连接PC,将升级文件发送至微控制器,程序将自动更新Flash存储器中的程序。 而Ymodem升级则是通过调用UART外设与上位机之间通信,采用基于CRC-16校验的Ymodem-M协议完成数据传输的无需Bootloader的升级方式。该方法优点是可以通过任何终端软件直接实现,缺点是升级速度可能会受到波特率和数据带宽限制,传输时间可能长。 综合来看,根据具体需求和情况选择合适的升级方式,既能提高升级效率,又能确保升级的稳定性和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值