单片机如何实现IAP升级啊?升级程序应该在制定的位置吧,要不它也就被擦除了吧?只能升级其他的ROM吧?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单片机如何实现IAP升级啊?升级程序应该在制定的位置吧,要不它也就被擦除了吧?只能升级其他的ROM吧?相关的知识,希望对你有一定的参考价值。

我用C8051F020上实现的一个IAP来举例吧。升级程序的确放在指定位置,因为C8051F020有64K的ROM,所以升级程序就占用ROM最后的4K的空间,前面64K就用来存放用户程序。

在每次单片机启动时,放在0000H位置的LJMP指令不是跳转到用户程序,而是直接跳转到了升级程序(60K开始的位置),这里升级程序初始化串口,等待串口发来的数据流,如果数据流的不正确或者没有收到数据流,就跳转回用户程序的入口执行用户上次下载进去的程序。

所以在这里用户的程序不能超过60K,当然升级程序也不会“自宫”,就没什么影响了。追问

哦,好办法,但是吧,我还有几个疑问啊。
1)、上电让他跳转到你的IAP程序处,这个地址你是已知的,但是如何保证你的IAP程序就正好烧录那个区域呢?
2)、当你没有升级的时候,你要跳转到正常的用户程序,你怎么知道这里的用户程序地址呢?
请继续赐教,还有就是可不可以发给我个你实现过了IAP功能的程序工程啊?1931181808 @ qq。com

追答

    IAP程序的位置是已知的,并且是被绝对定位到某个位置的,这个用编译器实现。比如在C8051F020上实现时,要在编译选项里设置ROM的start=60k,size=4k.

    因为51单片机程序,最开始的3个字节是LJMP指令,即跳转到用户程序入口的位置。IAP程序在从串口接收用户程序时最先收到的也是这3个字节的内容,所以IAP将其存储在一个固定的区域,然后将用户程序剩余的部分从0x0003开始烧写到ROM中,烧写完成后再执行那3个字节的跳转指令,这样就跳转到用户程序了。在以后启动时,如果IAP没有检测到更新,就执行那3字节的跳转指令,继续执行原来的用户程序。

    我修改过STM32F4的IAP,实现从U盘里读取用户程序烧写到单片机中,这比C8051F020的更容易。

参考技术A 单片机做IAP好像不太容易,有IAP功能的单片机很少吧,做个ISP就很不错了,有此功能的单片机现在很多了,入STC51单片机,AVR等都有。
不过做IAP一般还是将程序做到本身里面的,IAP先是将程序读入缓冲区,这个过程是靠你自己的程序来完成的,下一步就是将缓冲区的程序覆盖原来的程序,这是靠CPU的BOOT程序来实现的。追问

单片机IAP还是很简单的,而且也很多,比如老的SST单片机都有IAP功能,这是它的一大特色,还有STC的单片机也能,我现在用的瑞萨单片机也能,之前用过的LPC2138也能,LPC1114,如果单片机不支持IAP,那么升级困难,这样对产品的升级,维护很困难,比如你的产品卖到了意大利,那边就要求意大利语言的界面。
谢谢你的回答。

追答

瑞萨单片机我也做过IAP的,不过用的是SH7055,已经不能叫单片机了吧。做IAP的单片机首先必须有扩展RAM,所以51是具备这个条件的,其次单片机有自举的BOOT程序。做到IAP其实就是自己编一段程序在应用中,将从存储介质(如U盘、SD卡)从的升级程序读入扩展RAM,之后再由BOOT接管,将这部分程序搬入FLASH。

追问

哦,你原来写过的是这样的过程啊,那么我继续请教下啊:
1)、什么算自举BOOT程序?单片机都有吧?
2)、当初你的IAP应用程序放到了任意或者说随意的ROM区了吗?
3)、将数据读取到RAM,然后由BOOT接管,这个怎么个情况,是你配置好后BOOT,然后就去接管吗?
4)、是不是当BOOT接管后,放入FLASH时也就将你的IAP应用程序擦除了?

追答

BOOT程序是有IAP功能的CPU自带的你可以理解为一段Bios

IAP程序是你自己程序的一部分当然可能在任何的ROM区域。
程序运行时在RAM区的,所以擦除原来FLASH的程序不会影响IAP的过程。
BOOT程序只是在第一次载入程序时需要用到,之后升级不是必须的。当然这需要你的程序是在RAM区运行,不像普通51那样在ROM区运行。

基于STM32的IAP升级程序

基于STM32的IAP升级程序

IAP介绍

IAP(In Application Programming)即在应用编程,IAP 是用户自己的程序在运行过程中对User Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。 通常实现 IAP 功能时,即用户程序运行中作自身的更新操作,需要在设计固件程序时编写两个项目代码,第一个项目程序不执行正常的功能操作,而只是通过某种通信方式(如 USB、USART)接收程序或数据,执行对第二部分代码的更新;第二个项目代码才是真正的功能代码。这两部分项目代码都同时烧录在 User Flash 中,当芯片上电后,首先是第一个项目代码开始运行。
简单来说,就是程序首先运行在boot升级区,检测是否有升级程序,当有升级程序的时候,用户将升级的固件通过某种通信接口(如串口)传输到开发板的某个位置中,之后放在APP的位置。当没有升级程序,直接运行APP中的程序。

功能设计

将最新的产品固件通过串口上传到开发板中,按下按键1,开发板将固件更新到设置的功能程序存放地址,按下按键2,执行功能程序。

Created with Raphaël 2.3.0 开始 是否有升级程序 将升级固件暂存在RAM中 是否按下按键1 将RAM中的固件更新到Flash功能程序位置 是否按下按键2 跳转到执行产品功能程序 yes no yes no yes no

硬件设计

使用的MCU为STM32F103
使用元器件为两个按键和两个LED灯

软件设计

软件设计流程如下

  1. 编写需要升级的产品功能程序
  2. 设置产品功能程序在keil 5中Target的程序的Flash起始地址和大小,并且程序中设置中断向量表的偏移量
  3. 生成产品功能程序的固件bin文件
  4. 设置IAP升级程序存放的起始地址和大小
  5. 串口接收产品功能程序
  6. 将最新的升级程序放入到功能程序的Flash位置
  7. 跳转到功能程序的Flash地址处

完整程序

基于STM32的IAP升级程序(Bootloader)

具体实现

设计功能程序

主要为两处:

  1. 在main()函数中最开始处,添加
SCB->VTOR = FLASH_BASE|0x9C00; 
  1. 在keil 5中Target的程序的Flash起始地址和大小

生成bin文件:我们通过在 MDK 点击 Options for Target→User 选项卡,在 After Build/Rebuild 栏,
勾选 Run #1,并写入:D:\\32\\Keil 5\\ARM\\ARMCC\\bin\\fromelf.exe --bin -o …\\OBJ\\LED.bin …\\OBJ\\LED.axf

编译后,就会生成.bin文件了。

IAP实现程序

  1. IAP写入程序
    将暂存在RAM中的程序存放到Flash的对应地址中
    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);//将最后的一些内容字节写进去.  

  1. 运行地址偏移程序
    程序转移到指定地址运行
    跳转到应用程序段
    appxaddr:用户代码起始地址.
void iap_load_app(u32 appxaddr)

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

主程序

通过按键对接收到的升级程序进行更新,或者直接转入到功能程序地址。

	while(1)
	
	 	if(USART_RX_CNT)
		 
			if(oldcount==USART_RX_CNT)
			
				applenth=USART_RX_CNT;
				oldcount=0;
				USART_RX_CNT=0;
				printf("代码长度:%dBytes\\r\\n",applenth);
			else oldcount=USART_RX_CNT;			
		
		if(key==WKUP_PRES)
		
			if(applenth)
			
				printf("开始更新固件...\\r\\n");	
 				if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
					 
					iap_write_appbin(FLASH_APP2_ADDR,USART_RX_BUF,applenth);//更新FLASH代码 
					printf("固件更新完成!\\r\\n");	
				else 
				
	   printf("固件更新失败!\\r\\n");
					
				
 			else 
			
				printf("没有可以更新的固件!\\r\\n");
										 
		 
		if(key==KEY1_PRES)
		
			printf("开始执行FLASH用户代码!!\\r\\n");
			if(((*(vu32*)(FLASH_APP2_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
				 
				iap_load_app(FLASH_APP2_ADDR);//执行FLASH APP代码
			else 
			
				printf("非FLASH应用程序,无法执行!\\r\\n");
												 
				 
	  

后续

如果想了解更多物联网、智能家居项目知识,可以关注我的项目实战专栏。
或者关注公众号观看更多。

编写不易,感谢支持。

以上是关于单片机如何实现IAP升级啊?升级程序应该在制定的位置吧,要不它也就被擦除了吧?只能升级其他的ROM吧?的主要内容,如果未能解决你的问题,请参考以下文章

关于STM32单片机的IAP实现

基于STM32的IAP升级程序

单片机的IAP是啥意思?

基于STM32的IAP升级程序

简单实现stm32f103芯片usb模拟U盘进行IAP更新用户程序

单片机串口IAP原理