[活动] 【APM32F107VC MINIBOARD开发板测评】4.IAP程序升级

[复制链接]
2318|0
 楼主| xld0932 发表于 2023-2-27 21:42 | 显示全部楼层 |阅读模式
本帖最后由 xld0932 于 2023-2-27 21:49 编辑

IAP应用程序升级是最常用的技术了,也有很多开源的IAP程序框架,比如OpenBLT、mOTA等等,本文我们来基于对MCU内部FLASH读、写、擦除这3个基础操作,结合XMODEM传输协议来完成一个简易的IAP应用程序升级功能……首先我们需要有2个工程,一个是BOOTLOADER工程,它的作用是XMODEM协议传输、FLASH数据写入、以及程序跳转运行;另一个就是我们的应用程序工程,它是具体的应用……对不同的工程,我们需要有不同的配置……


BOOTLOADER工程:
XMODEM传输协议的实现:
  1. /*!
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]       Xmodem_SendData
  3.   *
  4.   * @param       None
  5.   *
  6.   * @retval      None
  7.   *
  8.   */
  9. void Xmodem_SendData(uint8_t Data)
  10. {
  11.     USART_TxData(USART1, Data);

  12.     while (RESET == USART_ReadStatusFlag(USART1, USART_FLAG_TXBE))
  13.     {
  14.     }
  15. }

  16. /*!
  17.   * [url=home.php?mod=space&uid=247401]@brief[/url]       Xmodem_CalcCheckCRC
  18.   *
  19.   * @param       Buffer & Length
  20.   *
  21.   * @retval      Result
  22.   *
  23.   */
  24. uint16_t Xmodem_CalcCheckCRC(uint8_t *Buffer, uint16_t Length)
  25. {
  26.     uint32_t Result = 0;

  27.     Length += 2;

  28.     while (Length--)
  29.     {
  30.         uint8_t Value = (Length < 2) ? 0 : *Buffer++;

  31.         for (uint8_t j = 0; j < 8; j++)
  32.         {
  33.             Result <<= 1;

  34.             if (Value & 0x00080)
  35.             {
  36.                 Result += 0x0001;
  37.             }

  38.             Value  <<= 1;

  39.             if (Result & 0x10000)
  40.             {
  41.                 Result ^= 0x1021;
  42.             }
  43.         }
  44.     }

  45.     Result &= 0xFFFF;

  46.     return (Result);
  47. }

  48. /*!
  49.   * [url=home.php?mod=space&uid=247401]@brief[/url]       Xmodem_CalcCheckSum
  50.   *
  51.   * @param       Buffer & Length
  52.   *
  53.   * @retval      Result
  54.   *
  55.   */
  56. uint8_t Xmodem_CalcCheckSum(uint8_t *Buffer, uint16_t Length)
  57. {
  58.     uint16_t Result = 0;

  59.     while (Length--)
  60.     {
  61.         Result += *Buffer++;
  62.     }

  63.     Result &= 0xFF;

  64.     return (Result);
  65. }

  66. /*!
  67.   * [url=home.php?mod=space&uid=247401]@brief[/url]       Xmodem_RxHandler
  68.   *
  69.   * @param       None
  70.   *
  71.   * @retval      None
  72.   *
  73.   */
  74. void Xmodem_RxHandler(void)
  75. {
  76.     uint32_t Address = (0x08000000 + 0x10000);
  77.     uint32_t StartTryTimtout = 0;

  78.     QUEUE_INIT();

  79.     Xmodem_State = XMODEM_RX_STATE_SOH;

  80.     while (1)
  81.     {
  82.         if (QUEUE_EMPTY() == 0)
  83.         {
  84.             uint8_t data = QUEUE_READ();

  85.             switch (Xmodem_State)
  86.             {
  87.                 case XMODEM_RX_STATE_SOH:
  88.                     if ((data == XMODEM_SOH) || (data == XMODEM_STX))
  89.                     {
  90.                         Xmodem_Length  = (data == XMODEM_STX) ? 1024 : 128;

  91.                         Xmodem_Index = 0;
  92.                         Xmodem_State = XMODEM_RX_STATE_NUM;
  93.                     }
  94.                     else if (data == XMODEM_EOT)
  95.                     {
  96.                         Xmodem_SendData(XMODEM_ACK);
  97.                         printf("\r\nXmodem Finish");
  98.                         return;
  99.                     }
  100.                     else if (data == XMODEM_CAN)
  101.                     {
  102.                         printf("\r\nXmodem Cancle");
  103.                         return;
  104.                     }
  105.                     else
  106.                     {
  107.                     }

  108.                     break;

  109.                 case XMODEM_RX_STATE_NUM:
  110.                     Xmodem_Number[Xmodem_Index++] = data;

  111.                     if (Xmodem_Index == 2)
  112.                     {
  113.                         Xmodem_Index = 0;
  114.                         Xmodem_State = XMODEM_RX_STATE_DAT;
  115.                     }

  116.                     break;

  117.                 case XMODEM_RX_STATE_DAT:
  118.                     Xmodem_Buffer[Xmodem_Index++] = data;

  119.                     if (Xmodem_Index == Xmodem_Length)
  120.                     {
  121.                         Xmodem_Index = 0;
  122.                         Xmodem_State = XMODEM_RX_STATE_CHK;
  123.                     }

  124.                     break;

  125.                 case XMODEM_RX_STATE_CHK:
  126.                     Xmodem_CheckData[Xmodem_Index++] = data;

  127.                     if ((Xmodem_CheckType == 1) && (Xmodem_Index == 1))
  128.                     {
  129.                         Xmodem_Index = 0;

  130.                         if (Xmodem_Number[0] == ((Xmodem_Number[1] ^ 0xFF) & 0xFF))
  131.                         {
  132.                             if (Xmodem_CheckData[0] == Xmodem_CalcCheckSum(Xmodem_Buffer, Xmodem_Length))
  133.                             {
  134.                                 if ((Address % FLASH_PAGE_SIZE) == 0)
  135.                                 {
  136.                                     FLASH_ErasePage(Address / FLASH_PAGE_SIZE);
  137.                                 }

  138.                                 FLASH_PageProgram(Address, Xmodem_Buffer, Xmodem_Length);
  139.                                 Address += Xmodem_Length;

  140.                                 Xmodem_SendData(XMODEM_ACK);
  141.                             }
  142.                             else
  143.                             {
  144.                                 Xmodem_SendData(XMODEM_NAK);
  145.                             }
  146.                         }
  147.                         else
  148.                         {
  149.                             Xmodem_SendData(XMODEM_NAK);
  150.                         }

  151.                         Xmodem_State = XMODEM_RX_STATE_SOH;
  152.                     }
  153.                     else if ((Xmodem_CheckType == 0) && (Xmodem_Index == 2))
  154.                     {
  155.                         Xmodem_Index = 0;

  156.                         if (Xmodem_Number[0] == ((Xmodem_Number[1] ^ 0xFF) & 0xFF))
  157.                         {
  158.                             uint16_t Result = 0;

  159.                             Result   = Xmodem_CheckData[0];
  160.                             Result <<= 8;
  161.                             Result  |= Xmodem_CheckData[1];

  162.                             if (Result == Xmodem_CalcCheckCRC(Xmodem_Buffer, Xmodem_Length))
  163.                             {
  164.                                 if ((Address % FLASH_PAGE_SIZE) == 0)
  165.                                 {
  166.                                     FLASH_ErasePage(Address / FLASH_PAGE_SIZE);
  167.                                 }

  168.                                 FLASH_PageProgram(Address, Xmodem_Buffer, Xmodem_Length);
  169.                                 Address += Xmodem_Length;

  170.                                 Xmodem_SendData(XMODEM_ACK);
  171.                             }
  172.                             else
  173.                             {
  174.                                 Xmodem_SendData(XMODEM_NAK);
  175.                             }
  176.                         }
  177.                         else
  178.                         {
  179.                             Xmodem_SendData(XMODEM_NAK);
  180.                         }

  181.                         Xmodem_State = XMODEM_RX_STATE_SOH;
  182.                     }
  183.                     else
  184.                     {
  185.                         /* do nothing */
  186.                     }

  187.                     break;

  188.                 default:
  189.                     break;
  190.             }
  191.         }
  192.         else
  193.         {
  194.             if (StartTryTimtout == 0)
  195.             {
  196.                 if (Xmodem_CheckType)
  197.                 {
  198.                     Xmodem_SendData(XMODEM_NAK);
  199.                 }
  200.                 else
  201.                 {
  202.                     Xmodem_SendData('C');
  203.                 }
  204.             }

  205.             StartTryTimtout = (StartTryTimtout + 1) % XMODEM_TRY_TIMEOUT;
  206.         }
  207.     }
  208. }

FLASH读、写、擦除操作:
  1. /*!
  2.   * @brief       Xmodem_FLASH_ErasePage
  3.   *
  4.   * @param       Page
  5.   *
  6.   * @retval      None
  7.   *
  8.   */
  9. void FLASH_ErasePage(uint32_t Page)
  10. {
  11.     FMC_Unlock();

  12.     FMC_ClearStatusFlag((FMC_FLAG_T)(FMC_FLAG_OC | FMC_FLAG_PE | FMC_FLAG_WPE));

  13.     FMC_ErasePage(FLASH_PAGE_SIZE * Page);

  14.     FMC_ClearStatusFlag(FMC_FLAG_OC);

  15.     FMC_Lock();
  16. }

  17. /*!
  18.   * @brief       Xmodem_FLASH_PageProgram
  19.   *
  20.   * @param       Address & Buffer & Length
  21.   *
  22.   * @retval      None
  23.   *
  24.   */
  25. void FLASH_PageProgram(uint32_t Address, uint8_t *Buffer, uint32_t Length)
  26. {
  27.     uint16_t *Data = (uint16_t *)Buffer;

  28.     FMC_Unlock();

  29.     FMC_ClearStatusFlag((FMC_FLAG_T)(FMC_FLAG_OC | FMC_FLAG_PE | FMC_FLAG_WPE));

  30.     for (uint32_t i = 0; i < Length; i += 2)
  31.     {
  32.         FMC_ProgramHalfWord(Address + i, *Data);

  33.         FMC_ClearStatusFlag(FMC_FLAG_OC);

  34.         if (*(volatile uint16_t *)(Address + i) != *Data)
  35.         {
  36.             while (1)
  37.             {
  38.                 GPIO_WriteBitValue(GPIOE, GPIO_PIN_5, BIT_RESET);
  39.                 GPIO_WriteBitValue(GPIOE, GPIO_PIN_6, BIT_RESET);
  40.             }
  41.         }

  42.         Data++;
  43.     }

  44.     FMC_Lock();
  45. }

程序跳转运行:
  1. int main(void)
  2. {
  3.     Xmodem_Init(115200);

  4.     printf("\r\nAPM32F107VC MINIBOARD V1.0 %s %s--->Bootloader\r\n", __DATE__, __TIME__);

  5.     KEY_Init();

  6.     LED_Init();

  7.     while (1)
  8.     {
  9.         if((BIT_RESET == GPIO_ReadInputBit(GPIOA, GPIO_PIN_0)) ||
  10.            (BIT_RESET == GPIO_ReadInputBit(GPIOA, GPIO_PIN_1)) )
  11.         {
  12.             Xmodem_RxHandler();
  13.         }
  14.         else
  15.         {
  16.             if(*(volatile uint32_t *)(ApplicationAddress) != 0xFFFFFFFF)
  17.             {
  18.                 USART_Disable(USART1);

  19.                 JumpAddress = *(volatile uint32_t *)(ApplicationAddress + 4);
  20.                 JumpToApplication = (pFunction)JumpAddress;

  21.                 /* Initialize user application's Stack Pointer */
  22.                 __set_MSP(*(volatile uint32_t *)ApplicationAddress);
  23.                 JumpToApplication();
  24.             }
  25.         }
  26.     }
  27. }

KEIL工程配置:
1.png


APPLICATION工程:
中断向量表重定义:
8.png

KEIL工程配置之程序空间划分:
2.png

KEIL工程配置之生成BIN文件:
3.png


IAP运行测试:
下载BOOTLOADER程序到开发板,通过串口终端软件进行监控:
4.png

按下开发板上的任一按键(除RST按键),MCU进入XMODEM传输模式:
5.png

XMODEM接收数据,并将数据写入到指定的FLASH空间:
6.png

XMODEM传输结束后,跳转到应用程序起始地址,开始运行:
7.png


软件工程源代码:
BOOTLOADER: Bootloader.zip (474.31 KB, 下载次数: 14)
APPLICATION: Application.zip (489.23 KB, 下载次数: 12)


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

本版积分规则

个人签名:King.Xu

77

主题

3023

帖子

38

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