谷动谷力

标题: 基于 STM32 的开源 Bootloader 框架 RT-THread RT-FOTA [打印本页]

作者: 鸣涧    时间: 2022-12-9 22:43
标题: 基于 STM32 的开源 Bootloader 框架 RT-THread RT-FOTA
基于 STM32 的开源 Bootloader 框架 RT-THread  RT-FOTA


简介

RT-Thread 官方推出了 STM32 系列单片机的通用 bootloader, 在其网站可以通过网页配置就可以生成 bootloader 的烧录文件,使广大嵌入式工程师不用编写一行代码,就能够轻松完成自己产品的 bootloader 功能。但是由于 RTT 官方的 bootloader 软件 RT-OTA 是商用性质,不公开源码,不仅仅限制了在其他平台的移植,而且也不方便加入产品的特定功能。本人软件水平有限,但是基于对开源精神的崇拜和 RTT 多年的感情,蒙发出利用业余时间编写一款开源的且基于 RTT 系统 bootloader 通用软件,贡献给大家。
由于 RTT 官方推出的 bootloader 名字叫 RT-OTA,因此为了蹭点 RTT 的流量,我这个 bootloader 名字就叫 RT-FOTA。
【RT-FOTA 的需求分析】
【RT-FOTA 主要的功能】

软件开发目录


软件开发目录参照 RTT 的目录形式,如下图所示:
我原本计划添加 SCONS 进行编译,但目前对 SCONS 的使用还不熟悉,下次再实现,因此暂时使用 MDK 完成。
可以看到我并未按照 RTT 官方推荐的使用 MDK 或 cube 生成 rtt-nano 的工程,原因是我有强迫症,感觉 IDE 生成的目录很不爽。

软件配置说明


RT-FOTA 的软件配置仍然集中在 rtconfig.h 中,其中一些. c 文件中有一些默认的配置宏,但可以根据需求进行修改。

/* RT-Thread config file */
#ifndef RT_CONFIG_H__
#define RT_CONFIG_H__

#define RT_THREAD_PRIORITY_MAX          8
#define RT_TICK_PER_SECOND                        1000
#define RT_ALIGN_SIZE                           4
#define RT_NAME_MAX                                           8

/* Kernel Device Object */
#define RT_USING_DEVICE
#define RT_USING_CONSOLE
#define RT_CONSOLEBUF_SIZE          512
#define RT_CONSOLE_DEVICE_NAME      "uart1"
#define RT_VER_NUM                                         0x30102

#define RT_USING_CPU_FFS

/* RT-Thread Components */
#define RT_USING_COMPONENTS_INIT
#define RT_USING_USER_MAIN

#define RT_DEBUG_INIT 0
#define RT_USING_OVERFLOW_CHECK
// #define RT_USING_HOOK
// #define RT_USING_IDLE_HOOK

/* Software timers Configuration */
#define RT_USING_TIMER_SOFT         0
#if RT_USING_TIMER_SOFT == 0
#undef RT_USING_TIMER_SOFT
#endif

#define RT_TIMER_THREAD_PRIO                4
#define RT_TIMER_THREAD_STACK_SIZE        512
#define RT_TIMER_TICK_PER_SECOND        100



/* IPC(Inter-process communication) Configuration */
#define RT_USING_SEMAPHORE
#define RT_USING_MUTEX
//#define RT_USING_EVENT
//#define RT_USING_MAILBOX
//#define RT_USING_MESSAGEQUEUE

/* Memory Management Configuration */
#define RT_USING_HEAP
#define RT_USING_MEMHEAP
#define RT_USING_SMALL_MEM

/* Finsh Configuration */
#define RT_USING_FINSH
#define FINSH_USING_MSH
#define FINSH_USING_MSH_ONLY
#define __FINSH_THREAD_PRIORITY     5
#define FINSH_THREAD_PRIORITY       (RT_THREAD_PRIORITY_MAX / 8 * __FINSH_THREAD_PRIORITY + 1)
#define FINSH_THREAD_STACK_SIZE     2048
#define FINSH_USING_HISTORY
#define FINSH_HISTORY_LINES                5
#define FINSH_USING_SYMTAB
#define FINSH_USING_AUTH                        /* 可配置 FINSH 的 authencation 功能, 防止随意使用 FINSH */
#define FINSH_DEFAULT_PASSWORD                 "radiation"
#define FINSH_PASSWORD_MIN                        6
#define FINSH_PASSWORD_MAX                         16

/* Device Drivers */
#define RT_USING_PIN
#define RT_USING_SERIAL
// #define RT_SERIAL_USING_DMA
#define RT_USING_RTC
#define RT_USING_SPI
#define RT_USING_SFUD
#define RT_SFUD_USING_SFDP
#define RT_SFUD_USING_FLASH_INFO_TABLE
#define RT_USING_WDT

/* RTT 组件配置 */
/* fal package */
#define PKG_USING_FAL
#define FAL_DEBUG_CONFIG
#define FAL_DEBUG 0
#define FAL_PART_HAS_TABLE_CFG
#define FAL_USING_SFUD_PORT
#define FAL_USING_NOR_FLASH_DEV_NAME         "nor_flash0"
#define PKG_USING_FAL_LATEST_VERSION
#define PKG_FAL_VER_NUM                                 0x99999

/* Tinycrypt package */
#define TINY_CRYPT_AES

/* Compress package */
#define QLZ_COMPRESSION_LEVEL        3

/* Hardware Drivers Config */
#define SOC_FAMILY_STM32
#define SOC_SERIES_STM32F4
#define SOC_STM32F407ZE

/* On-chip Peripheral Drivers */
#define BSP_USING_GPIO
#define BSP_USING_ON_CHIP_FLASH
#define BSP_USING_ONCHIP_RTC
#define BSP_USING_UART
#define BSP_USING_UART1
#define BSP_USING_SPI
#define BSP_USING_SPI1

/* Onboard Peripheral Drivers */
#define BSP_DATAFALSH_CS_PIN 30

/* Board extended module Drivers */
#define BSP_RS485_DIR_PIN 52

/* RT-FOTA module define */
#define RT_FOTA_SW_VERSION      "1.0.0"

/* Enable Ymodem OTA */
#define PKG_USING_YMODEM_OTA

/* 分区名字可以根据自己的需求而定 */
/* FOTA application partition name */
#ifndef RT_FOTA_APP_PART_NAME
#define RT_FOTA_APP_PART_NAME   "app"
#endif
/* FOTA download partition name */
#ifndef RT_FOTA_FM_PART_NAME
#define RT_FOTA_FM_PART_NAME    "fm_area"
#endif
/* FOTA default partition name */
#ifndef RT_FOTA_DF_PART_NAME
#define RT_FOTA_DF_PART_NAME    "df_area"
#endif

/* 此两项密码必须与 RTT 的打包软件设置一致 */
/* AES256 encryption algorithm option */
#define RT_FOTA_ALGO_AES_IV          "0123456789ABCDEF"
#define RT_FOTA_ALGO_AES_KEY         "0123456789ABCDEF0123456789ABCDEF"
#endif

RBL 文件说明

使用过 RTT 官方的 RT-OTA 组件的朋友都知道,下载的不是 bin 文件,而是需要通过 RTT 打包软件 “装饰” 成 rbl 文件之后,才能被 RT-OTA 识别。
RTT 的打包软件可以设置代码加密和压缩,其配置信息都存在 rbl 文件前 96 字节中:

rt-fota />fota show fm_area 0 96
00000000: 52 42 4C 00 00 02 00 00 5E A9 A4 5D 61 70 70 00
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 31 2E 30 2E
00000020: 36 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000030: 00 00 00 00 31 2E 30 2E 36 00 00 00 00 00 00 00
00000040: 00 00 00 00 00 00 00 00 00 00 00 00 43 33 29 0A
00000050: 47 08 F6 DA 84 BB 00 00 1C 84 00 00 C4 3D E3 B5


其具体含义如下:

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-FOTA 开机界面如下图:

可以看出使用了 RTT 的 SFUD 和 FAL 组件,同时列出了分区变信息。
RT-FOTA 源码公开,你想怎么改就怎么改, 不在受限制:)
最后一行是表示在 5 秒钟内,按下 Enter 键,即 0x0d,就可以进入命令行模式:

由于 FINSH 具备 authencation 功能,可以设置 shell 密码。具体详见 RTT 相关文档。

命令行模式


RT-FOTA 的命令行模式使用的 RTT 的 FINSH 组件, 除了 RTT 系统自带命令外,还增加 fota 和 ymdown 命令:
**fota 命令 **
键入 fota 命令后回车即可看到帮助命令:

rt-fota />fota
Usage:
fota probe                       - probe RBL file of partiton
fota show partition addr size    - show 'size' bytes starting at 'addr'
fota clone des_part src_part     - clone src partition to des partiton
fota exec                        - execute application program

probe 参数可以打印出当分区的 RBL 信息:

rt-fota />fota probe
[I/fota] ===== RBL of fm_area partition =====
[I/fota] | App partition name |         app |
[I/fota] | Algorithm mode     |  AES && QLZ |
[I/fota] | Firmware version   |       1.0.3 |
[I/fota] | Code raw size      |       48004 |
[I/fota] | Code package size  |       33824 |
[I/fota] | Build Timestamp    |  1571072350 |
[I/fota] ===== RBL of df_area partition =====
[I/fota] | App partition name |         app |
[I/fota] | Algorithm mode     |  AES && QLZ |
[I/fota] | Firmware version   |       1.0.3 |
[I/fota] | Code raw size      |       48004 |
[I/fota] | Code package size  |       33824 |
[I/fota] | Build Timestamp    |  1571072350 |


这里列出了 fm_area 和 df_area 分区中 RBL 文件的主要信息项, 便于开发者查询:
App partition name: 指的是 RTT 打包文件时设置的分区名
Algorithm mode : 指的是 RTT 打包文件使用那些算法:AES256/Quicklz/Fastlz
Firmware version : 指的是 RTT 打包文件设置的固件版本号
Code raw size : 指的代码原始大小
Code package size : 指的代码打包后的大小
Build Timestamp : 指的代码生成的时间戳
show 参数可以显示分区的具体实际数据,方便调试与检查:

rt-fota />fota show app 0 9600000000: C0 08 00 20 E5 57 02 08 5D 04 02 08 5F 04 02 0800000010: 63 04 02 08 67 04 02 08 6B 04 02 08 00 00 00 0000000020: 00 00 00 00 00 00 00 00 00 00 00 00 6F 04 02 0800000030: 71 04 02 08 00 00 00 00 73 04 02 08 75 04 02 0800000040: FF 57 02 08 FF 57 02 08 FF 57 02 08 49 55 02 0800000050: FF 57 02 08 FF 57 02 08 FF 57 02 08 FF 57 02 08

这里列出了 app 分区 0 到 96 字节的数据
**clone 参数是实现分区数据克隆 **

rt-fota />fota clone fm_area df_area
Clone df_area partition to fm_area partition:
#########################################################
#########################################################
#########################################################
#########################################################
############################
Clone partition success, total 1048576 bytes!


这里是将 df _ area 分区数据完整的克隆岛 fm _ area 中。
**exec 参数是用于执行 app 分区的应用代码 **
rt-fota />fota exec
[I/fota] Implement application now.
LCD ID:5510


**ymdown 命令 **
ymdown 是基于 Ymodem 协议的下载命令,使用 RTT 的 ymodem 和 ymodem _ ota 组件实现,其中将 ymodem _ ota.c 中的 DEFAULT_DOWNLOAD_PART 设置为需要默认使用分区名,即在使用 ymdown 不带参数的情况下就下载到 DEFAULT_DOWNLOAD_PART 分区,也可加分区名作为参数指定下载位置。

rt-fota />ymdown
Default save firmware on download partition.
Warning: Ymodem has started! This operator will not recovery.
Please select the ota firmware file and use Ymodem to send.
CCCCCC
Starting ymodem transfer.  Press Ctrl+C to cancel.
  100%      33 KB    6 KB/s 00:00:05       0 Errors

Download firmware to flash success.
Download firmware verify........[OK]
Reset system and apply new firmware.


下载完成后,会自动复位重新启动,将新固件搬运到 app 分区中:

____ _____      _____ ___  _____  _
|  _ \_   _|    |  ___/ _ \ _   _|/ \
| |_) || |_____ | |_  || ||  | | / _ \
|  _ < | |_____ |  _| ||_||  | |/ ___ \
|_| \_\|_|      |_|   \___/  |_/_/   \_\
2016 - 2019 Copyright by Radiation @ warfalcon
Version: 1.0.0 build Oct 18 2019

[SFUD] Find a Winbond flash chip. Size is 16777216 bytes.
[SFUD] nor_flash0 flash device is initialize success.
[I/FAL] ==================== FAL partition table ====================
[I/FAL] | name    | flash_dev    |   offset   |    length  |
[I/FAL] -------------------------------------------------------------
[I/FAL] | app     | onchip_flash | 0x00020000 | 0x000e0000 |
[I/FAL] | fm_area | nor_flash0   | 0x00000000 | 0x00100000 |
[I/FAL] | df_area | nor_flash0   | 0x00100000 | 0x00100000 |
[I/FAL] =============================================================
[I/FAL] RT-Thread Flash Abstraction Layer (V0.4.0) initialize success.
Please press [Enter] key into shell mode in 5 secs:
[I/fota] Partition[app] erase start:
[I/fota] Start to copy firmware from fm_area to app partition:
############
[I/fota] Upgrade success, total 48004 bytes.
[I/fota] Copy firmware version Success!
[I/fota] Implement application now.
LCD ID:5510


出厂固件恢复

恢复出厂固件的方式比较多,本人多年的工程实践经验,倾向于使用外部按键长按后进行出厂固件恢复。出厂固件存储在 df _ area 分区中(分区名在代码中任意设置),长按按键 10s 后 (长按时间在代码中任意设置),RT-FOTA 会自动解密解压 df _ area 分区代码,并搬运到 app 分区进行执行。

Default firmware key pressed:
>>>>>>>>>>
[I/fota] Partition[app] erase start:
[I/fota] Start to copy firmware from df_area to app partition:
############
[I/fota] Upgrade success, total 48004 bytes.
[I/fota] Implement application now.
LCD ID:5510


RT-FOTA 移植

RT-FOTA 移植很简单,只要 RT-Thread 源码包中有你的平台的 BSP 包即可:)
RT-FOTA 中使用的各种组件的修改也很简单,比如 FAL 和 SFUD 就可以参照 RTT 官方说明,SignalLED 参照源码包里的 README.md 即可。
RT-FOTA 可以直接使用在 RT-Thread 的完整版搭载,只需要将 * rt _ fota.c*、*rt _ fota.h * 和 * rt _ fota_crc.c * 放入工程中即可实现,然后用 env 配置相关组件即可。

编译下载

双击 bootloader.uvprojx 文件,打开 MDK5 工程,编译并下载程序到开发板。
工程默认配置使用 JLINK 仿真器下载程序,点击下载按钮即可下载程序到开发板

运行结果

下载程序成功之后,系统 RT-FOTA 会运行:
连接目标板的串口 1 到 PC , 在终端工具里打开相应的串口(115200-8-1-N),复位设备后,可以看到 RT-FOTA 的输出信息:
____ _____      _____ ___  _____  _
|  _ \_   _|    |  ___/ _ \ _   _|/ \
| |_) || |_____ | |_  || ||  | | / _ \
|  _ < | |_____ |  _| ||_||  | |/ ___ \
|_| \_\|_|      |_|   \___/  |_/_/   \_\
2016 - 2019 Copyright by Radiation @ warfalcon
Version: 1.0.0 build Oct 18 2019

[SFUD] Find a Winbond flash chip. Size is 16777216 bytes.
[SFUD] nor_flash0 flash device is initialize success.
[I/FAL] ==================== FAL partition table ====================
[I/FAL] | name    | flash_dev    |   offset   |    length  |
[I/FAL] -------------------------------------------------------------
[I/FAL] | app     | onchip_flash | 0x00020000 | 0x000e0000 |
[I/FAL] | fm_area | nor_flash0   | 0x00000000 | 0x00100000 |
[I/FAL] | df_area | nor_flash0   | 0x00100000 | 0x00100000 |
[I/FAL] =============================================================
[I/FAL] RT-Thread Flash Abstraction Layer (V0.4.0) initialize success.


注意事项
作者: 鸣涧    时间: 2022-12-9 22:51
gitee源码:https://gitee.com/spunky_973/rt-fota




欢迎光临 谷动谷力 (http://bbs.sunsili.com/) Powered by Discuz! X3.2