前言: 前边讲过stm32通用bootloader的实现方法,没有看过的,可以参考这一篇文章:STM32通用Bootloader——FOTA,这次将在上篇bootloader的基础上,介绍app如何通过多种固件下载器实现OTA升级。
先看下演示视频,此视频演示了四种升级方式,分别是:
阿里云物联网平台OTA
HTTP OTA
Ymodem OTA
不用app,使用Bootloader中的Ymodem OTA
此项目硬件使用的是STM32F429开发板,代码全部使用RT-Thread Studio搭积木的方式实现,仅仅改动了几行代码,开发效率非常高。此项目的地址:https://gitee.com/Aladdin-Wang/RT-FOTA-STM32L431.git
使用到的软件包和组件:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/af29a664c0ee945f21bcba91ee6e368f.png)
1.准备工作
1.1 新建工程
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/57e702d99663c1aae764946b77d5efa1.png)
由于此项目使用的esp8266需要一个串口,我使用的是uart2,所以需要还需要配置uart2:
![](https://i-blog.csdnimg.cn/blog_migrate/36363f8d52994062a174de517c5f8969.png)
增加uart接收缓冲区大小:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e56a1cde0588e2a2652aceb9e031889d.png)
1.2 打开fal和at device软件包
配置fal软件包
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ab678e1dee6017b064a6b22eb4e12daf.png)
配置sfud组件
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b3426bee6dd953fbe414070cd5242d6f.png)
配置SPI
![](https://i-blog.csdnimg.cn/blog_migrate/b58371442bf0b72f9fd686cf950a5742.png)
配置fal_cfg.h
1#ifndef _FAL_CFG_H_
2#define _FAL_CFG_H_
3
4#include <rtconfig.h>
5#include <board.h>
6
7#define FLASH_SIZE_GRANULARITY_16K (4 * 16 * 1024)
8#define FLASH_SIZE_GRANULARITY_64K (64 * 1024)
9#define FLASH_SIZE_GRANULARITY_128K (7 * 128 * 1024)
10
11#define STM32_FLASH_START_ADRESS_16K STM32_FLASH_START_ADRESS
12#define STM32_FLASH_START_ADRESS_64K (STM32_FLASH_START_ADRESS_16K + FLASH_SIZE_GRANULARITY_16K)
13#define STM32_FLASH_START_ADRESS_128K (STM32_FLASH_START_ADRESS_64K + FLASH_SIZE_GRANULARITY_64K)
14/* ===================== Flash device Configuration ========================= */
15extern const struct fal_flash_dev stm32_onchip_flash_16k;
16extern const struct fal_flash_dev stm32_onchip_flash_64k;
17extern const struct fal_flash_dev stm32_onchip_flash_128k;
18extern struct fal_flash_dev nor_flash0;
19
20/* flash device table */
21#define FAL_FLASH_DEV_TABLE \
22{ \
23 &stm32_onchip_flash_16k, \
24 &stm32_onchip_flash_64k, \
25 &stm32_onchip_flash_128k, \
26 &nor_flash0, \
27}
28/* ====================== Partition Configuration ========================== */
29#ifdef FAL_PART_HAS_TABLE_CFG
30/* partition table */
31#define FAL_PART_TABLE \
32{ \
33 {FAL_PART_MAGIC_WROD, "bootloader", "onchip_flash_16k", 0 , FLASH_SIZE_GRANULARITY_16K , 0}, \
34 {FAL_PART_MAGIC_WROD, "param", "onchip_flash_64k", 0 , FLASH_SIZE_GRANULARITY_64K , 0}, \
35 {FAL_PART_MAGIC_WROD, "app", "onchip_flash_128k", 0 , FLASH_SIZE_GRANULARITY_128K, 0}, \
36 {FAL_PART_MAGIC_WROD, "ef", "W25Q128", 0 , 1024 * 1024, 0}, \
37 {FAL_PART_MAGIC_WROD, "download", "W25Q128", 1024 * 1024 , 512 * 1024, 0}, \
38 {FAL_PART_MAGIC_WROD, "factory", "W25Q128", (1024 + 512) * 1024 , 512 * 1024, 0}, \
39}
40#endif /* FAL_PART_HAS_TABLE_CFG */
41
42#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
6#if defined(RT_USING_SFUD)
7static int rt_hw_spi_flash_init(void)
8{
9 __HAL_RCC_GPIOF_CLK_ENABLE();
10 rt_hw_spi_device_attach("spi5", "spi50", GPIOF, GPIO_PIN_6);
11
12 if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi50"))
13 {
14 return -RT_ERROR;
15 }
16
17 return RT_EOK;
18}
19INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
20#endif
1int fs_init(void)
2{
3 /* partition initialized */
4 fal_init();
5 return 0;
6}
7INIT_ENV_EXPORT(fs_init);
配置at device软件包
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/604f0d3fe1405b37b68460becc214e2a.png)
1.3 配置中断重定向
1/**
2 * Function ota_app_vtor_reconfig
3 * Description Set Vector Table base location to the start addr of app(RT_APP_PART_ADDR).
4*/
5static int ota_app_vtor_reconfig(void)
6{
7 #define NVIC_VTOR_MASK 0x3FFFFF80
8 /* Set the Vector Table base location by user application firmware definition */
9 SCB->VTOR = 0x8020000 & NVIC_VTOR_MASK;
10
11 return 0;
12}
13INIT_BOARD_EXPORT(ota_app_vtor_reconfig);
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/c94ee0b740d604a8a58b99dc55363ef8.png)
烧录bootloader:
bootloader的制作方法请参考官方的教程https://www.rt-thread.org/document/site/application-note/system/rtboot/an0028-rtboot/或者STM32通用Bootloader——FOTA
2.阿里云物联网平台OTA
注册 LinkPlatform 平台
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a2d229b510ab61ecc9c9f445bf3998c6.png)
创建产品
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d74414d6d0ae9fc6f60f8fe4cccd5424.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/252d44221a978a7cd2382ee4f21bb2a8.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e3541a5a4bbc0505f7cbe4787a547b8a.png)
产品详情:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/6257ee89ee871b6101e9417aa91b3244.png)
添加设备
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f10bd1a94e06bf961adbecf5d76d76a8.png)
添加自定义Topic
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5f778aec3b0100db80a0d68690ddf301.png)
配置ali iotkit软件包
将刚才新建的阿里云设备信息填写到配置信息里:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/51d7af30bd1b23fec4202bbe48095c6a.png)
将软件包的示例mqtt-example.c和ota_mqtt-example.c拷贝到applications目录备用
![](https://i-blog.csdnimg.cn/blog_migrate/85c42e72a13785c6434b4f0f216cf113.png)
配置mbedtls软件包
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/4123b5706670f770a66cf1de1c898a44.png)
更改ota_mqtt-example.c中的部分代码:
1static 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
10 // FILE *fp;
11 static char buf_ota[OTA_BUF_LEN];
12 const struct fal_partition * dl_part = RT_NULL;
13
14 // if (NULL == (fp = fopen("ota.bin", "wb+"))) {
15 // EXAMPLE_TRACE("open file failed");
16 // goto do_exit;
17 // }
18
19 /**< get device info*/
20 HAL_GetProductKey(g_product_key);
21 HAL_GetDeviceName(g_device_name);
22 HAL_GetDeviceSecret(g_device_secret);
23 /**< end*/
24
25 /* Device AUTH */
26 if (0 != IOT_SetupConnInfo(g_product_key, g_device_name, g_device_secret, (void **)&pconn_info)) {
27 EXAMPLE_TRACE("AUTH request failed!");
28 rc = -1;
29 goto do_exit;
30 }
31
32 /* Initialize MQTT parameter */
33 memset(&mqtt_params, 0x0, sizeof(mqtt_params));
34
35 mqtt_params.port = pconn_info->port;
36 mqtt_params.host = pconn_info->host_name;
37 mqtt_params.client_id = pconn_info->client_id;
38 mqtt_params.username = pconn_info->username;
39 mqtt_params.password = pconn_info->password;
40 mqtt_params.pub_key = pconn_info->pub_key;
41
42 mqtt_params.request_timeout_ms = 2000;
43 mqtt_params.clean_session = 0;
44 mqtt_params.keepalive_interval_ms = 60000;
45 mqtt_params.read_buf_size = OTA_MQTT_MSGLEN;
46 mqtt_params.write_buf_size = OTA_MQTT_MSGLEN;
47
48 mqtt_params.handle_event.h_fp = event_handle;
49 mqtt_params.handle_event.pcontext = NULL;
50
51 /* Construct a MQTT client with specify parameter */
52 pclient = IOT_MQTT_Construct(&mqtt_params);
53 if (NULL == pclient) {
54 EXAMPLE_TRACE("MQTT construct failed");
55 rc = -1;
56 goto do_exit;
57 }
58 h_ota = IOT_OTA_Init(g_product_key, g_device_name, pclient);
59 if (NULL == h_ota) {
60 rc = -1;
61 EXAMPLE_TRACE("initialize OTA failed");
62 goto do_exit;
63 }
64
65
66 do {
67 uint32_t firmware_valid;
68
69 EXAMPLE_TRACE("wait ota upgrade command....");
70
71 /* handle the MQTT packet received from TCP or SSL connection */
72 IOT_MQTT_Yield(pclient, 200);
73
74 if (IOT_OTA_IsFetching(h_ota)) {
75 uint32_t last_percent = 0, percent = 0;
76 char md5sum[33];
77 char version[128] = {0};
78 uint32_t len, size_downloaded, size_file;
79 IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, &size_file, 4);
80 /* Get download partition information and erase download partition data */
81 if ((dl_part = fal_partition_find(DEFAULT_DOWNLOAD_PART)) == RT_NULL)
82 {
83 LOG_E("Firmware download failed! Partition (%s) find error!", "download");
84 rc = -1;
85 goto do_exit;
86 }
87
88 LOG_I("Start erase flash (%s) partition!", dl_part->name);
89
90 if (fal_partition_erase(dl_part, 0, size_file) < 0)
91 {
92 LOG_E("Firmware download failed! Partition (%s) erase error!", dl_part->name);
93 rc = -1;
94 goto do_exit;
95 }
96 LOG_I("Erase flash (%s) partition success!", dl_part->name);
97
98 rt_uint32_t content_pos = 0, content_write_sz;
99
100 do {
101
102 len = IOT_OTA_FetchYield(h_ota, buf_ota, OTA_BUF_LEN, 1);
103 if (len > 0) {
104 content_write_sz = fal_partition_write(dl_part, content_pos, (uint8_t *)buf_ota, len);
105 if (content_write_sz != len)
106 {
107 LOG_I("Write OTA data to file failed");
108
109 IOT_OTA_ReportProgress(h_ota, IOT_OTAP_BURN_FAILED, RT_NULL);
110
111 goto do_exit;
112 }
113 else
114 {
115 content_pos = content_pos + len;
116 LOG_I("receive %d bytes, total recieve: %d bytes", content_pos, size_file);
117 }
118 } else {
119 IOT_OTA_ReportProgress(h_ota, IOT_OTAP_FETCH_FAILED, NULL);
120 EXAMPLE_TRACE("ota fetch fail");
121 }
122
123 /* get OTA information */
124 IOT_OTA_Ioctl(h_ota, IOT_OTAG_FETCHED_SIZE, &size_downloaded, 4);
125 IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, &size_file, 4);
126
127 last_percent = percent;
128 percent = (size_downloaded * 100) / size_file;
129 if (percent - last_percent > 0) {
130 IOT_OTA_ReportProgress(h_ota, percent, NULL);
131 }
132 IOT_MQTT_Yield(pclient, 100);
133 } while (!IOT_OTA_IsFetchFinish(h_ota));
134
135 IOT_OTA_Ioctl(h_ota, IOT_OTAG_MD5SUM, md5sum, 33);
136 IOT_OTA_Ioctl(h_ota, IOT_OTAG_VERSION, version, 128);
137 IOT_OTA_Ioctl(h_ota, IOT_OTAG_CHECK_FIRMWARE, &firmware_valid, 4);
138 if (0 == firmware_valid) {
139 EXAMPLE_TRACE("The firmware is invalid");
140 } else {
141 EXAMPLE_TRACE("The firmware is valid");
142 IOT_OTA_ReportVersion(h_ota, version);
143
144 LOG_I("Download firmware to flash success.");
145 LOG_I("System now will restart...");
146
147 HAL_SleepMs(1000);
148
149 /* Reset the device, Start new firmware */
150 extern void rt_hw_cpu_reset(void);
151 rt_hw_cpu_reset();
152 }
153
154 ota_over = 1;
155 }
156 HAL_SleepMs(2000);
157 } while (!ota_over);
158
159 HAL_SleepMs(1000);
160
161do_exit:
162
163 if (NULL != h_ota) {
164 IOT_OTA_Deinit(h_ota);
165 }
166
167 if (NULL != pclient) {
168 IOT_MQTT_Destroy(&pclient);
169 }
170
171 return rc;
172}
编译工程,将bin文件上传到阿里云:
阿里云不支持rbl格式的文件,直接将rt_ota_packaging_tool生成的rbl文件后缀改为bin,上传即可。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/eda8b8504e77b943c1c77402e7119877.png)
最后使用ali_ota_sample命令升级:
![](https://i-blog.csdnimg.cn/blog_migrate/70e43a3ffa487e421ca076f9bb00fbce.png)
3.HTTP OTA和Ymodem OTA
配置ota_downloader软件包
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/73bea0a8e09ba0012c425855f2b85db8.png)
如果暂时没有自己的服务器,可以使用MyWebServer进行测试:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5aa66fab6b20e3e1af9a8513e0448ce1.png)
配置完MyWebServer,可以打开浏览器输入IP地址查看:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f580e57aa602b7911db4719c0307a31b.png)
使用http_ota命令进行http_ota升级:
![](https://i-blog.csdnimg.cn/blog_migrate/224aca0801b34674c907fbe6a8012722.png)
使用ymodem_ota命令进行ymodem_ota升级:
![](https://i-blog.csdnimg.cn/blog_migrate/b81eb3e4e32c04663ff7c3c07b58d852.png)
4.不使用APP进行升级
rt-fota集成了ymodem_ota,上电短按恢复出厂设置按钮即可进入rt-fota命令行模式,通过ymodem_ota命令即可进行升级:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/bb52e7fa8c29c7a4a9c9e234e2150f93.png)
你可以添加微信17775982065为好友,注明:公司+姓名,拉进 RT-Thread 官方微信交流群!
RT-Thread
让物联网终端的开发变得简单、快速,芯片的价值得到最大化发挥。Apache2.0协议,可免费在商业产品中使用,不需要公布源码,无潜在商业风险。
长按二维码,关注我们
点击阅读原文,进入RT-Thread 官网
点个“在看”,让知识流行起来
“在看”的小可爱永远十八岁!
“在看”的小可爱永远十八岁!