基于HC32L13X系列的YModem升级方案

news/2024/11/8 14:49:52/

文章目录

  • 前言
  • 一、YMODEM协议理解
  • 二、程序设计
    • 1.程序设计说明
    • 2.BOOT程序
    • 3.APP程序
  • 三、功能验证
  • 四、总结


前言

鉴于项目需求,学习并移植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)) {//接收错误的数据,回复NAKYModem_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次中止符CAreturn -1;//返回}size = 0;YModem_SendByte(ACK);	//回复ACkYModem_SendByte(CRC16);//发送'C',询问数据printf("------------->>first packet\r\n");}else//文件名数据包为空,结束传输{YModem_SendByte(ACK);//回复ACKreturn 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次中止符CAreturn -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次中止符CAreturn -3;		//烧写中止case -3://发送端中止传输printf("ack -3\r\n");YModem_SendByte(ACK);//回复ACKreturn 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次中止符CAreturn 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


http://www.ppmy.cn/news/337025.html

相关文章

ECharts - 实用技巧集锦(持续更新)

柱状图 颜色渐变 type: "bar", itemStyle: {// 使用echarts内置的渐变生成器color: new echarts.graphic.LinearGradient(// 分别代表右/下/左/上4个方向&#xff0c;取值0或1// 其中一个取值为1&#xff0c;表示从哪个方向进行渐变0, 0, 1, 0, // 从左到右渐变[/…

【华大测评】+串口DMA收发数据

串口传输用中断实现的话,要频繁的进入中断函数,这样无疑增加MCU的负担,干扰正常程序的运行,对于一些实时性强的应用,如数字显示应用中,液晶屏显示可能受影响而不能正常显示。用DMA实现串口收发数据,进行数据收发过程中,不需要MCU的干预,由DMA独立完成数据的收发,接收…

【国产单片机】华大HC32L13系列使用printf进行调试(多种方法)

———————————————— 华大HC32L13系列国产32单片机开启串口打印&#xff08;汇总多种方法&#xff09; ———————————————— 官方demo存在的问题 使用keil5 MDK进行开发时&#xff0c;无法使用printf()函数进行串口调试&#xff0c;按照网上关于ARM…

博客园美化技巧汇总

首先得有js权限 1.1 页脚js代码 <script type"text/javascript"> /*功能&#xff1a;生成博客目录的JS工具测试&#xff1a;IE8&#xff0c;火狐&#xff0c;google测试通过zhang_derek2018-01-03 */ var BlogDirectory {/*获取元素位置&#xff0c;距浏览器左…

yolov8量化部署(基于openvino和tensorrt)

yolov8 openvino量化部署 环境配置&#xff1a; pip install ultralytics && pip install openvino-dev将pytorch模型转为openvino模型: from ultralytics import YOLO# Load a model model YOLO("./yolov8n.pt") # load an official model# Export the…

Scala概述及变量和常量的重点

1.什么是scala Scala是一种多范式的编程语言&#xff08;多范式&#xff1a;多种编程方法的意思。有面向过程、面向对象、泛型、函数式四种程序设计方法&#xff09;&#xff0c;其设计的初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于Java平台&#xff08;Jav…

软件设计说明书大纲

《软件需求分析与设计》课程综合实践 项目名称&#xff1a;《XX培训机构教学管理系统》 设计说明书 学院&#xff1a; 班级&#xff1a; 小组成员&#xff1a; 1引言 1.1编写目的 1.2背景 1.3定义 1.4参考资料 2总体设计 2.1需求规定 2.2运行环境 2.3基本设计概念 2.4…

【Python开发】FastAPI 10:SQLAlchemy 数据库操作

在 FastAPI 中使用 SQL 数据库可以使用多个 ORM 工具&#xff0c;例如 SQLAlchemy、Tortoise ORM 等&#xff0c;类似 Java 的 Mybatis 。这些 ORM 工具可以帮助我们方便地与关系型数据库进行交互&#xff0c;如 MySQL 、PostgreSQL等。本篇文章将介绍如何使用 SQLAlchemy 来完…