QT上位机给STM32设备串口IAP升级固件

QT上位机给STM32设备串口IAP升级固件

目录

QT上位机给STM32设备串口IAP升级固件

1,实现原理

2,程序流程

3,关键代码解析

4,相关工具及代码


废话不多说看看效果先


上位机源码连接:https://download.csdn.net/download/qq_28643619/10922262

1,实现原理

应用编程IAP(In-Application-Programming)是应用在Flash程序存储器的一种编程模式,它可以在应用程序正常运行的情况下,通过调用特定的IAP程序对另外一段程序Flash空间进行读/写操作,甚至可以控制对某段、某页甚至某个字节的读/写操作。主要用于数据存储和固件升级。对于IAP应用,通常会有两个程序,第一个程序Bootloader程序不执行正常功能,只是通过某种方式(串口,usb,SD卡)接收第二个程序,并进行更新。第二个程序APP程序是执行的主体,用于实现应用功能。
       对于stm32闪存模块,主要由主存储器、信息块和闪存存储器接口寄存器三部分构成。
                         
       主存储器,该部分用来存放代码和数据常数(如 const 类型的数据)。对于大容量产品,其被划分为 256 页,每页 2K 字节。注意, 小容量和中容量产品则每页只有 1K 字节。看出主存储器的起始地址就是 0X08000000, B0、 B1 都接GND 的时候,就是从 0X08000000开始运行代码的。

       信息块,该部分分为 2 个小部分,其中启动程序代码,是用来存储 ST 自带的启动程序,用于串口下载代码,当 B0 接 V3.3, B1 接 GND的时候,运行的就是这部分代码。用户选择字节,则一般用于配置写保护、读保护等功能,本章不作介绍。

       闪存存储器接口寄存器,该部分用于控制闪存读写等,是整个闪存模块的控制机构。

       对主存储器和信息块的写入由内嵌的闪存编程/擦除控制器(FPEC)管理;编程与擦除的高电压由内部产生。

    对于flash的读写的流程

    这里要特别留意一个闪存等待时间,因为 CPU 运行速度比 FLASH 快得多, STM32F103的 FLASH 最快访问速度≤24Mhz,如果 CPU 频率超过这个速度,那么必须加入等待时间,比如我们一般使用72Mhz的主频,那么FLASH等待周期就必须设置为 2,该设置通过 FLASH_ACR寄存器设置。

2,程序流程

编程流程

1、检查 FLASH_CR 的 LOCK 是否解锁,如果没有则先解锁,(向KEYR寄存器中写入特定序列KEY1和KEY2)

   (实际中需要查看当前要写入的扇区是否有数据,如果有数据,则需要进行擦除操作,然后再进行下面的步骤)

2、检查 FLASH_SR 寄存器的 BSY 位,以确认没有其他正在进行的编程操作
3、设置 FLASH_CR 寄存器的 PG 位为’1’,用于表示接下来进行写操作
4、在指定的地址写入要编程的半字
5、等待 BSY 位变为’0’,表示编程完成
6、读出写入的地址并验证数据

我们在 STM32 的 FLASH 编程的时候,要先判断缩写地址是否被擦除了

下面介绍页擦除过程


读出被擦除的页并做验证
1、检查 FLASH_CR 的 LOCK 是否解锁,如果没有则先解锁(向KEYR寄存器中写入特定序列KEY1和KEY2)
2、检查 FLASH_SR 寄存器的 BSY 位,以确认没有其他正在进行的闪存操作
3、设置 FLASH_CR 寄存器的 PER 位为’1’,用于表示进行页擦除操作
4、用 FLASH_AR 寄存器选择要擦除的页
5、置 FLASH_CR 寄存器的 STRT 位为‘1’表示开始一次擦除操作
6、等待 BSY 位变为’ 0’
读出被擦除的页并做验证
 

我们来了解下stm32的程序运行流程,如下图所示

程序运行的地址从0x08000000(FLASH)开始运行

1程序开始运行后,从中断向量表中取出复位中断向量,并执行服务程序。

2执行完中断向量程序会跳转至主main函数入口执行,并在死循环中一直执行。

3当在主函数中发生中断时间时,系统强制PC指针指向对应中断向量表对应位置。

4PC指针在中断向量表处取出中断服务程序入口地址,并跳转至对应位置执行。

5中断服务程序执行完成后,PC指针跳回发生中断时系统在main函数中的位置,继续往下执行。

当加入IAP应用后stm32的程序流程变为下图所示

程序运行的地址从0x08000000(FLASH)开始运行

1程序开始运行后,从中断向量表中取出复位中断向量,并执行服务程序。执行完中断向量程序会跳转至Bootloader程序main函数入口执行。

2在main中系统检查是否需要对第二部分代码进行更新,如果需要则执行更新操作,如果不需要则跳过更新操作,跳转至APP程序的入口

3在APP程序入口首先进入重新映射的中断向量口,根据新的中断复位向量,执行复位中断程序,然后跳转至APP程序main入口。

4当在主函数中发生中断时间时,系统强制PC指针指向对应中断向量表对应位置(这里还是强制跳转到地址0x0800004中断向量表位置,而不是APP程序的中断向量表)。

两个注意点:

1) 新程序必须在 IAP 程序之后的某个偏移量为 x 的地址开始;

2) 必须将新程序的中断向量表相应的移动,移动的偏移量为 x;

对于程序的设置

IAP程序

通过串口设置程序的接收

根据要求设置存储APP程序的地址

APP程序

设置程序存储区,与数据存储区 在Target->Read/Only Memory Areas-> IROM与IRAM处设置,这里APP程序的存储首地址设为0x08010000,大小为0x70000(即前0x10000为存放IAP程序)

设置中断向量表偏移地址SCB->VTOR = FLASH_BASE | 0x10000; 

生成BIN文件

3,关键代码解析

STM32F103的IAP关键代码:

int main(void)
{      
	uint32_t tick1;
	tick1 = SysTick_GetCurrent();
        MCU_Init();	
	AreaFlagFirstLoadInit();
	NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x8000000);  //iap初始都从0x8000000开始运行
	printf("init success\r\n");	   
	__enable_irq();	
	while(1)		
	{
		iapLoop();
		if((remainSend  == 0x00) && (upgradeDoneFlag == 0xaa55aa55)) 
		{			
	
			(currentAreaNum==areaA) ? (FlashDestination=ApplicationAddress_A) : (FlashDestination=ApplicationAddress_B);
			if(((*(__IO uint32_t*)FlashDestination) & 0x2FFE0000 ) == 0x20000000)				//binÎļþÉý¼¶
			{											 
				printf("Execute user APP1 Program upgradeDoneFlag=%x\r\n",upgradeDoneFlag);
				USART_Cmd(USART1, DISABLE);
				__disable_irq();	
				JumpAddress = *(__IO uint32_t*) (FlashDestination + 4);
				Jump_To_Application = (pFunction) JumpAddress;						
				MSR_MSP(*(vu32*)FlashDestination);
				Jump_To_Application();								
			}
			else 
			{			
				if(SysTick_GetLapse(tick1)>1000)
				{
					printf("ÎÞFLASHÓ¦ÓóÌÐò,ÎÞ·¨Ö´ÐÐ!\r\n");	
					tick1 = SysTick_GetCurrent();
				}
				
			}
		}
	}
}


uint8_t AreaFlagFirstLoadInit(void)
{
	uint8_t ret = 0;
	STMFLASH_Read(ADDR_FLASH_LAST_PAGE,&upgradeDoneFlag,1);  
	FLASH_Unlock();
	if(upgradeDoneFlag==0xffffffff || upgradeDoneFlag==0x00000000)
	{
		upgradeDoneFlag = 0xaa55aa55;
		FLASH_ProgramWord(ADDR_FLASH_LAST_PAGE,0xaa55aa55);
	}
	

	STMFLASH_Read(AREA_NUM_ADDR,&currentAreaNum,1);
	
	if(currentAreaNum == 0xffffffff || currentAreaNum==0x00000000)   
	{	
		printf("ÇøÓò±ê־λ³õʼ»¯");
		currentAreaNum = areaA;			
		if(FLASH_COMPLETE!=FLASH_ProgramWord(AREA_NUM_ADDR,areaA))
		{
			printf("ÇøÓòA±ê־λÉϵç³õʼ»¯Ê§°Ü");
			ret = 1;
		}
	}	
	FLASH_Lock();
	
	switch(currentAreaNum)
	{
		case areaA:
			addrCur = ApplicationAddress_B;
			break;
		
		case areaB:
			addrCur = ApplicationAddress_A;
			break;	
			
		default:
			break;
	}

	printf("addrCur=%x currentAreaNum=%x upgradeDoneFlag=%x\n",addrCur,currentAreaNum,upgradeDoneFlag);
	
	return ret;
}

单片机iap及app工程连接:

4,相关工具及代码

用到的工具软件:

猜你喜欢

转载自blog.csdn.net/qq_28643619/article/details/81286374