YModem协议解析-基于STM32的IAP实现


  这是以前就想写的一个小专题关于IAP,以及IAP在STM32编程的应用,专题分三小节,主要介绍常见的单片机烧录方式,IAP的实际应用,以及Ymodem协议在IAP编程中应用,在笔记吃灰很久了,终于拿出来晒晒太阳了@-@。
第一章:浅析ICP与ISP、及IAP三种单片机烧录方式
第二章:STM32应用IAP进行程序更新详解及实例
第三章:Ymodem协议解析-基于STM32的IAP实现


  简单认识一下常用的三种协议:XModem、YModem和ZModem协议。

  • XModem协议:是一种异步文件传输协议,这种协议以128字节块的形式传输数据,并且每个块都使用一个校验和过程来进行错误检测。
  • YModem协议:是由XModem协议演变而来的,每包数据可以达到1024字节,是一个非常高效的文件传输协议。
  • ZModem协议:Zmodem协议是针对modem的一种错误校验协议。利用Zmodem协议,可以在modem上发送512字节的数据块。如果某个数据块发生错误,接受端会发送“否认”应答,因此,数据块就会被重传。它是Xmodem 文件传输协议的一种增强形式,不仅能传输更大的数据,而且错误率更小。包含一种名为检查点重启的特性,如果通信链接在数据传输过程中中断,能从断点处而不是从开始处恢复传输。
      本文主要就STM32 IAP中使用来传输烧录文件的YModem协议进行介绍。
      首先了解一下Ymodem协议的数据包的帧的格式
      从ST提供的基于STM32的IAP实例demo中的ymodem.h文件中,我们或多或少可以稍稍窥探ymodem协议的一些内容:
#define SOH ((uint8_t)0x01)     /* start of 128-byte data packet */
#define STX ((uint8_t)0x02)     /* start of 1024-byte data packet */
#define EOT ((uint8_t)0x04)     /* end of transmission */
#define ACK ((uint8_t)0x06)     /* acknowledge */
#define NAK ((uint8_t)0x15)     /* negative acknowledge */
#define CA ((uint32_t)0x18)     /* two of these in succession aborts transfer */
#define CRC16 ((uint8_t)0x43)     /* 'C' == 0x43, request 16-bit CRC */

1、起始帧:数据的起始帧并不传输文件的数据,而是传输与文件基本信息相关的一些数据,如:文件名和文件大小,帧的格式如下:

数据包头 发送序号 发送序号补码 数据 CRC校验码高字节 CRC校验码低字节
S0H 00 FF filename+filesize+…(00 补齐128 Byte) CRCH CRCL

  起始帧由于不直接传输数据,所以通常使用以“S0H”开头的数据包,传输128 Byte的数据基本满足关于文件名和文件大小的传输。

2、数据帧:数据帧中数据包的大小为1K,基本格式相同

数据包头 发送序号 发送序号补码 数据 CRC校验码高字节 CRC校验码低字节
STX 01 FE (1024 Byte 数据,不足0x1A补齐) CRCH CRCL

  在数据帧传输过程中可能出现以下情况:

  • 1)文件剩余的大小在128 ~ 1024 Byte之间:使用STX格式数据帧进行传输,但是数据区间剩余的空间用0X1A进行填充。
  • 2)文件剩余的大小在小于等于128 Byte:使用SOH格式数据帧进行传输,同样数据区间的剩余空间使用0X1A进行填充。

3、结束帧

数据包头 发送序号 发送序号补码 数据 CRC校验码高字节 CRC校验码低字节
SOH 00 FF NULL[128 Byte] CRCH CRCL

  结束帧的数据包以“SOH”开头,且发送序号为00, 数据由0x00填充128 Byte。
  下图摘录来自Ymodem协议官方WiKi【http://wiki.synchro.net/ref:ymodem】的介绍,可以很清晰、直观地了解到使用该协议传输的交互流程:
YModem协议解析-基于STM32的IAP实现_第1张图片
下面来看一下代码实现:

/* Public functions ---------------------------------------------------------*/
/**
  * @brief  Receive a file using the ymodem protocol with CRC16.
  * @param  p_size The size of the file.
  * @retval COM_StatusTypeDef result of reception/programming
  */
COM_StatusTypeDef Ymodem_Receive ( uint32_t *p_size )
{
     
  uint32_t i, packet_length, session_done = 0, file_done, errors = 0, session_begin = 0;
  uint32_t flashdestination, ramsource, filesize;
  uint8_t *file_ptr;
  uint8_t file_size[FILE_SIZE_LENGTH], tmp, packets_received;
  COM_StatusTypeDef result = COM_OK;

  /* Initialize flashdestination variable */
  flashdestination = APPLICATION_ADDRESS;

  while ((session_done == 0) && (result == COM_OK))
  {
     
    packets_received = 0;
    file_done = 0;
    while ((file_done == 0) && (result == COM_OK))
    {
     
      switch (ReceivePacket(aPacketData, &packet_length, DOWNLOAD_TIMEOUT))
      {
     
        case HAL_OK:
          errors = 0;
          switch (packet_length)
          {
     
            case 2:
              /* Abort by sender */
              Serial_PutByte(ACK);
              result = COM_ABORT;
              break;
            case 0:
              /* End of transmission */
              Serial_PutByte(ACK);
              file_done = 1;
              break;
            default:
              /* Normal packet */
              if (aPacketData[PACKET_NUMBER_INDEX] != packets_received)
              {
     
                Serial_PutByte(NAK);
              }
              else
              {
     
                if (packets_received == 0)
                {
     
                  /* File name packet */
                  if (aPacketData[PACKET_DATA_INDEX] != 0)
                  {
     
                    /* File name extraction */
                    i = 0;
                    file_ptr = aPacketData + PACKET_DATA_INDEX;
                    while ( (*file_ptr != 0) && (i < FILE_NAME_LENGTH))
                    {
     
                      aFileName[i++] = *file_ptr++;
                    }

                    /* File size extraction */
                    aFileName[i++] = '\0';
                    i = 0;
                    file_ptr ++;
                    while ( (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH))
                    {
     
                      file_size[i++] = *file_ptr++;
                    }
                    file_size[i++] = '\0';
                    Str2Int(file_size, &filesize);

                    /* Test the size of the image to be sent */
                    /* Image size is greater than Flash size */
					*p_size = filesize;
                    if (*p_size > (USER_FLASH_SIZE + 1))
                    {
     
                      /* End session */
                      tmp = CA;
                      HAL_UART_Transmit(&huart2, &tmp, 1, NAK_TIMEOUT);
                      HAL_UART_Transmit(&huart2, &tmp, 1, NAK_TIMEOUT);
                      result = COM_LIMIT;
                    }
                    /* erase user application area */
                    FLASH_If_Erase(APPLICATION_ADDRESS);
                    

                    Serial_PutByte(ACK);
                    Serial_PutByte(CRC16);
                  }
                  /* File header packet is empty, end session */
                  else
                  {
     
                    Serial_PutByte(ACK);
                    file_done = 1;
                    session_done = 1;
                    break;
                  }
                }
                else /* Data packet */
                {
     
                  ramsource = (uint32_t) & aPacketData[PACKET_DATA_INDEX];
                  /* Write received data in Flash */
                  if (FLASH_If_Write(flashdestination, (uint32_t*) ramsource, packet_length/4) == FLASHIF_OK)                   
                  {
     
                    flashdestination += packet_length;
                    Serial_PutByte(ACK);
                  }
                  else /* An error occurred while writing to Flash memory */
                  {
     
                    /* End session */
                    Serial_PutByte(CA);
                    Serial_PutByte(CA);
                    result = COM_DATA;
                  }
                }
                packets_received ++;
                session_begin = 1;
              }
              break;
          }
          break;
        case HAL_BUSY: /* Abort actually */
          Serial_PutByte(CA);
          Serial_PutByte(CA);
          result = COM_ABORT;
          break;
        default:
          if (session_begin > 0)
          {
     
            errors ++;
          }
          if (errors > MAX_ERRORS)
          {
     
            /* Abort communication */
            Serial_PutByte(CA);
            Serial_PutByte(CA);
          }
          else
          {
     
            Serial_PutByte(CRC16); /* Ask for a packet */
          }
          break;
      }
    }
  }
  return result;
}

你可能感兴趣的:(#,嵌入式开发:STM32藏经阁,Ymodem,STM32)