0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

RT_Thread OTA组件使用记录

冬至子 来源:goldengrandpa 作者:goldengrandpa 2023-11-20 17:22 次阅读

RT_Thread版本:4.1.0

主控:STM32L471

4G模块:L610模块(AT指令方式)

这周花了一点时间,使用ota_downloader组件实现http_ota升级功能,在使用时遇到了一些坑,特别是到了搭建外网服务器部分,教程一般都是讲到本地使用webserve软件来当http服务器的。所以今天简单整理一下开发思路和我遇到的坑。

此处我只是提供思路以及参考文档链接,根据这些文档就可以实现想要的功能的。

1.制作Bootloader

此处如果不想自己写的话,可以用两个选择。

使用RT_Thread提供的通用bootloader

选择芯片系列,ROMRAM大小,引脚即可自动生成一个bin文件。

1.jpg

优点:

​ 一站式处理,十分简单,资源占用较小

​ 缺点:

​ 闭源,无法看到源代码,不支持QSPI(?)这点不是很确定,目前只支持STM32部分系列

使用Qboot等软件包

优点:

可以看到源代码出现问题可以自己改(个人看重的点),如果使用型号没有适配可以自己适配

缺点:

占用资源相对更大一些

由于本人还是比较看重程序的可控性,出现问题希望自己可以看到代码解决因此就选择Qboot的方案

此处需要注意的是加入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软件包

1.jpg

修改中断向量表和链接脚本

链接脚本修改

MEMORY
{
ROM (rx) : ORIGIN = 0x08010000, LENGTH = 1024k /* 1024KB flash /
RAM (rw) : ORIGIN = 0x20000000, LENGTH = 96k /
96KB sram */
}

中断向量表修改

/* 将中断向量表起始地址重新设置为 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擦除了。

1.jpg

下载后就可以使用RT的rbl打包工具进行固件打包放在服务器中了

打包工具在ota_downloader组件中

打包工具可以选择为固件进行加密,压缩等操作

并且为固件头增加了96字节的头,固件标识rbl头,固件大小,CRC,Hash值用于固件校验

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

由于4G模块连接的外网,本地直接使用webserver是无法访问的,因此我这个白嫖了一个月的阿里云服务器来部署

一开始我是使用了python的Flask框架来写后端程序,但是后面遇到了一些问题,因此就暂时放弃了。

这个加深了一下教训,调试时一定要控制变量,当时我不能确定是STM32程序的问题,还是后端的问题,两头排查还是比较痛苦的

因此这里我建议先使用mywebserver+内网穿透工具来验证stm32的程序。

这里内网穿透我建议用Copolar,免费并且目前仍在提供服务。

之后选择部署在服务器中的话,我这边使用的是Nginx可以很方便的搭建一个http服务器

遇到最大的坑:

在调试过程中发现OTA下载一次之后,想要OTA升级第二次时bootloader就提示app区写入固件失败,但是明明日志中说明Flash擦除成功,为何呢?

使用STM32CubeProg读取Flash时发现确实没有将APP区擦除

在packages/ota_downloader的static int http_ota_fw_download(const char* uri)

经过排查原来我用的芯片Flash使用双Bank模式,可用于备份升级的。

1.jpg

我当时分区的时候没有考虑这一点

#define FAL_PART_TABLE
{
{FAL_PART_MAGIC_WORD, "download", "onchip_flash", 1281024, 2981024, 0},
{FAL_PART_MAGIC_WORD, "app", "onchip_flash", 4261024, 2981024, 0},
{FAL_PART_MAGIC_WORD, "factory", "onchip_flash", 7241024, 2981024, 0}
}

刚好app区是跨bank的,在擦除时其实没有考虑到擦除跨bank的情况,导致擦除失败。

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", 641024, 4481024, 0},
{FAL_PART_MAGIC_WORD, "download", "onchip_flash", 5121024, 2561024, 0},
{FAL_PART_MAGIC_WORD, "factory", "onchip_flash", 7681024, 2561024, 0}
}

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FlaSh
    +关注

    关注

    10

    文章

    1551

    浏览量

    146721
  • OTA
    OTA
    +关注

    关注

    7

    文章

    529

    浏览量

    34615
  • RT-Thread
    +关注

    关注

    31

    文章

    1151

    浏览量

    38915
  • STM32L4
    +关注

    关注

    1

    文章

    42

    浏览量

    9263
  • 4G模块
    +关注

    关注

    1

    文章

    31

    浏览量

    8857
收藏 人收藏

    评论

    相关推荐

    rt_thread(3.0.3)的移植准备工作

    基于正点原子精英版stm32f103zet6进行rt_thread(3.0.3)的移植准备工作安装rt_thread nano 3.0.3 软件包裸机工程添加rt_thread源码RT-Thr
    发表于 08-03 07:44

    如何使用RT_Thread Studio进行点灯?

    如何使用RT_Thread Studio进行点灯?
    发表于 10-12 12:33

    怎么实现RT_thread STM32通用Bootloader做OTA升级?

    怎么实现RT_thread STM32通用Bootloader做OTA升级?
    发表于 11-26 06:19

    如何入门rt_thread

    rt_thread入门时笔记线程实例 空间分配技巧学习资料官方入门视频教程线程实例 空间分配技巧根据不同时间对rtt的认识,记录不同时刻的理解,尽可能展示学习rtt的过程.本笔记会根据使用进度进行
    发表于 01-11 08:13

    RT_Thread Studio进行RT_Thread Setting保存后自己创建的文件夹会消失是何原因

    RT_Thread Studio 进行RT_Thread Setting保存后自己创建的文件夹会消失,在applications中创建了mcu_sdk文件夹,但是进行RT_Thread
    发表于 10-25 10:28

    基于正点原子精英版stm32f103zet6进行rt_thread(3.0.3)的移植

    基于正点原子精英版stm32f103zet6进行rt_thread(3.0.3)的移植准备工作安装rt_thread nano 3.0.3 软件包裸机工程添加rt_thread源码RT-Thr
    发表于 12-05 11:21 0次下载
    基于正点原子精英版stm32f103zet6进行<b class='flag-5'>rt_thread</b>(3.0.3)的移植

    RT-ThreadOTA调试记录

    目录一、测试平台二、过程1.先明白OTA的原理2.搞清楚OTA的原理后,再看rt-threadOTA具体操作过程,先生成通用的Bootloader3.通用bootloader弄完后,
    发表于 12-09 14:51 20次下载
    <b class='flag-5'>RT-Thread</b>的<b class='flag-5'>OTA</b>调试<b class='flag-5'>记录</b>

    RTthread线程调度详解

    rt_schedule(void){ struct rt_thread *to_thread; struct rt_thread *from_th
    的头像 发表于 05-19 17:07 2031次阅读

    国民技术N32G4FR通用MCU RT_Thread设备注册应用笔记

    通用 MCU RT_Thread 设备注册应用笔记 简介 本文档主要描述 N32G45x 系列、N32G4FR 系列、N32WB452 系列、 N32G43x 系列、N32L40x 系列
    发表于 11-07 14:53 3次下载

    N32G432系列通用MCU RT_Thread设备注册应用笔记

    N32G432系列通用MCU RT_Thread设备注册应用笔记
    发表于 11-10 19:51 3次下载
    N32G432系列通用MCU <b class='flag-5'>RT_Thread</b>设备注册应用笔记

    N32L43x系列通用MCU RT_Thread设备注册应用笔记

    N32L43x系列通用MCU RT_Thread设备注册应用笔记
    发表于 11-10 19:51 0次下载
    N32L43x系列通用MCU <b class='flag-5'>RT_Thread</b>设备注册应用笔记

    N32G4FR系列通用MCU RT_Thread使用指南

    N32G4FR系列通用MCU RT_Thread使用指南
    发表于 11-11 21:50 2次下载
    N32G4FR系列通用MCU <b class='flag-5'>RT_Thread</b>使用指南

    N32G457系列通用MCU RT_Thread使用指南

    N32G457系列通用MCU RT_Thread使用指南
    发表于 11-11 21:50 0次下载
    N32G457系列通用MCU <b class='flag-5'>RT_Thread</b>使用指南

    N32G455系列通用MCU RT_Thread使用指南

    N32G455系列通用MCU RT_Thread使用指南
    发表于 11-11 21:50 1次下载
    N32G455系列通用MCU <b class='flag-5'>RT_Thread</b>使用指南

    N32G452系列通用MCU RT_Thread使用指南

    N32G452系列通用MCU RT_Thread使用指南
    发表于 11-11 21:50 3次下载
    N32G452系列通用MCU <b class='flag-5'>RT_Thread</b>使用指南