基于HC32L13X系列的YModem升级方案

1 篇文章 0 订阅
1 篇文章 0 订阅


前言

鉴于项目需求,学习并移植YModem在华大Hc32L系列MCU上,时间短,有欠缺的地方欢迎指正


一、YMODEM协议理解

示例:这里参照了一篇YModem协议说明,供参考,下载链接在结尾处,有需要的可自取。
在这里插入图片描述
Ymodem协议解释:
SENDER:发送方。(文件名:fileName.bin)
RECEIVER:接收方。
具体握手的步骤如下:
1、接收方发送一个字符’C’,也就是十六进制’43’。代表接收方已经处于接收数据的状态。
2、发送方接收到’C’之后,发送头帧数据包,内容如下:
SOH 00 FF fileName.bin NULL[116] CRC CRC
数据包内容解释:
2-1、SOH(第一字节):表示数据区大小有128字节。(STX表示本数据包数据区大小1024字节)。
2-2、00(第二字节):数据块编号。第一包为00,第二包为01,此后依次累加。FF后,继续从00循环。
2-3、FF(第三字节):数据块编号的反码。编号00-FF,01-FE,此后以此类推。
2-4、fileName.bin NULL[116]:数据区。128字节。fileName.bin是文件名,超级终端下,在文件名后面还有文件大小。数据区不足128字节的,用0x00补齐。
2-5、CRC校验(最后2个字节):16位CRC校验,高位字节在前,低位字节在后。(注意:只有数据区参与了CRC校验,不包含头,编码,编码反码)。
3、接收方收到数据包后,发送ACK正确应答,然后发送一个字符’C’。
4、发送方收到’C’后,开始发送第二帧数据。第二帧数据存放的是第一包数据。
5、接收方收好数据包后,发送ACK正确应答,然后等待下一包数据传送完毕,继续ACK应答。(循环)
6、数据传输完毕后,发送方第一次发送EOT,第一次接受方以NAK应答,进行二次确认。
7、发送方收到NAK后,第二次发送EOT。接收方第二次收到结束符,依次以ACK和C做应答。
8、发送方收到ACK和C之后,发送结束符SOH 00 FF 00 … 00[128个00]CRCH CRCL。
9、接收方收到结束符之后,以ACK做应答,然后通信正式结束。

二、程序设计

1.程序设计说明

Boot程序用UART0作数据传输,UART1作数据打印,while循环调用YModem_Receive_Proc函数处理数据。
App程序用UART1作数据打印,while循环调用systick获取当前时间量,1s打印一次数据。

2.BOOT程序

代码如下(示例):

/**
 * @brief Function Main
 */
int main(void)
{
	uint32_t	len;
	
	Flash_Init(NULL,4,FALSE);	 	
	Flash_WaitCycle(FlashWaitCycle1);

	Tsk_SystemInit();
	Tsk_Uart0Init();
	Tsk_Uart1Init();
	
	__enable_irq();
	
	printf("This is Boot\r\n");
	printf("Please send the bin file to MCU\r\n");
	Hal_Uart0_Send_Str("This is Boot,Please send the bin file to MCU.\r\n");
	
    while(1)
    {
		YModem_Receive_Proc(buff,&len);
	}
}
/*************************************************************
  Function   : YModem_Receive 
  Description: ymodem接收
  Input      : buf-存放接收到的数据 
			   length 接收数据的总长度
  return     : 
				
				0 -发送端传输中止
               -1 -固件过大
			   -2 -flash烧写错误
			   -3 -用户终止    
*************************************************************/
int YModem_Receive_Proc(unsigned char *buf, unsigned int *length)
{
	unsigned int		i,size;	
	unsigned int  		errors; 	
	unsigned int		packets_received;
	unsigned int 		packet_length;		
	unsigned int		app_bin_datalen;
	
	unsigned char  		*file_ptr, *buf_ptr;

	*length = 0;
	size = 0;
	errors = 0;
	
	packets_received = 0;		
	
	app_bin_datalen = 0;
	buf_ptr = buf;
	memset(buf_ptr,0xff,FLASH_PAGE_SIZE);
		
	while(1)	//死循环,不断接收数据
	{
		switch(YModem_RecvPacket(packet_data, &packet_length, NAK_TIMEOUT))//接收数据包
		{
			case 0:	//接收正常					
				errors = 0;
				if(packet_length)//接收数据中
				{						
					if((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff)) 
					{
						//接收错误的数据,回复NAK
						YModem_SendByte(NAK);
					}
					else	
					{
						if(packets_received == 0)//接收第一帧数据
						{
							if(packet_data[PACKET_HEADER] != 0)//包含文件信息:文件名,文件长度等
							{
								for(i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH); )
								{
									if(i < 16)	file_name[i++] = *file_ptr++;//保存文件名
									else
									{	
										file_name[i++] = '\0';		//文件名以'\0'结束 
										file_ptr++;	
									}
								}
								file_name[i++] = '\0';//文件名以'\0'结束 	
								for(i = 0, file_ptr++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH); )
								{
									file_size[i++] = *file_ptr++;//保存文件大小
								}
								file_size[i++] = '\0';//文件大小以'\0'结束 													
								size = w_atoi((char *)file_size);//将文件大小字符串转换成整型
								*length = size;
								if(UpdateAppCodeStart(file_name, size))	//
								{
									YModem_SendByte(CA);			 
									YModem_SendByte(CA);//连续发送2次中止符CA
									return -1;//返回
								}
								size = 0;
								YModem_SendByte(ACK);	//回复ACk
								YModem_SendByte(CRC16);//发送'C',询问数据
								printf("------------->>first packet\r\n");
							}
							else//文件名数据包为空,结束传输
							{
								YModem_SendByte(ACK);//回复ACK
								return 0;
							}
						}
						else 
						{
							file_ptr = packet_data + PACKET_HEADER;	
							while(packet_length)
							{
								if(packet_length >= (FLASH_PAGE_SIZE - app_bin_datalen))
								{
									printf("------------->>packet_length:%d\r\n",packet_length);
									memcpy(buf_ptr + app_bin_datalen, file_ptr, (FLASH_PAGE_SIZE - app_bin_datalen));//拷贝数据
									file_ptr += (FLASH_PAGE_SIZE - app_bin_datalen);
									packet_length -= (FLASH_PAGE_SIZE - app_bin_datalen);
									//接收到1页固件资料,就更新写入
									if(UpdateAppCode(buf_ptr))
									{
										printf("------------->>error -2\r\n");
										YModem_SendByte(CA);	 
										YModem_SendByte(CA);//flash烧写错误,连续发送2次中止符CA
										return -2;//烧写错误
									}
									size += FLASH_PAGE_SIZE;
									app_bin_datalen = 0;
									memset(buf_ptr,0xff,FLASH_PAGE_SIZE);	
								}
								else
								{
									printf("-------------<<packet_length:%d\r\n",packet_length);
									//由 file_ptr 所指内存区域复制 packet_length 个字节到 buf_ptr + app_bin_datalen 所指内存区域。
								 	memcpy(buf_ptr + app_bin_datalen, file_ptr, packet_length);//拷贝数据
									app_bin_datalen += packet_length;
									packet_length = 0;
								}
							}									
							YModem_SendByte(ACK);//flash烧写成功,回复ACK
						}
						packets_received++;//收到数据包的个数
					}						
				}
				else
				{
					YModem_SendByte(ACK);
					//接收完成	
					UpdateAppCodeEnd(buf_ptr, app_bin_datalen);
					size += app_bin_datalen;	
					printf("------------->>size:%d\r\n",size);
					return size;
				}
				break;
					
			case -2:		                //用户中止
				printf("ack -2\r\n");
				YModem_SendByte(CA);
				YModem_SendByte(CA);    //连续发送2次中止符CA
				return -3;		//烧写中止
				
			case -3:
				//发送端中止传输
				printf("ack -3\r\n");
				YModem_SendByte(ACK);//回复ACK
				return 0;
			
			case -1:
				if(packets_received > 0)   //传输过程中发生错误
				{
					errors++;
					if(errors > MAX_ERRORS) //错误超过上限
					{
						printf("errors %d\r\n",errors);
						YModem_SendByte(CA);
						YModem_SendByte(CA);//连续发送2次中止符CA
						return 0;	//传输过程发生过多错误
					}						
				}
				
				if(eot_flag)
				{
					YModem_SendByte(CRC16); //发送'C',继续接收
					if(ca_index++ > 0)
					{
						eot_flag = 0;
						printf("------------->>JumpToApp\r\n");
						Hal_Uart0_Send_Str("------>>Ok\r\n");
						iap_load_app(APP_FW_START_ADDR);
					}
				}
				else
				{
					YModem_SendByte(CRC16); //发送'C',继续接收
				}
				break;
		} 
	}
}

3.APP程序

/**
 * @brief Function Main
 */
int main(void)
{
	uint32_t	timedelay;
	
	SCB->VTOR = 0x4000;
	
	Flash_Init(NULL,4,FALSE);	 	
	Flash_WaitCycle(FlashWaitCycle1);

	Tsk_SystemInit();
	Tsk_Uart0Init();
	Tsk_Uart1Init();
	
	__enable_irq();
	
	timedelay = uTick;
	
	printf("-------------->>This is App\r\n");

    while(1)
    {
		if((uTick - timedelay) > 1000)
		{
			timedelay = uTick; 
			printf("-------------->>App run %d\r\n",i++);
		}
	}
}

三、功能验证

在这里插入图片描述
在这里插入图片描述

四、总结

1.Boot程序注意数据收完跳转APP程序的方式;
2.App程序注意设置偏移地址

源文件下载地址:https://download.csdn.net/download/qq_34413603/34864984?spm=1001.2014.3001.5501

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值