[uCOS/RTOS] 零代码玩转OTA升级

[复制链接]
1064|1
 楼主| akqbdlk 发表于 2020-6-22 09:43 | 显示全部楼层 |阅读模式
本帖最后由 akqbdlk 于 2020-6-22 09:50 编辑

前言: 前边讲过stm32通用bootloader的实现方法,没有看过的,可以参考这一篇**:STM32通用Bootloader——FOTA:https://blog.csdn.net/sinat_31039061/article/details/106344081,这一篇将在上篇bootloader的基础上,介绍app如何通过多种固件下载器实现OTA升级。先看下演示视频,此视频演示了四种升级方式,分别是:
  • 阿里云物联网平台OTA
  • HTTP OTA
  • Ymodem OTA
  • 不用app,使用Bootloader中的Ymodem OTA

演示视频:https://www.bilibili.com/video/bv1zK411p7uH

此项目硬件使用的是STM32F429开发板,代码全部使用RT-Thread Studio搭积木的方式实现,仅仅改动了几行代码,开发效率非常高。
此项目的地址:https://gitee.com/Aladdin-Wang/RT-FOTA-STM32L431.git
使用到的软件包和组件:

1.准备工作1.1 新建工程

由于此项目使用的esp8266需要一个串口,我使用的是uart2,所以需要还需要配置uart2


增加uart接收缓冲区大小:

1.2 打开fal和at device软件包
打开fal软件包

配置sfud组件

配置SPI

配置fal_cfg.h
  1. #ifndef _FAL_CFG_H_
  2. #define _FAL_CFG_H_

  3. #include <rtconfig.h>
  4. #include <board.h>

  5. #define FLASH_SIZE_GRANULARITY_16K   (4 * 16 * 1024)
  6. #define FLASH_SIZE_GRANULARITY_64K   (64 * 1024)
  7. #define FLASH_SIZE_GRANULARITY_128K  (7 * 128 * 1024)

  8. #define STM32_FLASH_START_ADRESS_16K  STM32_FLASH_START_ADRESS
  9. #define STM32_FLASH_START_ADRESS_64K  (STM32_FLASH_START_ADRESS_16K + FLASH_SIZE_GRANULARITY_16K)
  10. #define STM32_FLASH_START_ADRESS_128K (STM32_FLASH_START_ADRESS_64K + FLASH_SIZE_GRANULARITY_64K)
  11. /* ===================== Flash device Configuration ========================= */
  12. extern const struct fal_flash_dev stm32_onchip_flash_16k;
  13. extern const struct fal_flash_dev stm32_onchip_flash_64k;
  14. extern const struct fal_flash_dev stm32_onchip_flash_128k;
  15. extern struct fal_flash_dev nor_flash0;

  16. /* flash device table */
  17. #define FAL_FLASH_DEV_TABLE                                          \
  18. {                                                                    \
  19.     &stm32_onchip_flash_16k,                                         \
  20.     &stm32_onchip_flash_64k,                                         \
  21.     &stm32_onchip_flash_128k,                                        \
  22.     &nor_flash0,                                                     \
  23. }
  24. /* ====================== Partition Configuration ========================== */
  25. #ifdef FAL_PART_HAS_TABLE_CFG
  26. /* partition table */
  27. #define FAL_PART_TABLE                                                               \
  28. {                                                                                    \
  29.     {FAL_PART_MAGIC_WROD, "bootloader", "onchip_flash_16k",  0 , FLASH_SIZE_GRANULARITY_16K , 0}, \
  30.     {FAL_PART_MAGIC_WROD, "param",      "onchip_flash_64k",  0 , FLASH_SIZE_GRANULARITY_64K , 0}, \
  31.     {FAL_PART_MAGIC_WROD, "app",        "onchip_flash_128k", 0 , FLASH_SIZE_GRANULARITY_128K, 0}, \
  32.     {FAL_PART_MAGIC_WROD, "ef",         "W25Q128",           0 , 1024 * 1024, 0}, \
  33.     {FAL_PART_MAGIC_WROD, "download",   "W25Q128",          1024 * 1024 , 512 * 1024, 0}, \
  34.     {FAL_PART_MAGIC_WROD, "factory",    "W25Q128",          (1024 + 512) * 1024 , 512 * 1024, 0}, \
  35. }
  36. #endif /* FAL_PART_HAS_TABLE_CFG */

  37. #endif /* _FAL_CFG_H_ */

初始化spi flash和fal软件包
  1. #include <rtthread.h>
  2. #include "spi_flash.h"
  3. #include "spi_flash_sfud.h"
  4. #include "drv_spi.h"

  5. #if defined(RT_USING_SFUD)
  6. static int rt_hw_spi_flash_init(void)
  7. {
  8.     __HAL_RCC_GPIOF_CLK_ENABLE();
  9.     rt_hw_spi_device_attach("spi5", "spi50", GPIOF, GPIO_PIN_6);

  10.     if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi50"))
  11.     {
  12.         return -RT_ERROR;
  13.     }

  14.     return RT_EOK;
  15. }
  16. INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
  17. #endif

  1. int fs_init(void)
  2. {
  3.     /* partition initialized */
  4.     fal_init();
  5.     return 0;
  6. }
  7. INIT_ENV_EXPORT(fs_init);



配置at device软件包

1.3 配置中断重定向/**

  1. * Function    ota_app_vtor_reconfig
  2. * Description Set Vector Table base location to the start addr of app(RT_APP_PART_ADDR).
  3. */
  4. static int ota_app_vtor_reconfig(void)
  5. {
  6.     #define NVIC_VTOR_MASK   0x3FFFFF80
  7.     /* Set the Vector Table base location by user application firmware definition */
  8.     SCB->VTOR = 0x8020000 & NVIC_VTOR_MASK;

  9.     return 0;
  10. }
  11. INIT_BOARD_EXPORT(ota_app_vtor_reconfig);

烧录bootloader:
bootloader的制作方法请参考官方的教程https://www.rt-thread.org/document/site/application-note/system/rtboot/an0028-rtboot/或者https://blog.csdn.net/sinat_31039061/article/details/106344081

2.阿里云物联网平台OTA
注册 LinkPlatform 平台
创建产品
产品详情:
添加设备
添加自定义Topic
配置ali iotkit软件包
将刚才新建的阿里云设备信息填写到配置信息里:
将软件包的示例mqtt-example.c和ota_mqtt-example.c拷贝到applications目录备用
配置mbedtls软件包
更改ota_mqtt-example.c中的部分代码:



  1. static int _ota_mqtt_client(void)
  2. {
  3. #define OTA_BUF_LEN        (16385)
  4. #define DEFAULT_DOWNLOAD_PART "download"
  5.     int rc = 0, ota_over = 0;
  6.     void *pclient = NULL, *h_ota = NULL;
  7.     iotx_conn_info_pt pconn_info;
  8.     iotx_mqtt_param_t mqtt_params;

  9.     // FILE *fp;
  10.     static char buf_ota[OTA_BUF_LEN];
  11.     const struct fal_partition * dl_part = RT_NULL;

  12.     // if (NULL == (fp = fopen("ota.bin", "wb+"))) {
  13.     //     EXAMPLE_TRACE("open file failed");
  14.     //     goto do_exit;
  15.     // }

  16.     /**< get device info*/
  17.     HAL_GetProductKey(g_product_key);
  18.     HAL_GetDeviceName(g_device_name);
  19.     HAL_GetDeviceSecret(g_device_secret);
  20.     /**< end*/

  21.     /* Device AUTH */
  22.     if (0 != IOT_SetupConnInfo(g_product_key, g_device_name, g_device_secret, (void **)&pconn_info)) {
  23.         EXAMPLE_TRACE("AUTH request failed!");
  24.         rc = -1;
  25.         goto do_exit;
  26.     }

  27.     /* Initialize MQTT parameter */
  28.     memset(&mqtt_params, 0x0, sizeof(mqtt_params));

  29.     mqtt_params.port = pconn_info->port;
  30.     mqtt_params.host = pconn_info->host_name;
  31.     mqtt_params.client_id = pconn_info->client_id;
  32.     mqtt_params.username = pconn_info->username;
  33.     mqtt_params.password = pconn_info->password;
  34.     mqtt_params.pub_key = pconn_info->pub_key;

  35.     mqtt_params.request_timeout_ms = 2000;
  36.     mqtt_params.clean_session = 0;
  37.     mqtt_params.keepalive_interval_ms = 60000;
  38.     mqtt_params.read_buf_size = OTA_MQTT_MSGLEN;
  39.     mqtt_params.write_buf_size = OTA_MQTT_MSGLEN;

  40.     mqtt_params.handle_event.h_fp = event_handle;
  41.     mqtt_params.handle_event.pcontext = NULL;

  42.     /* Construct a MQTT client with specify parameter */
  43.     pclient = IOT_MQTT_Construct(&mqtt_params);
  44.     if (NULL == pclient) {
  45.         EXAMPLE_TRACE("MQTT construct failed");
  46.         rc = -1;
  47.         goto do_exit;
  48.     }
  49.     h_ota = IOT_OTA_Init(g_product_key, g_device_name, pclient);
  50.     if (NULL == h_ota) {
  51.         rc = -1;
  52.         EXAMPLE_TRACE("initialize OTA failed");
  53.         goto do_exit;
  54.     }


  55.         do {
  56.             uint32_t firmware_valid;

  57.             EXAMPLE_TRACE("wait ota upgrade command....");

  58.             /* handle the MQTT packet received from TCP or SSL connection */
  59.             IOT_MQTT_Yield(pclient, 200);

  60.             if (IOT_OTA_IsFetching(h_ota)) {
  61.                 uint32_t last_percent = 0, percent = 0;
  62.                 char md5sum[33];
  63.                 char version[128] = {0};
  64.                 uint32_t len, size_downloaded, size_file;
  65.                 IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, &size_file, 4);
  66.                 /* Get download partition information and erase download partition data */
  67.                 if ((dl_part = fal_partition_find(DEFAULT_DOWNLOAD_PART)) == RT_NULL)
  68.                 {
  69.                     LOG_E("Firmware download failed! Partition (%s) find error!", "download");
  70.                     rc = -1;
  71.                     goto do_exit;
  72.                 }

  73.                 LOG_I("Start erase flash (%s) partition!", dl_part->name);

  74.                 if (fal_partition_erase(dl_part, 0, size_file) < 0)
  75.                 {
  76.                     LOG_E("Firmware download failed! Partition (%s) erase error!", dl_part->name);
  77.                     rc = -1;
  78.                     goto do_exit;
  79.                 }
  80.                 LOG_I("Erase flash (%s) partition success!", dl_part->name);

  81.                 rt_uint32_t content_pos = 0, content_write_sz;

  82.                 do {

  83.                     len = IOT_OTA_FetchYield(h_ota, buf_ota, OTA_BUF_LEN, 1);
  84.                     if (len > 0) {
  85.                         content_write_sz = fal_partition_write(dl_part, content_pos, (uint8_t *)buf_ota, len);
  86.                         if (content_write_sz !=  len)
  87.                         {
  88.                             LOG_I("Write OTA data to file failed");

  89.                             IOT_OTA_ReportProgress(h_ota, IOT_OTAP_BURN_FAILED, RT_NULL);

  90.                             goto do_exit;
  91.                         }
  92.                         else
  93.                         {
  94.                             content_pos = content_pos + len;
  95.                             LOG_I("receive %d bytes, total recieve: %d bytes", content_pos, size_file);
  96.                         }
  97.                     } else {
  98.                         IOT_OTA_ReportProgress(h_ota, IOT_OTAP_FETCH_FAILED, NULL);
  99.                         EXAMPLE_TRACE("ota fetch fail");
  100.                     }

  101.                     /* get OTA information */
  102.                     IOT_OTA_Ioctl(h_ota, IOT_OTAG_FETCHED_SIZE, &size_downloaded, 4);
  103.                     IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, &size_file, 4);

  104.                     last_percent = percent;
  105.                     percent = (size_downloaded * 100) / size_file;
  106.                     if (percent - last_percent > 0) {
  107.                         IOT_OTA_ReportProgress(h_ota, percent, NULL);
  108.                     }
  109.                     IOT_MQTT_Yield(pclient, 100);
  110.                 } while (!IOT_OTA_IsFetchFinish(h_ota));

  111.                 IOT_OTA_Ioctl(h_ota, IOT_OTAG_MD5SUM, md5sum, 33);
  112.                 IOT_OTA_Ioctl(h_ota, IOT_OTAG_VERSION, version, 128);
  113.                 IOT_OTA_Ioctl(h_ota, IOT_OTAG_CHECK_FIRMWARE, &firmware_valid, 4);
  114.                 if (0 == firmware_valid) {
  115.                     EXAMPLE_TRACE("The firmware is invalid");
  116.                 } else {
  117.                     EXAMPLE_TRACE("The firmware is valid");
  118.                     IOT_OTA_ReportVersion(h_ota, version);

  119.                     LOG_I("Download firmware to flash success.");
  120.                     LOG_I("System now will restart...");

  121.                     HAL_SleepMs(1000);

  122.                     /* Reset the device, Start new firmware */
  123.                     extern void rt_hw_cpu_reset(void);
  124.                     rt_hw_cpu_reset();
  125.                 }

  126.                 ota_over = 1;
  127.             }
  128.             HAL_SleepMs(2000);
  129.         } while (!ota_over);

  130.     HAL_SleepMs(1000);

  131. do_exit:

  132.     if (NULL != h_ota) {
  133.         IOT_OTA_Deinit(h_ota);
  134.     }

  135.     if (NULL != pclient) {
  136.         IOT_MQTT_Destroy(&pclient);
  137.     }

  138.     return rc;
  139. }

编译工程,将bin文件上传到阿里云:
阿里云不支持rbl格式的文件,直接将rt_ota_packaging_tool生成的rbl文件后缀改为bin,上传即可。
最后使用ali_ota_sample命令升级:

3.HTTP OTA和Ymodem OTA
配置ota_downloader软件包
如果暂时没有自己的服务器,可以使用MyWebServer进行测试:
配置完MyWebServer,可以打开浏览器输入IP地址查看:
使用http_ota命令进行http_ota升级:
使用ymodem_ota命令进行ymodem_ota升级:
4.不适用APP进行升级
rt-fota集成了ymodem_ota,上电短按恢复出厂设置按钮即可进入rt-fota命令行模式,通过ymodem_ota命令即可进行升级:
联系作者:欢迎关注本人公众号,加**流:




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| akqbdlk 发表于 2020-6-22 09:50 | 显示全部楼层
原文地址:https://blog.csdn.net/sinat_31039061/article/details/106790838
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

16

帖子

0

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