6902|10

565

帖子

0

TA的资源

一粒金砂(高级)

楼主
 

【GD32L233C-START评测】9、IAP程序升级——基于YMODEM协议 [复制链接]

 
本帖最后由 freeelectron 于 2022-2-7 12:57 编辑

相关文章:

【GD32L233C-START评测】1、优点与缺点都很明显的GD32L233C-START(开箱)

【GD32L233C-START评测】2、非阻塞方式点灯,blink,blink,blink……

【GD32L233C-START评测】3、pwm实现呼吸灯

【GD32L233C-START评测】4、串口不定长数据接收

【GD32L233C-START评测】5、Flash读写——使用内部Flash存储数据

【GD32L233C-START评测】6、硬件I2C驱动0.96吋OLED

【GD32L233C-START评测】7、硬件SPI1驱动RC522

【GD32L233C-START评测】8、获取MCU96位唯一ID、SRAM、FLASH大小

 

 

1、什么是IAP

IAP是In Application Programming的缩写,即在应用编程,IAP是用户自己的程序在运行过程中对User Flash的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。可以通过串口、USB、网络、无线等方式进行升级数据的传输。

2、IAP要点

(1)程序分两部分,BOOT和APP分别编写;
(2)flash空间划分(flash空间足够大的情况下,可以分成APP1和APP2进行备份升级);

(3)flash可编程(读、写、擦除);GD32L233flash编程,可查看【GD32L233C-START评测】5、Flash读写——使用内部Flash存储数据,里面有关于flash的的读、写、擦除操作;

(4)从BOOT跳转到APP的时候需要,关闭中断,判断栈顶地址、设置栈指针;

(5)APP程序编译设置,flash起始地址;

(6)App程序中设置,中断开和中断向量位置。

 

3、YMODEM协议

3.1、YMODEM 帧格式
Ymodem 有两种帧格式,主要区别是信息块长度不一样。

帧头    包序号    包序号 取反    信息块    校验
SOH/STX    PN    XPN    DATA    CRC
1byte    1byte    1byte    128/1024byte    2byte

3.1.1、帧头
帧头表示两种数据帧长度,主要是信息块长度不同。
当帧头为SOH(0x01)时,信息块为128字节;
当帧头为STX(0x02)时,信息块为1024字节。

3.1.2、包序号
数据包序号只有1字节,因此计算范围是0~255;对于数据包大于255的,序号归零重复计算。

3.1.3、帧长度
以SOH(0x01)开始的数据包,信息块是128字节,该类型帧总长度为133字节;
以STX(0x02)开始的数据包,信息块是1024字节,该类型帧总长度为1029字节。

3.1.4、校验
Ymodem采用的是CRC16校验算法,校验值为2字节,传输时CRC高八位在前,低八位在后;CRC计算数据为信息块数据,不包含帧头、包号、包号反码。

3.2、YMODEM起始帧
Ymodem起始帧并不直接传输文件内容,而是先将文件名和文件大小置于数据帧中传输;起始帧是以SOH 133字节长度帧传输,格式如下。

帧头    包序号    包序号 取反    文件名称    文件大小    填充区    校验
SOH    0x00    0xFF    filename+0x00    filesize+0x00    n字节0x00    CRC16
其中包号为固定为0;
filename为文件名称,文件名称后必须加0x00作为结束;
filesize为文件大小值,文件大小值后必须加0x00作为结束;
余下未满128字节数据区域,则以0x00填充。
可以看出起始帧也是遵守3.1中Ymodem包格式的。

3.3、YMODEM数据帧
Ymodem数据帧传输,在信息块填充有效数据。
传输有效数据时主要考虑的是最后一包数据的是处理,SOH帧和STR帧有不同的处理。
(1)对于SOH帧,若余下数据小于128字节,则以0x1A填充,该帧长度仍为133字节。
(2)对于STX帧需考虑几种情况:

余下数据等于1024字节,以1029长度帧发送;
余下数据小于1024字节,但大于128字节,以1029字节帧长度发送,无效数据以0x1A填充;
余下数据等于128字节,以133字节帧长度发送;
余下数据小于128字节,以133字节帧长度发送,无效数据以0x1A填充。

3.4、YMODEM结束帧
Ymodem的结束帧采用SOH 133字节长度帧传输,该帧不携带数据(空包),即数据区、校验都以0x00填充。

帧头    包序号    包序号 取反    信息块    校验
0x01    0x00    0xff    128个0x00    0x00 0x00

3.5、YMODEM握手信号
握手信号由接收方发起,在发送方开始传输文件前,接收方需发送YMODEM_C (字符C,ASII码为0x43)命令,发送方收到后,开始传输起始帧。

3.6、YMODEM命令
命令    命令码    说明
SOH    0x01    128字节数据包
STX    0x02    1024字节的数据包
EOT    0x04    结束传输
ACK    0x06    回应
NAK    0x15    没回应,需要重传当前数据包
CA    0x18    取消传输
C    0x43    握手

4、YMODEM工具

5、核心代码

(1)操作菜单,通过输入代码,选择执行的操作

  • void Main_Menu(void)
  • {
  • uint8_t key = 0;
  • while (1)
  • {
  • SerialPutString("\r\n================== Main Menu ===============================\r\n\n");
  • SerialPutString(" Download Image To the GD32L233CCT6 Internal Flash ------- 1\r\n\n");
  • SerialPutString(" Upload Image From the GD32L233CCT6 Internal Flash ------- 2\r\n\n");
  • SerialPutString(" Execute The New Program --------------------------------- 3\r\n\n");
  • SerialPutString("=============================================================\r\n\n");
  • key = GetKey();
  • if (key == 0x31)
  • {
  • /* Download user application in the Flash */
  • SerialDownload();
  • }
  • else if (key == 0x32)
  • {
  • /* Upload user application from the Flash */
  • SerialUpload();
  • }
  • else if (key == 0x33)
  • {
  • if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000) //判断栈顶地址是否在合法范围内
  • {
  • JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
  • /* Jump to user application */
  • Jump_To_Application = (pFunction) JumpAddress;
  • /* Initialize user application's Stack Pointer */
  • __set_MSP(*(__IO uint32_t*) ApplicationAddress);
  • Jump_To_Application();
  • }
  • }
  • else
  • {
  • SerialPutString("Invalid Number ! ==> The number should be either 1, 2 or 3\r");
  • }
  • }
  • }

(2)ymodem发送

  • uint8_t Ymodem_Transmit (uint8_t *buf, const uint8_t* sendFileName, uint32_t sizeFile)
  • {
  • uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD];
  • uint8_t FileName[FILE_NAME_LENGTH];
  • uint8_t *buf_ptr, tempCheckSum ;
  • uint16_t tempCRC, blkNumber;
  • uint8_t receivedC[2], CRC16_F = 0, i;
  • uint32_t errors, ackReceived, size = 0, pktSize;
  • errors = 0;
  • ackReceived = 0;
  • for (i = 0; i < (FILE_NAME_LENGTH - 1); i++)
  • {
  • FileName = sendFileName;
  • }
  • CRC16_F = 1;
  • /* Prepare first block */
  • Ymodem_PrepareIntialPacket(&packet_data[0], FileName, &sizeFile);
  • do
  • {
  • /* Send Packet */
  • Ymodem_SendPacket(packet_data, PACKET_SIZE + PACKET_HEADER);
  • /* Send CRC or Check Sum based on CRC16_F */
  • if (CRC16_F)
  • {
  • tempCRC = Cal_CRC16(&packet_data[3], PACKET_SIZE);
  • Send_Byte(tempCRC >> 8);
  • Send_Byte(tempCRC & 0xFF);
  • }
  • else
  • {
  • tempCheckSum = CalChecksum (&packet_data[3], PACKET_SIZE);
  • Send_Byte(tempCheckSum);
  • }
  • /* Wait for Ack and 'C' */
  • if (Receive_Byte(&receivedC[0], 10000) == 0)
  • {
  • if (receivedC[0] == ACK)
  • {
  • /* Packet transfered correctly */
  • ackReceived = 1;
  • }
  • }
  • else
  • {
  • errors++;
  • }
  • }while (!ackReceived && (errors < 0x0A));
  • if (errors >= 0x0A)
  • {
  • return errors;
  • }
  • buf_ptr = buf;
  • size = sizeFile;
  • blkNumber = 0x01;
  • /* Here 1024 bytes package is used to send the packets */
  • /* Resend packet if NAK for a count of 10 else end of commuincation */
  • while (size)
  • {
  • /* Prepare next packet */
  • Ymodem_PreparePacket(buf_ptr, &packet_data[0], blkNumber, size);
  • ackReceived = 0;
  • receivedC[0]= 0;
  • errors = 0;
  • do
  • {
  • /* Send next packet */
  • if (size >= PACKET_1K_SIZE)
  • {
  • pktSize = PACKET_1K_SIZE;
  • }
  • else
  • {
  • pktSize = PACKET_SIZE;
  • }
  • Ymodem_SendPacket(packet_data, pktSize + PACKET_HEADER);
  • /* Send CRC or Check Sum based on CRC16_F */
  • /* Send CRC or Check Sum based on CRC16_F */
  • if (CRC16_F)
  • {
  • tempCRC = Cal_CRC16(&packet_data[3], pktSize);
  • Send_Byte(tempCRC >> 8);
  • Send_Byte(tempCRC & 0xFF);
  • }
  • else
  • {
  • tempCheckSum = CalChecksum (&packet_data[3], pktSize);
  • Send_Byte(tempCheckSum);
  • }
  • /* Wait for Ack */
  • if ((Receive_Byte(&receivedC[0], 0xffffff) == 0) && (receivedC[0] == ACK))
  • {
  • ackReceived = 1;
  • if (size > pktSize)
  • {
  • buf_ptr += pktSize;
  • size -= pktSize;
  • if (blkNumber == (APP_IMAGE_SIZE/1024))
  • {
  • return 0xFF; /* error */
  • }
  • else
  • {
  • blkNumber++;
  • }
  • }
  • else
  • {
  • buf_ptr += pktSize;
  • size = 0;
  • }
  • }
  • else
  • {
  • errors++;
  • }
  • }while(!ackReceived && (errors < 0x0A));
  • /* Resend packet if NAK for a count of 10 else end of commuincation */
  • if (errors >= 0x0A)
  • {
  • return errors;
  • }
  • }
  • ackReceived = 0;
  • receivedC[0] = 0x00;
  • errors = 0;
  • do
  • {
  • Send_Byte(EOT);
  • /* Send (EOT); */
  • /* Wait for Ack */
  • if ((Receive_Byte(&receivedC[0], 0xffffff) == 0) && receivedC[0] == ACK)
  • {
  • ackReceived = 1;
  • }
  • else
  • {
  • errors++;
  • }
  • }while (!ackReceived && (errors < 0x0A));
  • if (errors >= 0x0A)
  • {
  • return errors;
  • }
  • /* Last packet preparation */
  • ackReceived = 0;
  • receivedC[0] = 0x00;
  • errors = 0;
  • packet_data[0] = SOH;
  • packet_data[1] = 0;
  • packet_data [2] = 0xFF;
  • for (i = PACKET_HEADER; i < (PACKET_SIZE + PACKET_HEADER); i++)
  • {
  • packet_data = 0x00;
  • }
  • do
  • {
  • /* Send Packet */
  • Ymodem_SendPacket(packet_data, PACKET_SIZE + PACKET_HEADER);
  • /* Send CRC or Check Sum based on CRC16_F */
  • tempCRC = Cal_CRC16(&packet_data[3], PACKET_SIZE);
  • Send_Byte(tempCRC >> 8);
  • Send_Byte(tempCRC & 0xFF);
  • /* Wait for Ack and 'C' */
  • if (Receive_Byte(&receivedC[0], 0xffffff) == 0)
  • {
  • if (receivedC[0] == ACK)
  • {
  • /* Packet transfered correctly */
  • ackReceived = 1;
  • }
  • }
  • else
  • {
  • errors++;
  • }
  • }while (!ackReceived && (errors < 0x0A));
  • /* Resend packet if NAK for a count of 10 else end of commuincation */
  • if (errors >= 0x0A)
  • {
  • return errors;
  • }
  • do
  • {
  • Send_Byte(EOT);
  • /* Send (EOT); */
  • /* Wait for Ack */ //0xffffff
  • if ((Receive_Byte(&receivedC[0], 0xfff) == 0) && receivedC[0] == ACK)
  • {
  • ackReceived = 1;
  • }
  • else
  • {
  • errors++;
  • }
  • }while (!ackReceived && (errors < 0x0A));
  • if (errors >= 0x0A)
  • {
  • return errors;
  • }
  • return 0; /* file trasmitted successfully */
  • }

(3)ymodem接收


  • int32_t Ymodem_Receive (uint8_t *buf)
  • {
  • uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH], *file_ptr, *buf_ptr;
  • int32_t i, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0;
  • /* Initialize FlashDestination variable */
  • FlashDestination = ApplicationAddress;
  • for (session_done = 0, errors = 0, session_begin = 0; ;)
  • {
  • for (packets_received = 0, file_done = 0, buf_ptr = buf; ;)
  • {
  • switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT))
  • {
  • case 0:
  • errors = 0;
  • switch (packet_length)
  • {
  • /* Abort by sender */
  • case - 1:
  • Send_Byte(ACK);
  • return 0;
  • /* End of transmission */
  • case 0:
  • Send_Byte(ACK);
  • file_done = 1;
  • break;
  • /* Normal packet */
  • default:
  • if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff))
  • {
  • Send_Byte(NAK);
  • }
  • else
  • {
  • if (packets_received == 0) //第一个包
  • {
  • /* Filename packet */
  • if (packet_data[PACKET_HEADER] != 0)
  • {
  • /* Filename packet has valid data */
  • for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);)
  • {
  • file_name[i++] = *file_ptr++;
  • }
  • file_name[i++] = '\0';
  • for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);)
  • {
  • file_size[i++] = *file_ptr++;
  • }
  • file_size[i++] = '\0';
  • Str2Int(file_size, &size);
  • /* Test the size of the image to be sent */
  • /* Image size is greater than Flash size */
  • if (size > (FLASH_SIZE - 1)) //文件大小,大于flash容量
  • {
  • /* End session */
  • Send_Byte(CA);
  • Send_Byte(CA);
  • return -1;
  • }
  • FlashErase(FlashDestination,FlashDestination+size);
  • Send_Byte(ACK);
  • Send_Byte(CRC16);
  • }
  • /* Filename packet is empty, end session */
  • else
  • {
  • Send_Byte(ACK);
  • file_done = 1;
  • session_done = 1;
  • break;
  • }
  • }
  • /* Data packet */
  • else
  • {
  • memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
  • RamSource = (uint32_t)buf;
  • {
  • FlashWrite(packet_length,buf_ptr,FlashDestination);
  • FlashDestination+=packet_length;
  • }
  • Send_Byte(ACK);
  • }
  • packets_received ++;
  • session_begin = 1;
  • }
  • }
  • break;
  • case 1:
  • Send_Byte(CA);
  • Send_Byte(CA);
  • return -3;
  • default:
  • if (session_begin > 0)
  • {
  • errors ++;
  • }
  • if (errors > MAX_ERRORS)
  • {
  • Send_Byte(CA);
  • Send_Byte(CA);
  • return 0;
  • }
  • Send_Byte(CRC16);
  • break;
  • }
  • if (file_done != 0)
  • {
  • break;
  • }
  • }
  • if (session_done != 0)
  • {
  • break;
  • }
  • }
  • return (int32_t)size;
  • }

6、现象

(1)上电复位,选择操作

(2)升级程序

 

(3)读取mcu中的app部分flash

 

注:这里从mcu读取了app所有空间的flash。

 

此帖出自GD32 MCU论坛

最新回复

为你的奉献精神点个赞!   详情 回复 发表于 2023-12-22 12:43
点赞(3) 关注(1)
个人签名stm32/LoRa物联网:304350312
 

回复
举报

565

帖子

0

TA的资源

一粒金砂(高级)

沙发
 

串口ymodem协议升级,本人在多个mcu上使用过,上传完整工程代码: GD32L233_ymodem_boot.rar (367.5 KB, 下载次数: 106)

此帖出自GD32 MCU论坛

点评

为你的奉献精神点个赞!  详情 回复 发表于 2023-12-22 12:43
 
个人签名stm32/LoRa物联网:304350312
 
 

回复

7793

帖子

2

TA的资源

五彩晶圆(高级)

板凳
 

谢谢分享,YMODEN,收藏了!

此帖出自GD32 MCU论坛

点评

相互交流  详情 回复 发表于 2022-1-25 08:58
 
个人签名

默认摸鱼,再摸鱼。2022、9、28

 
 

回复

565

帖子

0

TA的资源

一粒金砂(高级)

4
 
freebsder 发表于 2022-1-24 21:09 谢谢分享,YMODEN,收藏了!

相互交流

此帖出自GD32 MCU论坛
 
个人签名stm32/LoRa物联网:304350312
 
 

回复

1397

帖子

3

TA的资源

版主

5
 

Ymode协议可以使用485或者232吗?

此帖出自GD32 MCU论坛

点评

Ymodem是纯软件协议,与硬件没关系  详情 回复 发表于 2022-1-25 17:03
 
个人签名

没有什么不可以,我就是我,不一样的烟火! 

 
 

回复

565

帖子

0

TA的资源

一粒金砂(高级)

6
 
annysky2012 发表于 2022-1-25 17:02 Ymode协议可以使用485或者232吗?

Ymodem是纯软件协议,与硬件没关系

此帖出自GD32 MCU论坛
 
个人签名stm32/LoRa物联网:304350312
 
 

回复

556

帖子

3

TA的资源

纯净的硅(初级)

7
 

厉害了

此帖出自GD32 MCU论坛
 
 
 

回复

565

帖子

0

TA的资源

一粒金砂(高级)

8
个人签名stm32/LoRa物联网:304350312
 
 

回复

312

帖子

0

TA的资源

纯净的硅(初级)

9
 

收藏了,感谢分享

此帖出自GD32 MCU论坛
 
 
 

回复

1249

帖子

67

TA的资源

纯净的硅(中级)

10
 

学习了,谢谢分享

此帖出自GD32 MCU论坛
 
 
 

回复

110

帖子

0

TA的资源

一粒金砂(中级)

11
 
freeelectron 发表于 2022-1-24 16:28 串口ymodem协议升级,本人在多个mcu上使用过,上传完整工程代码:

为你的奉献精神点个赞!

此帖出自GD32 MCU论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
推荐帖子
上海贝尔 PCB 设 计 规 范.pdf

上海贝尔 PCB 设 计 规 范.pdf

单片机系统外围电路中的电子器件选型简单指南

各种类型电阻选用经验 1.固定电阻器的选用 固定电阻器有多种类型,选择哪一种材料和结构的电阻器, 应根据应用电路的具体要求 ...

分享今天的收获,8962接18B20

代码如下,经调试运行稳定(显示稳定和空调的显示稳定一致:loveliness: ),特别提醒必须加上拉电阻,我就是在这个问题上耽搁了2 ...

【已发放】2021年9月份版主工作奖励

获得2021年9月份版主工作奖励的名单如下: 用户名 发帖 回帖 加精 ...

变压器的材料决定变压器的工作频率吗

工频50HZ的变压器在高频时效率很低,这不知道是什么原因有说是因为材料涡流损耗造成的,但是开关电源的设计书中通常讲到变压器设 ...

【花雕动手做】有趣好玩的音乐可视化项目(11)---WS2812幻彩灯带

偶然心血来潮,想要做一个声音可视化的系列专题。这个专题的难度有点高,涉及面也比较广泛,相关的FFT和FHT等算法也相当复杂,不 ...

【BIGTREETECH CB1】搭建视频转码服务器

随着互联网技术的发展和通讯带宽的提高,人们对视频的清晰度要求越来越高,前几年1080P分辨率的电影是主流,最近几年4K分辨 ...

颁奖:ST有奖直播智能开关在工业自动化领域中的应用

颁奖:ST有奖直播智能开关在工业自动化领域中的应用 名单详见下方列表。请获奖者务必在2023年6月15日23:59前,按照下方领 ...

2025年1月版主工作奖励

获得25年1月版主工作奖励的有: 用户名 发帖 回帖 加精 评分次数 ...

测评汇总:《Hello算法》,动画图解、一键运行的数据结构与算法教程,GitHub Star 63.9k

活动详情:【《Hello算法》,动画图解、一键运行的数据结构与算法教程,GitHub Star 63.9k】更新至 2025-02-21测评报告汇总:@ar ...

关闭
站长推荐上一条 1/10 下一条
有奖直播:当AI遇见仿真,会有什么样的电子行业革新之路?
首场直播:Simcenter AI 赋能电子行业研发创新
直播时间:04月15日14:00-14:50

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网 10

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表