[活动专区] 【AT-START-F425测评】11、IAP程序升级——基于YMODEM协议

[复制链接]
 楼主| freeelectron 发表于 2022-3-17 18:01 | 显示全部楼层 |阅读模式
本帖最后由 freeelectron 于 2022-3-17 18:05 编辑


1、什么是IAP

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


2、IAP要点

(1)程序分两部分,BOOT和APP分别编写;
(2)flash空间划分(flash空间足够大的情况下,可以分成APP1和APP2进行备份升级),本应用中前14k用于boot程序,后面50k用于app程序;

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

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

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

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


3、YMODEM协议

本文基于YMODEM协议实现升级,关于YMODEM协议此次不展开,可自行百度。


4、YMODEM工具 88195623300fc0c792.png

本文使用SecureCRT,其他工具亦可。


5、核心代码

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

  1. void Main_Menu(void)
  2. {
  3.   uint8_t key = 0;

  4.   while (1)
  5.   {
  6.     SerialPutString("\r\n================== Main Menu ===============================\r\n\n");
  7.     SerialPutString("  Download Image To the AT32F425 Internal Flash ----------- 1\r\n\n");
  8.     SerialPutString("  Upload Image From the AT32F425 Internal Flash ----------- 2\r\n\n");
  9.     SerialPutString("  Execute The New Program --------------------------------- 3\r\n\n");
  10.     SerialPutString("=============================================================\r\n\n");
  11.    
  12.     key = GetKey();

  13.     if (key == 0x31)
  14.     {
  15.       /* Download user application in the Flash */
  16.       SerialDownload();
  17.     }
  18.     else if (key == 0x32)
  19.     {
  20.       /* Upload user application from the Flash */
  21.       SerialUpload();
  22.     }
  23.     else if (key == 0x33)
  24.     {
  25.                 if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000) //判断栈顶地址是否在合法范围内
  26.                 {
  27.                   __disable_irq();  /* 禁止全局中断*/

  28.                   JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);

  29.                   /* Jump to user application */
  30.                   Jump_To_Application = (pFunction) JumpAddress;
  31.                   /* Initialize user application's Stack Pointer */
  32.                   __set_MSP(*(__IO uint32_t*) ApplicationAddress);
  33.                   Jump_To_Application();
  34.                 }
  35.                 else
  36.                 {
  37.                         SerialPutString("\r\n  Jump app fail!\r\n");
  38.                 }
  39.     }
  40.         else if(key==0x34)
  41.         {
  42.                 SerialPutString("\r\n  Enter 4,use debug!\r\n");
  43.         }
  44.     else
  45.     {
  46.        SerialPutString("Invalid Number ! ==> The number should be either 1, 2 or 3\r");
  47.     }
  48.   }
  49. }

(2)ymodem发送

  1. uint8_t Ymodem_Transmit (uint8_t *buf, const uint8_t* sendFileName, uint32_t sizeFile)
  2. {
  3.   
  4.   uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD];
  5.   uint8_t FileName[FILE_NAME_LENGTH];
  6.   uint8_t *buf_ptr, tempCheckSum ;
  7.   uint16_t tempCRC, blkNumber;
  8.   uint8_t receivedC[2], CRC16_F = 0, i;
  9.   uint32_t errors, ackReceived, size = 0, pktSize;

  10.   errors = 0;
  11.   ackReceived = 0;
  12.   for (i = 0; i < (FILE_NAME_LENGTH - 1); i++)
  13.   {
  14.     FileName[i] = sendFileName[i];
  15.   }
  16.   CRC16_F = 1;      
  17.    
  18.   /* Prepare first block */
  19.   Ymodem_PrepareIntialPacket(&packet_data[0], FileName, &sizeFile);
  20.   
  21.   do
  22.   {
  23.     /* Send Packet */
  24.     Ymodem_SendPacket(packet_data, PACKET_SIZE + PACKET_HEADER);
  25.     /* Send CRC or Check Sum based on CRC16_F */
  26.     if (CRC16_F)
  27.     {
  28.        tempCRC = Cal_CRC16(&packet_data[3], PACKET_SIZE);
  29.        Send_Byte(tempCRC >> 8);
  30.        Send_Byte(tempCRC & 0xFF);
  31.     }
  32.     else
  33.     {
  34.        tempCheckSum = CalChecksum (&packet_data[3], PACKET_SIZE);
  35.        Send_Byte(tempCheckSum);
  36.     }
  37.   
  38.     /* Wait for Ack and 'C' */
  39.     if (Receive_Byte(&receivedC[0], 10000) == 0)  
  40.     {
  41.       if (receivedC[0] == ACK)
  42.       {
  43.         /* Packet transfered correctly */
  44.         ackReceived = 1;
  45.       }
  46.     }
  47.     else
  48.     {
  49.         errors++;
  50.     }
  51.   }while (!ackReceived && (errors < 0x0A));
  52.   
  53.   if (errors >=  0x0A)
  54.   {
  55.     return errors;
  56.   }
  57.   buf_ptr = buf;
  58.   size = sizeFile;
  59.   blkNumber = 0x01;
  60.   /* Here 1024 bytes package is used to send the packets */
  61.   
  62.   
  63.   /* Resend packet if NAK  for a count of 10 else end of commuincation */
  64.   while (size)
  65.   {
  66.     /* Prepare next packet */
  67.     Ymodem_PreparePacket(buf_ptr, &packet_data[0], blkNumber, size);
  68.     ackReceived = 0;
  69.     receivedC[0]= 0;
  70.     errors = 0;
  71.     do
  72.     {
  73.       /* Send next packet */
  74.       if (size >= PACKET_1K_SIZE)
  75.       {
  76.         pktSize = PACKET_1K_SIZE;
  77.       
  78.       }
  79.       else
  80.       {
  81.         pktSize = PACKET_SIZE;
  82.       }
  83.       Ymodem_SendPacket(packet_data, pktSize + PACKET_HEADER);
  84.       /* Send CRC or Check Sum based on CRC16_F */
  85.       /* Send CRC or Check Sum based on CRC16_F */
  86.       if (CRC16_F)
  87.       {
  88.          tempCRC = Cal_CRC16(&packet_data[3], pktSize);
  89.          Send_Byte(tempCRC >> 8);
  90.          Send_Byte(tempCRC & 0xFF);
  91.       }
  92.       else
  93.       {
  94.         tempCheckSum = CalChecksum (&packet_data[3], pktSize);
  95.         Send_Byte(tempCheckSum);
  96.       }
  97.       
  98.       /* Wait for Ack */
  99.       if ((Receive_Byte(&receivedC[0], 0xffffff) == 0)  && (receivedC[0] == ACK))
  100.       {
  101.         ackReceived = 1;  
  102.         if (size > pktSize)
  103.         {
  104.            buf_ptr += pktSize;  
  105.            size -= pktSize;
  106.            if (blkNumber == (APP_IMAGE_SIZE/1024))
  107.            {
  108.              return 0xFF; /*  error */
  109.            }
  110.            else
  111.            {
  112.               blkNumber++;
  113.            }
  114.         }
  115.         else
  116.         {
  117.           buf_ptr += pktSize;
  118.           size = 0;
  119.         }
  120.       }
  121.       else
  122.       {
  123.         errors++;
  124.       }
  125.     }while(!ackReceived && (errors < 0x0A));
  126.     /* Resend packet if NAK  for a count of 10 else end of commuincation */
  127.    
  128.     if (errors >=  0x0A)
  129.     {
  130.       return errors;
  131.     }
  132.    
  133.   }
  134.   ackReceived = 0;
  135.   receivedC[0] = 0x00;
  136.   errors = 0;
  137.   do
  138.   {
  139.     Send_Byte(EOT);
  140.     /* Send (EOT); */
  141.     /* Wait for Ack */
  142.       if ((Receive_Byte(&receivedC[0], 0xffffff) == 0)  && receivedC[0] == ACK)
  143.       {
  144.         ackReceived = 1;  
  145.       }
  146.       else
  147.       {
  148.         errors++;
  149.       }
  150.   }while (!ackReceived && (errors < 0x0A));
  151.    
  152.   if (errors >=  0x0A)
  153.   {
  154.     return errors;
  155.   }
  156.   
  157.   /* Last packet preparation */
  158.   ackReceived = 0;
  159.   receivedC[0] = 0x00;
  160.   errors = 0;

  161.   packet_data[0] = SOH;
  162.   packet_data[1] = 0;
  163.   packet_data [2] = 0xFF;

  164.   for (i = PACKET_HEADER; i < (PACKET_SIZE + PACKET_HEADER); i++)
  165.   {
  166.      packet_data [i] = 0x00;
  167.   }
  168.   
  169.   do
  170.   {
  171.     /* Send Packet */
  172.     Ymodem_SendPacket(packet_data, PACKET_SIZE + PACKET_HEADER);
  173.     /* Send CRC or Check Sum based on CRC16_F */
  174.     tempCRC = Cal_CRC16(&packet_data[3], PACKET_SIZE);
  175.     Send_Byte(tempCRC >> 8);
  176.     Send_Byte(tempCRC & 0xFF);
  177.   
  178.     /* Wait for Ack and 'C' */
  179.     if (Receive_Byte(&receivedC[0], 0xffffff) == 0)  
  180.     {
  181.       if (receivedC[0] == ACK)
  182.       {
  183.         /* Packet transfered correctly */
  184.         ackReceived = 1;
  185.       }
  186.     }
  187.     else
  188.     {
  189.         errors++;
  190.     }

  191.   }while (!ackReceived && (errors < 0x0A));
  192.   /* Resend packet if NAK  for a count of 10  else end of commuincation */
  193.   if (errors >=  0x0A)
  194.   {
  195.     return errors;
  196.   }  
  197.   
  198.   do
  199.   {
  200.     Send_Byte(EOT);
  201.     /* Send (EOT); */
  202.     /* Wait for Ack */  //0xffffff
  203.       if ((Receive_Byte(&receivedC[0], 0xfff) == 0)  && receivedC[0] == ACK)
  204.       {
  205.         ackReceived = 1;  
  206.       }
  207.       else
  208.       {
  209.         errors++;
  210.       }
  211.   }while (!ackReceived && (errors < 0x0A));
  212.    
  213.   if (errors >=  0x0A)
  214.   {
  215.     return errors;
  216.   }
  217.   return 0; /* file trasmitted successfully */
  218. }

(3)ymodem接收
  1. int32_t Ymodem_Receive (uint8_t *buf)
  2. {
  3.   uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH], *file_ptr, *buf_ptr;
  4.   int32_t i, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0;

  5.   /* Initialize FlashDestination variable */
  6.   FlashDestination = ApplicationAddress;

  7.   for (session_done = 0, errors = 0, session_begin = 0; ;)
  8.   {
  9.     for (packets_received = 0, file_done = 0, buf_ptr = buf; ;)
  10.     {
  11.       switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT))
  12.       {
  13.         case 0:
  14.           errors = 0;
  15.           switch (packet_length)
  16.           {
  17.             /* Abort by sender */
  18.             case - 1:
  19.               Send_Byte(ACK);
  20.               return 0;
  21.             /* End of transmission */
  22.             case 0:
  23.               Send_Byte(ACK);
  24.               file_done = 1;
  25.               break;
  26.             /* Normal packet */
  27.             default:
  28.               if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff))
  29.               {
  30.                 Send_Byte(NAK);
  31.               }
  32.               else
  33.               {
  34.                 if (packets_received == 0) //第一个包
  35.                 {
  36.                   /* Filename packet */
  37.                   if (packet_data[PACKET_HEADER] != 0)
  38.                   {
  39.                     /* Filename packet has valid data */
  40.                     for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);)
  41.                     {
  42.                       file_name[i++] = *file_ptr++;
  43.                     }
  44.                     file_name[i++] = '\0';
  45.                     for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);)
  46.                     {
  47.                       file_size[i++] = *file_ptr++;
  48.                     }
  49.                     file_size[i++] = '\0';
  50.                     Str2Int(file_size, &size);

  51.                     /* Test the size of the image to be sent */
  52.                     /* Image size is greater than Flash size */
  53.                     if (size > (FLASH_SIZE - 1))  //文件大小,大于flash容量
  54.                     {
  55.                       /* End session */
  56.                       Send_Byte(CA);
  57.                       Send_Byte(CA);
  58.                       return -1;
  59.                     }
  60.                                         FlashErase(FlashDestination,FlashDestination+size);
  61.                                 
  62.                     Send_Byte(ACK);
  63.                     Send_Byte(CRC16);
  64.                   }
  65.                   /* Filename packet is empty, end session */
  66.                   else
  67.                   {
  68.                     Send_Byte(ACK);
  69.                     file_done = 1;
  70.                     session_done = 1;
  71.                     break;
  72.                   }
  73.                 }
  74.                 /* Data packet */
  75.                 else
  76.                 {
  77.                   memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
  78.                   RamSource = (uint32_t)buf;
  79.                                        
  80.                                   {
  81.                                          FlashWrite(packet_length,buf_ptr,FlashDestination);
  82.                                          FlashDestination+=packet_length;
  83.                                   }
  84.                                 
  85.                   Send_Byte(ACK);
  86.                 }
  87.                 packets_received ++;
  88.                 session_begin = 1;
  89.               }
  90.           }
  91.           break;
  92.         case 1:
  93.           Send_Byte(CA);
  94.           Send_Byte(CA);
  95.           return -3;
  96.         default:
  97.           if (session_begin > 0)
  98.           {
  99.             errors ++;
  100.           }
  101.           if (errors > MAX_ERRORS)
  102.           {
  103.             Send_Byte(CA);
  104.             Send_Byte(CA);
  105.             return 0;
  106.           }
  107.           Send_Byte(CRC16);
  108.           break;
  109.       }
  110.       if (file_done != 0)
  111.       {
  112.         break;
  113.       }
  114.     }
  115.     if (session_done != 0)
  116.     {
  117.       break;
  118.     }
  119.   }
  120.   return (int32_t)size;
  121. }
6、现象

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

9137623303ce2d767.gif

可以输入1,2,3选择操作,如果都没有输入,那么会在10s后自动跳转到app。


(2)升级程序

400636233051d417df.gif

输入1,选择ymodem发送,选择要升级的文件即可,升级完成之后,输入3,跳转到APP执行。


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

475596233066556418.gif

输入1,然后选择ymodem接收,这里我们提前选择了接收文件存放的位置为桌面,接收完成之后,输入3,直接跳转到APP执行。



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






muyichuan2012 发表于 2022-3-18 07:34 来自手机 | 显示全部楼层
感谢分享
 楼主| freeelectron 发表于 2022-3-18 08:38 | 显示全部楼层
1021256354 发表于 2023-10-23 21:44 | 显示全部楼层
有源码吗?
HeTui 发表于 2024-8-20 16:11 | 显示全部楼层
求源码
muyichuan2012 发表于 2024-8-20 17:38 | 显示全部楼层
这里有一份apnote
目的是提供在AT32微控制器上创建IAP by Ymodem应用程序的方法。
https://www.arterytek.com/file/download/1340
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

65

主题

785

帖子

11

粉丝
快速回复 在线客服 返回列表 返回顶部