Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
http_ota
ota在线升级
RT_Thread OTA组件使用记录
发布于 2023-11-19 13:11:09 浏览:1644
订阅该版
[tocm] ####
RT_Thread OTA组件使用记录
RT_Thread版本:4.1.0 主控:STM32L471 4G模块:L610模块(AT指令方式) 这周花了一点时间,使用ota_downloader组件实现http_ota升级功能,在使用时遇到了一些坑,特别是到了搭建外网服务器部分,教程一般都是讲到本地使用webserve软件来当http服务器的。所以今天简单整理一下开发思路和我遇到的坑。 此处我只是提供思路以及参考文档链接,根据这些文档就可以实现想要的功能的。 ##### 1.制作Bootloader 此处如果不想自己写的话,可以用两个选择。 - 使用RT_Thread提供的通用bootloader 参考资料: ``` https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/application-note/system/rtboot/an0028-rtboot ``` 选择芯片系列,ROM,RAM大小,引脚即可自动生成一个bin文件。 ![1700322420447.png](https://oss-club.rt-thread.org/uploads/20231119/8e0dc55ad5aa7db13c89ed10b439eb8f.png.webp) 优点: 一站式处理,十分简单,资源占用较小 缺点: 闭源,无法看到源代码,不支持QSPI(?)这点不是很确定,目前只支持STM32部分系列 - 使用Qboot等软件包 参考链接: ``` https://gitee.com/qiyongzhong0/rt-thread-qboot/ ``` 优点: 可以看到源代码出现问题可以自己改(个人看重的点),如果使用型号没有适配可以自己适配 缺点: 占用资源相对更大一些 由于本人还是比较看重程序的可控性,出现问题希望自己可以看到代码解决因此就选择Qboot的方案 Qboot使用方法直接参考下面链接的即可 ``` https://gitee.com/qiyongzhong0/rt-thread-qboot/blob/master/doc/QBoot%E4%BD%BF%E7%94%A8%E6%8C%87%E5%AF%BC.md ``` 此处需要注意的是加入FAL组件后,发现没有添加drv_flash_l4.c是因为没有在Kconfig中增加 ``` menu "On-chip Peripheral Drivers" config BSP_USING_ON_CHIP_FLASH bool "Enable on-chip FLASH" default y ``` 此处已经默认使能了,直接`scons --target=cmake`即可 ##### 2.APP程序 此处主要使能ota_downloader软件包 ![1700364294816.png](https://oss-club.rt-thread.org/uploads/20231119/1deb1f99f2ddd1e71b12572e10802987.png) 修改中断向量表和链接脚本 链接脚本修改 ``` MEMORY { ROM (rx) : ORIGIN = 0x08010000, LENGTH = 1024k /* 1024KB flash */ RAM (rw) : ORIGIN = 0x20000000, LENGTH = 96k /* 96KB sram */ } ``` 中断向量表修改 ```c /* 将中断向量表起始地址重新设置为 app 分区的起始地址 */ static int ota_app_vtor_reconfig(void) { #define NVIC_VTOR_MASK 0xFFFFFF80 #define RT_APP_PART_ADDR (0x08000000 + 64*1024)//app partition begin address /* 根据应用设置向量表 */ SCB->VTOR = RT_APP_PART_ADDR & NVIC_VTOR_MASK; return 0; } INIT_BOARD_EXPORT(ota_app_vtor_reconfig); ``` 之后如果使用ST-Link的话可以选择STM32CubeProg指定地址烧录固件 或者可以使用Jlink使用J-Flash进行烧录 需要注意此处烧录起始地址为app区地址,不要把bootloader擦除了。 ![1700364630837.png](https://oss-club.rt-thread.org/uploads/20231119/5b75439e0fe406718801c90202a0228d.png.webp) 下载后就可以使用RT的rbl打包工具进行固件打包放在服务器中了 打包工具在ota_downloader组件中 ``` https://github.com/RT-Thread-packages/ota_downloader/tree/master/tools/ota_packager ``` 打包工具可以选择为固件进行加密,压缩等操作 并且为固件头增加了96字节的头,固件标识rbl头,固件大小,CRC,Hash值用于固件校验 rbl头的具体内容如下 引用自:[RT-Thread-基于nano的通用Bootloader框架(兼容官方打包加密软件)RT-Thread问答社区 - RT-Thread](https://club.rt-thread.org/ask/question/7f86c42e3d013915.html) ``` typedef struct { char type[4]; /* RBL字符头 */ rt_uint16_t fota_algo; /* 算法配置: 表示是否加密或者使用了压缩算法 */ rt_uint8_t fm_time[6]; /* 原始bin文件的时间戳, 6位时间戳, 使用了4字节, 包含年月日信息 */ char app_part_name[16]; /* app执行分区名 */ char download_version[24]; /* 固件代码版本号 */ char current_version[24]; /* 这个域在rbl文件生成时都是一样的,我用于表示app分区当前运行固件的版本号,判断是否固件需要升级 */ rt_uint32_t code_crc; /* 代码的CRC32校验值,它是的打包后的校验值,即rbl文件96字节后的数据 */ rt_uint32_t hash_val; /* 估计这个域是指的原始代码本身的校验值,但不知道算法,无法确认,故在程序中未使用 */ rt_uint32_t raw_size; /* 原始代码的大小 */ rt_uint32_t com_size; /* 打包代码的大小 */ rt_uint32_t head_crc; /* rbl文件头的CRC32校验值,即rbl文件的前96字节 */ } rt_fota_part_head, *rt_fota_part_head_t ———————————————— 版权声明:本文为RT-Thread论坛用户「Spunky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://club.rt-thread.org/ask/question/7f86c42e3d013915.html ``` 由于4G模块连接的外网,本地直接使用webserver是无法访问的,因此我这个白嫖了一个月的阿里云服务器来部署 一开始我是使用了python的Flask框架来写后端程序,但是后面遇到了一些问题,因此就暂时放弃了。 **这个加深了一下教训,调试时一定要控制变量,当时我不能确定是STM32程序的问题,还是后端的问题,两头排查还是比较痛苦的** 因此这里我建议先使用mywebserver+内网穿透工具来验证stm32的程序。 这里内网穿透我建议用Copolar,免费并且目前仍在提供服务。 具体使用方法参考链接如下: ``` https://www.cpolar.com/docs ``` 之后选择部署在服务器中的话,我这边使用的是Nginx可以很方便的搭建一个http服务器 参考链接如下,按照该文章可以实现文件服务器的功能。 ``` https://blog.csdn.net/datadev_sh/article/details/83819791#:~:text=%E6%90%AD%E5%BB%BA%E6%96%87%E4%BB%B6%E6%9C%8D%E5%8A%A1%E5%99%A8%201%201.%E6%94%B9%E4%B8%BAroot%E7%94%A8%E6%88%B7%20%E5%8E%9F%E6%9D%A5%E7%9A%84nginx.conf%E9%87%8C%EF%BC%8C%E7%AC%AC%E4%B8%80%E8%A1%8C%E6%98%AF%20user%20ngix%3B%20%23%20%E4%B8%8D%E5%90%8C%E7%89%88%E6%9C%AC%E7%9A%84%E4%B8%8D%E4%B8%80%E6%A0%B7,pid%20%2Frun%2Fnginx.pid%3B%20%20%23%20Load%20dynamic%20modules.%20 ``` ##### 遇到最大的坑: 在调试过程中发现OTA下载一次之后,想要OTA升级第二次时bootloader就提示app区写入固件失败,但是明明日志中说明Flash擦除成功,为何呢? 使用STM32CubeProg读取Flash时发现确实没有将APP区擦除 在packages/ota_downloader的`static int http_ota_fw_download(const char* uri)` 经过排查原来我用的芯片Flash使用双Bank模式,可用于备份升级的。 ![1700369735503.png](https://oss-club.rt-thread.org/uploads/20231119/60eb76358609487bbe28e7dfc731d9b1.png.webp) 我当时分区的时候没有考虑这一点 ``` #define FAL_PART_TABLE \ { \ {FAL_PART_MAGIC_WORD, "download", "onchip_flash", 128*1024, 298*1024, 0}, \ {FAL_PART_MAGIC_WORD, "app", "onchip_flash", 426*1024, 298*1024, 0}, \ {FAL_PART_MAGIC_WORD, "factory", "onchip_flash", 724*1024, 298*1024, 0} } ``` 刚好app区是跨bank的,在擦除时其实没有考虑到擦除跨bank的情况,导致擦除失败。 ```c int stm32_flash_erase(rt_uint32_t addr, size_t size) { rt_err_t result = RT_EOK; uint32_t FirstPage = 0, NbOfPages = 0, BankNumber = 0; uint32_t PAGEError = 0; if ((addr + size) > STM32_FLASH_END_ADDRESS) { LOG_E("ERROR: erase outrange flash size! addr is (0x%p)\n", (void*)(addr + size)); return -RT_EINVAL; } /*Variable used for Erase procedure*/ FLASH_EraseInitTypeDef EraseInitStruct; /* Unlock the Flash to enable the flash control register access *************/ HAL_FLASH_Unlock(); /* Clear OPTVERR bit set on virgin samples */ __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR | FLASH_FLAG_PGSERR); /* Get the 1st page to erase */ FirstPage = GetPage(addr); /* Get the number of pages to erase from 1st page */ NbOfPages = GetPage(addr + size - 1) - FirstPage + 1; /* Get the bank */ BankNumber = GetBank(addr); /* Fill EraseInit structure*/ EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.Banks = BankNumber; EraseInitStruct.Page = FirstPage; EraseInitStruct.NbPages = NbOfPages; if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) { result = -RT_ERROR; goto __exit; } __exit: HAL_FLASH_Lock(); if (result != RT_EOK) { return result; } LOG_D("erase done: addr (0x%p), size %d", (void*)addr, size); return size; } ``` 目前简单的解决办法是修改分区,然后分区跨bank,之后有空的话可以提个PR修复一下。 ``` #define FAL_PART_TABLE \ { \ {FAL_PART_MAGIC_WORD, "app", "onchip_flash", 64*1024, 448*1024, 0}, \ {FAL_PART_MAGIC_WORD, "download", "onchip_flash", 512*1024, 256*1024, 0}, \ {FAL_PART_MAGIC_WORD, "factory", "onchip_flash", 768*1024, 256*1024, 0} \ } ```
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
goldengrandpa
这家伙很懒,什么也没写!
文章
11
回答
19
被采纳
2
关注TA
发私信
相关文章
1
OTA 片上FLASH擦除失败
2
请教一下用私有协议数据包进行OTA的具体的实现流程
3
OTA跳转后基于RTT的app运行失败
4
使用finsh 进行ota成功,线程里开ota失败
5
http_ota 每次下载一半就断线
6
bootloader跳转到app无法正常运行
7
针对腾讯云IOT的软件包OTAbug功能反馈
8
自己写的bootloader无法正常升级基于RTT的程序
9
OTA升级,APP程序下载问题
10
bootloader下载APP后不能正常跳转
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
a1012112796
20
个答案
3
次被采纳
张世争
11
个答案
3
次被采纳
踩姑娘的小蘑菇
7
个答案
3
次被采纳
rv666
9
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
RTT_逍遥
1
篇文章
6
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部