RK3588平台双存储(SPI+PCIE)OTA升级方案教学文档 电子说
在嵌入式设备中,单一存储介质可能存在容量限制或可靠性风险。RK3588 平台的双存储 OTA 升级方案支持SPI(如 SPI NAND/NOR)与 PCIE 存储(如 PCIE SSD) 混合部署场景,通过统一升级引擎实现跨存储设备的固件管理,解决多存储介质下的升级兼容性问题,同时保障升级过程的安全性与可靠性。
•混合存储支持:同时适配 SPI(MTD 设备)与 PCIE(块设备)存储,支持不同类型分区独立升级。
•固件格式扩展:新增多存储固件格式,兼容原有单存储固件。
•精细化存储识别:每个分区独立标记存储类型(MTD / 非 MTD),替代全局判断。
•安全校验增强:针对不同存储类型优化校验逻辑,确保数据完整性。
开启升级功能并指定新升级引擎,确保编译时包含必要组件:
|
# 开启升级相关功能
BR2_PACKAGE_RECOVERY=y
# 使用新升级程序(替代原有流程)
BR2_PACKAGE_RECOVERY_USE_UPDATEENGINE=y
# 编译recovery二进制文件
BR2_PACKAGE_RECOVERY_RECOVERYBIN=y
# 编译新升级引擎二进制文件
BR2_PACKAGE_RECOVERY_UPDATEENGINEBIN=y
# 关闭UI(适用于无显示场景)
BR2_PACKAGE_RECOVERY_NO_UI=y
|
为兼容双存储升级引擎,将 glibc 版本从 2.38 降级至 2.31:
|
# 原版本
# GLIBC_VERSION = 2.38-27-g750a45a783906a19591fb8ff6b7841470f1f5701
# 调整后版本
GLIBC_VERSION = 2.31-54-g6fdf971c9dbf7dac9bea552113fe4694015bbc4d
|
注:版本调整需根据实际兼容性测试结果确认。
定义支持的存储类型,包含 SPI 与 PCIE:
|
typedef enum {
STORAGE_FLASH_CODE = 1<<0, // 闪存
STORAGE_EMMC_CODE = 1<<1, // eMMC
STORAGE_SD0_CODE = 1<<2, // SD卡0
STORAGE_SD1_CODE = 1<<3, // SD卡1
STORAGE_SPINOR_CODE = 1<<9, // SPI NOR(MTD设备)
STORAGE_SPINAND_CODE = 1<<8, // SPI NAND(MTD设备)
STORAGE_USB_CODE = 1<<7, // USB存储
STORAGE_PCIE_CODE = 1<<11 // PCIE存储(块设备)
// 其他存储类型...
} STORAGE_CODE;
|
通过标签区分固件类型:
|
// 多存储固件标签(SPI+PCIE等混合存储)
#define SSFW_TAG 0x57465353
// 普通单存储固件标签
#define RKFW_TAG 0x57464B52
|
双存储固件采用分层打包结构,外层为容器,内层包含各存储设备的独立固件:
|
update_ssfw.img(外层容器)
├── STORAGE_FW_HDR(头部,4KB)
│ ├── tag: SSFW_TAG(标识多存储固件)
│ ├── head_size: 头部大小
│ ├── entry_count: 存储设备数量(如2个:SPI和PCIE)
│ └── entry_size: 每个存储条目的大小
├── STORAGE_ENTRY(条目表,可变长)
│ ├── [SPI存储条目]
│ │ ├── storage: STORAGE_SPINAND_CODE(存储类型)
│ │ ├── offset: SPI固件在内层的偏移量
│ │ └── size: SPI固件大小
│ └── [PCIE存储条目]
│ ├── storage: STORAGE_PCIE_CODE
│ ├── offset: PCIE固件在内层的偏移量
│ └── size: PCIE固件大小
├── SPI固件(内层,RKFW格式)
└── PCIE固件(内层,RKFW格式)
|
analyticImage函数根据固件标签判断类型,分支处理:
|
int analyticImage(const char *filepath, PRKIMAGE_HDR phdr, PRKIMAGE_STORAGE image_storage, int num) {
// 读取固件头部标签
if (rkimage_tag == SSFW_TAG) {
// 解析多存储固件(SPI+PCIE)
return analyticDualStorageImage(filepath, phdr, image_storage, num);
} else if (rkimage_tag == RKFW_TAG) {
// 解析普通单存储固件
return analyticRKFWImage(filepath, phdr, 0, fileSize);
}
}
|
1.读取外层容器头部,验证 SSFW_TAG;
2.解析条目表,获取 SPI 和 PCIE 固件的偏移量与大小;
3.分别解析内层 SPI 固件和 PCIE 固件(调用analyticRKFWImage);
4.整合所有分区信息,并标记每个分区的存储类型(is_mtd):
◦SPI 存储的分区(如 SPI NAND)标记为is_mtd = true;
◦PCIE 存储的分区标记为is_mtd = false。
将全局存储类型判断改为分区级判断,适配 SPI(MTD)与 PCIE(块设备):
|
// 原逻辑:全局判断是否为MTD设备
// if (is_sdboot || is_usbboot || !isMtdDevice()) {
// 新逻辑:使用当前分区的is_mtd属性
if (is_sdboot || is_usbboot || !pcmd->is_mtd) {
// 块设备操作(如PCIE存储):直接写入/dev/block路径
} else {
// MTD设备操作(如SPI存储):通过mtd-utils工具操作
}
|
为comparefile函数增加is_mtd参数,根据存储类型选择校验方式:
|
// 新增is_mtd参数
bool comparefile(..., bool is_mtd) {
if (is_mtd) {
// MTD设备校验(SPI存储):使用mtd读取接口
checkdata_mtd(dest_path, md5sum_dest, dest_offset, checkSize);
} else {
// 块设备校验(PCIE存储):使用普通文件读取接口
checkdata(dest_path, md5sum_dest, dest_offset, checkSize);
}
}
|
1.升级前解析固件时,通过image_storage记录各分区的is_mtd属性;
2.升级执行时,为每个分区的update_cmd设置is_mtd;
3.调用烧写函数(flash_normal/flash_bootloader)和校验函数(comparefile)时,传入is_mtd参数,确保操作与存储类型匹配。
|
技术点
|
作用
|
实现方式
|
|
多存储固件格式
|
支持 SPI 与 PCIE 固件打包
|
外层 SSFW 容器 + 内层 RKFW 固件
|
|
分区级存储标识
|
区分每个分区的存储类型
|
is_mtd属性(true=SPI,false=PCIE)
|
|
动态烧写适配
|
针对存储类型选择操作接口
|
块设备直接写入 / MTD 设备通过 mtd-utils
|
|
校验逻辑适配
|
确保不同存储类型的校验准确性
|
根据is_mtd选择校验方法
|
1.基础功能测试:分别升级 SPI 和 PCIE 存储的分区,验证单独升级有效性;
2.混合升级测试:同时升级 SPI(如 uboot)和 PCIE(如 rootfs)分区,验证跨存储协同;
3.容错测试:升级中断后重启,检查是否支持断点续传或回滚;
4.兼容性测试:验证对原有单存储固件(RKFW_TAG)的兼容能力。


•升级成功率:≥99.5%(1000 次测试);
•升级速度:SPI NAND(≥8MB/s),PCIE SSD(≥30MB/s);
•校验准确性:100% 识别数据篡改(通过人工修改固件测试)。
本方案通过扩展固件格式、引入分区级存储标识、适配动态烧写与校验逻辑,实现了 RK3588 平台 SPI 与 PCIE 双存储的 OTA 升级。方案兼顾兼容性与灵活性,可满足复杂存储场景下的升级需求,为多存储设备的嵌入式系统提供可靠的固件更新能力。
全部0条评论
快来发表一下你的评论吧 !