LPC1768学习笔记

文章目录[隐藏]

LPC1768学习笔记:IAP升级

1.需求:通过串口给主机升级,主机的通信串口与升级串口相同
2.方法:要完成APP与IAP程序的切换判断,我们需要一个flag_update单独标识地址的,当flag_update为0xFF的时候,视为正常上电状态,程序由IAP(0x10000000)可以直接跳转到APP中执行;当flag_update为0x55的时候,视为远程烧写状态,程序由IAP开始之后,不跳转APP,而是执行自己的等待烧写流程。这边具体的流程和应用后面会具体介绍。
为了满足切换判断的功能,就需要该标志位不随APP程序的烧写而发生变化,所以我这边选择将IAP存储区之后的一个扇区,即地址0x10009000作为flag_update的存储地址,这样,在IAP程序不变的情况下,随便怎么烧写APP,只要目标地址满足上述表格中的要求,该标志位就不会发生变化。当然,使用用其他满足条件的存储方式(诸如存入外部Flash、存入EEPROM等)都可以。
一.芯片内存划分:芯片总内存为512K
(1)IAP程序内存 :0x0000 0000 - 0x0000 8FFF -36K(可根据自己调整)
(2)升级标志内存:0x0000 9000 - 0x0000 9FFF -4K
(3)数据缓冲内存:0x0000 B000 - 0x0000 BFFF -4k
(4)APP程序内存 :0x0000 C000 - 0x0007 FFFF -472k
芯片手册内存分布地址:
在这里插入图片描述
二.IAP流程图说明:
【IAP】:对于IAP程序来说,首先根据flag_update状态判断是否跳转APP,如果不跳转,则等待升级包。待升级包传输完毕,全部写到APP的地址中之后,再执行跳转到APP程序的起始地址执行(或者直接重启)。跳转或者重启之前需要将flag_update重新置为正常上电状态(0xFF),这样以避免下一次重启之后,程序仍然跑在IAP中。
【APP】:对于APP程序来说,需要实现的很简单,就是在串口收到某些外部指令的时候(可自由设置),将flag_update置为远程烧写状态(0x55),并重启。重启之后,MCU会重新从IAP程序开始执行,执行到flag_update判断,不跳转APP,进而执行IAP中等待升级文件的流程。
在这里插入图片描述
三:程序跳转与地址改写
APP:程序主要包括地址配置和跳转IAP两方面功能:
【1】地址配置:
将其地址配置为功能介绍中规划的地址,同时在系统初始化程序中,将SCB->VTOR的地址配置为APP程序的起始地址
在这里插入图片描述
在系统void SystemInit (void)改写
在这里插入图片描述
【2】跳转IAP:
APP程序需要修改的核心程序体如下所示,串口收数据处理逻辑中,如果收到满足条件的通信码,则改写flag_update所在地址上的值:


if(/*收到满足条件的通信码*/)
    {
        iap_init(BANK0);
        Iap_Write_Config_Value(0x55); //改写标志地址值
        //runIap(); // 跳转函数
        __set_FAULTMASK(1);  //直接重启
        NVIC_SystemReset();

四:IAP部分程序:主要概括为以下几个点:地址配置、跳转APP、串口读写
【1】:将其地址配置为功能介绍中规划的地址,同时在系统初始化程序中,将SCB->VTOR的地址配置为APP程序的起始地址:
在这里插入图片描述
在系统void SystemInit (void)改写
在这里插入图片描述
【2】跳转APP:
IAP程序中需要修改的核心程序体如下所示,上电IAP程序自检,如果位于0X10009000的标志位值为0xFF,则进入APP程序地址运行,反之执行自身的烧写流程:

int main (void)
{
	uint8_t  APP_UPDATE_VALUE=0xFF;
    uint8_t  work_mode=0;
	uint8_t *flag_update=(uint8_t *)FLAG_UPDATE_ADDRESS; //	 0x00009000  ---用户升级标志区 0xFF跳转APP--0X55停留IAP等待升级程序
	  	                                                                 
	UARTInit()	 ;  			 /* 初始化UART2---9600		*/	
	GucRcvOver  = 0;
	GulRcvCount = 0;
	memset(GucIapTmp, 0, 4096);		/* 缓冲区清零					*/

	if((*flag_update)==APP_UPDATE_VALUE)	   //0xFF
	 {
	 	work_mode=0;
		RunApp();
	 }
	 else
	 {
	   UARTSend((uint8_t *)(" 等待升级程序BIN文件中 "), strlen(" 等待升级程序BIN文件中 "));

	   zyIrqDisable(); 					   /* 禁止所有中断	        */
	   u32IAP_PrepareSectors(12, 29);		   /* 选择12-29扇区			*/
	   u32IAP_EraseSectors	(12, 29);		   /* 擦除12-29扇区         */
	   zyIrqEnable(); 
	   work_mode=1;				
	 }

	while(work_mode==1)
	{
		if(GucRcvOver == 0) //接收完成标志
		{
		  if (GulRcvCount != 0) 
		  {
			zyIrqDisable();  //禁止中断
    		userDataProgram();	    /*****下载更新程序*****/				
			zyIrqEnable();
		  }
		}
		else
		{
		 	*flag_update=0x55;	   /*****修改程序跳转标志*****/
			UARTSend((uint8_t *)(" 升级结束,等到重启中 "), strlen(" 升级结束,等到重启中 "));
			myDelay (5);                             /*	延时等待稳定		*/
			memset(GucIapTmp, 0x00, 256);			/* 	临时缓冲区清空		*/
	
	   		/**刚烧录完跳转有时不稳,直接重启***/
		    __set_FAULTMASK(1);
		    NVIC_SystemReset();
		}
	}
}

其中跳转接口runApp逻辑如下所示:

void RunApp(void )
{
  	 	/*  Change the Vector Table to the USER_FLASH_START 
			in case the user application uses interrupts 
			将矢量表更改为用户闪存启动 如果用户应用程序使用中断 */
//	SCB->VTOR = USER_APP_START_ADD ;
	JMP_Boot(USER_APP_START_ADD );
//	iap_load_app(USER_APP_START_ADD );

}
__asm void JMP_Boot( uint32_t address ){
   LDR SP, [R0]		;Load new stack pointer address
   LDR PC, [R0, #4]	;Load new program counter address
}

【3】:串口收发就是正常串口收发配置即可;

void UART2_IRQHandler (void) 
{
//  uint8_t IIRValue, LSRValue;
  uint8_t Dummy = Dummy;
   volatile  uint8_t i; 

   while ((UART2->IIR & 0x01) == 0)
   {                                       								/* 判断是否有中断挂起           */
      switch (UART2->IIR & 0x0E) {                                      /* 判断中断标志                 */
        
		case 0x04:                                         				/* 接收数据中断      A&E=0X04  */
            for (i = 0; i < 8; i++) {                 				    /* 连续接收8个字节              */
                puiRcvData[GulRcvCount++] = UART2->RBR;            	    /*  接收缓冲寄存器				*/
            }
            break;
        case 0x0C:                                                      /* 字符超时中断                 */
            while ((UART2->LSR & 0x01) == 0x01) {                            /* 判断数据是否接收完毕         */ 
                puiRcvData[GulRcvCount++] = UART2->RBR;
            }
		    GucRcvOver = 1;
            break; 
        default:
            break;
        }
    } 	
								
}

【5】:将缓冲区的代码复制进去APP区代码:

void  userDataProgram (void)
{
	uint32_t  ulAddr= 0;	/* 字节偏移量清0*/							/* Addr:字节偏移量 				*/
	uint32_t  ulProgramCount;						                    /* ProgramCount:编程到Flash扇   */
                                                 
	while (GulRcvCount != 0) 
	{
		if (GulRcvCount > (1024 * 4)) 
		{									/* 一次最多写入4K代码量			*/
			memcpy(GucIapTmp, puiRcvData + ulAddr, 1024 * 4);
			GulRcvCount 	-= (1024 * 4);	        //清零
			ulProgramCount = 1024 * 4;
		   UARTSend((uint8_t *)(" 写入数据错误,请重新发送BIN文件 "), strlen(" 写入数据错误,请重新发送BIN文件 "));
		}
		else 
		 {
			memcpy(GucIapTmp, puiRcvData + ulAddr, GulRcvCount);	//puiRcvData --数据缓冲区
			ulProgramCount = GulRcvCount;	
			GulRcvCount = 0;
			if ((ulProgramCount   == 256 ) 
			    ||(ulProgramCount == 512 )
			    ||(ulProgramCount == 1024)
			    ||(ulProgramCount == 4096)) {
				
				goto flashProgram;
			}

			/* 
			 *  满足编程字节数的要求,256、512、1024等 
			 */
			if (ulProgramCount < 256) {
				ulProgramCount = 256;					
				goto flashProgram;
			}
			if (ulProgramCount < 512) {
				ulProgramCount = 512;
				goto flashProgram;
			}
			if (ulProgramCount < 1024) {
				ulProgramCount = 1024;
				goto flashProgram;
			}
			if (ulProgramCount < 4096) {
				ulProgramCount = 4096;
				goto flashProgram;
			}
		}
        flashProgram:

		/******* 升级用户程序空间 *******/
			zyIrqDisable();
			u32IAP_PrepareSectors(12, 29);									    /* 选择扇区			        */

			u32IAP_CopyRAMToFlash(USERLOW + ulAddr, (uint32_t)GucIapTmp, ulProgramCount);	   /* 写数据到FLASH 		        */
                                      
			zyIrqEnable();
			ulAddr += ulProgramCount;

	}
}

版权声明:本文为CSDN博主「weixin_45588193」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45588193/article/details/122558875

LPC1768学习笔记:IAP升级

1.需求:通过串口给主机升级,主机的通信串口与升级串口相同
2.方法:要完成APP与IAP程序的切换判断,我们需要一个flag_update单独标识地址的,当flag_update为0xFF的时候,视为正常上电状态,程序由IAP(0x10000000)可以直接跳转到APP中执行;当flag_update为0x55的时候,视为远程烧写状态,程序由IAP开始之后,不跳转APP,而是执行自己的等待烧写流程。这边具体的流程和应用后面会具体介绍。
为了满足切换判断的功能,就需要该标志位不随APP程序的烧写而发生变化,所以我这边选择将IAP存储区之后的一个扇区,即地址0x10009000作为flag_update的存储地址,这样,在IAP程序不变的情况下,随便怎么烧写APP,只要目标地址满足上述表格中的要求,该标志位就不会发生变化。当然,使用用其他满足条件的存储方式(诸如存入外部Flash、存入EEPROM等)都可以。
一.芯片内存划分:芯片总内存为512K
(1)IAP程序内存 :0x0000 0000 - 0x0000 8FFF -36K(可根据自己调整)
(2)升级标志内存:0x0000 9000 - 0x0000 9FFF -4K
(3)数据缓冲内存:0x0000 B000 - 0x0000 BFFF -4k
(4)APP程序内存 :0x0000 C000 - 0x0007 FFFF -472k
芯片手册内存分布地址:
在这里插入图片描述
二.IAP流程图说明:
【IAP】:对于IAP程序来说,首先根据flag_update状态判断是否跳转APP,如果不跳转,则等待升级包。待升级包传输完毕,全部写到APP的地址中之后,再执行跳转到APP程序的起始地址执行(或者直接重启)。跳转或者重启之前需要将flag_update重新置为正常上电状态(0xFF),这样以避免下一次重启之后,程序仍然跑在IAP中。
【APP】:对于APP程序来说,需要实现的很简单,就是在串口收到某些外部指令的时候(可自由设置),将flag_update置为远程烧写状态(0x55),并重启。重启之后,MCU会重新从IAP程序开始执行,执行到flag_update判断,不跳转APP,进而执行IAP中等待升级文件的流程。
在这里插入图片描述
三:程序跳转与地址改写
APP:程序主要包括地址配置和跳转IAP两方面功能:
【1】地址配置:
将其地址配置为功能介绍中规划的地址,同时在系统初始化程序中,将SCB->VTOR的地址配置为APP程序的起始地址
在这里插入图片描述
在系统void SystemInit (void)改写
在这里插入图片描述
【2】跳转IAP:
APP程序需要修改的核心程序体如下所示,串口收数据处理逻辑中,如果收到满足条件的通信码,则改写flag_update所在地址上的值:


if(/*收到满足条件的通信码*/)
    {
        iap_init(BANK0);
        Iap_Write_Config_Value(0x55); //改写标志地址值
        //runIap(); // 跳转函数
        __set_FAULTMASK(1);  //直接重启
        NVIC_SystemReset();

四:IAP部分程序:主要概括为以下几个点:地址配置、跳转APP、串口读写
【1】:将其地址配置为功能介绍中规划的地址,同时在系统初始化程序中,将SCB->VTOR的地址配置为APP程序的起始地址:
在这里插入图片描述
在系统void SystemInit (void)改写
在这里插入图片描述
【2】跳转APP:
IAP程序中需要修改的核心程序体如下所示,上电IAP程序自检,如果位于0X10009000的标志位值为0xFF,则进入APP程序地址运行,反之执行自身的烧写流程:

int main (void)
{
	uint8_t  APP_UPDATE_VALUE=0xFF;
    uint8_t  work_mode=0;
	uint8_t *flag_update=(uint8_t *)FLAG_UPDATE_ADDRESS; //	 0x00009000  ---用户升级标志区 0xFF跳转APP--0X55停留IAP等待升级程序
	  	                                                                 
	UARTInit()	 ;  			 /* 初始化UART2---9600		*/	
	GucRcvOver  = 0;
	GulRcvCount = 0;
	memset(GucIapTmp, 0, 4096);		/* 缓冲区清零					*/

	if((*flag_update)==APP_UPDATE_VALUE)	   //0xFF
	 {
	 	work_mode=0;
		RunApp();
	 }
	 else
	 {
	   UARTSend((uint8_t *)(" 等待升级程序BIN文件中 "), strlen(" 等待升级程序BIN文件中 "));

	   zyIrqDisable(); 					   /* 禁止所有中断	        */
	   u32IAP_PrepareSectors(12, 29);		   /* 选择12-29扇区			*/
	   u32IAP_EraseSectors	(12, 29);		   /* 擦除12-29扇区         */
	   zyIrqEnable(); 
	   work_mode=1;				
	 }

	while(work_mode==1)
	{
		if(GucRcvOver == 0) //接收完成标志
		{
		  if (GulRcvCount != 0) 
		  {
			zyIrqDisable();  //禁止中断
    		userDataProgram();	    /*****下载更新程序*****/				
			zyIrqEnable();
		  }
		}
		else
		{
		 	*flag_update=0x55;	   /*****修改程序跳转标志*****/
			UARTSend((uint8_t *)(" 升级结束,等到重启中 "), strlen(" 升级结束,等到重启中 "));
			myDelay (5);                             /*	延时等待稳定		*/
			memset(GucIapTmp, 0x00, 256);			/* 	临时缓冲区清空		*/
	
	   		/**刚烧录完跳转有时不稳,直接重启***/
		    __set_FAULTMASK(1);
		    NVIC_SystemReset();
		}
	}
}

其中跳转接口runApp逻辑如下所示:

void RunApp(void )
{
  	 	/*  Change the Vector Table to the USER_FLASH_START 
			in case the user application uses interrupts 
			将矢量表更改为用户闪存启动 如果用户应用程序使用中断 */
//	SCB->VTOR = USER_APP_START_ADD ;
	JMP_Boot(USER_APP_START_ADD );
//	iap_load_app(USER_APP_START_ADD );

}
__asm void JMP_Boot( uint32_t address ){
   LDR SP, [R0]		;Load new stack pointer address
   LDR PC, [R0, #4]	;Load new program counter address
}

【3】:串口收发就是正常串口收发配置即可;

void UART2_IRQHandler (void) 
{
//  uint8_t IIRValue, LSRValue;
  uint8_t Dummy = Dummy;
   volatile  uint8_t i; 

   while ((UART2->IIR & 0x01) == 0)
   {                                       								/* 判断是否有中断挂起           */
      switch (UART2->IIR & 0x0E) {                                      /* 判断中断标志                 */
        
		case 0x04:                                         				/* 接收数据中断      A&E=0X04  */
            for (i = 0; i < 8; i++) {                 				    /* 连续接收8个字节              */
                puiRcvData[GulRcvCount++] = UART2->RBR;            	    /*  接收缓冲寄存器				*/
            }
            break;
        case 0x0C:                                                      /* 字符超时中断                 */
            while ((UART2->LSR & 0x01) == 0x01) {                            /* 判断数据是否接收完毕         */ 
                puiRcvData[GulRcvCount++] = UART2->RBR;
            }
		    GucRcvOver = 1;
            break; 
        default:
            break;
        }
    } 	
								
}

【5】:将缓冲区的代码复制进去APP区代码:

void  userDataProgram (void)
{
	uint32_t  ulAddr= 0;	/* 字节偏移量清0*/							/* Addr:字节偏移量 				*/
	uint32_t  ulProgramCount;						                    /* ProgramCount:编程到Flash扇   */
                                                 
	while (GulRcvCount != 0) 
	{
		if (GulRcvCount > (1024 * 4)) 
		{									/* 一次最多写入4K代码量			*/
			memcpy(GucIapTmp, puiRcvData + ulAddr, 1024 * 4);
			GulRcvCount 	-= (1024 * 4);	        //清零
			ulProgramCount = 1024 * 4;
		   UARTSend((uint8_t *)(" 写入数据错误,请重新发送BIN文件 "), strlen(" 写入数据错误,请重新发送BIN文件 "));
		}
		else 
		 {
			memcpy(GucIapTmp, puiRcvData + ulAddr, GulRcvCount);	//puiRcvData --数据缓冲区
			ulProgramCount = GulRcvCount;	
			GulRcvCount = 0;
			if ((ulProgramCount   == 256 ) 
			    ||(ulProgramCount == 512 )
			    ||(ulProgramCount == 1024)
			    ||(ulProgramCount == 4096)) {
				
				goto flashProgram;
			}

			/* 
			 *  满足编程字节数的要求,256、512、1024等 
			 */
			if (ulProgramCount < 256) {
				ulProgramCount = 256;					
				goto flashProgram;
			}
			if (ulProgramCount < 512) {
				ulProgramCount = 512;
				goto flashProgram;
			}
			if (ulProgramCount < 1024) {
				ulProgramCount = 1024;
				goto flashProgram;
			}
			if (ulProgramCount < 4096) {
				ulProgramCount = 4096;
				goto flashProgram;
			}
		}
        flashProgram:

		/******* 升级用户程序空间 *******/
			zyIrqDisable();
			u32IAP_PrepareSectors(12, 29);									    /* 选择扇区			        */

			u32IAP_CopyRAMToFlash(USERLOW + ulAddr, (uint32_t)GucIapTmp, ulProgramCount);	   /* 写数据到FLASH 		        */
                                      
			zyIrqEnable();
			ulAddr += ulProgramCount;

	}
}

版权声明:本文为CSDN博主「weixin_45588193」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45588193/article/details/122558875

生成海报
点赞 0

weixin_45588193

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

LPC1768学习笔记

LPC1768学习笔记:IAP升级 1.需求:通过串口给主机升级,主机的通信串口与升级串口相同 2.方法:要完成APP与IAP程序的切换判断,我们需要一个flag_upda

基于8051单片机实现电子时钟+数字秒表设计

概述 电子时钟是一种利用数字电路来显示秒、分、时的计时装置,与传统的机械钟相比,它具有走时准确、显 示直观、无机械传动装置等优点,因而得到广泛应用。随着人们生活环境的不断改善和美化,在许