天天看点

4.STM32在应用更新程序IAP1.IAP原理2.APP程序设置3.Bootloader程序设计4.APP程序设计5.演示6参考文献7源代码及分析

在一些工业监测应用中,设备布置在户外或者一些不方便人工烧录程序的场景,同时希望可以更新程序。通过整理和研究了一套IAP(In Application Programming,在应用编程)程序,可以通过串口等通信工具更新程序,不用对控制板卡进行插拔仿真器,也不需要对板卡进行任何操作,通过串口即可完成程序的更新。

在监测项目中,通常会有一个DTU或者其他GPRS模块,配置好服务器IP地址后,即可和服务器进行通信,但是对于板卡来说,其实质也是串口通信,所以可以利用DTU模块对板卡进行在应用更新程序。

1.IAP原理

正常程序的执行流程:

4.STM32在应用更新程序IAP1.IAP原理2.APP程序设置3.Bootloader程序设计4.APP程序设计5.演示6参考文献7源代码及分析

IAP的执行流程:

4.STM32在应用更新程序IAP1.IAP原理2.APP程序设置3.Bootloader程序设计4.APP程序设计5.演示6参考文献7源代码及分析

IAP程序必须满足:

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

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

2.APP程序设置

有两个APP程序,一个为FLASH的APP,程序运行在FLASH,另一个SRAM的APP,运行在SRAM。

FLASH APP正常程序的起始地址为:0X0800 0000,长度为0X80000(19位,512K)。

4.STM32在应用更新程序IAP1.IAP原理2.APP程序设置3.Bootloader程序设计4.APP程序设计5.演示6参考文献7源代码及分析

APP程序放在0X0801 0000,长度为0X70000(7*2^16,448K)。前面长度0X10000(2^16,64K,(应该是0X200,512的整数倍)),用于放Bootloader程序,所以Bootloader不应大于64K。

SRAM APP起始地址为:0X0200 1000,长度为0XC000(12*2^12,48K)。

4.STM32在应用更新程序IAP1.IAP原理2.APP程序设置3.Bootloader程序设计4.APP程序设计5.演示6参考文献7源代码及分析

IRAM起始地址0X0200 D000,长度0X3000(3*2^12,12K)用于存放SRAM APP的内存。

由于偏移地址是0X10000,所以需要在SystemInit函数中设置SCB SCB->VTOR = FLASH_BASE | 0x10000;这是设置中断向量表的起始偏移地址。SRAM APP的设置方法SCB SCB->VTOR = SRAM_BASE | 0x1000;

MDK生成的是.hex文件,IAP需要的是.bin文件,使用fromelf.exe功能将.axf转换成.bin,fromelf.exe的转换格式为转换工具的语法格式为:fromelf [options] input。

通过在 MDK点击 Options for Target→User选项卡,在After Build/Rebuild栏,勾选 Run #1,并写入:

D:\tools\mdk5.14\ARM\ARMCC\bin\fromelf.exe   --bin -o  ..\OBJ\RTC.bin ..\OBJ\RTC.axf

(本机的fromelf.exe放在C:\Keil_v5\ARM\ARMCC\bin,需要改路径为对应路径,其他文件也要改文件名)

然后只需要将这个.bin文件发给STM32就可以执行IAP升级

3.Bootloader程序设计

进入接受APP程序,在接受完APP后,即可执行IAP。

iap_write_appbin函数用于将存放在串口接收buf里面的APP程序写入到FLASH。Iap_load_app函数,用于跳转到APP程序运行,参数appxaddr为APP程序的其实地址,程序先判断栈顶地址是否合法,在得到合法的栈顶地址后,通过MSR_MSP函数,设置栈顶地址,最后通过虚拟函数jump2app跳转到APP程序执行代码,实现IAP→APP的跳转。

usart.h中定义USART_RX_BUF数组保存接收的APP程序,长度USART_REC_LEN为55K,串口最大可接受55K,本BootLoader最大能接受APP的大小。指定USART_RX_BUF地址,使其保存在固定的RAM地址。

Bootloader程序是正常地址的程序,需要删除掉一些无用的程序,只用于接收数据,更新程序,跳转程序等操作。

Bootloader程序的主要流程为,上电后判断串口是否有数据,若一定时间内(例10秒)无串口数据,则自动进入跳转到之前保存的IAP APP程序,如果无合法的APP程序,则进入一个死循环或者继续等待串口接收数据都可以。这样便可以在板卡上电后自动跳转到的之前的程序,而不再需要上位机发送指令或者程序。

 如果在时间段内有数据流,则把接收到的所有数据保存到RAM中,接收完所有数据后(以时间间隔(10ms)无新数据作为判断标志,因为数据长度是不定的,没办法事前约定),判断程序数据是否合法,合法则把程序保存到指定的FLASH中,然后进行跳转到该FLASH。

到此Bootloader程序设计完成了,需要添加一些提示信息提示当前状态。

3.1一定时间到自动跳转到APP程序

4.STM32在应用更新程序IAP1.IAP原理2.APP程序设置3.Bootloader程序设计4.APP程序设计5.演示6参考文献7源代码及分析
time_count ++;
		if(time_count == 1000)//10S
		{
			time_count = 0;
			printf("10秒时间到,开始执行FLASH APP程序...\r\n");
			run_IAP();
		}
		delay_ms(10);
           

3.2串口接收数据

接收数据为普通的串口接收程序,在中断接收保存数据,然后在主函数或者定时器中断中判断时间间隔作为接收完成判断均可,建议在主函数中判断,不使用定时器,可以减少Bootloader程序的大小。

3.3更新程序

4.STM32在应用更新程序IAP1.IAP原理2.APP程序设置3.Bootloader程序设计4.APP程序设计5.演示6参考文献7源代码及分析
if(oldcount==USART_RX_CNT)//新周期内,没有收到任何数据,认为本次数据接收完成.
			{
				applenth=USART_RX_CNT;
				oldcount=0;
				USART_RX_CNT=0;
				printf("用户程序接收完成!\r\n");
				printf("代码长度:%dBytes\r\n",applenth);
				printf("开始更新固件...\r\n");
				if(update_IAP(applenth)==1)//更新固件
					run_IAP();
			}else
			{
				time_count = 0;//重新计时10秒
				oldcount=USART_RX_CNT;
			}
           

在接收完程序数据后,先判断程序是否合法,合法则更新到FLASH中,然后在跳转到该APP程序。

3.4备注

对跳转和更新程序进行了简单的封装如下:

4.STM32在应用更新程序IAP1.IAP原理2.APP程序设置3.Bootloader程序设计4.APP程序设计5.演示6参考文献7源代码及分析
void run_IAP(void)
{
	if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
	{
		iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
	}
	else
	{
		printf("非FLASH应用程序,无法执行!\r\n");
	}
}

u8 update_IAP(u16 applenth)
{
	if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
	{	 
		iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth);//更新FLASH代码   
		printf("固件更新完成!\r\n");
		return 1;
	}else 
	{	   
		printf("非FLASH应用程序!\r\n");
		return 0;
	}
}
           
4.STM32在应用更新程序IAP1.IAP原理2.APP程序设置3.Bootloader程序设计4.APP程序设计5.演示6参考文献7源代码及分析
iapfun jump2app; 
u16 iapbuf[1024];   
//appxaddr:应用程序的起始地址
//appbuf:应用程序CODE.
//appsize:应用程序大小(字节).
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
{
	u16 t;
	u16 i=0;
	u16 temp;
	u32 fwaddr=appxaddr;//当前写入的地址
	u8 *dfu=appbuf;
	for(t=0;t<appsize;t+=2)
	{						    
		temp=(u16)dfu[1]<<8;
		temp+=(u16)dfu[0];	  
		dfu+=2;//偏移2个字节
		iapbuf[i++]=temp;	    
		if(i==1024)
		{
			i=0;
			STMFLASH_Write(fwaddr,iapbuf,1024);	
			fwaddr+=2048;//偏移2048  16=2*8.所以要乘以2.
		}
	}
	if(i)STMFLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去.  
}

//跳转到应用程序段
//appxaddr:用户代码起始地址.
void iap_load_app(u32 appxaddr)
{
	if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)	//检查栈顶地址是否合法.
	{ 
		jump2app=(iapfun)*(vu32*)(appxaddr+4);		//用户代码区第二个字为程序开始地址(复位地址)		
		MSR_MSP(*(vu32*)appxaddr);					//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
		jump2app();									//跳转到APP.
	}
}
           

4.APP程序设计

APP程序最重要的部分就是需要保存在约定好的地址内,然后需要在程序开始前设置好保存中断服务函数起始地址的中断向量表偏移量,其他都是正常的程序。但是由于需要在APP程序运行中,根据需要可以进行在应用编程,并且我们在Bootloader程序中设计了更新代码,只需要在APP在添加复位代码,即可自动进入到Bootloader中,进行代码的更新。

4.1程序保存地址

程序保存在约定的地址内,在2中已经讲解了。

4.2设置中断向量表偏移量

STM32的设置中断向量表偏移量。

SCB->VTOR = FLASH_BASE | 0x10000;

4.3远程控制软件复位

STM32串口复位方法:

4.STM32在应用更新程序IAP1.IAP原理2.APP程序设置3.Bootloader程序设计4.APP程序设计5.演示6参考文献7源代码及分析
receive_usart1.rcbuf[receive_usart1.recount]='\0';
	
if(strcmp(receive_usart1.rcbuf,"[RESTART]")==0)//无论任何模式收到服务器发的重启指令,则单片机复位
{
	printf("[RESTARTING]");//STM32重启中
	__set_FAULTMASK(1);//关闭所有中断
	NVIC_SystemReset();//复位函数
	while(1);//死循环,强制看门狗复位
}
           

串口接受到对应的[RESTART]指令后即可进行程序软件复位。

APP程序的其他部分均与正常程序一致。

5.演示

第一次操作需要先通过ISP给板卡烧录Bootloader程序,复位板卡,在串口软件中打开对应的.bin文件,在设置好的一定时间内(10秒)发送bin文件,发送后将自动运行APP程序。

4.STM32在应用更新程序IAP1.IAP原理2.APP程序设置3.Bootloader程序设计4.APP程序设计5.演示6参考文献7源代码及分析

在之后的程序中,一般来说程序都是在运行APP程序(并且板卡因为电源等原因复位后,也可以正常运行APP程序),这时候通过串口发送[RESTART]指令对板卡进入复位即可,然后再一定时间内发送bin文件即可在应用更新程序。

6参考文献

[1]正点原子.STM32F103ZET6精英板标准例程库函数版本.

[2]正点原子.STM32F1开发指南(精英版)-库函数版本_V1.2.pdf

7源代码及分析

7.1代码大小限制

最后附上工程源代码,工程现在是一次性发送代码,发送完成后导入到FLASH,跳转,用的STM32F103ZE,RAM空间为64K,但是堆栈等占用了大概6K空间,程序设置的最大可用RAM空间为55K,所以本例程最大的代码空间为55K,一般的工程是足够了。

但是如果代码足够复杂,或者用的F103C8芯片,RAM只有20K,可用只有15K左右,非常有限,所以在此基础上再继续优化代码,可以将文件分次发送,在STM32段分次保存,发送完毕后再跳转。但是这需要重新开发上位机,后面有时间再研究一下这个。

7.2代码校验

源代码里面没有对程序数据进行校验,最好是加上对CRC校验更加可靠,或者使用文件传输协议YMODEM进行传输,但是同时这也需要上位机配合,可以和分次发送同时研究一下。

源代码链接:https://pan.baidu.com/s/1WWXmuNHHrL47x1xIZoUB1w   提取码:lk07

(实现板卡:反客STM32F103ZET6(FK103M5),其中APP程序为现场监测源代码)

继续阅读