6296|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, 下载次数: 100)

此帖出自GD32 MCU论坛

点评

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

回复

7452

帖子

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
 
 

回复

1412

帖子

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
 
 

回复

539

帖子

3

TA的资源

纯净的硅(初级)

7
 

厉害了

此帖出自GD32 MCU论坛
 
 
 

回复

565

帖子

0

TA的资源

一粒金砂(高级)

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

回复

295

帖子

0

TA的资源

纯净的硅(初级)

9
 

收藏了,感谢分享

此帖出自GD32 MCU论坛
 
 
 

回复

1237

帖子

66

TA的资源

纯净的硅(中级)

10
 

学习了,谢谢分享

此帖出自GD32 MCU论坛
 
 
 

回复

104

帖子

0

TA的资源

一粒金砂(中级)

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

为你的奉献精神点个赞!

此帖出自GD32 MCU论坛
 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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

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

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

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