RT-Thread的OTA调试记录

目录

一、测试平台

二、过程

1.先明白OTA的原理

2.搞清楚OTA的原理后,再看rt-thread的OTA具体操作过程,先生成通用的Bootloader

3.通用bootloader弄完后,再把OTA软件包移植到应用程序,实现通过串口(或网口)接收固件,并存放到download区域

4.bootloader烧录到板子中了,APP程序也烧录到板子中了,就差download区域的固件了,现在制作升级用的固件


一、测试平台

正点原子探索者(STM32F407VGT6)

二、过程

参考:

RT-Thread 文档中心

1.先明白OTA的原理

1.1)烧录的固件(bin文件)是要烧录到STM32内部Flash中

1.2)然后,STM32启动时,会被引导到从Flash的起始地址(0x8000000)开始运行

1.3)要知道STM32启动后,虽然是从Flash起始地址开始运行,但是在运行中,程序可以控制其跳转到Flash的指定位置继续运行

1.4)基于1.3的“特性”,所以可以人为的将Flash分成不同的区域,存放不同的程序,想运行什么程序就跳转到哪个区域;

1.5)Flash分区域是人为分的,所以根据自己的需求去分,以rt-thread OTA举例,他将Flash分成三个区域:区域1、区域2、区域3,其中区域1的起始地址是Flash的起始地址,也就是说STM32上电后会被引导到区域1运行;

1.6)区域1的程序逻辑就是:判断区域3和区域2的固件版本是否一致,一致的话,跳转到区域2运行,不一致的话,将区域3的固件拷贝到区域2,然后重启,又回到判断区域3和区域2的固件版本是否一致,因为重启前拷贝了,所以现在一致,就直接跳转到区域2运行,相当于把区域2的固件升级了。

1.7)所以区域1存放的就是bootloader,区域2存放的是设备运行的应用程序APP,区域3存放的是区域2要升级的固件,区域3就是download

1.8)也就是说,要是想给设备升级,先想办法把固件烧录到区域3-download,然后区域1-bootloader程序就自动把固件升级到区域2-app了;

1.9)至于怎么把固件先搞到区域3-download里面,可以在app运行时接收串口/网口等数据存到区域3-download,或是在bootloader运行时接收串口/网口数据存到区域3-download,这是你自己决定的,你想怎么实现就怎么写程序,思路反正是这样;

1.10)rt-thread的OTA是在APP运行时,接收固件存放到download区域,然后重启运行bootloader,bootloader再将download的固件拷贝替换掉app区域的固件,就升级成功了。

2.搞清楚OTA的原理后,再看rt-thread的OTA具体操作过程,先生成通用的Bootloader

2.1)Bootloader 可以通过网页端在线生成的方式来获取。我们根据自己使用的芯片,填写相关参数,然后点击生成按钮,即可在线生成 Bootloader。

Bootloader 在线获取地址:iot_admin

2.2)新建产品

2.3)如下图,根据自己的MCU填写相关信息,生成bootloader

2.4)生成bootloader(rt-boot.zip)用j-link烧录到开发板

2.5)烧录bootloader后,串口1打印提示信息如下,说明bootloader正常运行

3.通用bootloader弄完后,再把OTA软件包移植到应用程序,实现通过串口(或网口)接收固件,并存放到download区域

3.1)下载rt-thread源码,我下载的是V4.0.3;

3.2)rtt-thread源码适配了多个MCU/开发板,包含多个BSP和libcpu等,但我只想在工程中保留与我用的MCU有关的BSP等文件,所以先生成一个实际项目开发时的工程;

3.3)我用的是正点原子的探索者开发板,在rtt源码中,进入bsp->stm32->stm32f407-atk-explorer目录下,右键进入env工具,输入scons –dist,会生成一个dist文件夹,此文件夹只保留了rtt相关代码和正点原子开发的的bsp等相关文件,可以移植dist到任何目录下进行开发工作,如下图:(注意,在执行scons –dist时,首先保证rt-thread源码放置的路径中没有中文才行

3.4)进入dist-> stm32f407-atk-explorer目录下,使用env工具,进入menuconfig,添加ota_downloader软件包和flash的驱动,过程如下:

选择OTA软件包后,回到主菜单,再配置flash的驱动程序,如下:

3.5)退出menuconfig并保存刚才的配置,然后env工具更新下载软件包到工程中,输入“pkgs --update”,再编译生成mdk5工程,输入“scons –target=mdk5”,如下:

 
3.6)打开mdk5工程,再编译,没有报错,如下:

3.7)然后需要配置fal_cfg.h,就是app程序也要把flash分区域,而且要跟bootloader分的区域相同,所以需要看到懂bootloader的上电打印信息,如下:

3.8)所以app程序中也将flash分成3部分,分别对应bootloader、app、download即可,在drv_flash_f4.c中,将“片上flash”分成了3个flash设备,但是每个flash设备的名称以及空间大小没有与bootloader对应,所以注释掉原代码,重新分配flash,如下:

#if defined(PKG_USING_FAL)

//static int fal_flash_read_16k(long offset, rt_uint8_t *buf, size_t size);
//static int fal_flash_read_64k(long offset, rt_uint8_t *buf, size_t size);
//static int fal_flash_read_128k(long offset, rt_uint8_t *buf, size_t size);

//static int fal_flash_write_16k(long offset, const rt_uint8_t *buf, size_t size);
//static int fal_flash_write_64k(long offset, const rt_uint8_t *buf, size_t size);
//static int fal_flash_write_128k(long offset, const rt_uint8_t *buf, size_t size);

//static int fal_flash_erase_16k(long offset, size_t size);
//static int fal_flash_erase_64k(long offset, size_t size);
//static int fal_flash_erase_128k(long offset, size_t size);

//const struct fal_flash_dev stm32_onchip_flash_16k = { "onchip_flash_16k", STM32_FLASH_START_ADRESS_16K, FLASH_SIZE_GRANULARITY_16K, (16 * 1024), {NULL, fal_flash_read_16k, fal_flash_write_16k, fal_flash_erase_16k} };
//const struct fal_flash_dev stm32_onchip_flash_64k = { "onchip_flash_64k", STM32_FLASH_START_ADRESS_64K, FLASH_SIZE_GRANULARITY_64K, (64 * 1024), {NULL, fal_flash_read_64k, fal_flash_write_64k, fal_flash_erase_64k} };
//const struct fal_flash_dev stm32_onchip_flash_128k = { "onchip_flash_128k", STM32_FLASH_START_ADRESS_128K, FLASH_SIZE_GRANULARITY_128K, (128 * 1024), {NULL, fal_flash_read_128k, fal_flash_write_128k, fal_flash_erase_128k} };

//static int fal_flash_read_16k(long offset, rt_uint8_t *buf, size_t size)
//{
//    return stm32_flash_read(stm32_onchip_flash_16k.addr + offset, buf, size);
//}
//static int fal_flash_read_64k(long offset, rt_uint8_t *buf, size_t size)
//{
//    return stm32_flash_read(stm32_onchip_flash_64k.addr + offset, buf, size);
//}
//static int fal_flash_read_128k(long offset, rt_uint8_t *buf, size_t size)
//{
//    return stm32_flash_read(stm32_onchip_flash_128k.addr + offset, buf, size);
//}

//static int fal_flash_write_16k(long offset, const rt_uint8_t *buf, size_t size)
//{
//    return stm32_flash_write(stm32_onchip_flash_16k.addr + offset, buf, size);
//}
//static int fal_flash_write_64k(long offset, const rt_uint8_t *buf, size_t size)
//{
//    return stm32_flash_write(stm32_onchip_flash_64k.addr + offset, buf, size);
//}
//static int fal_flash_write_128k(long offset, const rt_uint8_t *buf, size_t size)
//{
//    return stm32_flash_write(stm32_onchip_flash_128k.addr + offset, buf, size);
//}

//static int fal_flash_erase_16k(long offset, size_t size)
//{
//    return stm32_flash_erase(stm32_onchip_flash_16k.addr + offset, size);
//}
//static int fal_flash_erase_64k(long offset, size_t size)
//{
//    return stm32_flash_erase(stm32_onchip_flash_64k.addr + offset, size);
//}
//static int fal_flash_erase_128k(long offset, size_t size)
//{
//    return stm32_flash_erase(stm32_onchip_flash_128k.addr + offset, size);
//}


static int fal_flash_read_bl_128k(long offset, rt_uint8_t *buf, size_t size);
static int fal_flash_read_app_128k(long offset, rt_uint8_t *buf, size_t size);
static int fal_flash_read_dl_128k(long offset, rt_uint8_t *buf, size_t size);

static int fal_flash_write_bl_128k(long offset, const rt_uint8_t *buf, size_t size);
static int fal_flash_write_app_128k(long offset, const rt_uint8_t *buf, size_t size);
static int fal_flash_write_dl_128k(long offset, const rt_uint8_t *buf, size_t size);

static int fal_flash_erase_bl_128k(long offset, size_t size);
static int fal_flash_erase_app_128k(long offset, size_t size);
static int fal_flash_erase_dl_128k(long offset, size_t size);

const struct fal_flash_dev stm32_onchip_flash_bl_128k = { "onchip_flash_bl_128k", STM32_FLASH_START_ADRESS_BL_128K, FLASH_SIZE_GRANULARITY_128K, (128 * 1024), {NULL, fal_flash_read_bl_128k, fal_flash_write_bl_128k, fal_flash_erase_bl_128k} };
const struct fal_flash_dev stm32_onchip_flash_app_128k = { "onchip_flash_app_128k", STM32_FLASH_START_ADRESS_APP_128K, FLASH_SIZE_GRANULARITY_128K, (128 * 1024), {NULL, fal_flash_read_app_128k, fal_flash_write_app_128k, fal_flash_erase_app_128k} };
const struct fal_flash_dev stm32_onchip_flash_dl_128k = { "onchip_flash_dl_128k", STM32_FLASH_START_ADRESS_DL_128K, FLASH_SIZE_GRANULARITY_128K, (128 * 1024), {NULL, fal_flash_read_dl_128k, fal_flash_write_dl_128k, fal_flash_erase_dl_128k} };

static int fal_flash_read_bl_128k(long offset, rt_uint8_t *buf, size_t size)
{
    return stm32_flash_read(stm32_onchip_flash_bl_128k.addr + offset, buf, size);
}
static int fal_flash_read_app_128k(long offset, rt_uint8_t *buf, size_t size)
{
    return stm32_flash_read(stm32_onchip_flash_app_128k.addr + offset, buf, size);
}
static int fal_flash_read_dl_128k(long offset, rt_uint8_t *buf, size_t size)
{
    return stm32_flash_read(stm32_onchip_flash_dl_128k.addr + offset, buf, size);
}

static int fal_flash_write_bl_128k(long offset, const rt_uint8_t *buf, size_t size)
{
    return stm32_flash_write(stm32_onchip_flash_bl_128k.addr + offset, buf, size);
}
static int fal_flash_write_app_128k(long offset, const rt_uint8_t *buf, size_t size)
{
    return stm32_flash_write(stm32_onchip_flash_app_128k.addr + offset, buf, size);
}
static int fal_flash_write_dl_128k(long offset, const rt_uint8_t *buf, size_t size)
{
    return stm32_flash_write(stm32_onchip_flash_dl_128k.addr + offset, buf, size);
}

static int fal_flash_erase_bl_128k(long offset, size_t size)
{
    return stm32_flash_erase(stm32_onchip_flash_bl_128k.addr + offset, size);
}
static int fal_flash_erase_app_128k(long offset, size_t size)
{
    return stm32_flash_erase(stm32_onchip_flash_app_128k.addr + offset, size);
}
static int fal_flash_erase_dl_128k(long offset, size_t size)
{
    return stm32_flash_erase(stm32_onchip_flash_dl_128k.addr + offset, size);
}

#endif

3.9)并根据drv_flash_f4.c中的flash设备,修改fal_cfg.h文件,如下:

/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-12-5      SummerGift   first version
 */

#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_

#include <rtthread.h>
#include <board.h>

//#define FLASH_SIZE_GRANULARITY_16K   (4 * 16 * 1024)
//#define FLASH_SIZE_GRANULARITY_64K   (64 * 1024)
//#define FLASH_SIZE_GRANULARITY_128K  (7 * 128 * 1024)

//#define STM32_FLASH_START_ADRESS_16K  STM32_FLASH_START_ADRESS
//#define STM32_FLASH_START_ADRESS_64K  (STM32_FLASH_START_ADRESS_16K + FLASH_SIZE_GRANULARITY_16K)
//#define STM32_FLASH_START_ADRESS_128K (STM32_FLASH_START_ADRESS_64K + FLASH_SIZE_GRANULARITY_64K)

//extern const struct fal_flash_dev stm32_onchip_flash_16k;
//extern const struct fal_flash_dev stm32_onchip_flash_64k;
//extern const struct fal_flash_dev stm32_onchip_flash_128k;

///* flash device table */
//#define FAL_FLASH_DEV_TABLE                                          \
//{                                                                    \
//    &stm32_onchip_flash_16k,                                         \
//    &stm32_onchip_flash_64k,                                         \
//    &stm32_onchip_flash_128k,                                        \
//}
///* ====================== Partition Configuration ========================== */
//#ifdef FAL_PART_HAS_TABLE_CFG

///* partition table */
//#define FAL_PART_TABLE                                                                                                     \
//{                                                                                                                          \
//    {FAL_PART_MAGIC_WROD, "bootloader", "onchip_flash_16k",  0 , FLASH_SIZE_GRANULARITY_16K , 0}, \
//    {FAL_PART_MAGIC_WROD, "param",      "onchip_flash_64k",  0 , FLASH_SIZE_GRANULARITY_64K , 0}, \
//    {FAL_PART_MAGIC_WROD, "app",        "onchip_flash_128k", 0 , FLASH_SIZE_GRANULARITY_128K, 0}, \
//}


#define FLASH_SIZE_GRANULARITY_128K   (128 * 1024)
//#define FLASH_SIZE_GRANULARITY_64K   (64 * 1024)
//#define FLASH_SIZE_GRANULARITY_128K  (7 * 128 * 1024)

#define STM32_FLASH_START_ADRESS_BL_128K    STM32_FLASH_START_ADRESS
#define STM32_FLASH_START_ADRESS_APP_128K   (STM32_FLASH_START_ADRESS_BL_128K + FLASH_SIZE_GRANULARITY_128K)
#define STM32_FLASH_START_ADRESS_DL_128K    (STM32_FLASH_START_ADRESS_APP_128K + FLASH_SIZE_GRANULARITY_128K)

extern const struct fal_flash_dev stm32_onchip_flash_bl_128k;
extern const struct fal_flash_dev stm32_onchip_flash_app_128k;
extern const struct fal_flash_dev stm32_onchip_flash_dl_128k;

/* flash device table */
#define FAL_FLASH_DEV_TABLE                                          \
{                                                                    \
    &stm32_onchip_flash_bl_128k,                                     \
    &stm32_onchip_flash_app_128k,                                    \
    &stm32_onchip_flash_dl_128k,                                     \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG

/* partition table */
#define FAL_PART_TABLE                                                                                                     \
{                                                                                                                          \
    {FAL_PART_MAGIC_WROD, "bootloader", "onchip_flash_bl_128k",  0 , FLASH_SIZE_GRANULARITY_128K , 0}, \
    {FAL_PART_MAGIC_WROD, "app",        "onchip_flash_app_128k",  0 , FLASH_SIZE_GRANULARITY_128K , 0}, \
    {FAL_PART_MAGIC_WROD, "download",   "onchip_flash_dl_128k", 0 , FLASH_SIZE_GRANULARITY_128K, 0}, \
}


#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */

3.10)重新编译程序,没有错误。然后,因为APP是在flash中的0x8020000开始运行,所以修改固件的链接地址为0x8020000,长度为0x20000,如下:

注意:Use Memory Layout from TargetDialog不要勾选,如果勾选了,配置Target中的Read/Only Memory Areas即可,.sct会自动同步配置,但是我试了一下会编译出错,所以还是不勾选直接改.sct吧。

3.11)再修改app的中断向量表地址,我是修改的system_stm32f4xx.c中的向量表基地址偏移字段,为0x20000,如下:

3.12)再修改main.c,将fal初始化,并添加版本信息的打印,如下:

3.13)再编译没有报错,j-link直接下载到板子,查看打印信息为1.0.0,说明bootloader和app都正常运行,如下:

4.bootloader烧录到板子中了,APP程序也烧录到板子中了,就差download区域的固件了,现在制作升级用的固件

4.1)修改main.c中的版本打印信息为1.0.1,如下:

4.2)在生成通用bootloader时,我选择了AES256加密和fastlz算法对编译生成的bin文件进行压缩,所以要写入download区域中的固件也需要提前完成加密和压缩,等bootloader将其拷贝到app区域时会进行解压缩和解密。使用工具rt_ota_packaging_tool.exe(在前面生成的dist目录dist\stm32f407-atk-explorer\packages\ota_downloader-latest\tools\ota_packager)生成最终的固件rtthread.rbl,如下:

4.3)为啥选择固件时知道是选rtthread.bin呢?可以看keil在编译完成后的提示信息,keil在编译完后自动使用fromelf工具将.axf文件转换为.bin文件,指定的bin文件名字就是rtthread.bin。

这个自动生成bin文件是在魔术棒里面设置的,如下:

4.4)将生成的rtthread.rbl文件通过Xshell的y-modem发送到板子,如下:

①在msh>中输入ymodem_ota指令并回车

②然后鼠标右键选择“传输->YMODEM(Y)->用YMODEM发送”选择rtthread.rbl文件进行发送

4.5)固件写入到download区域后,设备会自动重启进入bootloader,bootloader对download和APP区域的版本进行比较,发现不同,则将download的固件拷贝到APP,然后重启,再进入bootloader,对download和APP区域的版本进行比较,发现相同,则跳转到APP运行,即开始运行新的版本V1.0.1固件了,升级成功,如下:

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

izar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值